struct link *link_serve_address(const char *addr, int port) { struct link *link = 0; struct sockaddr_in address; int success; int value; link = link_create(); if(!link) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; value = 1; setsockopt(link->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof(value)); link_window_configure(link); if(addr != 0 || port != LINK_PORT_ANY) { memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(addr) { string_to_ip_address(addr, (unsigned char *) &address.sin_addr.s_addr); } else { address.sin_addr.s_addr = htonl(INADDR_ANY); } success = bind(link->fd, (struct sockaddr *) &address, sizeof(address)); if(success < 0) goto failure; } success = listen(link->fd, 5); if(success < 0) goto failure; if(!link_nonblocking(link, 1)) goto failure; debug(D_TCP, "listening on port %d", port); return link; failure: if(link) link_close(link); return 0; }
struct link *link_connect(const char *addr, int port, time_t stoptime) { struct sockaddr_in address; struct link *link = 0; int result; int save_errno; link = link_create(); if(!link) goto failure; link_squelch(); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(!string_to_ip_address(addr, (unsigned char *) &address.sin_addr)) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; link_window_configure(link); /* sadly, cygwin does not do non-blocking connect correctly */ #ifdef CCTOOLS_OPSYS_CYGWIN if(!link_nonblocking(link, 0)) goto failure; #else if(!link_nonblocking(link, 1)) goto failure; #endif debug(D_TCP, "connecting to %s:%d", addr, port); do { result = connect(link->fd, (struct sockaddr *) &address, sizeof(address)); /* On some platforms, errno is not set correctly. */ /* If the remote address can be found, then we are really connected. */ /* Also, on bsd-derived systems, failure to connect is indicated by a second connect returning EINVAL. */ if(result < 0 && !errno_is_temporary(errno)) { if(errno == EINVAL) errno = ECONNREFUSED; break; } if(link_address_remote(link, link->raddr, &link->rport)) { debug(D_TCP, "made connection to %s:%d", link->raddr, link->rport); #ifdef CCTOOLS_OPSYS_CYGWIN link_nonblocking(link, 1); #endif return link; } } while(link_sleep(link, stoptime, 0, 1)); debug(D_TCP, "connection to %s:%d failed (%s)", addr, port, strerror(errno)); failure: save_errno = errno; if(link) link_close(link); errno = save_errno; return 0; }
struct link *link_connect(const char *addr, int port, time_t stoptime) { struct sockaddr_in address; struct link *link = 0; int result; int save_errno; link = link_create(); if(!link) goto failure; link_squelch(); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; address.sin_port = htons(port); if(!string_to_ip_address(addr, (unsigned char *) &address.sin_addr)) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; link_window_configure(link); /* sadly, cygwin does not do non-blocking connect correctly */ #ifdef CCTOOLS_OPSYS_CYGWIN if(!link_nonblocking(link, 0)) goto failure; #else if(!link_nonblocking(link, 1)) goto failure; #endif debug(D_TCP, "connecting to %s:%d", addr, port); while(1) { // First attempt a non-blocking connect result = connect(link->fd, (struct sockaddr *) &address, sizeof(address)); // On many platforms, non-blocking connect sets errno in unexpected ways: // On OSX, result=-1 and errno==EISCONN indicates a successful connection. if(result<0 && errno==EISCONN) result=0; // On BSD-derived systems, failure to connect is indicated by errno = EINVAL. // Set it to something more explanatory. if(result<0 && errno==EINVAL) errno=ECONNREFUSED; // Otherwise, a non-temporary errno should cause us to bail out. if(result<0 && !errno_is_temporary(errno)) break; // If the remote address is valid, we are connected no matter what. if(link_address_remote(link, link->raddr, &link->rport)) { debug(D_TCP, "made connection to %s:%d", link->raddr, link->rport); #ifdef CCTOOLS_OPSYS_CYGWIN link_nonblocking(link, 1); #endif return link; } // if the time has expired, bail out if( time(0) >= stoptime ) { errno = ETIMEDOUT; break; } // wait for some activity on the socket. link_sleep(link, stoptime, 0, 1); // No matter how the sleep ends, we want to go back to the top // and call connect again to get a proper errno. } debug(D_TCP, "connection to %s:%d failed (%s)", addr, port, strerror(errno)); failure: save_errno = errno; if(link) link_close(link); errno = save_errno; return 0; }
struct link *link_serve_address(const char *addr, int port) { struct link *link = 0; struct sockaddr_in address; int success; int value; link = link_create(); if(!link) goto failure; link->fd = socket(AF_INET, SOCK_STREAM, 0); if(link->fd < 0) goto failure; value = fcntl(link->fd, F_GETFD); if (value == -1) goto failure; value |= FD_CLOEXEC; if (fcntl(link->fd, F_SETFD, value) == -1) goto failure; value = 1; setsockopt(link->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &value, sizeof(value)); link_window_configure(link); memset(&address, 0, sizeof(address)); #if defined(CCTOOLS_OPSYS_DARWIN) address.sin_len = sizeof(address); #endif address.sin_family = AF_INET; if(addr) { string_to_ip_address(addr, (unsigned char *) &address.sin_addr.s_addr); } else { address.sin_addr.s_addr = htonl(INADDR_ANY); } int low = TCP_LOW_PORT_DEFAULT; int high = TCP_HIGH_PORT_DEFAULT; if(port < 1) { const char *lowstr = getenv("TCP_LOW_PORT"); if (lowstr) low = atoi(lowstr); const char *highstr = getenv("TCP_HIGH_PORT"); if (highstr) high = atoi(highstr); } else { low = high = port; } if(high < low) fatal("high port %d is less than low port %d in range", high, low); for (port = low; port <= high; port++) { address.sin_port = htons(port); success = bind(link->fd, (struct sockaddr *) &address, sizeof(address)); if(success == -1) { if(errno == EADDRINUSE) { //If a port is specified, fail! if (low == high) { goto failure; } else { continue; } } else { goto failure; } } break; } success = listen(link->fd, 5); if(success < 0) goto failure; if(!link_nonblocking(link, 1)) goto failure; debug(D_TCP, "listening on port %d", port); return link; failure: if(link) link_close(link); return 0; }