Rev 83436 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 2001-2022 The R 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, a copy is available at* https://www.R-project.org/Licenses/*//* <UTF8> chars are only handled as a whole */#ifdef HAVE_CONFIG_H#include <config.h>#endif/* ------------------- socket connections --------------------- */#define R_USE_SIGNALS 1#include <Defn.h>#include <Rconnections.h>#include "sock.h"#include <errno.h>static void listencleanup(void *data){int *psock = data;R_SockClose(*psock);}static Rboolean sock_open(Rconnection con){Rsockconn this = (Rsockconn)con->private;int sock, sock1, mlen;int timeout = this->timeout;char buf[256];if(timeout == NA_INTEGER || timeout <= 0) timeout = 60;this->pend = this->pstart = this->inbuf;if(this->server) {if (this->serverfd == -1) {sock1 = R_SockOpen(this->port); /* socket(), bind(), listen() */if(sock1 < 0) {warning("port %d cannot be opened", this->port);return FALSE;}{RCNTXT cntxt;/* set up a context which will close socket on jump. */begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv,R_BaseEnv, R_NilValue, R_NilValue);cntxt.cend = &listencleanup;cntxt.cenddata = &sock1;sock = R_SockListen(sock1, buf, 256, timeout); /* accept() */endcontext(&cntxt);}R_SockClose(sock1);if(sock < 0) {/* NOTE: potentially confusing as the error was in accept() */warning("problem in listening on this socket");return FALSE;}} else {/* accept() */sock = R_SockListen(this->serverfd, buf, 256, timeout);if(sock < 0) {/* "accepting" as this is used with socketAccept() */warning("problem in accepting connections on this socket");return FALSE;}}free(con->description);size_t sz = strlen(buf) + 10;con->description = (char *) malloc(sz); // FIXME check allocationsnprintf(con->description, sz, "<-%s:%d", buf, this->port);} else {sock = R_SockConnect(this->port, con->description, timeout);if(sock < 0) {warning("%s:%d cannot be opened", con->description, this->port);return FALSE;}snprintf(buf, 256, "->%s:%d", con->description, this->port);strcpy(con->description, buf);}this->fd = sock;if (this->options & RSC_SET_TCP_NODELAY)R_set_nodelay(sock);mlen = (int) strlen(con->mode);con->isopen = TRUE;if(mlen >= 2 && con->mode[mlen - 1] == 'b') con->text = FALSE;else con->text = TRUE;set_iconv(con); /* OK for output, at least */con->save = -1000;return TRUE;}static void sock_close(Rconnection con){Rsockconn this = (Rsockconn)con->private;R_SockClose(this->fd);con->isopen = FALSE;}static void servsock_close(Rconnection con){Rservsockconn this = (Rservsockconn)con->private;R_SockClose(this->fd);con->isopen = FALSE;}static ssize_t sock_read_helper(Rconnection con, void *ptr, size_t size){Rsockconn this = (Rsockconn)con->private;ssize_t res;size_t nread = 0, n;con->incomplete = FALSE;do {/* read data into the buffer if it's empty and size > 0 */if (size > 0 && this->pstart == this->pend) {this->pstart = this->pend = this->inbuf;dores = R_SockRead(this->fd, this->inbuf, 4096,con->blocking, this->timeout);#ifdef Win32while (-res == WSAEINTR);if (! con->blocking && -res == WSAEWOULDBLOCK) {#elsewhile (-res == EINTR);if (! con->blocking && (-res == EAGAIN || -res == EWOULDBLOCK)) {#endifcon->incomplete = TRUE;return nread;}else if (res == 0) /* should mean EOF */return nread;else if (res < 0) return res;else this->pend = this->inbuf + res;}/* copy data from buffer to ptr */if (this->pstart + size <= this->pend)n = size;elsen = this->pend - this->pstart;memcpy(ptr, this->pstart, n);ptr = ((char *) ptr) + n;this->pstart += n;size -= n;nread += n;} while (size > 0);return nread;}static int sock_fgetc_internal(Rconnection con){unsigned char c;ssize_t n;n = sock_read_helper(con, (char *)&c, 1);return (n == 1) ? c : R_EOF;}static size_t sock_read(void *ptr, size_t size, size_t nitems,Rconnection con){ssize_t n = sock_read_helper(con, ptr, size * nitems)/((ssize_t)size);return n > 0 ? n : 0;}static size_t sock_write(const void *ptr, size_t size, size_t nitems,Rconnection con){Rsockconn this = (Rsockconn)con->private;ssize_t n = R_SockWrite(this->fd, ptr, (size_t)(size * nitems),this->timeout)/((ssize_t)size);return n > 0 ? n : 0;}Rconnection in_R_newsock(const char *host, int port, int server, int serverfd,const char * const mode, int timeout, int options){Rconnection new;new = (Rconnection) malloc(sizeof(struct Rconn));if(!new) error(_("allocation of socket connection failed"));new->class = (char *) malloc(strlen("sockconn") + 1);if(!new->class) {free(new);error(_("allocation of socket connection failed"));/* for Solaris 12.5 */ new = NULL;}strcpy(new->class, "sockconn");new->description = (char *) malloc(strlen(host) + 10);if(!new->description) {free(new->class); free(new);error(_("allocation of socket connection failed"));/* for Solaris 12.5 */ new = NULL;}init_con(new, host, CE_NATIVE, mode);new->open = &sock_open;new->close = &sock_close;new->vfprintf = &dummy_vfprintf;new->fgetc_internal = &sock_fgetc_internal;new->fgetc = &dummy_fgetc;new->read = &sock_read;new->write = &sock_write;new->private = (void *) malloc(sizeof(struct sockconn));if(!new->private) {free(new->description); free(new->class); free(new);error(_("allocation of socket connection failed"));/* for Solaris 12.5 */ new = NULL;}((Rsockconn)new->private)-> port = port;((Rsockconn)new->private)-> server = server;((Rsockconn)new->private)-> timeout = timeout;((Rsockconn)new->private)-> serverfd = serverfd;((Rsockconn)new->private)-> options = options;return new;}Rconnection in_R_newservsock(int port){Rconnection new;new = (Rconnection) malloc(sizeof(struct Rconn));if(!new) error(_("allocation of server socket connection failed"));new->class = (char *) malloc(strlen("servsockconn") + 1);if(!new->class) {free(new);error(_("allocation of server socket connection failed"));/* for Solaris 12.5 */ new = NULL;}strcpy(new->class, "servsockconn");new->description = (char *) malloc(strlen("localhost") + 10);if(!new->description) {free(new->class); free(new);error(_("allocation of server socket connection failed"));/* for Solaris 12.5 */ new = NULL;}init_con(new, "localhost", CE_NATIVE, "a+");new->close = &servsock_close;new->private = (void *) malloc(sizeof(struct servsockconn));if(!new->private) {free(new->description); free(new->class); free(new);error(_("allocation of server socket connection failed"));/* for Solaris 12.5 */ new = NULL;}((Rservsockconn)new->private)-> port = port;/* socket(), bind(), listen() */int sock = R_SockOpen(port);if(sock < 0) {free(new->private); free(new->description); free(new->class); free(new);error(_("creation of server socket failed: port %d cannot be opened"),port);/* for Solaris 12.5 */ new = NULL;}((Rservsockconn)new->private)-> fd = sock;new->isopen = TRUE;return new;}