int main(void) { tls_client_t client = {0}; const char *gnutls_ver = NULL; time_t start = 0; time_t end = 0; int ret = 0; int i = 0; /* initialise signal handling */ set_signal(); coap_log_set_level(COAP_LOG_DEBUG); gnutls_ver = gnutls_check_version(NULL); if (gnutls_ver == NULL) { coap_log_error("Unable to determine GnuTLS version"); return EXIT_FAILURE; } coap_log_info("GnuTLS version: %s", gnutls_ver); ret = tls_init(); if (ret != SOCK_OK) { coap_log_error("%s", sock_strerror(ret)); return EXIT_FAILURE; } ret = tls_client_create(&client, TRUST_FILE_NAME, CERT_FILE_NAME, KEY_FILE_NAME); if (ret != SOCK_OK) { coap_log_error("%s", sock_strerror(ret)); tls_deinit(); return EXIT_FAILURE; } for (i = 0; i < NUM_ITER; i++) { start = time(NULL); ret = client_run(&client); end = time(NULL); if (ret != SOCK_OK) { coap_log_error("%s", sock_strerror(ret)); tls_client_destroy(&client); tls_deinit(); return EXIT_FAILURE; } coap_log_info("Result: %s", sock_strerror(ret)); coap_log_debug("Time: %d sec", (int)(end - start)); coap_log_debug("Sleeping for %d seconds...", DELAY); sleep(DELAY); } tls_client_destroy(&client); tls_deinit(); return EXIT_SUCCESS; }
int check_connection_completion(int fd) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 10); struct pollfd pfd; int retval; pfd.fd = fd; pfd.events = POLLOUT; #ifndef _WIN32 do { retval = poll(&pfd, 1, 0); } while (retval < 0 && errno == EINTR); #else retval = WSAPoll(&pfd, 1, 0); #endif if (retval == 1) { if (pfd.revents & POLLERR) { ssize_t n = send(fd, "", 1, 0); if (n < 0) { return sock_errno(); } else { VLOG_ERR_RL(&rl, "poll return POLLERR but send succeeded"); return EPROTO; } } return 0; } else if (retval < 0) { VLOG_ERR_RL(&rl, "poll: %s", sock_strerror(sock_errno())); return errno; } else { return EAGAIN; } }
/* Sets 'fd' to non-blocking mode. Returns 0 if successful, otherwise a * positive errno value. */ int set_nonblocking(int fd) { #ifndef _WIN32 int flags = fcntl(fd, F_GETFL, 0); if (flags != -1) { if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1) { return 0; } else { VLOG_ERR("fcntl(F_SETFL) failed: %s", ovs_strerror(errno)); return errno; } } else { VLOG_ERR("fcntl(F_GETFL) failed: %s", ovs_strerror(errno)); return errno; } #else unsigned long arg = 1; if (ioctlsocket(fd, FIONBIO, &arg)) { int error = sock_errno(); VLOG_ERR("set_nonblocking failed: %s", sock_strerror(error)); return error; } return 0; #endif }
static int new_tcp_stream(const char *name, int fd, int connect_status, struct stream **streamp) { struct sockaddr_storage local; socklen_t local_len = sizeof local; int on = 1; int retval; /* Get the local IP and port information */ retval = getsockname(fd, (struct sockaddr *) &local, &local_len); if (retval) { memset(&local, 0, sizeof local); } retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); if (retval) { int error = sock_errno(); VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, sock_strerror(error)); close(fd); return error; } return new_fd_stream(name, fd, connect_status, streamp); }
void setsockopt_tcp_nodelay(int fd) { int on = 1; int retval; retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); if (retval) { retval = sock_errno(); VLOG_ERR("setsockopt(TCP_NODELAY): %s", sock_strerror(retval)); } }
/** * \param tds the famous socket * \param buffer data to send * \param buflen bytes in buffer * \param last 1 if this is the last packet, else 0 * \return length written (>0), <0 on failure */ int tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, size_t buflen) { int len; size_t sent = 0; assert(tds && buffer); while (sent < buflen) { /* TODO if send buffer is full we block receive !!! */ len = tds_select(tds, TDSSELWRITE, tds->query_timeout); if (len > 0) { len = tds_socket_write(tds->conn, tds, buffer + sent, buflen - sent); if (len == 0) continue; if (len < 0) return len; sent += len; continue; } /* error */ if (len < 0) { int err = sock_errno; char *errstr; if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */ continue; errstr = sock_strerror(err); tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n", err, errstr); sock_strerror_free(errstr); tds_connection_close(tds->conn); tdserror(tds_get_ctx(tds), tds, TDSEWRIT, err); return -1; } /* timeout */ tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n"); switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) { case TDS_INT_CONTINUE: break; default: case TDS_INT_CANCEL: tds_close_socket(tds); return -1; } } return (int) sent; }
int check_connection_completion(int fd) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 10); struct pollfd pfd; int retval; pfd.fd = fd; pfd.events = POLLOUT; #ifndef _WIN32 do { retval = poll(&pfd, 1, 0); } while (retval < 0 && errno == EINTR); #else fd_set wrset, exset; FD_ZERO(&wrset); FD_ZERO(&exset); FD_SET(fd, &exset); FD_SET(fd, &wrset); pfd.revents = 0; struct timeval tv = { 0, 0 }; /* WSAPoll is broken on Windows, instead do a select */ retval = select(0, NULL, &wrset, &exset, &tv); if (retval == 1) { if (FD_ISSET(fd, &wrset)) { pfd.revents |= pfd.events; } if (FD_ISSET(fd, &exset)) { pfd.revents |= POLLERR; } } #endif if (retval == 1) { if (pfd.revents & POLLERR) { ssize_t n = send(fd, "", 1, 0); if (n < 0) { return sock_errno(); } else { VLOG_ERR_RL(&rl, "poll return POLLERR but send succeeded"); return EPROTO; } } return 0; } else if (retval < 0) { VLOG_ERR_RL(&rl, "poll: %s", sock_strerror(sock_errno())); return errno; } else { return EAGAIN; } }
void wnt_cleanup (void) { if (WSACleanup ()) { #ifdef SERVER_ACTIVE if (server_active || error_use_protocol) /* FIXME: how are we supposed to report errors? As of now (Sep 98), error() can in turn call us (if it is out of memory) and in general is built on top of lots of stuff. */ ; else #endif fprintf (stderr, "cvs: cannot WSACleanup: %s\n", sock_strerror (WSAGetLastError ())); } }
/*-------------------------------------------------------------------------*\ * Tries to bind socket to (address, port) \*-------------------------------------------------------------------------*/ const char *inet_trybind(p_sock ps, const char *address, unsigned short port) { struct sockaddr_in local; int err; memset(&local, 0, sizeof(local)); /* address is either wildcard or a valid ip address */ local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); local.sin_family = AF_INET; if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) { struct hostent *hp = NULL; struct in_addr **addr; err = sock_gethostbyname(address, &hp); if (err != IO_DONE) return sock_hoststrerror(err); addr = (struct in_addr **) hp->h_addr_list; memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); } err = sock_bind(ps, (SA *) &local, sizeof(local)); if (err != IO_DONE) sock_destroy(ps); return sock_strerror(err); }
/*-------------------------------------------------------------------------*\ * Tries to connect to remote address (address, port) \*-------------------------------------------------------------------------*/ const char *inet_tryconnect(p_sock ps, const char *address, unsigned short port, p_tm tm) { struct sockaddr_in remote; int err; memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; remote.sin_port = htons(port); if (strcmp(address, "*")) { if (!inet_aton(address, &remote.sin_addr)) { struct hostent *hp = NULL; struct in_addr **addr; err = sock_gethostbyname(address, &hp); if (err != IO_DONE) return sock_hoststrerror(err); addr = (struct in_addr **) hp->h_addr_list; memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); } } else remote.sin_family = AF_UNSPEC; err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm); if (err != IO_DONE) sock_destroy(ps); return sock_strerror(err); }
/** * Write to an OS socket * @returns 0 if blocking, <0 error >0 bytes readed */ static int tds_socket_write(TDSCONNECTION *conn, TDSSOCKET *tds, const unsigned char *buf, int buflen) { int err, len; char *errstr; #if ENABLE_EXTRA_CHECKS /* this simulate the fact that send can return less bytes */ if (buflen >= 5) { static int cnt = 0; if (++cnt == 5) { cnt = 0; buflen -= 3; } } #endif #if defined(__APPLE__) && defined(SO_NOSIGPIPE) len = send(conn->s, buf, buflen, 0); #else len = WRITESOCKET(conn->s, buf, buflen); #endif if (len > 0) return len; err = sock_errno; if (0 == len || TDSSOCK_WOULDBLOCK(err)) return 0; assert(len < 0); /* detect connection close */ errstr = sock_strerror(err); tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n", err, errstr); sock_strerror_free(errstr); tds_connection_close(conn); tdserror(conn->tds_ctx, tds, TDSEWRIT, err); return -1; }
/*-------------------------------------------------------------------------*\ * Tries to create a new inet socket \*-------------------------------------------------------------------------*/ const char *inet_trycreate(p_sock ps, int type) { return sock_strerror(sock_create(ps, AF_INET, type, 0)); }
/*=========================================================================*\ * Lua methods \*=========================================================================*/ const char *udp_strerror(int err) { /* a 'closed' error on an unconnected means the target address was not * accepted by the transport layer */ if (err == IO_CLOSED) return "refused"; else return sock_strerror(err); }
/* * pool_user_create * accepts a client connection and adds it to the users list and returns it */ TDS_POOL_USER * pool_user_create(TDS_POOL * pool, TDS_SYS_SOCKET s) { TDS_POOL_USER *puser; TDS_SYS_SOCKET fd; TDSSOCKET *tds; LOGIN_EVENT *ev; tdsdump_log(TDS_DBG_NETWORK, "accepting connection\n"); if (TDS_IS_SOCKET_INVALID(fd = tds_accept(s, NULL, NULL))) { char *errstr = sock_strerror(errno); tdsdump_log(TDS_DBG_ERROR, "error calling assert :%s\n", errstr); sock_strerror_free(errstr); return NULL; } if (tds_socket_set_nonblocking(fd) != 0) { CLOSESOCKET(fd); return NULL; } puser = pool_user_find_new(pool); if (!puser) { CLOSESOCKET(fd); return NULL; } tds = tds_alloc_socket(pool->ctx, BLOCKSIZ); if (!tds) { CLOSESOCKET(fd); return NULL; } ev = (LOGIN_EVENT *) calloc(1, sizeof(*ev)); if (!ev || TDS_FAILED(tds_iconv_open(tds->conn, "UTF-8", 0))) { free(ev); tds_free_socket(tds); CLOSESOCKET(fd); return NULL; } /* FIX ME - little endian emulation should be config file driven */ tds->conn->emul_little_endian = 1; tds_set_s(tds, fd); tds->state = TDS_IDLE; tds->out_flag = TDS_LOGIN; puser->sock.tds = tds; puser->user_state = TDS_SRV_QUERY; puser->sock.poll_recv = false; puser->sock.poll_send = false; /* launch login asyncronously */ ev->puser = puser; ev->pool = pool; if (tds_thread_create_detached(login_proc, ev) != 0) { pool_free_user(pool, puser); fprintf(stderr, "error creating thread\n"); return NULL; } return puser; }
int DL_send( channel chan, int32 address, int16 port, sys_scatter *scat ) { #ifndef ARCH_SCATTER_NONE struct msghdr msg; #else /* ARCH_SCATTER_NONE */ char pseudo_scat[MAX_PACKET_SIZE]; #endif /* ARCH_SCATTER_NONE */ struct sockaddr_in soc_addr; struct timeval select_delay = { 0, 10000 }; int ret; int total_len; int i; int num_try; char *send_errormsg = NULL; /* fool compiler */ /* Check that the scatter passed is small enough to be a valid system scatter */ assert(scat->num_elements <= ARCH_SCATTER_SIZE); memset(&soc_addr, 0, sizeof(soc_addr)); soc_addr.sin_family = AF_INET; soc_addr.sin_addr.s_addr= htonl(address); soc_addr.sin_port = htons(port); #ifdef HAVE_SIN_LEN_IN_STRUCT_SOCKADDR_IN soc_addr.sin_len = sizeof(soc_addr); #endif #ifdef ARCH_PC_HOME soc_addr.sin_addr.s_addr= htonl(-1073741814); #endif /* ARCH_PC_HOME */ #ifndef ARCH_SCATTER_NONE memset(&msg, 0, sizeof(msg)); msg.msg_name = (caddr_t) &soc_addr; msg.msg_namelen = sizeof(soc_addr); msg.msg_iov = (struct iovec *)scat->elements; msg.msg_iovlen = scat->num_elements; #endif /* ARCH_SCATTER_NONE */ #ifdef ARCH_SCATTER_CONTROL msg.msg_controllen = 0; #endif /* ARCH_SCATTER_CONTROL */ #ifdef ARCH_SCATTER_ACCRIGHTS msg.msg_accrightslen = 0; #endif /* ARCH_SCATTER_ACCRIGHTS */ for( i=0, total_len=0; i < scat->num_elements; i++) { #ifdef ARCH_SCATTER_NONE memcpy( &pseudo_scat[total_len], scat->elements[i].buf, scat->elements[i].len ); #endif /* ARCH_SCATTER_NONE */ total_len+=scat->elements[i].len; } #if 0 #ifndef ARCH_SCATTER_NONE if( msg.msg_iovlen > 16) { Alarm(EXIT, "Too Big iovec of size %d\n", msg.msg_iovlen); } #endif #endif for( ret=-10, num_try=0; ret < 0 && num_try < 10; num_try++ ) { #ifndef ARCH_SCATTER_NONE ret = sendmsg(chan, &msg, 0); #else /* ARCH_SCATTER_NONE */ ret = sendto(chan, pseudo_scat, total_len, 0, (struct sockaddr *)&soc_addr, sizeof(soc_addr) ); #endif /* ARCH_SCATTER_NONE */ if(ret < 0) { /* delay for a short while */ send_errormsg = sock_strerror(sock_errno); Alarm( DATA_LINK, "DL_send: delaying after failure in send to " IPF ", ret is %d\n", IP(address), ret); select( 0, 0, 0, 0, &select_delay ); select_delay.tv_sec = 0; select_delay.tv_usec = 10000; } } if (ret < 0) { for( i=0; i < scat->num_elements; i++) Alarm( DATA_LINK, "DL_send: element[%d]: %d bytes\n", i,scat->elements[i].len); Alarm( DATA_LINK, "DL_send: error: %s\n sending %d bytes on channel %d to address " IPF "\n", send_errormsg, total_len,chan,IP(address) ); }else if(ret < total_len){ Alarm( DATA_LINK, "DL_send: partial sending %d out of %d\n", ret,total_len); } Alarm( DATA_LINK, "DL_send: sent a message of %d bytes to (" IPF ":%d) on channel %d\n", ret,IP(address),port,chan); return(ret); }
channel DL_init_channel( int32 channel_type, int16 port, int32 mcast_address, int32 interface_address ) { channel chan; struct sockaddr_in soc_addr; int on=1, off=0; #ifdef IP_MULTICAST_TTL unsigned char ttl_val; #endif if((chan = socket(AF_INET, SOCK_DGRAM, 0)) == -1) Alarm( EXIT, "DL_init_channel: socket error for port %d\n", port ); if ( channel_type & SEND_CHANNEL ) { if (setsockopt(chan, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) Alarm( EXIT, "DL_init_channel: setsockopt error for port %d\n",port); Alarm( DATA_LINK, "DL_init_channel: setsockopt for send and broadcast went ok\n"); #ifdef IP_MULTICAST_TTL /* ### Isn't this for sending??? */ ttl_val = 1; if (setsockopt(chan, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl_val, sizeof(ttl_val)) < 0) { Alarm( DATA_LINK, "DL_init_channel: problem in setsockopt of multicast ttl %d - ignore in WinNT or Win95\n", ttl_val ); } Alarm( DATA_LINK, "DL_init_channel: setting Mcast TTL to %d\n",ttl_val); #endif } if ( channel_type & RECV_CHANNEL ) { memset(&soc_addr, 0, sizeof(soc_addr)); soc_addr.sin_family = AF_INET; soc_addr.sin_port = htons(port); memset(&soc_addr.sin_zero, 0, sizeof(soc_addr.sin_zero)); #ifdef HAVE_SIN_LEN_IN_STRUCT_SOCKADDR_IN soc_addr.sin_len = sizeof(soc_addr); #endif /* If mcast channel, the interface means the interface to receive mcast packets on, and not interface to bind. Must bind multicast address instead */ if (mcast_address != 0 && IS_MCAST_ADDR(mcast_address) && !(channel_type & DL_BIND_ALL) ) soc_addr.sin_addr.s_addr= htonl(mcast_address); else if (interface_address != 0) soc_addr.sin_addr.s_addr= htonl(interface_address); else soc_addr.sin_addr.s_addr= INADDR_ANY; /* Older Version if (interface_address == 0) soc_addr.sin_addr.s_addr= INADDR_ANY; else soc_addr.sin_addr.s_addr= htonl(interface_address); */ if ( channel_type & REUSE_ADDR ) { if(setsockopt(chan, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on))) { Alarm( EXIT, "DL_init_channel: Failed to set socket option REUSEADDR, errno: %d\n", errno); } } if(bind( chan, (struct sockaddr *) &soc_addr, sizeof(soc_addr)) == -1) { Alarm( EXIT, "DL_init_channel: bind error (%d): %s for port %d, with sockaddr (" IPF ": %d) probably already running\n", sock_errno, sock_strerror(sock_errno), port, IP_NET(soc_addr.sin_addr.s_addr), ntohs(soc_addr.sin_port)); } Alarm( DATA_LINK, "DL_init_channel: bind for recv_channel for " IPF " port %d with chan %d ok\n", IP_NET(soc_addr.sin_addr.s_addr), port, chan); if( IS_MCAST_ADDR(mcast_address) ) { #ifdef IP_MULTICAST_TTL struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = htonl( mcast_address ); /* the interface could be changed to a specific interface if needed */ /* WAS: mreq.imr_interface.s_addr = INADDR_ANY; * If specified, then want to route through it instead of * based on routing decisions at the kernel */ /* IP_ADD_MEMBERSHIP requires that the imr_interface be an actual physical interface * or INADDR_ANY. So if this is the special case of binding to multicast or broadcast, * switch the join to use INADDR_ANY. In the case when the passed in interface * is a regular physical interface, then join only on that one. */ if ( IS_MCAST_ADDR(interface_address) ) mreq.imr_interface.s_addr = htonl( INADDR_ANY ); else mreq.imr_interface.s_addr = htonl( interface_address ); if (setsockopt(chan, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { Alarm( EXIT, "DL_init_channel: problem (errno %d:%s) in setsockopt to multicast address " IPF "\n", sock_errno, sock_strerror(sock_errno), IP(mcast_address) ); } if ( channel_type & NO_LOOP ) { if (setsockopt(chan, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&off, 1) < 0) { Alarm( EXIT, "DL_init_channel: problem (errno %d:%s) in setsockopt loop setting " IPF "\n", sock_errno, sock_strerror(sock_errno), IP(mcast_address)); } } Alarm( DATA_LINK, "DL_init_channel: Joining multicast address " IPF " went ok\n", IP(mcast_address) ); #else /* no multicast support */ Alarm( EXIT, "DL_init_channel: Old SunOS architecture does not support IP multicast: " IPF "\n", IP(mcast_address)); #endif } else { if (setsockopt(chan, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) Alarm( EXIT, "DL_init_channel: setsockopt SO_BROADCAST error for port %d, socket %d\n",port,chan); Alarm( DATA_LINK, "DL_init_channel: setsockopt for recv and broadcast went ok\n"); } } Alarm( DATA_LINK, "DL_init_channel: went ok on channel %d\n",chan); return ( chan ); }
int pword_authenticate(int fd, void *data_p) { struct user_password *user_p; int ret; char response; user_p = data_p; /* Send username and password */ while(((ret = send( fd, user_p->username, MAX_PWORD_USERNAME, 0 )) == -1) && ((sock_errno == EINTR) || (sock_errno == EAGAIN) || (sock_errno == EWOULDBLOCK))) ; if( ret != (MAX_PWORD_USERNAME) ) { printf("pword_authenticate: unable to send username %d %d: %s\n", ret, MAX_PWORD_USERNAME, sock_strerror(sock_errno)); return( 0 ); } while(((ret = send( fd, user_p->password, MAX_PWORD_PASSWORD, 0 )) == -1) && ((errno == EINTR) || (errno == EAGAIN) || (sock_errno == EWOULDBLOCK))) ; if( ret != (MAX_PWORD_PASSWORD) ) { printf("pword_authenticate: unable to send password %d %d: %s\n", ret, MAX_PWORD_PASSWORD, sock_strerror(sock_errno)); return( 0 ); } /* Receive response code */ ret = recv( fd, &response, 1, 0 ); if( ret < 0 ) { printf("pword_authenticate: reading response failed on mailbox %d\n", fd ); return( 0 ); } if( ret < 1 ) { printf("pword_authenticate: reading response string SHORT on mailbox %d\n", fd ); return( 0 ); } if ( response == 1 ) return( 1 ); else return( 0 ); }
TDSERRNO tds_open_socket(TDSSOCKET *tds, struct addrinfo *addr, unsigned int port, int timeout, int *p_oserr) { ioctl_nonblocking_t ioctl_nonblocking; SOCKLEN_T optlen; TDSCONNECTION *conn = tds->conn; char ipaddr[128]; int retval, len; TDSERRNO tds_error = TDSECONN; *p_oserr = 0; tds_addrinfo_set_port(addr, port); tds_addrinfo2str(addr, ipaddr, sizeof(ipaddr)); tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", ipaddr, port, TDS_MAJOR(conn), TDS_MINOR(conn)); conn->s = socket(addr->ai_family, SOCK_STREAM, 0); if (TDS_IS_SOCKET_INVALID(conn->s)) { char *errstr = sock_strerror(*p_oserr = sock_errno); tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr); sock_strerror_free(errstr); return TDSESOCK; } tds->state = TDS_IDLE; #ifdef SO_KEEPALIVE len = 1; setsockopt(conn->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len)); #endif #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) len = 40; setsockopt(conn->s, SOL_TCP, TCP_KEEPIDLE, (const void *) &len, sizeof(len)); len = 2; setsockopt(conn->s, SOL_TCP, TCP_KEEPINTVL, (const void *) &len, sizeof(len)); #endif #if defined(__APPLE__) && defined(SO_NOSIGPIPE) len = 1; if (setsockopt(conn->s, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &len, sizeof(len))) { *p_oserr = sock_errno; tds_connection_close(conn); return TDSESOCK; } #endif len = 1; #if defined(USE_NODELAY) setsockopt(conn->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); #elif defined(USE_CORK) if (setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0) setsockopt(conn->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); #else #error One should be defined #endif #ifdef DOS32X /* the other connection doesn't work on WATTCP32 */ if (connect(conn->s, addr->ai_addr, addr->ai_addrlen) < 0) { char *message; *p_oserr = sock_errno; if (asprintf(&message, "tds_open_socket(): %s:%d", ipaddr, port) >= 0) { perror(message); free(message); } tds_connection_close(conn); return TDSECONN; } #else if (!timeout) { /* A timeout of zero means wait forever; 90,000 seconds will feel like forever. */ timeout = 90000; } /* enable non-blocking mode */ ioctl_nonblocking = 1; if (IOCTLSOCKET(conn->s, FIONBIO, &ioctl_nonblocking) < 0) { *p_oserr = sock_errno; tds_connection_close(conn); return TDSEUSCT; /* close enough: "Unable to set communications timer" */ } retval = connect(conn->s, addr->ai_addr, addr->ai_addrlen); if (retval == 0) { tdsdump_log(TDS_DBG_INFO2, "connection established\n"); } else { int err = *p_oserr = sock_errno; char *errstr = sock_strerror(err); tdsdump_log(TDS_DBG_ERROR, "tds_open_socket: connect(2) returned \"%s\"\n", errstr); sock_strerror_free(errstr); #if DEBUGGING_CONNECTING_PROBLEM if (err != ECONNREFUSED && err != ENETUNREACH && err != TDSSOCK_EINPROGRESS) { tdsdump_dump_buf(TDS_DBG_ERROR, "Contents of sockaddr_in", addr->ai_addr, addr->ai_addrlen); tdsdump_log(TDS_DBG_ERROR, " sockaddr_in:\t" "%s = %x\n" "\t\t\t%s = %x\n" "\t\t\t%s = %s\n" , "sin_family", addr->ai_family , "port", port , "address", ipaddr ); } #endif if (err != TDSSOCK_EINPROGRESS) goto not_available; *p_oserr = TDSSOCK_ETIMEDOUT; if (tds_select(tds, TDSSELWRITE|TDSSELERR, timeout) == 0) { tds_error = TDSECONN; goto not_available; } } #endif /* not DOS32X */ /* check socket error */ optlen = sizeof(len); len = 0; if (tds_getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (char *) &len, &optlen) != 0) { char *errstr = sock_strerror(*p_oserr = sock_errno); tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) failed: %s\n", errstr); sock_strerror_free(errstr); goto not_available; } if (len != 0) { char *errstr = sock_strerror(*p_oserr = len); tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) reported: %s\n", errstr); sock_strerror_free(errstr); goto not_available; } tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() succeeded\n"); return TDSEOK; not_available: tds_connection_close(conn); tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() failed\n"); return tds_error; }
TDSERRNO tds_open_socket(TDSSOCKET *tds, struct addrinfo *addr, unsigned int port, int timeout, int *p_oserr) { TDSCONNECTION *conn = tds->conn; int len; TDSERRNO tds_error; *p_oserr = 0; conn->s = socket(addr->ai_family, SOCK_STREAM, 0); if (TDS_IS_SOCKET_INVALID(conn->s)) { char *errstr = sock_strerror(*p_oserr = sock_errno); tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", errstr); sock_strerror_free(errstr); return TDSESOCK; } tds->state = TDS_IDLE; #ifdef SO_KEEPALIVE len = 1; setsockopt(conn->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len)); #endif #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) len = 40; setsockopt(conn->s, SOL_TCP, TCP_KEEPIDLE, (const void *) &len, sizeof(len)); len = 2; setsockopt(conn->s, SOL_TCP, TCP_KEEPINTVL, (const void *) &len, sizeof(len)); #endif #if defined(__APPLE__) && defined(SO_NOSIGPIPE) len = 1; if (setsockopt(conn->s, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &len, sizeof(len))) { *p_oserr = sock_errno; tds_connection_close(conn); return TDSESOCK; } #endif len = 1; #if defined(USE_NODELAY) setsockopt(conn->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); #elif defined(USE_CORK) if (setsockopt(conn->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0) setsockopt(conn->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); #else #error One should be defined #endif while ((tds_error = tds_connect_socket(tds, addr, port, timeout, p_oserr)) != TDSEOK) { addr = addr->ai_next; if (!addr) { tds_connection_close(conn); tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() failed\n"); return tds_error; } } tdsdump_log(TDS_DBG_INFO2, "tds_open_socket() succeeded\n"); return TDSEOK; }
/** * Select on a socket until it's available or the timeout expires. * Meanwhile, call the interrupt function. * \return >0 ready descriptors * 0 timeout * <0 error (cf. errno). Caller should close socket and return failure. * This function does not call tdserror or close the socket because it can't know the context in which it's being called. */ int tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds) { int rc, seconds; unsigned int poll_seconds; assert(tds != NULL); assert(timeout_seconds >= 0); /* * The select loop. * If an interrupt handler is installed, we iterate once per second, * else we try once, timing out after timeout_seconds (0 == never). * If select(2) is interrupted by a signal (e.g. press ^C in sqsh), we timeout. * (The application can retry if desired by installing a signal handler.) * * We do not measure current time against end time, to avoid being tricked by ntpd(8) or similar. * Instead, we just count down. * * We exit on the first of these events: * 1. a descriptor is ready. (return to caller) * 2. select(2) returns an important error. (return to caller) * A timeout of zero says "wait forever". We do that by passing a NULL timeval pointer to select(2). */ poll_seconds = (tds_get_ctx(tds) && tds_get_ctx(tds)->int_handler)? 1 : timeout_seconds; for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) { struct pollfd fds[2]; int timeout = poll_seconds ? poll_seconds * 1000 : -1; if (TDS_IS_SOCKET_INVALID(tds_get_s(tds))) return -1; if ((tds_sel & TDSSELREAD) != 0 && tds->conn->tls_session && tds_ssl_pending(tds->conn)) return POLLIN; fds[0].fd = tds_get_s(tds); fds[0].events = tds_sel; fds[0].revents = 0; fds[1].fd = tds->conn->s_signaled; fds[1].events = POLLIN; fds[1].revents = 0; rc = poll(fds, 2, timeout); if (rc > 0 ) { if (fds[0].revents & POLLERR) return -1; rc = fds[0].revents; if (fds[1].revents) { #if ENABLE_ODBC_MARS tds_check_cancel(tds->conn); #endif rc |= TDSPOLLURG; } return rc; } if (rc < 0) { char *errstr; switch (sock_errno) { case TDSSOCK_EINTR: /* FIXME this should be global maximun, not loop one */ seconds += poll_seconds; break; /* let interrupt handler be called */ default: /* documented: EFAULT, EBADF, EINVAL */ errstr = sock_strerror(sock_errno); tdsdump_log(TDS_DBG_ERROR, "error: poll(2) returned %d, \"%s\"\n", sock_errno, errstr); sock_strerror_free(errstr); return rc; } } assert(rc == 0 || (rc < 0 && sock_errno == TDSSOCK_EINTR)); if (tds_get_ctx(tds) && tds_get_ctx(tds)->int_handler) { /* interrupt handler installed */ /* * "If hndlintr() returns INT_CANCEL, DB-Library sends an attention token [TDS_BUFSTAT_ATTN] * to the server. This causes the server to discontinue command processing. * The server may send additional results that have already been computed. * When control returns to the mainline code, the mainline code should do * one of the following: * - Flush the results using dbcancel * - Process the results normally" */ int timeout_action = (*tds_get_ctx(tds)->int_handler) (tds_get_parent(tds)); switch (timeout_action) { case TDS_INT_CONTINUE: /* keep waiting */ continue; case TDS_INT_CANCEL: /* abort the current command batch */ /* FIXME tell tds_goodread() not to call tdserror() */ return 0; default: tdsdump_log(TDS_DBG_NETWORK, "tds_select: invalid interupt handler return code: %d\n", timeout_action); return -1; } } /* * We can reach here if no interrupt handler was installed and we either timed out or got EINTR. * We cannot be polling, so we are about to drop out of the loop. */ assert(poll_seconds == timeout_seconds); } return 0; }
const char *sock_ioerror(p_sock ps, int err) { (void) ps; return sock_strerror(err); }
static TDSERRNO tds_connect_socket(TDSSOCKET *tds, struct addrinfo *addr, unsigned int port, int timeout, int *p_oserr) { SOCKLEN_T optlen; TDSCONNECTION *conn = tds->conn; char ipaddr[128]; int retval, len; tds_addrinfo_set_port(addr, port); tds_addrinfo2str(addr, ipaddr, sizeof(ipaddr)); if (TDS_IS_SOCKET_INVALID(conn->s)) return TDSECONN; *p_oserr = 0; tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", ipaddr, port, TDS_MAJOR(conn), TDS_MINOR(conn)); #ifdef DOS32X /* the other connection doesn't work on WATTCP32 */ if (connect(conn->s, addr->ai_addr, addr->ai_addrlen) < 0) { *p_oserr = sock_errno; tdsdump_log(TDS_DBG_ERROR, "tds_open_socket(): %s:%d", ipaddr, port); return TDSECONN; } #else if (!timeout) { /* A timeout of zero means wait forever; 90,000 seconds will feel like forever. */ timeout = 90000; } if ((*p_oserr = tds_socket_set_nonblocking(conn->s)) != 0) { tds_connection_close(conn); return TDSEUSCT; /* close enough: "Unable to set communications timer" */ } retval = connect(conn->s, addr->ai_addr, addr->ai_addrlen); if (retval == 0) { tdsdump_log(TDS_DBG_INFO2, "connection established\n"); } else { int err = *p_oserr = sock_errno; char *errstr = sock_strerror(err); tdsdump_log(TDS_DBG_ERROR, "tds_open_socket: connect(2) returned \"%s\"\n", errstr); sock_strerror_free(errstr); #if DEBUGGING_CONNECTING_PROBLEM if (err != ECONNREFUSED && err != ENETUNREACH && err != TDSSOCK_EINPROGRESS) { tdsdump_dump_buf(TDS_DBG_ERROR, "Contents of sockaddr_in", addr->ai_addr, addr->ai_addrlen); tdsdump_log(TDS_DBG_ERROR, " sockaddr_in:\t" "%s = %x\n" "\t\t\t%s = %x\n" "\t\t\t%s = %s\n" , "sin_family", addr->ai_family , "port", port , "address", ipaddr ); } #endif if (err != TDSSOCK_EINPROGRESS) return TDSECONN; *p_oserr = TDSSOCK_ETIMEDOUT; if (tds_select(tds, TDSSELWRITE|TDSSELERR, timeout) == 0) return TDSECONN; } #endif /* not DOS32X */ /* check socket error */ optlen = sizeof(len); len = 0; if (tds_getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (char *) &len, &optlen) != 0) { char *errstr = sock_strerror(*p_oserr = sock_errno); tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) failed: %s\n", errstr); sock_strerror_free(errstr); return TDSECONN; } if (len != 0) { char *errstr = sock_strerror(*p_oserr = len); tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) reported: %s\n", errstr); sock_strerror_free(errstr); return TDSECONN; } return TDSEOK; }