static void done_send_request(void * args) { AsyncReqInfo * req = (AsyncReqInfo *) args; PortConnection * conn = (PortConnection *) (req)->client_data; int idx = conn->send_in_progress; port_unlock(conn); conn->send_in_progress = -1; if (conn->connected == 0) { port_connection_close(conn); return; } if (req->u.sio.rval == 0 || (req->u.sio.rval == -1 && req->error != EINTR)) { /* Check if we are in auto connect mode and server has not been * shut down */ if (conn->server->auto_connect && conn->server->sock != -1) { /* Client has disconnected; don't close the connection if we * are in auto connect mode but simply unbind the client from * the port. */ port_connection_unbind(conn); /* Still read packets from the target even if no client is * connected. This may have to be revisited. */ read_packet(conn, idx); } else port_connection_close(conn); return; } if (conn->pending_send_req != 0) { int next_idx; int loop; /* Get the next packet to send. In general, it is the next buffer * but there are some error cases (connection lost, empty packet * received from TCF agent) which may break this rule. */ for (loop = 0; loop < MAX_STREAM_READ; loop++) { next_idx = (idx + loop) % MAX_STREAM_READ; if (conn->pending_send_req & (1 << next_idx)) break; } assert (loop != MAX_STREAM_READ && (conn->pending_send_req & (1 << next_idx))); conn->send_in_progress = next_idx; conn->pending_send_req &= ~(1 << next_idx); conn->send_req.u.sio.bufp = conn->read_buffer[next_idx]; conn->send_req.u.sio.bufsz = conn->read_buffer_size[next_idx]; port_lock(conn); conn->send_req.u.sio.sock = conn->fd; conn->send_req.u.sio.addr = &conn->server->client_addr; conn->send_req.u.sio.addrlen = conn->server->client_addr_len; async_req_post(&conn->send_req); } read_packet(conn, idx); }
static void start_timer(void * args) { memset(&timer_req, 0, sizeof(timer_req)); timer_req.type = AsyncReqTimer; async_req_post(&timer_req); }
void channel_np_connect(PeerServer * ps, ChannelConnectCallBack callback, void * callback_args) { const char * host = peer_server_getprop(ps, "Host", NULL); const char * port = peer_server_getprop(ps, "Port", NULL); const char * get_url = peer_server_getprop(ps, "GetUrl", NULL); const char * host_name = peer_server_getprop(ps, "HostName", NULL); #if ENABLE_WebSocket_SOCKS_V5 const char * proxy = peer_server_getprop(ps, "Proxy", NULL); #endif ChannelConnectInfo * info = NULL; char port_str[16]; struct addrinfo hints; struct addrinfo * reslist = NULL; int error; ini_nopoll(); if (port == NULL) { sprintf(port_str, "%d", DISCOVERY_TCF_PORT); port = port_str; } memset(&hints, 0, sizeof hints); hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; error = loc_getaddrinfo(host, port, &hints, &reslist); if (error) error = set_gai_errno(error); if (!error) { struct addrinfo * res; info = (ChannelConnectInfo *)loc_alloc_zero(sizeof(ChannelConnectInfo)); for (res = reslist; res != NULL; res = res->ai_next) { info->addr_len = res->ai_addrlen; info->addr_buf = (struct sockaddr *)loc_alloc(res->ai_addrlen); memcpy(info->addr_buf, res->ai_addr, res->ai_addrlen); error = 0; break; } loc_freeaddrinfo(reslist); } if (!error && info->addr_buf == NULL) error = ENOENT; if (error) { if (info != NULL) { loc_free(info->addr_buf); loc_free(info); } callback(callback_args, error, NULL); } else { noPollCtx * np_ctx_client; np_ctx_client = nopoll_ctx_new(); /*nopoll_log_enable(np_ctx_client, nopoll_true);*/ #if ENABLE_WebSocket_SOCKS_V5 if (proxy != NULL) { /* save global proxy values */ char * proxy_host = socks_v5_host; char * proxy_port = socks_v5_port; if (parse_socks_v5_proxy(proxy) != 0) { socks_v5_host = proxy_host; socks_v5_port = proxy_port; if (info != NULL) { loc_free(info->addr_buf); loc_free(info); } callback(callback_args, errno, NULL); return; } if (socks_v5_host != NULL) nopoll_conn_set_socks_v5_proxy(np_ctx_client, socks_v5_host, socks_v5_port); /* Restore global proxy values */ socks_v5_host = proxy_host; socks_v5_port = proxy_port; } #endif info->callback = callback; info->callback_args = callback_args; info->is_ssl = strcmp(peer_server_getprop(ps, "TransportName", ""), "WSS") == 0; info->req.client_data = info; info->req.done = channel_np_connect_done; info->req.type = AsyncReqUser; info->req.u.user.func = np_wt_connect; info->req.u.user.data = info; info->host = loc_strdup(host == NULL ? "127.0.0.1" : host); info->port = loc_strdup(port); info->get_url = get_url; info->host_name = host_name; info->np_ctx = np_ctx_client; async_req_post(&info->req); } }
static PortServer * create_server(Channel * c, PortAttribute * attrs) { int sock = -1; struct sockaddr_in addr; PortAttribute * attr = attrs; #if defined(_WRS_KERNEL) int addrlen; #else socklen_t addrlen; #endif u_short port_number; PortServer * server = NULL; int is_udp = 0; /* do we use a server UDP -or TCP- port? */ char * port_config = NULL; int error = 0; int auto_connect = 0; uint64_t auto_connect_period = 0; unsigned int local_port = 0; while (attr != NULL) { if (strcmp(attr->name, "Port") == 0) { ByteArrayInputStream buf; InputStream * inp = create_byte_array_input_stream(&buf, attr->value, strlen(attr->value)); port_config = json_read_alloc_string(inp); if (strncasecmp(port_config, "udp:", strlen("udp:")) == 0) { is_udp = 1; } } else if (strcmp(attr->name, "AutoConnect") == 0) { ByteArrayInputStream buf; InputStream * inp = create_byte_array_input_stream(&buf, attr->value, strlen(attr->value)); auto_connect = json_read_boolean(inp); } else if (strcmp(attr->name, "AutoConnectPeriod") == 0) { ByteArrayInputStream buf; InputStream * inp = create_byte_array_input_stream(&buf, attr->value, strlen(attr->value)); auto_connect_period = json_read_ulong(inp); } else if (strcmp(attr->name, "LocalPort") == 0) { ByteArrayInputStream buf; InputStream * inp = create_byte_array_input_stream(&buf, attr->value, strlen(attr->value)); local_port = (unsigned int) json_read_uint64(inp); } attr = attr->next; } if (port_config == NULL) { error = set_errno(ERR_OTHER, "No port configuration is specified"); } if (error == 0) { loc_free(port_config); memset((void *) &addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = (u_short) htons(local_port); if (is_udp) sock = socket(AF_INET, SOCK_DGRAM, 0); else if ((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0) set_socket_options(sock); /* set socket options */ if (sock == -1) error = errno; } if (error == 0) { if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { error = errno; } } if (error == 0 && !is_udp) { if (listen(sock, 16) != 0) error = errno; } if (error == 0) { /* Get port property in case the default port could not be used or * the client specified a port that the system converts to a * dynamic port number. */ addrlen = sizeof addr; if (getsockname(sock, (struct sockaddr *) &addr, &addrlen) < 0) error = errno; } if (error == 0) { port_number = (u_short) ntohs(addr.sin_port); server = (PortServer *)loc_alloc_zero(sizeof(PortServer)); server->sock = sock; server->is_udp = is_udp; #if defined(SOCK_MAXADDRLEN) server->addr_len = SOCK_MAXADDRLEN; #else server->addr_len = 0x1000; #endif server->addr_buf = (struct sockaddr *)loc_alloc(server->addr_len); server->local_port = port_number; if (!server->is_udp) { server->accept_in_progress = 1; server->auto_connect = auto_connect; server->accreq.done = port_server_accept_done; server->accreq.client_data = server; server->accreq.type = AsyncReqAccept; server->accreq.u.acc.sock = sock; server->accreq.u.acc.addr = server->addr_buf; server->accreq.u.acc.addrlen = server->addr_len; async_req_post(&server->accreq); } else { /* For UDP, automatically connect to the port since there is no * connection request we can detect. */ server->auto_connect = 1; } server->auto_connect_period = auto_connect_period; list_add_last(&server->link, &server_list); channel_lock_with_msg(server->channel = c, channel_lock_svr_msg); snprintf (server->id, sizeof(server->id), "PS%" PRIu64, port_server_id++); server->attrs = attrs; } if (error == 0) return server; else { if (sock != -1) closesocket(sock); loc_free(server); return NULL ; } }