Exemple #1
0
/**@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;
}
Exemple #5
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));	
}
Exemple #7
0
/**
* 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;
}