static TCPConnection* TCPConnection_Host_checkNewPeerLink(TCPConnection* tcp,const char*& out_peerName,long& peerPort){ #ifdef WIN32 typedef int TAcceptSizeType; #else typedef unsigned int TAcceptSizeType; #endif struct sockaddr peer_addr; TAcceptSizeType peer_addrLen=(TAcceptSizeType)sizeof(peer_addr); memset(&peer_addr,0,peer_addrLen); TSOCKET peer_sockFD=accept(tcp->sockFD,&peer_addr,&peer_addrLen); if (peer_sockFD<0) return 0; else { TCPConnection* peerTCP=TCPConnection_create(); peerTCP->sockFD=peer_sockFD; peerTCP->addr=*(sockaddr_in*)&peer_addr; peerTCP->he=gethostbyaddr((const char*)&(peerTCP->addr.sin_addr),sizeof(peerTCP->addr.sin_addr),AF_INET); out_peerName=peerTCP->he->h_name; //const char* peerName=inet_ntoa(peerTCP->addr.sin_addr); //out_peerName=peerName; peerPort=peerTCP->addr.sin_port; return peerTCP; } }
inline TCPConnection* TCPConnection_connect (CString host, uint16 port) { const int fd = socket(AF_INET, SOCK_STREAM, 0); report_zero_if(ERROR_MESSAGE("socket"), fd == -1); // Make it so that we can early-return from this scope using one-liners. struct Cleanup { explicit Cleanup (int fd) : ok(false), fd(fd) {} ~Cleanup () { return_if(ok); close(fd); } bool ok; int fd; } cleanup(fd); // FIXME: Use the IPv6-compliant getaddrinfo. struct hostent* ip = ::gethostbyname(host); report_zero_if(ERROR_MESSAGE("gethostbyname"), ip == NULL); sockaddr_in address; address.sin_family = AF_INET; memcpy(&address.sin_addr, ip->h_addr_list[0], ip->h_length); address.sin_port = htons(port); { // Put the socket into non-blocking mode. int flags = fcntl(fd, F_GETFL, 0); int status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); report_zero_if(ERROR_MESSAGE("fcntl"), status < 0); } { // Perform the non-blocking connection dance. int status = 0; do { status = ::connect(fd, (sockaddr*) &address, sizeof(address)); } while (-1 == status && EINTR == errno); // In the extreme case where connect got interrupted by a signal. if (0 != status) // TCPConnection did not immediately succeed. { switch (errno) // Investigate the error, and take action. { case EINPROGRESS: // The connection is in progress. { static const int connectionTimeoutInMilliseconds = 500; // Poll the socket for writing, with a timeout. const int ret = select_single_write(fd, connectionTimeoutInMilliseconds); // Select might actually have returned EINPROGRESS, here. // Currently, we behave as if the connection failed when it times out. // FIXME: Introduce an asynchronous callback connection mechanism in parallel to this blocking one. // Abort if select failed. report_zero_unless(ERROR_MESSAGE("select"), 0 < ret); // Also abort if select returned with a descriptor not ready for writing. report_zero_if("Connection timed out.", 0 == ret); // Make sure that the connection is error-free. int err = 0; socklen_t len = sizeof(int); report_zero_unless(ERROR_MESSAGE("getsockopt"), 0 == getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len)); report_zero_unless(formatted("connect: %s", strerror(err)).get(), 0 == err); break; // The connection is now established. } default: // The connection failed for other reasons. { uplink_log_error(ERROR_MESSAGE("connect")); return 0; } } } } { // Put the socket back into blocking mode. int flags = fcntl(fd, F_GETFL, 0); int status = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); report_zero_if(ERROR_MESSAGE("fcntl"), status < 0); } cleanup.ok = true; return TCPConnection_create(fd); }
TNetLinkImportHandle netLink_create(){ TCPConnection* tcp=TCPConnection_create(); return tcp; }