/**@ingroup tnet_socket_group * @retval Zero if succeed and nonzero error code otherwise. */ int tnet_socket_handle_brokenpipe(tnet_socket_t* self) { int ret; tnet_fd_t fd_old, fd_new; if (!self || !TNET_SOCKET_TYPE_IS_DGRAM(self->type)) { // Must be UDP TSK_DEBUG_ERROR("Invalid parameter"); return -1; } fd_old = self->fd; fd_new = TNET_INVALID_FD; // close old fd ret = tnet_sockfd_close(&self->fd); // try to create an fd binding to the same address if ((ret = tnet_sockfd_init(self->ip, self->port, self->type, &fd_new)) != 0) { TNET_PRINT_LAST_ERROR("Find to bind to %s:%d", self->ip, self->port); // TODO: Create completly new socket? return ret; } #if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR /* disable SIGPIPE signal */ { int yes = 1; if (setsockopt(fd_new, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){ TNET_PRINT_LAST_ERROR("setsockopt(%d, SO_NOSIGPIPE) have failed", fd_new); } } #endif /* TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR */ TSK_DEBUG_INFO("Broken pipe result for {%s:%d}: %d -> %d", self->ip, self->port, fd_old, fd_new); self->fd = fd_new; return 0; }
/*== Remove socket ==*/ int removeSocketAtIndex(int index, transport_context_t *context) { int i; tsk_safeobj_lock(context); if (index < (int)context->count) { transport_socket_t *sock = context->sockets[index]; // Free tls context //TSK_OBJECT_SAFE_FREE(sock->tlshandle); // Invalidate CFSocket if (sock->cf_socket) { if (CFSocketIsValid(sock->cf_socket)) { CFSocketInvalidate(sock->cf_socket); } CFRelease(sock->cf_socket); } // Close and free read stream if (sock->cf_read_stream) { // TODO: Investigate if we really need to do that //if (CFReadStreamGetStatus(sock->cf_read_stream) == kCFStreamStatusOpen) { // CFReadStreamClose(sock->cf_read_stream); //} CFRelease(sock->cf_read_stream); } // Close and free write stream if (sock->cf_write_stream) { // TODO: Investigate if we really need to do that //if (CFWriteStreamGetStatus(sock->cf_write_stream) == kCFStreamStatusOpen) { // CFWriteStreamClose(sock->cf_write_stream); //} CFRelease(sock->cf_write_stream); } // Close the socket if we are the owner. if (sock->owner) { tnet_sockfd_close(&(sock->fd)); } TSK_FREE(sock); for(i=index ; i<context->count-1; i++) { context->sockets[i] = context->sockets[i+1]; } context->sockets[context->count-1] = 0; context->count--; TSK_DEBUG_INFO("Socket removed"); } tsk_safeobj_unlock(context); return 0; }
/*== Remove socket ==*/ int removeSocket(int index, transport_context_t *context) { int i; tsk_safeobj_lock(context); if(index < (int)context->count) { /* Close the socket if we are the owner. */ TSK_DEBUG_INFO("Socket to remove: fd=%d, index=%d, tail.count=%d", context->sockets[index]->fd, index, (int)context->count); if(context->sockets[index]->owner) { // do not close the socket while it's being poll()ed // http://stackoverflow.com/questions/5039608/poll-cant-detect-event-when-socket-is-closed-locally if(context->polling) { TSK_DEBUG_INFO("RemoveSocket(fd=%d) has been requested but we are poll()ing the socket. ShutdownSocket(fd) called on the socket and we deferred the request.", context->sockets[index]->fd); TSK_DEBUG_INFO("ShutdownSocket(fd=%d)", context->sockets[index]->fd); tnet_sockfd_shutdown(context->sockets[index]->fd); goto done; } tnet_sockfd_close(&(context->sockets[index]->fd)); } /* Free tls context */ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle); // Free socket TSK_FREE(context->sockets[index]); for(i=index ; i<context->count-1; i++) { context->sockets[i] = context->sockets[i+1]; context->ufds[i] = context->ufds[i+1]; } context->sockets[context->count-1] = tsk_null; context->ufds[context->count-1].fd = TNET_INVALID_FD; context->ufds[context->count-1].events = 0; context->ufds[context->count-1].revents = 0; context->count--; } done: tsk_safeobj_unlock(context); return 0; }
/*== Remove socket ==*/ static int removeSocket(int index, transport_context_t *context) { tsk_size_t i; tsk_safeobj_lock(context); if (index < (int)context->count) { /* Close the socket if we are the owner. */ if (context->sockets[index]->owner) { tnet_sockfd_close(&(context->sockets[index]->fd)); } /* Free tls context */ if (context->sockets[index]->tlshandle) { TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle); } // Free socket TSK_FREE(context->sockets[index]); // Close event WSACloseEvent(context->events[index]); for (i = index; i < context->count - 1; i++) { context->sockets[i] = context->sockets[i + 1]; context->events[i] = context->events[i + 1]; } context->sockets[context->count - 1] = 0; context->events[context->count - 1] = 0; context->count--; TSK_DEBUG_INFO("Transport sockets count = %u", context->count); } tsk_safeobj_unlock(context); return 0; }
/*== Remove socket ==*/ int removeSocket(int index, transport_context_t *context) { int i; tsk_safeobj_lock(context); if(index < (int)context->count){ /* Close the socket if we are the owner. */ TSK_DEBUG_INFO("Socket to remove: fd=%d, index=%d, tail.count=%d", context->sockets[index]->fd, index, context->count); if(context->sockets[index]->owner){ tnet_sockfd_close(&(context->sockets[index]->fd)); } /* Free tls context */ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle); // Free socket TSK_FREE(context->sockets[index]); for(i=index ; i<context->count-1; i++){ context->sockets[i] = context->sockets[i+1]; context->ufds[i] = context->ufds[i+1]; } context->sockets[context->count-1] = tsk_null; context->ufds[context->count-1].fd = TNET_INVALID_FD; context->ufds[context->count-1].events = 0; context->ufds[context->count-1].revents = 0; context->count--; } tsk_safeobj_unlock(context); return 0; }
/**@ingroup tnet_socket_group * Closes a socket. * @param sock The socket to close. * @retval Zero if succeed and nonzero error code otherwise. **/ int tnet_socket_close(tnet_socket_t *sock) { return tnet_sockfd_close(&(sock->fd)); }
/** * Connects a socket. * @param handle The transport to use to connect() the socket. The new socket will be managed by this transport. * @param host The remote @a host to connect() to. * @param port The remote @a port to connect() to. * @param type The type of the socket to use to connect() to the remote @a host. * @retval The newly connected socket. For non-blocking sockets you should use @ref tnet_sockfd_waitUntilWritable to check * the socket for writability. * @sa tnet_sockfd_waitUntilWritable. */ tnet_fd_t tnet_transport_connectto(const tnet_transport_handle_t *handle, const char* host, tnet_port_t port, tnet_socket_type_t type) { tnet_transport_t *transport = (tnet_transport_t*)handle; struct sockaddr_storage to; int status = -1; tnet_fd_t fd = TNET_INVALID_FD; tnet_tls_socket_handle_t* tls_handle = tsk_null; if(!transport || !transport->master){ TSK_DEBUG_ERROR("Invalid transport handle"); goto bail; } if((TNET_SOCKET_TYPE_IS_STREAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_STREAM(type)) || (TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_DGRAM(type))){ TSK_DEBUG_ERROR("Master/destination types mismatch [%u/%u]", transport->master->type, type); goto bail; } /* Init destination sockaddr fields */ if((status = tnet_sockaddr_init(host, port, type, &to))){ TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u]", host, port); goto bail; } else if(TNET_SOCKET_TYPE_IS_IPV46(type)){ /* Update the type (unambiguously) */ if(to.ss_family == AF_INET6){ TNET_SOCKET_TYPE_SET_IPV6Only(type); } else{ TNET_SOCKET_TYPE_SET_IPV4Only(type); } } /* * STREAM ==> create new socket and connect it to the remote host. * DGRAM ==> connect the master to the remote host. */ if(TNET_SOCKET_TYPE_IS_STREAM(type)){ /* Create client socket descriptor. */ if((status = tnet_sockfd_init(transport->local_host, TNET_SOCKET_PORT_ANY, type, &fd))){ TSK_DEBUG_ERROR("Failed to create new sockfd."); goto bail; } } else{ fd = transport->master->fd; } if((status = tnet_sockfd_connectto(fd, (const struct sockaddr_storage *)&to))){ if(fd != transport->master->fd){ tnet_sockfd_close(&fd); } goto bail; } else{ static const tsk_bool_t __isClient = tsk_true; static const tsk_bool_t __takeOwnership = tsk_true; if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)){ #if HAVE_OPENSSL tls_handle = tnet_tls_socket_create(fd, transport->tls.ctx_client); if((status = tnet_tls_socket_connect(tls_handle))){ tnet_sockfd_close(&fd); goto bail; } #endif } /* Add the socket */ // socket must be added after connect() otherwise many Linux systems when return POLLHUP as the fd is not active yet if((status = tnet_transport_add_socket(handle, fd, type, __takeOwnership, __isClient, tls_handle))){ TNET_PRINT_LAST_ERROR("Failed to add new socket"); tnet_sockfd_close(&fd); goto bail; } } bail: TSK_OBJECT_SAFE_FREE(tls_handle); return fd; }
tnet_fd_t tnet_transport_connectto_3(const tnet_transport_handle_t *handle, struct tnet_socket_s* socket, const char* host, tnet_port_t port, tnet_socket_type_t type) { tnet_transport_t *transport = (tnet_transport_t*)handle; struct sockaddr_storage to; int status = -1; tnet_fd_t fd = socket ? socket->fd : TNET_INVALID_FD; tnet_tls_socket_handle_t* tls_handle = tsk_null; tsk_bool_t owe_socket = socket ? tsk_false : tsk_true; tsk_bool_t use_proxy = TNET_SOCKET_TYPE_IS_STREAM(type); const char* to_host = host; tnet_port_t to_port = port; tnet_socket_type_t to_type = type; tnet_proxyinfo_t* proxy_info = tsk_null; if (!transport || !transport->master) { TSK_DEBUG_ERROR("Invalid transport handle"); goto bail; } if ((TNET_SOCKET_TYPE_IS_STREAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_STREAM(type)) || (TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_DGRAM(type))) { TSK_DEBUG_ERROR("Master/destination types mismatch [%u/%u]", transport->master->type, type); goto bail; } if (use_proxy) { // auto-detect the proxy if (transport->proxy.auto_detect) { char* url = tsk_null; // The proxy detection implementations are designed for a browser and expect a "http://" or "https://" schemes (will work with socks). tsk_sprintf(&url, "%s://%s:%d", TNET_SOCKET_TYPE_IS_TLS(to_type) ? "https" : "http", to_host, to_port); proxy_info = tnet_proxydetect_get_info_fast(url, to_type); TSK_FREE(url); } // fall-back to the hard proxy if auto-detection failed if (!tnet_proxyinfo_is_valid(proxy_info) && tnet_proxyinfo_is_valid(transport->proxy.info)) { proxy_info = tsk_object_ref(transport->proxy.info); } } use_proxy &= tnet_proxyinfo_is_valid(proxy_info); if (use_proxy) { if (tnet_proxy_node_is_nettransport_supported(proxy_info->type, type)) { to_host = proxy_info->hostname; to_port = proxy_info->port; // SOCKS still doesn't define RFC for SSL security (https://tools.ietf.org/html/draft-ietf-aft-socks-ssl-00) but Kerberos6 authentication is supported if (proxy_info->type == tnet_proxy_type_http || proxy_info->type == tnet_proxy_type_socks4 || proxy_info->type == tnet_proxy_type_socks4a || proxy_info->type == tnet_proxy_type_socks5) { // Send CONNET to the proxy using unsecure connection then begin SSL handshaking if needed TNET_SOCKET_TYPE_UNSET(to_type, TLS); // Make the type unsecure (will keep other flags-e.g. IP version-) TNET_SOCKET_TYPE_SET(to_type, TCP); // Use plain TCP } } else { // Not an error. TSK_DEBUG_INFO("No proxy plugin to handle network transport type = %d", type); use_proxy = tsk_false; } } TSK_DEBUG_INFO("tnet_transport_connectto_3(host=%s, port=%d, type=%d, fd=%d, use_proxy=%d, to_host=%s, to_port=%d, to_type=%d, proxy_type=%d)" , host, port, type, fd, use_proxy, to_host, to_port, to_type, proxy_info ? proxy_info->type : 0); /* Init destination sockaddr fields */ if ((status = tnet_sockaddr_init(to_host, to_port, to_type, &to))) { TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u]", host, port); goto bail; } if (TNET_SOCKET_TYPE_IS_IPV46(type)) { /* Update the type (unambiguously) */ if (to.ss_family == AF_INET6) { TNET_SOCKET_TYPE_SET_IPV6Only(type); } else { TNET_SOCKET_TYPE_SET_IPV4Only(type); } } /* * STREAM ==> create new socket and connect it to the remote host. * DGRAM ==> connect the master to the remote host. */ if (fd == TNET_INVALID_FD) { // Create client socket descriptor. if ((status = tnet_sockfd_init(transport->local_host, TNET_SOCKET_PORT_ANY, to_type, &fd))) { TSK_DEBUG_ERROR("Failed to create new sockfd."); goto bail; } } if ((status = tnet_sockfd_connectto(fd, (const struct sockaddr_storage *)&to))) { if (fd != transport->master->fd) { tnet_sockfd_close(&fd); } goto bail; } else { static const tsk_bool_t __isClient = tsk_true; if (TNET_SOCKET_TYPE_IS_TLS(to_type) || TNET_SOCKET_TYPE_IS_WSS(to_type)) { #if HAVE_OPENSSL tls_handle = tnet_tls_socket_create(fd, transport->tls.ctx_client); if (socket) { TSK_OBJECT_SAFE_FREE(socket->tlshandle); socket->tlshandle = tsk_object_ref(tls_handle); } if ((status = tnet_tls_socket_connect(tls_handle))) { tnet_sockfd_close(&fd); goto bail; } #endif } /* Add the socket */ // socket must be added after connect() otherwise many Linux systems will return POLLHUP as the fd is not active yet if ((status = tnet_transport_add_socket_2(handle, fd, to_type, owe_socket, __isClient, tls_handle, host, port, proxy_info))) { TNET_PRINT_LAST_ERROR("Failed to add new socket"); tnet_sockfd_close(&fd); goto bail; } } bail: TSK_OBJECT_SAFE_FREE(tls_handle); TSK_OBJECT_SAFE_FREE(proxy_info); return status == 0 ? fd : TNET_INVALID_FD; }