tcpcon_t * tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout, int ssl) { struct net_hostent *hp; char *tmphstbuf; int fd, r, err, herr, optval; const char *errtxt; struct sockaddr_in in; socklen_t errlen = sizeof(int); if(!strcmp(hostname, "localhost")) { if((fd = getstreamsocket(AF_INET, errbuf, errbufsize)) == -1) return NULL; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); } else { herr = 0; tmphstbuf = NULL; /* free NULL is a nop */ hp = netGetHostByName(hostname); if(hp == NULL) herr = h_errno; if(herr != 0) { switch(herr) { case HOST_NOT_FOUND: errtxt = "Unknown host"; break; case NO_ADDRESS: errtxt = "The requested name is valid but does not have an IP address"; break; case NO_RECOVERY: errtxt = "A non-recoverable name server error occurred"; break; case TRY_AGAIN: errtxt = "A temporary error occurred on an authoritative name server"; break; default: errtxt = "Unknown error"; break; } snprintf(errbuf, errbufsize, "%s", errtxt); free(tmphstbuf); return NULL; } else if(hp == NULL) { snprintf(errbuf, errbufsize, "Resolver internal error"); free(tmphstbuf); return NULL; } if((fd = getstreamsocket(hp->h_addrtype, errbuf, errbufsize)) == -1) { free(tmphstbuf); return NULL; } switch(hp->h_addrtype) { case AF_INET: memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); lv2_void* netaddrlist = (lv2_void*)(u64)hp->h_addr_list; memcpy(&in.sin_addr, (char*)(u64)netaddrlist[0], sizeof(struct in_addr)); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); break; default: snprintf(errbuf, errbufsize, "Invalid protocol family"); free(tmphstbuf); return NULL; } free(tmphstbuf); } if(r < 0) { if(net_errno == NET_EINPROGRESS) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; r = netPoll(&pfd, 1, timeout); if(r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); netClose(fd); return NULL; } if(r == -1) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(net_errno)); netClose(fd); return NULL; } netGetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = net_errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); netClose(fd); return NULL; } optval = 0; r = netSetSockOpt(fd, SOL_SOCKET, SO_NBIO, &optval, sizeof(optval)); if(r < 0) { snprintf(errbuf, errbufsize, "Unable to go blocking: %s", strerror(net_errno)); netClose(fd); return NULL; } tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); if(ssl) { #if ENABLE_POLARSSL if(1) { tc->ssl = malloc(sizeof(ssl_context)); if(ssl_init(tc->ssl)) { snprintf(errbuf, errlen, "SSL failed to initialize"); close(fd); free(tc->ssl); free(tc); return NULL; } tc->ssn = malloc(sizeof(ssl_session)); tc->hs = malloc(sizeof(havege_state)); havege_init(tc->hs); memset(tc->ssn, 0, sizeof(ssl_session)); ssl_set_endpoint(tc->ssl, SSL_IS_CLIENT ); ssl_set_authmode(tc->ssl, SSL_VERIFY_NONE ); ssl_set_rng(tc->ssl, havege_rand, tc->hs ); ssl_set_bio(tc->ssl, net_recv, &tc->fd, net_send, &tc->fd); ssl_set_ciphers(tc->ssl, ssl_default_ciphers ); ssl_set_session(tc->ssl, 1, 600, tc->ssn ); tc->read = polarssl_read; tc->write = polarssl_write; } else #endif { snprintf(errbuf, errlen, "SSL not supported"); tcp_close(tc); return NULL; } } else { tc->read = tcp_read; tc->write = tcp_write; } return tc; }
tcpcon_t * tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout, int ssl) { struct hostent *hp; char *tmphstbuf; int fd, val, r, err, herr; const char *errtxt; #if !defined(__APPLE__) struct hostent hostbuf; size_t hstbuflen; int res; #endif struct sockaddr_in6 in6; struct sockaddr_in in; socklen_t errlen = sizeof(int); if(!strcmp(hostname, "localhost")) { if((fd = getstreamsocket(AF_INET, errbuf, errbufsize)) == -1) return NULL; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); } else { #if defined(__APPLE__) herr = 0; tmphstbuf = NULL; /* free NULL is a nop */ /* TODO: AF_INET6 */ hp = gethostbyname(hostname); if(hp == NULL) herr = h_errno; #else hstbuflen = 1024; tmphstbuf = malloc(hstbuflen); while((res = gethostbyname_r(hostname, &hostbuf, tmphstbuf, hstbuflen, &hp, &herr)) == ERANGE) { hstbuflen *= 2; tmphstbuf = realloc(tmphstbuf, hstbuflen); } #endif if(herr != 0) { switch(herr) { case HOST_NOT_FOUND: errtxt = "Unknown host"; break; case NO_ADDRESS: errtxt = "The requested name is valid but does not have an IP address"; break; case NO_RECOVERY: errtxt = "A non-recoverable name server error occurred"; break; case TRY_AGAIN: errtxt = "A temporary error occurred on an authoritative name server"; break; default: errtxt = "Unknown error"; break; } snprintf(errbuf, errbufsize, "%s", errtxt); free(tmphstbuf); return NULL; } else if(hp == NULL) { snprintf(errbuf, errbufsize, "Resolver internal error"); free(tmphstbuf); return NULL; } if((fd = getstreamsocket(hp->h_addrtype, errbuf, errbufsize)) == -1) { free(tmphstbuf); return NULL; } switch(hp->h_addrtype) { case AF_INET: memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); memcpy(&in.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); break; case AF_INET6: memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_port = htons(port); memcpy(&in6.sin6_addr, hp->h_addr_list[0], sizeof(struct in6_addr)); r = connect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in6)); break; default: snprintf(errbuf, errbufsize, "Invalid protocol family"); free(tmphstbuf); return NULL; } free(tmphstbuf); } if(r == -1) { if(errno == EINPROGRESS) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; r = poll(&pfd, 1, timeout); if(r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); close(fd); return NULL; } if(r == -1) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno)); close(fd); return NULL; } getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); close(fd); return NULL; } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); val = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); if(ssl) { #if ENABLE_OPENSSL if(showtime_ssl_ctx != NULL) { char errmsg[120]; if((tc->ssl = SSL_new(showtime_ssl_ctx)) == NULL) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL: %s", errmsg); tcp_close(tc); return NULL; } if(SSL_set_fd(tc->ssl, tc->fd) == 0) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL fd: %s", errmsg); tcp_close(tc); return NULL; } if(SSL_connect(tc->ssl) <= 0) { ERR_error_string(ERR_get_error(), errmsg); snprintf(errbuf, errlen, "SSL connect: %s", errmsg); tcp_close(tc); return NULL; } SSL_set_mode(tc->ssl, SSL_MODE_AUTO_RETRY); tc->read = ssl_read; tc->write = ssl_write; } else #elif ENABLE_POLARSSL if(1) { tc->ssl = malloc(sizeof(ssl_context)); if(ssl_init(tc->ssl)) { snprintf(errbuf, errlen, "SSL failed to initialize"); close(fd); free(tc->ssl); free(tc); return NULL; } tc->ssn = malloc(sizeof(ssl_session)); tc->hs = malloc(sizeof(havege_state)); havege_init(tc->hs); memset(tc->ssn, 0, sizeof(ssl_session)); ssl_set_endpoint(tc->ssl, SSL_IS_CLIENT ); ssl_set_authmode(tc->ssl, SSL_VERIFY_NONE ); ssl_set_rng(tc->ssl, havege_rand, tc->hs ); ssl_set_bio(tc->ssl, net_recv, &tc->fd, net_send, &tc->fd); ssl_set_ciphers(tc->ssl, ssl_default_ciphers ); ssl_set_session(tc->ssl, 1, 600, tc->ssn ); tc->read = polarssl_read; tc->write = polarssl_write; } else #endif { snprintf(errbuf, errlen, "SSL not supported"); tcp_close(tc); return NULL; } } else { tc->read = tcp_read; tc->write = tcp_write; } return tc; }