/*
 * socketutil.cpp
 *
 */
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/select.h>
#include <netinet/in.h>

#include "HA_log.h"
#include "socketutil.h"

ssize_t readsock(const int fd, const void *buf, const size_t len, timeval *timeout, int *isTimeOutOccur)
{
	ssize_t read_cnt = 0;
	ssize_t remain = len;
	unsigned char *tmpbuf = reinterpret_cast<unsigned char *>(const_cast<void *>(buf));

	if (isTimeOutOccur != NULL) {
		*isTimeOutOccur = 0;
		if (timeout != NULL) {

        RETRY:

			fd_set rfds;
			FD_ZERO(&rfds);
			FD_SET(fd, &rfds);

			int ret = ::select(fd + 1, &rfds, NULL, NULL, timeout);
			if (ret < 0) {
				if (errno == EINTR) {
					goto RETRY;
				} else {
					LOGE("select Error");
					return(-1);
				}
			} else if (ret > 0) {
				// OK
			} else {
				// timeout
				*isTimeOutOccur = 1;
				return(0);
			}


		}
	}

	while(remain > 0) {
		ssize_t tmp = ::recv(fd, reinterpret_cast<void *>(tmpbuf), remain, 0);

		switch(tmp) {
		case 0:
			return(read_cnt);
		case -1:
			return(-1);
		default:
			remain -= tmp;
			read_cnt += tmp;
			tmpbuf += tmp;
			break;
		}

	}

	return(read_cnt);

}

ssize_t writesock(const int fd, const void *buf, const size_t len, timeval *timeout, int *isTimeOutOccur)
{

	ssize_t write_cnt = 0;
	ssize_t remain = len;
	unsigned char *tmpbuf = reinterpret_cast<unsigned char *>(const_cast<void *>(buf));

	while(remain > 0) {
		ssize_t tmp = ::send(fd, reinterpret_cast<void *>(tmpbuf), remain, 0);

		switch(tmp) {
		case 0:
			return(write_cnt);
		case -1:
			return(-1);
		default:
			remain -= tmp;
			write_cnt += tmp;
			tmpbuf += tmp;
			break;
		}

	}

	return(write_cnt);
}
