Rev 25220 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1996, 1997 Robert Gentleman and Ross Ihaka* Copyright (C) 1998-2003 Robert Gentleman, Ross Ihaka and the* R Development Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifdef Win32extern void R_ProcessEvents(void);#define R_SelectEx(n,rfd,wrd,efd,tv,ih) select(n,rfd,wrd,efd,tv)#endif#ifdef HAVE_STRINGS_H/* may be needed to define bzero in FD_ZERO (eg AIX) */#include <strings.h>#endif#include <stdlib.h> /* for NULL */#include <limits.h>#include <stdio.h>#include <string.h>#include <sys/types.h>/* #include <errno.h>*/#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "sock.h"static int sock_inited = 0;static int enter_sock(int fd){#ifdef DEBUGprintf("enter_sock(%d)\n", fd);#endifif (fd == -1) return 0; else return fd;}static int close_sock(int fd){return Sock_close(fd, NULL) == -1 ? 0 : 1 ;}static void check_init(void){if (! sock_inited) {#ifdef DEBUGprintf("initing\n");#endifSock_init();sock_inited = 1;}}void in_Rsockopen(int *port){check_init();*port = enter_sock(Sock_open(*port, NULL));}void in_Rsocklisten(int *sockp, char **buf, int *len){check_init();*sockp = enter_sock(Sock_listen(*sockp, *buf , *len, NULL));}void in_Rsockconnect(int *port, char **host){check_init();#ifdef DEBUGprintf("connect to %d at %s\n",*port, *host);#endif*port = enter_sock(Sock_connect(*port, *host, NULL));}void in_Rsockclose(int *sockp){*sockp = close_sock(*sockp);}void in_Rsockread(int *sockp, char **buf, int *maxlen){check_init();#ifdef DEBUGprintf("Reading from %d\n",*sockp);#endif*maxlen = (int) Sock_read(*sockp, *buf, *maxlen, NULL);}void in_Rsockwrite(int *sockp, char **buf, int *start, int *end, int *len){ssize_t n;if (*end > *len)*end = *len;if (*start < 0)*start = 0;if (*end < *start){*len = -1;return;}check_init();#ifdef DEBUGprintf("writing %s to %d", *buf, *sockp);#endifn = Sock_write(*sockp, *buf + *start, *end - *start, NULL);*len = (int) n;}/* --------- for use in socket connections ---------- */#ifdef HAVE_SOCKETS#include <R_ext/R-ftp-http.h>#ifdef Win32#include <winsock.h>#include <io.h>#define EWOULDBLOCK WSAEWOULDBLOCK#define EINPROGRESS WSAEINPROGRESS#endif#ifdef HAVE_BSD_NETWORKING# include <netdb.h># include <sys/socket.h># include <netinet/in.h>#endif#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif#ifdef HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifndef Win32#define closesocket(s) close(s)#define SOCKET int#endifstatic int socket_errno(void){#ifdef Win32return(WSAGetLastError());#elsereturn(errno);#endif}#ifdef Unix#include <R_ext/eventloop.h>/* modified from src/unix/sys-std.c */static intsetSelectMask(InputHandler *handlers, fd_set *readMask){int maxfd = -1;InputHandler *tmp = handlers;FD_ZERO(readMask);while(tmp) {if(tmp->fileDescriptor > 0) {FD_SET(tmp->fileDescriptor, readMask);maxfd = maxfd < tmp->fileDescriptor ? tmp->fileDescriptor : maxfd;}tmp = tmp->next;}return(maxfd);}#endifstatic unsigned int timeout = 60;static int R_SocketWait(int sockfd, int write){fd_set rfd, wfd;struct timeval tv;double used = 0.0;while(1) {int maxfd = 0, howmany;#ifdef UnixInputHandler *what;if(R_wait_usec > 0) {R_PolledEvents();tv.tv_sec = 0;tv.tv_usec = R_wait_usec;} else {tv.tv_sec = timeout;tv.tv_usec = 0;}#elif defined(Win32)tv.tv_sec = 0;tv.tv_usec = 2e5;R_ProcessEvents();#elsetv.tv_sec = timeout;tv.tv_usec = 0;#endif#ifdef Unixmaxfd = setSelectMask(R_InputHandlers, &rfd);#elseFD_ZERO(&rfd);#endifFD_ZERO(&wfd);if(write) FD_SET(sockfd, &wfd); else FD_SET(sockfd, &rfd);if(maxfd < sockfd) maxfd = sockfd;howmany = R_SelectEx(maxfd+1, &rfd, &wfd, NULL, &tv, NULL);if (howmany < 0) {return -1;}if (howmany == 0) {used += tv.tv_sec + 1e-6 * tv.tv_usec;if(used >= timeout) return 1;continue;}#ifdef Unixif((!write && !FD_ISSET(sockfd, &rfd)) ||(write && !FD_ISSET(sockfd, &wfd)) ||howmany > 1) {/* was one of the extras */what = getSelectedHandler(R_InputHandlers, &rfd);if(what != NULL) what->handler((void*) NULL);continue;}#endif/* the socket was ready */break;}return 0;}void R_SockTimeout(int delay){timeout = (unsigned int) delay;}int R_SockConnect(int port, char *host){SOCKET s;fd_set wfd, rfd;struct timeval tv;int status = 0;double used = 0.0;struct sockaddr_in server;struct hostent *hp;check_init();s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);if (s == -1) return -1;#ifdef Win32{u_long one = 1;status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;}#else#ifdef HAVE_FCNTLif ((status = fcntl(s, F_GETFL, 0)) != -1) {#ifdef O_NONBLOCKstatus |= O_NONBLOCK;#else /* O_NONBLOCK */#ifdef F_NDELAYstatus |= F_NDELAY;#endif /* F_NDELAY */#endif /* !O_NONBLOCK */status = fcntl(s, F_SETFL, status);}#endifif (status < 0) {closesocket(s);return(-1);}#endifif (! (hp = gethostbyname(host))) return -1;memcpy((char *)&server.sin_addr, hp->h_addr_list[0], hp->h_length);server.sin_port = htons((short)port);server.sin_family = AF_INET;if ((connect(s, (struct sockaddr *) &server, sizeof(server)) == -1)) {switch (socket_errno()) {case EINPROGRESS:case EWOULDBLOCK:break;default:closesocket(s);return(-1);}}while(1) {int maxfd = 0;#ifdef UnixInputHandler *what;if(R_wait_usec > 0) {R_PolledEvents();tv.tv_sec = 0;tv.tv_usec = R_wait_usec;} else {tv.tv_sec = timeout;tv.tv_usec = 0;}#elif defined(Win32)tv.tv_sec = 0;tv.tv_usec = 2e5;R_ProcessEvents();#elsetv.tv_sec = timeout;tv.tv_usec = 0;#endif#ifdef Unixmaxfd = setSelectMask(R_InputHandlers, &rfd);#elseFD_ZERO(&rfd);#endifFD_ZERO(&wfd);FD_SET(s, &wfd);if(maxfd < s) maxfd = s;switch(R_SelectEx(maxfd+1, &rfd, &wfd, NULL, &tv, NULL)){case 0:/* Time out */used += tv.tv_sec + 1e-6 * tv.tv_usec;if(used < timeout) continue;closesocket(s);return(-1);case -1:/* Ermm.. ?? */closesocket(s);return(-1);}if ( FD_ISSET(s, &wfd) ) {SOCKLEN_T len;len = sizeof(status);if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0){/* Solaris error code */return (-1);}if ( status ) {closesocket(s);errno = status;return (-1);} else return(s);#ifdef Unix} else { /* some other handler needed */what = getSelectedHandler(R_InputHandlers, &rfd);if(what != NULL) what->handler((void*) NULL);continue;#endif}}/* not reached */return(-1);}int R_SockClose(int sockp){return closesocket(sockp);}int R_SockRead(int sockp, void *buf, int len, int blocking){int res;if(blocking && R_SocketWait(sockp, 0) != 0) return 0;res = (int) recv(sockp, buf, len, 0);return (res >= 0) ? res : -socket_errno();}int R_SockOpen(int port){check_init();return Sock_open(port, NULL);}int R_SockListen(int sockp, char *buf, int len){check_init();return Sock_listen(sockp, buf, len, NULL);}int R_SockWrite(int sockp, const void *buf, int len){int res, out = 0;/* Rprintf("socket %d writing |%s|\n", sockp, buf); *//* This function is not passed a `blocking' argument so the codehere is equivalent to blocking == TRUE; it's not clearnon-blocking writes make much sense with the current connectioninterface since there is no way to tell how much, if anything,has been written. LT */do {if(/*blocking && */R_SocketWait(sockp, 1) != 0) return out;res = (int) send(sockp, buf, len, 0);if (res < 0 && socket_errno() != EWOULDBLOCK)return -socket_errno();else {{ const char *cbuf = buf; cbuf += res; buf = cbuf; }len -= res;out += res;}} while (/* ! blocking && */len > 0);return out;}#endif