/* * %CopyrightBegin% * * Copyright Ericsson AB 1996-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% * */ #ifdef __WIN32__ #include #include #include #include #include #include #include #include #include static unsigned long param_zero = 0; static unsigned long param_one = 1; #define SET_BLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_zero) #define SET_NONBLOCKING(Sock) ioctlsocket((Sock),FIONBIO,¶m_one) #define ERROR_WOULDBLOCK WSAEWOULDBLOCK #define ERROR_TIMEDOUT WSAETIMEDOUT #define ERROR_INPROGRESS WSAEINPROGRESS #define GET_SOCKET_ERROR() WSAGetLastError() #define MEANS_SOCKET_ERROR(Ret) ((Ret == SOCKET_ERROR)) #define IS_INVALID_SOCKET(Sock) ((Sock) == INVALID_SOCKET) #elif VXWORKS #include #include #include #include #include #include #include #include #include #include static unsigned long param_zero = 0; static unsigned long param_one = 1; #define SET_BLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_zero) #define SET_NONBLOCKING(Sock) ioctl((Sock),FIONBIO,(int)¶m_one) #define ERROR_WOULDBLOCK EWOULDBLOCK #define ERROR_TIMEDOUT ETIMEDOUT #define ERROR_INPROGRESS EINPROGRESS #define GET_SOCKET_ERROR() (errno) #define MEANS_SOCKET_ERROR(Ret) ((Ret) == ERROR) #define IS_INVALID_SOCKET(Sock) ((Sock) < 0) #else /* other unix */ #include #include #include #include #include #include #include #ifndef EWOULDBLOCK #define ERROR_WOULDBLOCK EAGAIN #else #define ERROR_WOULDBLOCK EWOULDBLOCK #endif #define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \ fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK) #define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \ fcntl((fd), F_GETFL, 0) | O_NONBLOCK) #define ERROR_TIMEDOUT ETIMEDOUT #define ERROR_INPROGRESS EINPROGRESS #define GET_SOCKET_ERROR() (errno) #define MEANS_SOCKET_ERROR(Ret) ((Ret) < 0) #define IS_INVALID_SOCKET(Sock) ((Sock) < 0) #endif /* common includes */ #include "eidef.h" #include #include #include #include "ei_portio.h" #include "ei_internal.h" #ifdef HAVE_SYS_TIME_H #include #else #include #endif #ifdef HAVE_WRITEV static int ei_writev_t(int fd, struct iovec *iov, int iovcnt, unsigned ms) { int res; if (ms != 0) { fd_set writemask; struct timeval tv; tv.tv_sec = (time_t) (ms / 1000U); ms %= 1000U; tv.tv_usec = (time_t) (ms * 1000U); FD_ZERO(&writemask); FD_SET(fd,&writemask); switch (select(fd+1, NULL, &writemask, NULL, &tv)) { case -1 : return -1; /* i/o error */ case 0: return -2; /* timeout */ default: if (!FD_ISSET(fd, &writemask)) { return -1; /* Other error */ } } } res = writev(fd, iov, iovcnt); return (res < 0) ? -1 : res; } int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms) { int i; int done; struct iovec *iov_base = NULL; struct iovec *current_iov; int current_iovcnt; int sum; for (sum = 0, i = 0; i < iovcnt; ++i) { sum += iov[i].iov_len; } if (ms != 0U) { SET_NONBLOCKING(fd); } current_iovcnt = iovcnt; current_iov = (struct iovec *) iov; done = 0; for (;;) { i = ei_writev_t(fd, current_iov, current_iovcnt, ms); if (i <= 0) { /* ei_writev_t should always return at least 1 */ if (ms != 0U) { SET_BLOCKING(fd); } if (iov_base != NULL) { free(iov_base); } return (i); } done += i; if (done < sum) { if (iov_base == NULL) { iov_base = malloc(sizeof(struct iovec) * iovcnt); if (iov_base == NULL) { return -1; } memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt); current_iov = iov_base; } while (i > 0) { if (i < current_iov[0].iov_len) { char *p = (char*)current_iov[0].iov_base; current_iov[0].iov_base = p + i; current_iov[0].iov_len -= i; i = 0; } else { i -= current_iov[0].iov_len; current_iov++; current_iovcnt--; } } } else { break; } } if (ms != 0U) { SET_BLOCKING(fd); } if (iov_base != NULL) { free(iov_base); } return (sum); } #endif int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms) { int res; int error; int s_res; struct timeval tv; fd_set writefds; fd_set exceptfds; if (ms == 0) { res = connect(fd, sinp, sin_siz); return (res < 0) ? -1 : res; } else { SET_NONBLOCKING(fd); res = connect(fd, sinp, sin_siz); error = GET_SOCKET_ERROR(); SET_BLOCKING(fd); if (!MEANS_SOCKET_ERROR(res)) { return (res < 0) ? -1 : res; } else { if (error != ERROR_WOULDBLOCK && error != ERROR_INPROGRESS) { return -1; } else { tv.tv_sec = (long) (ms/1000U); ms %= 1000U; tv.tv_usec = (long) (ms * 1000U); FD_ZERO(&writefds); FD_SET(fd,&writefds); FD_ZERO(&exceptfds); FD_SET(fd,&exceptfds); s_res = select(fd + 1, NULL, &writefds, &exceptfds, &tv); switch (s_res) { case 0: return -2; case 1: if (FD_ISSET(fd, &exceptfds)) { return -1; } else { return 0; /* Connect completed */ } default: return -1; } } } } } int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms) { int res; if (ms != 0) { fd_set readmask; struct timeval tv; tv.tv_sec = (time_t) (ms / 1000U); ms %= 1000U; tv.tv_usec = (time_t) (ms * 1000U); FD_ZERO(&readmask); FD_SET(fd,&readmask); switch (select(fd+1, &readmask, NULL, NULL, &tv)) { case -1 : return -1; /* i/o error */ case 0: return -2; /* timeout */ default: if (!FD_ISSET(fd, &readmask)) { return -1; /* Other error */ } } } res = (int) accept(fd,addr,addrlen); return (res < 0) ? -1 : res; } static int ei_read_t(int fd, char* buf, int len, unsigned ms) { int res; if (ms != 0) { fd_set readmask; struct timeval tv; tv.tv_sec = (time_t) (ms / 1000U); ms %= 1000U; tv.tv_usec = (time_t) (ms * 1000U); FD_ZERO(&readmask); FD_SET(fd,&readmask); switch (select(fd+1, &readmask, NULL, NULL, &tv)) { case -1 : return -1; /* i/o error */ case 0: return -2; /* timeout */ default: if (!FD_ISSET(fd, &readmask)) { return -1; /* Other error */ } } } res = readsocket(fd, buf, len); return (res < 0) ? -1 : res; } static int ei_write_t(int fd, const char* buf, int len, unsigned ms) { int res; if (ms != 0) { fd_set writemask; struct timeval tv; tv.tv_sec = (time_t) (ms / 1000U); ms %= 1000U; tv.tv_usec = (time_t) (ms * 1000U); FD_ZERO(&writemask); FD_SET(fd,&writemask); switch (select(fd+1, NULL, &writemask, NULL, &tv)) { case -1 : return -1; /* i/o error */ case 0: return -2; /* timeout */ default: if (!FD_ISSET(fd, &writemask)) { return -1; /* Other error */ } } } res = writesocket(fd, buf, len); return (res < 0) ? -1 : res; } /* * Fill buffer, return buffer length, 0 for EOF, < 0 (and sets errno) * for error. */ int ei_read_fill_t(int fd, char* buf, int len, unsigned ms) { int i,got=0; do { i = ei_read_t(fd, buf+got, len-got, ms); if (i <= 0) return (i); got += i; } while (got < len); return (len); } /* read_fill */ int ei_read_fill(int fd, char* buf, int len) { return ei_read_fill_t(fd, buf, len, 0); } /* write entire buffer on fd or fail (setting errno) */ int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms) { int i,done=0; if (ms != 0U) { SET_NONBLOCKING(fd); } do { i = ei_write_t(fd, buf+done, len-done, ms); if (i <= 0) { if (ms != 0U) { SET_BLOCKING(fd); } return (i); } done += i; } while (done < len); if (ms != 0U) { SET_BLOCKING(fd); } return (len); } int ei_write_fill(int fd, const char *buf, int len) { return ei_write_fill_t(fd, buf, len, 0); }