int do_connect(int type) { int sock = 0; if (type != SOCK_STREAM && type != SOCK_DGRAM) return -1; /* We need a socket that can be inherited by child processes in ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from nbase. */ sock = inheritable_socket(targetss.storage.ss_family, type, 0); if (srcaddr.storage.ss_family != AF_UNSPEC) { size_t sa_len; #ifdef HAVE_SOCKADDR_SA_LEN sa_len = srcaddr.sockaddr.sa_len; #else sa_len = sizeof(srcaddr); #endif if (bind(sock, &srcaddr.sockaddr, sa_len) < 0) { bye("bind to %s:%hu: %s.", inet_socktop(&srcaddr), inet_port(&srcaddr), socket_strerror(socket_errno())); } } if (sock != -1) { if (connect(sock, &targetss.sockaddr, (int) targetsslen) != -1) return sock; else if (socket_errno() == EINPROGRESS || socket_errno() == EAGAIN) return sock; } return -1; }
void setup_environment(struct fdinfo *info) { union sockaddr_u su; char ip[INET6_ADDRSTRLEN]; char port[16]; socklen_t alen = sizeof(su); if (getpeername(info->fd, &su.sockaddr, &alen) != 0) { bye("getpeername failed: %s", socket_strerror(socket_errno())); } #ifdef HAVE_SYS_UN_H if (su.sockaddr.sa_family == AF_UNIX) { /* say localhost to keep it backwards compatible */ setenv_portable("NCAT_REMOTE_ADDR", "localhost"); setenv_portable("NCAT_REMOTE_PORT", ""); } else #endif if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { setenv_portable("NCAT_REMOTE_ADDR", ip); setenv_portable("NCAT_REMOTE_PORT", port); } else { bye("getnameinfo failed: %s", socket_strerror(socket_errno())); } if (getsockname(info->fd, (struct sockaddr *)&su, &alen) < 0) { bye("getsockname failed: %s", socket_strerror(socket_errno())); } #ifdef HAVE_SYS_UN_H if (su.sockaddr.sa_family == AF_UNIX) { /* say localhost to keep it backwards compatible, else su.un.sun_path */ setenv_portable("NCAT_LOCAL_ADDR", "localhost"); setenv_portable("NCAT_LOCAL_PORT", ""); } else #endif if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { setenv_portable("NCAT_LOCAL_ADDR", ip); setenv_portable("NCAT_LOCAL_PORT", port); } else { bye("getnameinfo failed: %s", socket_strerror(socket_errno())); } switch(o.proto) { case IPPROTO_TCP: setenv_portable("NCAT_PROTO", "TCP"); break; case IPPROTO_SCTP: setenv_portable("NCAT_PROTO", "SCTP"); break; case IPPROTO_UDP: setenv_portable("NCAT_PROTO", "UDP"); break; } }
static int xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt, const char * xmt_ptr, int outlen) { int total_sent = 0; if ( (ctxt->state & XML_NANO_HTTP_WRITE) && (xmt_ptr != NULL ) ) { while (total_sent < outlen) { int nsent = send(ctxt->fd, xmt_ptr + total_sent, outlen - total_sent, 0); if (nsent>0) total_sent += nsent; else if ( ( nsent == -1 ) && #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK ( socket_errno( ) != EAGAIN ) && #endif ( socket_errno( ) != EWOULDBLOCK ) ) { __xmlIOErr(XML_FROM_HTTP, 0, "send failed\n"); if ( total_sent == 0 ) total_sent = -1; break; } else { /* ** No data sent ** Since non-blocking sockets are used, wait for ** socket to be writable or default timeout prior ** to retrying. */ struct timeval tv; fd_set wfd; tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO( &wfd ); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4018) #endif FD_SET( ctxt->fd, &wfd ); #ifdef _MSC_VER #pragma warning(pop) #endif (void)select( ctxt->fd + 1, NULL, &wfd, NULL, &tv ); } } } return total_sent; }
int get_authenticated_socket( const char * host, int port) { int remote = 0 ; int ret; dest_host = strdup(host); dest_port = port; if (0 < connect_timeout) set_timeout (connect_timeout); //if (check_direct(dest_host)) // relay_method = METHOD_DIRECT; if ( relay_method == METHOD_DIRECT ) { remote = open_connection (dest_host, dest_port); if ( remote == SOCKET_ERROR ) g_error( "Unable to connect to destination host, errno=%d\n", socket_errno()); } else { remote = open_connection (relay_host, relay_port); if ( remote == SOCKET_ERROR ) g_error( "Unable to connect to relay host, errno=%d\n", socket_errno()); } if (socks_ns.sin_addr.s_addr != 0) switch_ns (&socks_ns); switch ( relay_method ) { case METHOD_HTTP: ret = begin_http_relay(remote); switch (ret) { case START_ERROR: close (remote); g_error("failed to begin relaying via HTTP.\n"); case START_OK: break; case START_RETRY: close (remote); } break; case METHOD_DIRECT: g_debug("Did not using proxy bypass ...(%s,%d)",__FILE__, __LINE__); break; } return remote; }
/* Create the actual socket (nse->iod->sd) underlying the iod. This unblocks the * socket, binds to the localaddr address, sets IP options, and sets the * broadcast flag. Trying to change these functions after making this call will * not have an effect. This function needs to be called before you try to read * or write on the iod. */ static int nsock_make_socket(struct npool *ms, struct niod *iod, int family, int type, int proto) { /* inheritable_socket is from nbase */ iod->sd = (int)inheritable_socket(family, type, proto); if (iod->sd == -1) { nsock_log_error("Socket trouble: %s", socket_strerror(socket_errno())); return -1; } unblock_socket(iod->sd); iod->lastproto = proto; if (iod->locallen) mksock_bind_addr(ms, iod); if (iod->ipoptslen && family == AF_INET) mksock_set_ipopts(ms, iod); if (ms->device) mksock_bind_device(ms, iod); if (ms->broadcast && type != SOCK_STREAM) mksock_set_broadcast(ms, iod); /* mksock_* functions can raise warnings/errors * but we don't let them stop us for now. */ return iod->sd; }
/* Broadcast a message to all the descriptors in fds. Returns -1 if any of the sends failed. */ int ncat_broadcast(fd_set *fds, const fd_list_t *fdlist, const char *msg, size_t size) { struct fdinfo *fdn; int i, ret; if (o.recvonly) return size; ret = 0; for (i = 0; i <= fdlist->fdmax; i++) { if (!FD_ISSET(i, fds)) continue; fdn = get_fdinfo(fdlist, i); ncat_assert(fdn != NULL); if (blocking_fdinfo_send(fdn, msg, size) <= 0) { if (o.debug > 1) logdebug("Error sending to fd %d: %s.\n", i, socket_strerror(socket_errno())); ret = -1; } } ncat_log_send(msg, size); return ret; }
ssize_t R_SockRead(int sockp, void *buf, size_t len, int blocking, int timeout) { ssize_t res; if(blocking && R_SocketWait(sockp, 0, timeout) != 0) return 0; res = recv(sockp, buf, len, 0); return (res >= 0) ? res : -socket_errno(); }
ssize_t R_SockRead(int sockp, void *buf, size_t len, int blocking, int timeout) { ssize_t res; if(blocking && (res = R_SocketWait(sockp, 0, timeout)) != 0) return res < 0 ? res : 0; /* socket error or timeout */ res = recv(sockp, buf, len, 0); return (res >= 0) ? res : -socket_errno(); }
obj_t bigloo_socket_read_returns_data(int fd) { char buf; if ((0 == recv(fd, &buf, 1, MSG_PEEK)) && (socket_errno() != EAGAIN)) { return BFALSE; } else { return BTRUE; } }
void setup_environment(struct fdinfo *info) { union sockaddr_u su; char ip[INET6_ADDRSTRLEN]; char port[16]; socklen_t alen = sizeof(su); if (getpeername(info->fd, &su.sockaddr, &alen) != 0) { bye("getpeername failed: %s", socket_strerror(socket_errno())); } if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { setenv_portable("NCAT_REMOTE_ADDR", ip); setenv_portable("NCAT_REMOTE_PORT", port); } else { bye("getnameinfo failed: %s", socket_strerror(socket_errno())); } if (getsockname(info->fd, (struct sockaddr *)&su, &alen) < 0) { bye("getsockname failed: %s", socket_strerror(socket_errno())); } if (getnameinfo((struct sockaddr *)&su, alen, ip, sizeof(ip), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { setenv_portable("NCAT_LOCAL_ADDR", ip); setenv_portable("NCAT_LOCAL_PORT", port); } else { bye("getnameinfo failed: %s", socket_strerror(socket_errno())); } switch(o.proto) { case IPPROTO_TCP: setenv_portable("NCAT_PROTO", "TCP"); break; case IPPROTO_SCTP: setenv_portable("NCAT_PROTO", "SCTP"); break; case IPPROTO_UDP: setenv_portable("NCAT_PROTO", "UDP"); break; } }
int htsp_tcp_read(socket_t fd, void *buf, size_t len) { int x = recv(fd, buf, len, MSG_WAITALL); if(x == -1) return socket_errno(); if(x != len) return ECONNRESET; return 0; }
static int mksock_bind_addr(struct npool *ms, struct niod *iod) { int rc; int one = 1; rc = setsockopt(iod->sd, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(one)); if (rc == -1) { int err = socket_errno(); nsock_log_error("Setting of SO_REUSEADDR failed (#%li): %s (%d)", iod->id, socket_strerror(err), err); } nsock_log_info("Binding to %s (IOD #%li)", get_localaddr_string(iod), iod->id); rc = bind(iod->sd, (struct sockaddr *)&iod->local, (int) iod->locallen); if (rc == -1) { int err = socket_errno(); nsock_log_error("Bind to %s failed (IOD #%li): %s (%d)", get_localaddr_string(iod), iod->id, socket_strerror(err), err); } return 0; }
static int mksock_set_broadcast(struct npool *ms, struct niod *iod) { int rc; int one = 1; rc = setsockopt(iod->sd, SOL_SOCKET, SO_BROADCAST, (const char *)&one, sizeof(one)); if (rc == -1) { int err = socket_errno(); nsock_log_error("Setting of SO_BROADCAST failed (IOD #%li): %s (%d)", iod->id, socket_strerror(err), err); } return 0; }
ssize_t R_SockWrite(int sockp, const void *buf, size_t len, int timeout) { ssize_t res, out = 0; /* Rprintf("socket %d writing |%s|\n", sockp, buf); */ /* This function is not passed a `blocking' argument so the code here is equivalent to blocking == TRUE; it's not clear non-blocking writes make much sense with the current connection interface since there is no way to tell how much, if anything, has been written. LT */ do { if(R_SocketWait(sockp, 1, timeout) != 0) return out; res = 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; }
static int mksock_set_ipopts(struct npool *ms, struct niod *iod) { int rc; errno = 0; rc = setsockopt(iod->sd, IPPROTO_IP, IP_OPTIONS, (const char *)iod->ipopts, iod->ipoptslen); if (rc == -1) { int err = socket_errno(); nsock_log_error("Setting of IP options failed (IOD #%li): %s (%d)", iod->id, socket_strerror(err), err); } return 0; }
int sendf(SOCKET s, const char *fmt,...) { static char buf[10240]; va_list args; va_start( args, fmt ); vsnprintf( buf, sizeof(buf), fmt, args ); va_end( args ); //report_text(">>>", buf); if ( send(s, buf, strlen(buf), 0) == SOCKET_ERROR ) { g_debug("failed to send http request. errno=%d\n", socket_errno()); return -1; } return 0; }
static int mksock_bind_device(struct npool *ms, struct niod *iod) { int rc; rc = socket_bindtodevice(iod->sd, ms->device); if (!rc) { int err = socket_errno(); if (err != EPERM) nsock_log_error("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)", iod->id, socket_strerror(err), err); else nsock_log_debug_all("Setting of SO_BINDTODEVICE failed (IOD #%li): %s (%d)", iod->id, socket_strerror(err), err); } return 0; }
/* * socktoa - return a numeric host name from a sockaddr_storage structure */ const char * socktoa( const sockaddr_u *sock ) { int saved_errno; char * res; char * addr; u_long scope; saved_errno = socket_errno(); LIB_GETBUF(res); if (NULL == sock) { strlcpy(res, "(null)", LIB_BUFLENGTH); } else { switch(AF(sock)) { case AF_INET: case AF_UNSPEC: inet_ntop(AF_INET, PSOCK_ADDR4(sock), res, LIB_BUFLENGTH); break; case AF_INET6: inet_ntop(AF_INET6, PSOCK_ADDR6(sock), res, LIB_BUFLENGTH); scope = SCOPE_VAR(sock); if (0 != scope && !strchr(res, '%')) { addr = res; LIB_GETBUF(res); snprintf(res, LIB_BUFLENGTH, "%s%%%lu", addr, scope); res[LIB_BUFLENGTH - 1] = '\0'; } break; default: snprintf(res, LIB_BUFLENGTH, "(socktoa unknown family %d)", AF(sock)); } } errno = saved_errno; return res; }
int atomic_out( SOCKET s, char *buf, int size ) { int ret, len; assert( buf != NULL ); assert( 0<=size ); ret = 0; while ( 0 < size ) { len = send( s, buf+ret, size, 0 ); if ( len == -1 ) g_error("atomic_out() failed to send(), %d\n", socket_errno()); ret += len; size -= len; } g_debug("atomic_out() [%d bytes]\n", ret); return ret; }
int htsp_tcp_read_timeout(socket_t fd, char *buf, size_t len, int timeout) { int x, tot = 0, val, err; fd_set fd_read; struct timeval tv; assert(timeout > 0); while(tot != len) { tv.tv_sec = timeout / 1000; tv.tv_usec = 1000 * (timeout % 1000); FD_ZERO(&fd_read); FD_SET(fd, &fd_read); x = select((int)fd+1, &fd_read, NULL, NULL, &tv); if(x == 0) return ETIMEDOUT; val = 1; ioctlsocket(fd, FIONBIO, &val); x = recv(fd, buf + tot, len - tot, 0); err = socket_errno(); val = 0; ioctlsocket(fd, FIONBIO, &val); if(x == 0) return ECONNRESET; else if(x == -1) { if(err == EAGAIN) continue; return err; } tot += x; } return 0; }
int async_connect(int socket, const struct sockaddr* address, socklen_t length) { int result = connect(socket, address, length); if (result == 0) { return 0; } if (sched_errno != EINPROGRESS) { return -1; } sched_event_wait(socket, WAITOUT); int error = socket_errno(socket); if (error != 0) { sched_errno = error; return -1; } return 0; }
/* Converts an IP address given in a sockaddr_u to an IPv4 or IPv6 IP address string. Since a static buffer is returned, this is not thread-safe and can only be used once in calls like printf() */ const char *inet_socktop(const union sockaddr_u *su) { static char buf[INET6_ADDRSTRLEN + 1]; void *addr; if (su->storage.ss_family == AF_INET) addr = (void *) &su->in.sin_addr; #if HAVE_IPV6 else if (su->storage.ss_family == AF_INET6) addr = (void *) &su->in6.sin6_addr; #endif else addr = NULL; if (inet_ntop(su->storage.ss_family, addr, buf, sizeof(buf)) == NULL) { bye("Failed to convert address to presentation format! Error: %s.", strerror(socket_errno())); } return buf; }
const char * sockporttoa( const sockaddr_u *sock ) { int saved_errno; const char * atext; char * buf; saved_errno = socket_errno(); atext = socktoa(sock); LIB_GETBUF(buf); snprintf(buf, LIB_BUFLENGTH, (IS_IPV6(sock)) ? "[%s]:%u" : "%s:%u", atext, SRCPORT(sock)); errno = saved_errno; return buf; }
int atomic_in( SOCKET s, char *buf, int size ) { int ret, len; assert( buf != NULL ); assert( 0<=size ); ret = 0; while ( 0 < size ) { len = recv( s, buf+ret, size, 0 ); if ( len == -1 ) { g_error("atomic_in() failed to recv(), %d\n", socket_errno()); } else if ( len == 0 ) { g_error( "Connection closed by peer.\n"); } ret += len; size -= len; } g_debug("atomic_in() [some bytes]\n"); return ret; }
/* Return a listening socket after setting various characteristics on it. Returns -1 on error. */ int do_listen(int type, int proto, const union sockaddr_u *srcaddr_u) { int sock = 0, option_on = 1; size_t sa_len; if (type != SOCK_STREAM && type != SOCK_DGRAM) return -1; /* We need a socket that can be inherited by child processes in ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from nbase. */ sock = inheritable_socket(srcaddr_u->storage.ss_family, type, proto); if (sock < 0) return -1; Setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option_on, sizeof(int)); /* IPPROTO_IPV6 is defined in Visual C++ only when _WIN32_WINNT >= 0x501. Nbase's nbase_winunix.h defines _WIN32_WINNT to a lower value for compatibility with older versions of Windows. This code disables IPv6 sockets that also receive IPv4 connections. This is the default on Windows anyway so it doesn't make a difference. http://support.microsoft.com/kb/950688 http://msdn.microsoft.com/en-us/library/bb513665 */ #ifdef IPPROTO_IPV6 #ifdef IPV6_V6ONLY if (srcaddr_u->storage.ss_family == AF_INET6) { int set = 1; /* Tell it to not try and bind to IPV4 */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &set, sizeof(set)) == -1) die("Unable to set IPV6 socket to bind only to IPV6"); } #endif #endif #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) sa_len = SUN_LEN(&srcaddr_u->un); else #endif #ifdef HAVE_SOCKADDR_SA_LEN sa_len = srcaddr_u->sockaddr.sa_len; #else sa_len = sizeof(*srcaddr_u); #endif if (bind(sock, &srcaddr_u->sockaddr, sa_len) < 0) { #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) bye("bind to %s: %s.", srcaddr_u->un.sun_path, socket_strerror(socket_errno())); else #endif bye("bind to %s:%hu: %s.", inet_socktop(srcaddr_u), inet_port(srcaddr_u), socket_strerror(socket_errno())); } if (type == SOCK_STREAM) Listen(sock, BACKLOG); if (o.verbose) { #ifdef HAVE_SYS_UN_H if (srcaddr_u->storage.ss_family == AF_UNIX) loguser("Listening on %s\n", srcaddr_u->un.sun_path); else #endif loguser("Listening on %s:%hu\n", inet_socktop(srcaddr_u), inet_port(srcaddr_u)); } if (o.test) logtest("LISTEN\n"); return sock; }
static SOCKET xmlNanoHTTPConnectAttempt(struct sockaddr *addr) { #ifndef HAVE_POLL_H fd_set wfd; #ifdef _WINSOCKAPI_ fd_set xfd; #endif struct timeval tv; #else /* !HAVE_POLL_H */ struct pollfd p; #endif /* !HAVE_POLL_H */ int status; int addrlen; SOCKET s; #ifdef SUPPORT_IP6 if (addr->sa_family == AF_INET6) { s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); addrlen = sizeof(struct sockaddr_in6); } else #endif { s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); addrlen = sizeof(struct sockaddr_in); } if (s == INVALID_SOCKET) { #ifdef DEBUG_HTTP perror("socket"); #endif __xmlIOErr(XML_FROM_HTTP, 0, "socket failed\n"); return INVALID_SOCKET; } #ifdef _WINSOCKAPI_ { u_long one = 1; status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0; } #else /* _WINSOCKAPI_ */ #if defined(VMS) { int enable = 1; status = ioctl(s, FIONBIO, &enable); } #else /* VMS */ #if defined(__BEOS__) && !defined(__HAIKU__) { bool noblock = true; status = setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &noblock, sizeof(noblock)); } #else /* __BEOS__ */ if ((status = fcntl(s, F_GETFL, 0)) != -1) { #ifdef O_NONBLOCK status |= O_NONBLOCK; #else /* O_NONBLOCK */ #ifdef F_NDELAY status |= F_NDELAY; #endif /* F_NDELAY */ #endif /* !O_NONBLOCK */ status = fcntl(s, F_SETFL, status); } if (status < 0) { #ifdef DEBUG_HTTP perror("nonblocking"); #endif __xmlIOErr(XML_FROM_HTTP, 0, "error setting non-blocking IO\n"); closesocket(s); return INVALID_SOCKET; } #endif /* !__BEOS__ */ #endif /* !VMS */ #endif /* !_WINSOCKAPI_ */ if (connect(s, addr, addrlen) == -1) { switch (socket_errno()) { case EINPROGRESS: case EWOULDBLOCK: break; default: __xmlIOErr(XML_FROM_HTTP, 0, "error connecting to HTTP server"); closesocket(s); return INVALID_SOCKET; } } #ifndef HAVE_POLL_H tv.tv_sec = timeout; tv.tv_usec = 0; #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4018) #endif #ifndef _WINSOCKAPI_ if (s > FD_SETSIZE) return INVALID_SOCKET; #endif FD_ZERO(&wfd); FD_SET(s, &wfd); #ifdef _WINSOCKAPI_ FD_ZERO(&xfd); FD_SET(s, &xfd); switch (select(s + 1, NULL, &wfd, &xfd, &tv)) #else switch (select(s + 1, NULL, &wfd, NULL, &tv)) #endif #ifdef _MSC_VER #pragma warning(pop) #endif #else /* !HAVE_POLL_H */ p.fd = s; p.events = POLLOUT; switch (poll(&p, 1, timeout * 1000)) #endif /* !HAVE_POLL_H */ { case 0: /* Time out */ __xmlIOErr(XML_FROM_HTTP, 0, "Connect attempt timed out"); closesocket(s); return INVALID_SOCKET; case -1: /* Ermm.. ?? */ __xmlIOErr(XML_FROM_HTTP, 0, "Connect failed"); closesocket(s); return INVALID_SOCKET; } #ifndef HAVE_POLL_H if (FD_ISSET(s, &wfd) #ifdef _WINSOCKAPI_ || FD_ISSET(s, &xfd) #endif ) #else /* !HAVE_POLL_H */ if (p.revents == POLLOUT) #endif /* !HAVE_POLL_H */ { XML_SOCKLEN_T len; len = sizeof(status); #ifdef SO_ERROR if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &status, &len) < 0) { /* Solaris error code */ __xmlIOErr(XML_FROM_HTTP, 0, "getsockopt failed\n"); return INVALID_SOCKET; } #endif if (status) { __xmlIOErr(XML_FROM_HTTP, 0, "Error connecting to remote host"); closesocket(s); errno = status; return INVALID_SOCKET; } } else { /* pbm */ __xmlIOErr(XML_FROM_HTTP, 0, "select failed\n"); closesocket(s); return INVALID_SOCKET; } return (s); }
static int xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) { #ifdef HAVE_POLL_H struct pollfd p; #else fd_set rfd; struct timeval tv; #endif while (ctxt->state & XML_NANO_HTTP_READ) { if (ctxt->in == NULL) { ctxt->in = (char *) xmlMallocAtomic(65000 * sizeof(char)); if (ctxt->in == NULL) { xmlHTTPErrMemory("allocating input"); ctxt->last = -1; return (-1); } ctxt->inlen = 65000; ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in; } if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) { int delta = ctxt->inrptr - ctxt->in; int len = ctxt->inptr - ctxt->inrptr; memmove(ctxt->in, ctxt->inrptr, len); ctxt->inrptr -= delta; ctxt->content -= delta; ctxt->inptr -= delta; } if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) { int d_inptr = ctxt->inptr - ctxt->in; int d_content = ctxt->content - ctxt->in; int d_inrptr = ctxt->inrptr - ctxt->in; char *tmp_ptr = ctxt->in; ctxt->inlen *= 2; ctxt->in = (char *) xmlRealloc(tmp_ptr, ctxt->inlen); if (ctxt->in == NULL) { xmlHTTPErrMemory("allocating input buffer"); xmlFree(tmp_ptr); ctxt->last = -1; return (-1); } ctxt->inptr = ctxt->in + d_inptr; ctxt->content = ctxt->in + d_content; ctxt->inrptr = ctxt->in + d_inrptr; } ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0); if (ctxt->last > 0) { ctxt->inptr += ctxt->last; return (ctxt->last); } if (ctxt->last == 0) { return (0); } if (ctxt->last == -1) { switch (socket_errno()) { case EINPROGRESS: case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK case EAGAIN: #endif break; case ECONNRESET: case ESHUTDOWN: return (0); default: __xmlIOErr(XML_FROM_HTTP, 0, "recv failed\n"); return (-1); } } #ifdef HAVE_POLL_H p.fd = ctxt->fd; p.events = POLLIN; if ((poll(&p, 1, timeout * 1000) < 1) #if defined(EINTR) && (errno != EINTR) #endif ) return (0); #else /* !HAVE_POLL_H */ #ifndef _WINSOCKAPI_ if (ctxt->fd > FD_SETSIZE) return 0; #endif tv.tv_sec = timeout; tv.tv_usec = 0; FD_ZERO(&rfd); #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4018) #endif FD_SET(ctxt->fd, &rfd); #ifdef _MSC_VER #pragma warning(pop) #endif if ((select(ctxt->fd + 1, &rfd, NULL, NULL, &tv) < 1) #if defined(EINTR) && (errno != EINTR) #endif ) return (0); #endif /* !HAVE_POLL_H */ } return (0); }
/** * New inbound connection for httpd. * * @param[in] fd socket file descriptor * @param[in] id I/O ID */ void hio_connection(iosrc_t fd, ioid_t id) { socket_t t; union { struct sockaddr sa; struct sockaddr_in sin; #if defined(X3270_IPV6) /*[*/ struct sockaddr_in6 sin6; #endif /*]*/ } sa; socklen_t len; char hostbuf[128]; session_t *session; len = sizeof(sa); t = accept(listen_s, &sa.sa, &len); if (t == INVALID_SOCKET) { vtrace("httpd accept error: %s%s\n", socket_errtext(), (socket_errno() == SE_EWOULDBLOCK)? " (harmless)": ""); return; } if (n_sessions >= N_SESSIONS) { vtrace("Too many connections.\n"); SOCK_CLOSE(t); return; } session = Malloc(sizeof(session_t)); memset(session, 0, sizeof(session_t)); vb_init(&session->pending.result); session->s = t; #if defined(_WIN32) /*[*/ session->event = CreateEvent(NULL, FALSE, FALSE, NULL); if (session->event == NULL) { vtrace("httpd: can't create socket handle\n"); SOCK_CLOSE(t); Free(session); return; } if (WSAEventSelect(session->s, session->event, FD_READ | FD_CLOSE) != 0) { vtrace("httpd: Can't set socket handle events\n"); CloseHandle(session->event); SOCK_CLOSE(t); Free(session); return; } #endif /*]*/ if (sa.sa.sa_family == AF_INET) { session->dhandle = httpd_new(session, lazyaf("%s:%u", inet_ntop(AF_INET, &sa.sin.sin_addr, hostbuf, sizeof(hostbuf)), ntohs(sa.sin.sin_port))); } #if defined(X3270_IPV6) /*[*/ else if (sa.sa.sa_family == AF_INET6) { session->dhandle = httpd_new(session, lazyaf("%s:%u", inet_ntop(AF_INET6, &sa.sin6.sin6_addr, hostbuf, sizeof(hostbuf)), ntohs(sa.sin6.sin6_port))); } #endif /*]*/ else { session->dhandle = httpd_new(session, "???"); } #if !defined(_WIN32) /*[*/ session->ioid = AddInput(t, hio_socket_input); #else /*][*/ session->ioid = AddInput(session->event, hio_socket_input); #endif /*]*/ /* Set the timeout for the first line of input. */ session->toid = AddTimeOut(IDLE_MAX * 1000, hio_timeout); llist_insert_before(&session->link, sessions.next); n_sessions++; }
/** * New inbound data for an httpd connection. * * @param[in] fd socket file descriptor * @param[in] id I/O ID */ void hio_socket_input(iosrc_t fd, ioid_t id) { session_t *session; char buf[1024]; ssize_t nr; session = NULL; FOREACH_LLIST(&sessions, session, session_t *) { if (session->ioid == id) { break; } } FOREACH_LLIST_END(&sessions, session, session_t *); if (session == NULL) { vtrace("httpd mystery input\n"); return; } /* Move this session to the front of the list. */ llist_unlink(&session->link); llist_insert_before(&session->link, sessions.next); session->idle = 0; if (session->toid != NULL_IOID) { RemoveTimeOut(session->toid); session->toid = NULL_IOID; } nr = recv(session->s, buf, sizeof(buf), 0); if (nr <= 0) { const char *ebuf; bool harmless = false; if (nr < 0) { if (socket_errno() == SE_EWOULDBLOCK) { harmless = true; } ebuf = lazyaf("recv error: %s", socket_errtext()); vtrace("httpd %s%s\n", ebuf, harmless? " (harmless)": ""); } else { ebuf = "session EOF"; } if (!harmless) { httpd_close(session->dhandle, ebuf); hio_socket_close(session); } } else { httpd_status_t rv; rv = httpd_input(session->dhandle, buf, nr); if (rv < 0) { httpd_close(session->dhandle, "protocol error"); hio_socket_close(session); } else if (rv == HS_PENDING) { /* Stop input on this socket. */ RemoveInput(session->ioid); session->ioid = NULL_IOID; } else if (session->toid == NULL_IOID) { /* Leave input enabled and start the timeout. */ session->toid = AddTimeOut(IDLE_MAX * 1000, hio_timeout); } } }
/* Returns -1 if an error, otherwise the number of newly written bytes */ static int do_actual_read(struct npool *ms, struct nevent *nse) { char buf[8192]; int buflen = 0; struct niod *iod = nse->iod; int err = 0; int max_chunk = NSOCK_READ_CHUNK_SIZE; int startlen = fs_length(&nse->iobuf); if (nse->readinfo.read_type == NSOCK_READBYTES) max_chunk = nse->readinfo.num; if (!iod->ssl) { do { struct sockaddr_storage peer; socklen_t peerlen; peerlen = sizeof(peer); buflen = recvfrom(iod->sd, buf, sizeof(buf), 0, (struct sockaddr *)&peer, &peerlen); /* Using recv() was failing, at least on UNIX, for non-network sockets * (i.e. stdin) in this case, a read() is done - as on ENOTSOCK we may * have a non-network socket */ if (buflen == -1) { if (socket_errno() == ENOTSOCK) { peer.ss_family = AF_UNSPEC; peerlen = 0; buflen = read(iod->sd, buf, sizeof(buf)); } } if (buflen == -1) { err = socket_errno(); break; } if (peerlen > 0) { assert(peerlen <= sizeof(iod->peer)); memcpy(&iod->peer, &peer, peerlen); iod->peerlen = peerlen; } if (buflen > 0) { if (fs_cat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return after a * somewhat large amount to avoid monopolizing resources and avoid DOS * attacks. */ if (fs_length(&nse->iobuf) > max_chunk) return fs_length(&nse->iobuf) - startlen; /* No good reason to read again if we we were successful in the read but * didn't fill up the buffer. Especially for UDP, where we want to * return only one datagram at a time. The consistency of the above * assignment of iod->peer depends on not consolidating more than one * UDP read buffer. */ if (buflen > 0 && buflen < sizeof(buf)) return fs_length(&nse->iobuf) - startlen; } } while (buflen > 0 || (buflen == -1 && err == EINTR)); if (buflen == -1) { if (err != EINTR && err != EAGAIN) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = err; return -1; } } } else { #if HAVE_OPENSSL /* OpenSSL read */ while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) { if (fs_cat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return * after a somewhat large amount to avoid monopolizing resources * and avoid DOS attacks. */ if (fs_length(&nse->iobuf) > max_chunk) return fs_length(&nse->iobuf) - startlen; } if (buflen == -1) { err = SSL_get_error(iod->ssl, buflen); if (err == SSL_ERROR_WANT_READ) { int evclr; evclr = socket_count_dec_ssl_desire(nse); socket_count_read_inc(iod); update_events(iod, ms, EV_READ, evclr); nse->sslinfo.ssl_desire = err; } else if (err == SSL_ERROR_WANT_WRITE) { int evclr; evclr = socket_count_dec_ssl_desire(nse); socket_count_write_inc(iod); update_events(iod, ms, EV_WRITE, evclr); nse->sslinfo.ssl_desire = err; } else { /* Unexpected error */ nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; nsock_log_info("SSL_read() failed for reason %s on NSI %li", ERR_error_string(err, NULL), iod->id); return -1; } } #endif /* HAVE_OPENSSL */ } if (buflen == 0) { nse->event_done = 1; nse->eof = 1; if (fs_length(&nse->iobuf) > 0) { nse->status = NSE_STATUS_SUCCESS; return fs_length(&nse->iobuf) - startlen; } else { nse->status = NSE_STATUS_EOF; return 0; } } return fs_length(&nse->iobuf) - startlen; }