/*== Add new socket ==*/ int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client) { transport_context_t *context = transport?transport->context:0; if(context){ transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt)); sock->fd = fd; sock->type = type; sock->owner = take_ownership; if((TNET_SOCKET_TYPE_IS_TLS(sock->type) || TNET_SOCKET_TYPE_IS_WSS(sock->type)) && transport->tls.enabled){ #if HAVE_OPENSSL sock->tlshandle = tnet_tls_socket_create(sock->fd, is_client ? transport->tls.ctx_client : transport->tls.ctx_server); #endif } tsk_safeobj_lock(context); context->ufds[context->count].fd = fd; context->ufds[context->count].events = (fd == context->pipeR) ? TNET_POLLIN : context->events; context->ufds[context->count].revents = 0; context->sockets[context->count] = sock; context->count++; tsk_safeobj_unlock(context); TSK_DEBUG_INFO("Socket added: fd=%d, tail.count=%d", fd, context->count); return 0; } else{ TSK_DEBUG_ERROR("Context is Null."); return -1; } }
static int _tnet_transport_ssl_init(tnet_transport_t* transport) { if(!transport){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } #if HAVE_OPENSSL { tnet_socket_type_t type = tnet_transport_get_type(transport); tsk_bool_t is_tls = (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)); tsk_bool_t is_dtls = TNET_SOCKET_TYPE_IS_DTLS(type); if(is_dtls && !tnet_dtls_is_supported()){ TSK_DEBUG_ERROR("Requesting to create DTLS transport but source code not built with support for this feature"); return -1; } if(is_tls && !tnet_tls_is_supported()){ TSK_DEBUG_ERROR("Requesting to create TLS transport but source code not built with support for this feature"); return -1; } if((transport->tls.enabled = is_tls)){ if(!transport->tls.ctx_client && !(transport->tls.ctx_client = SSL_CTX_new(SSLv23_client_method()))){ TSK_DEBUG_ERROR("Failed to create SSL client context"); return -2; } if(!transport->tls.ctx_server && !(transport->tls.ctx_server = SSL_CTX_new(SSLv23_server_method()))){ TSK_DEBUG_ERROR("Failed to create SSL server context"); return -3; } SSL_CTX_set_mode(transport->tls.ctx_client, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(transport->tls.ctx_server, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(transport->tls.ctx_server, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs() SSL_CTX_set_verify(transport->tls.ctx_client, SSL_VERIFY_NONE, tsk_null); // to be updated by tnet_transport_tls_set_certs() if(SSL_CTX_set_cipher_list(transport->tls.ctx_client, TNET_CIPHER_LIST) <= 0 || SSL_CTX_set_cipher_list(transport->tls.ctx_server, TNET_CIPHER_LIST) <= 0){ TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); return -4; } } #if HAVE_OPENSSL_DTLS if((transport->dtls.enabled = is_dtls)){ if(!transport->dtls.ctx && !(transport->dtls.ctx = SSL_CTX_new(DTLSv1_method()))){ TSK_DEBUG_ERROR("Failed to create DTLSv1 context"); TSK_OBJECT_SAFE_FREE(transport); return -5; } SSL_CTX_set_read_ahead(transport->dtls.ctx, 1); // SSL_CTX_set_options(transport->dtls.ctx, SSL_OP_ALL); // SSL_CTX_set_mode(transport->dtls.ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_verify(transport->dtls.ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, tsk_null); // to be updated by tnet_transport_tls_set_certs() if(SSL_CTX_set_cipher_list(transport->dtls.ctx, TNET_CIPHER_LIST) <= 0){ TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%s]", ERR_error_string(ERR_get_error(), tsk_null)); return -6; } transport->dtls.activated = tsk_true; } #endif /* HAVE_OPENSSL_DTLS */ } #endif /* HAVE_OPENSSL */ return 0; }
/*== Add new socket ==*/ static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle) { transport_context_t *context; if (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) { #if !HAVE_OPENSSL TSK_DEBUG_ERROR("Cannot create TLS socket: OpenSSL missing"); return -2; #endif } if ((context = transport ? transport->context : tsk_null)) { transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt)); sock->fd = fd; sock->type = type; sock->owner = take_ownership ? 1 : 0; if ((TNET_SOCKET_TYPE_IS_TLS(sock->type) || TNET_SOCKET_TYPE_IS_WSS(sock->type)) && transport->tls.enabled) { if (tlsHandle) { sock->tlshandle = tsk_object_ref(tlsHandle); } else { #if HAVE_OPENSSL sock->tlshandle = tnet_tls_socket_create(sock->fd, is_client ? transport->tls.ctx_client : transport->tls.ctx_server); #endif } } tsk_safeobj_lock(context); context->events[context->count] = WSACreateEvent(); context->sockets[context->count] = sock; context->count++; TSK_DEBUG_INFO("Transport[%s] sockets count = %u", transport->description, context->count); tsk_safeobj_unlock(context); return 0; } else { TSK_DEBUG_ERROR("Context is Null."); return -1; } }
/**@ingroup tnet_socket_group * Returns the number of bytes sent (or negative value on error) */ int tnet_socket_send_stream(tnet_socket_t* self, const void* data, tsk_size_t size) { if (!self || self->fd == TNET_INVALID_FD || !data || !size || !TNET_SOCKET_TYPE_IS_STREAM(self->type)) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if (self->tlshandle && (TNET_SOCKET_TYPE_IS_TLS(self->type) || TNET_SOCKET_TYPE_IS_WSS(self->type))) { return tnet_tls_socket_send(self->tlshandle, data, size) == 0 ? (int)size : -1; // returns zero on success } return (int)tnet_sockfd_send(self->fd, data, size, 0); }
/*== Add new socket ==*/ int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client, tnet_tls_socket_handle_t* tlsHandle) { transport_context_t *context = transport?transport->context:0; if(context) { transport_socket_xt *sock = tsk_calloc(1, sizeof(transport_socket_xt)); sock->fd = fd; sock->type = type; sock->owner = take_ownership; if((TNET_SOCKET_TYPE_IS_TLS(sock->type) || TNET_SOCKET_TYPE_IS_WSS(sock->type)) && transport->tls.enabled) { if(tlsHandle) { sock->tlshandle = tsk_object_ref(tlsHandle); } else { #if HAVE_OPENSSL sock->tlshandle = tnet_tls_socket_create(sock->fd, is_client ? transport->tls.ctx_client : transport->tls.ctx_server); #endif } } tsk_safeobj_lock(context); context->ufds[context->count].fd = fd; context->ufds[context->count].events = (fd == context->pipeR) ? TNET_POLLIN : (TNET_POLLIN | TNET_POLLNVAL | TNET_POLLERR); if(TNET_SOCKET_TYPE_IS_STREAM(sock->type) && fd != context->pipeR) { context->ufds[context->count].events |= TNET_POLLOUT; // emulate WinSock2 FD_CONNECT event } context->ufds[context->count].revents = 0; context->sockets[context->count] = sock; context->count++; tsk_safeobj_unlock(context); TSK_DEBUG_INFO("Socket added[%s]: fd=%d, tail.count=%d", transport->description, fd, (int)context->count); return 0; } else { TSK_DEBUG_ERROR("Context is Null."); return -1; } }
int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle) { tnet_transport_t *transport = (tnet_transport_t*)handle; transport_context_t* context; static char c = '\0'; int ret = -1; if(!transport) { TSK_DEBUG_ERROR("Invalid server handle."); return ret; } if(!(context = (transport_context_t*)transport->context)) { TSK_DEBUG_ERROR("Invalid context."); return -2; } if(TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) { transport->tls.enabled = 1; } if((ret = addSocket(fd, type, transport, take_ownership, isClient, tlsHandle))) { TSK_DEBUG_ERROR("Failed to add new Socket."); return ret; } // signal if(context->pipeW && (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started)) { if((ret = write(context->pipeW, &c, 1)) > 0) { TSK_DEBUG_INFO("Socket added (external call) %d", fd); return 0; } else { TSK_DEBUG_ERROR("Failed to add new Socket."); return ret; } } else { TSK_DEBUG_INFO("pipeW (write site) not initialized yet."); return 0; //Will be taken when mainthead start } }
/* * Add new socket to the watcher. */ int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient, tnet_tls_socket_handle_t* tlsHandle) { tnet_transport_t *transport = (tnet_transport_t*)handle; transport_context_t* context; int ret = -1; if (!transport) { TSK_DEBUG_ERROR("Invalid server handle."); return ret; } if (!(context = (transport_context_t*)transport->context)) { TSK_DEBUG_ERROR("Invalid context."); return -2; } if (TNET_SOCKET_TYPE_IS_TLS(type) || TNET_SOCKET_TYPE_IS_WSS(type)) { transport->tls.enabled = tsk_true; } addSocket(fd, type, transport, take_ownership, isClient, tlsHandle); if (WSAEventSelect(fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR) { removeSocket((int)(context->count - 1), context); TNET_PRINT_LAST_ERROR("WSAEventSelect have failed."); return -1; } /* Signal if transport is running */ if (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started) { if (WSASetEvent(context->events[0])) { TSK_DEBUG_INFO("New socket added to the network transport."); return 0; } TSK_DEBUG_ERROR("Transport not started yet"); return -1; } TSK_DEBUG_INFO("Adding socket delayed"); return 0; }
static int tsip_transac_dst_deliver(struct tsip_transac_dst_s* self, tsip_dialog_event_type_t event_type, const tsip_message_t *msg) { if(!self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } switch(self->type){ case tsip_transac_dst_type_dialog: { return self->dialog.dlg->callback( self->dialog.dlg, event_type, msg ); } case tsip_transac_dst_type_net: { if(!msg){ TSK_DEBUG_ERROR("Message is null"); return -1; } // all messages coming from WebSocket transport have to be updated (AoR, Via...) before network delivering // all other messages MUST not unless specified from the dialog layer TSIP_MESSAGE(msg)->update |= (TNET_SOCKET_TYPE_IS_WS(msg->src_net_type) || TNET_SOCKET_TYPE_IS_WSS(msg->src_net_type)); return tsip_transport_layer_send( self->stack->layer_transport, msg->firstVia ? msg->firstVia->branch : tsk_null, TSIP_MESSAGE(msg) ); } default: { TSK_DEBUG_ERROR("Unexpected code called"); return -2; } } }
/** * 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; }