static void done_recv_request(void * args) { AsyncReqInfo * req = (AsyncReqInfo *) args; PortConnection * conn = (PortConnection *) (req)->client_data; port_unlock(conn); 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); } else port_connection_close(conn); return; } port_lock(conn); conn->server->client_addr_len = req->u.sio.addrlen; send_packet(conn, req->u.sio.bufp, req->u.sio.rval); }
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 * shutdown */ 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 port_server_shutdown(PortServer * server) { PortConnection * conn; /* It seems we need to use shutdown to unblock threads blocked on recv/send */ if (server->sock != -1) { shutdown(server->sock, SHUT_RDWR); if (closesocket(server->sock) == -1) perror("closesocket"); server->sock = -1; list_remove(&server->link); /* Closing socket is enough; the various port connections * will be deleted when server deletion will be detected. In this * case this API will be called again. */ return; } for (conn = server->list; conn != NULL; ) { PortConnection * next_conn; next_conn = conn->next; port_connection_close(conn); conn = next_conn; } if (server->list != NULL) return; /* Wait for all port connections to be closed */ if (server->accept_in_progress) return; /* Wait for accept request to be aborted */ channel_unlock_with_msg(server->channel, channel_lock_svr_msg); if (server->redir_info) free_port_redirection_info(server->redir_info); loc_free(server->addr_buf); loc_free(server); }
static void connect_port_callback(PortConnection * conn, int error) { assert(is_dispatch_thread()); port_unlock(conn); if (conn->shutdown_in_progress) return; if (error != 0) { port_connection_close(conn); return; } else { int idx; if (conn->server->connect_callback) conn->server->connect_callback(conn->server, conn->server->callback_data); conn->connected = 1; if (conn->fd != -1) { port_lock(conn); conn->recv_req.u.sio.sock = conn->fd; conn->recv_req.u.sio.addr = &conn->server->client_addr; conn->recv_req.u.sio.addrlen = sizeof(conn->server->client_addr); async_req_post(&conn->recv_req); } /* Send multiple TCF streams read requests in parallel; this is * to limit the performance impact on network with high latency. */ for (idx = 0; idx < MAX_STREAM_READ; idx++) read_packet(conn, idx); } }
static void delete_config_done(Channel *c, void *client_data, int error) { PortConnection * conn = (PortConnection *) client_data; Trap trap; if (set_trap(&trap)) { if (!error) { error = read_errno(&c->inp); json_test_char(&c->inp, MARKER_EOM); } clear_trap(&trap); } else { error = trap.error; } if (!conn->auto_connect_stream) { protocol_send_command(conn->server->channel, "Streams", "disconnect", disconnect_stream_done, conn); json_write_string(&conn->server->channel->out, conn->out_stream_id); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); } else { loc_free(conn->out_stream_id); conn->out_stream_id = NULL; loc_free(conn->in_stream_id); conn->in_stream_id = NULL; port_unlock(conn); port_connection_close(conn); } }
static void send_packet_callback(PortConnection * conn, int error) { assert(is_dispatch_thread()); port_unlock(conn); if (error != 0) { port_connection_close(conn); } else { port_lock(conn); conn->recv_req.u.sio.sock = conn->fd; conn->recv_req.u.sio.addrlen = sizeof(conn->server->client_addr); async_req_post(&conn->recv_req); } }
static void read_packet_callback(PortConnection * conn, int error, int idx, size_t size) { assert(is_dispatch_thread()); port_unlock(conn); if (error != 0 || size == 0) { port_connection_close(conn); } else { conn->read_buffer_size[idx] = size; /* Call read hooks if any. Note that those hooks can modify the content of the * packets (remove characters). */ if (conn->server->recv_callback) { conn->server->recv_callback(conn->server, conn->read_buffer[idx], &conn->read_buffer_size[idx], IN_BUF_SIZE, conn->server->callback_data); } /* If no client is connected or if the filter has removed all the packet content, * do not post a send request. */ if (conn->fd != -1 && conn->read_buffer_size[idx] != 0) { /* If there is already a send progress in request; postpone the * current one until it is completed. */ if (conn->send_in_progress != -1) { conn->pending_send_req |= 1 << idx; return; } port_lock(conn); conn->send_in_progress = idx; assert (conn->pending_send_req == 0); conn->send_req.u.sio.bufp = conn->read_buffer[idx]; conn->send_req.u.sio.bufsz = conn->read_buffer_size[idx]; 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); } else { read_packet(conn, idx); } } }
static void delete_config_done(Channel *c, void *client_data, int error) { PortConnection * conn = (PortConnection *) client_data; Trap trap; if (set_trap(&trap)) { if (!error) { error = read_errno(&c->inp); json_test_char(&c->inp, MARKER_EOM); } clear_trap(&trap); } else { error = trap.error; } loc_free(conn->out_stream_id); conn->out_stream_id = NULL; loc_free(conn->in_stream_id); conn->in_stream_id = NULL; port_unlock(conn); port_connection_close(conn); }