diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface/src/misc/ei_portio.c | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src/misc/ei_portio.c')
-rw-r--r-- | lib/erl_interface/src/misc/ei_portio.c | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c new file mode 100644 index 0000000000..b73ebebbe1 --- /dev/null +++ b/lib/erl_interface/src/misc/ei_portio.c @@ -0,0 +1,377 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + + */ +#ifdef __WIN32__ +#include <winsock2.h> +#include <windows.h> +#include <process.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> +#include <errno.h> + +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 <vxWorks.h> +#include <hostLib.h> +#include <ifLib.h> +#include <sockLib.h> +#include <taskLib.h> +#include <inetLib.h> +#include <selectLib.h> +#include <sys/types.h> +#include <ioLib.h> +#include <unistd.h> + +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 <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ei_portio.h" +#include "ei_internal.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#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); + memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt); + current_iov = iov_base; + } + while (i > 0) { + if (i < current_iov[0].iov_len) { + 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); +} + |