📄 rpc_transport.c
字号:
/* need a non-blocking socket, otherwise accept() has a potential * race-condition (poll() says it is readable, connection drops, * and accept() blocks until the next connection comes...) */ blocking = 1; ret = ioctlsocket(sock, FIONBIO, &blocking); if (ret < 0) { WARN("couldn't make socket non-blocking, error %d\n", ret); RPCRT4_DestroyConnection(&tcpc->common); status = RPC_S_OUT_OF_RESOURCES; continue; } tcpc->common.Next = first_connection; first_connection = &tcpc->common; } freeaddrinfo(ai); /* if at least one connection was created for an endpoint then * return success */ if (first_connection) { RpcConnection *conn; /* find last element in list */ for (conn = first_connection; conn->Next; conn = conn->Next) ; EnterCriticalSection(&protseq->cs); conn->Next = protseq->conn; protseq->conn = first_connection; LeaveCriticalSection(&protseq->cs); TRACE("listening on %s\n", endpoint); return RPC_S_OK; } ERR("couldn't listen on port %s\n", endpoint); return status;}static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn){ int ret; struct sockaddr_in address; socklen_t addrsize; u_long blocking; RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; addrsize = sizeof(address); ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); if (ret < 0) { ERR("Failed to accept a TCP connection: error %d\n", ret); return RPC_S_OUT_OF_RESOURCES; } /* reset to blocking behaviour */ blocking = 0; ret = ioctlsocket(ret, FIONBIO, &blocking); client->sock = ret; TRACE("Accepted a new TCP connection\n"); return RPC_S_OK;}static int rpcrt4_conn_tcp_read(RpcConnection *Connection, void *buffer, unsigned int count){ RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; int r = recv(tcpc->sock, buffer, count, MSG_WAITALL); TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); return r;}static int rpcrt4_conn_tcp_write(RpcConnection *Connection, const void *buffer, unsigned int count){ RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; int r = write(tcpc->sock, buffer, count); TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); return r;}static int rpcrt4_conn_tcp_close(RpcConnection *Connection){ RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; TRACE("%d\n", tcpc->sock); if (tcpc->sock != -1) close(tcpc->sock); tcpc->sock = -1; return 0;}static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, const char *networkaddr, const char *endpoint){ twr_tcp_floor_t *tcp_floor; twr_ipv4_floor_t *ipv4_floor; struct addrinfo *ai; struct addrinfo hints; int ret; size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor); TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); if (!tower_data) return size; tcp_floor = (twr_tcp_floor_t *)tower_data; tower_data += sizeof(*tcp_floor); ipv4_floor = (twr_ipv4_floor_t *)tower_data; tcp_floor->count_lhs = sizeof(tcp_floor->protid); tcp_floor->protid = EPM_PROTOCOL_TCP; tcp_floor->count_rhs = sizeof(tcp_floor->port); ipv4_floor->count_lhs = sizeof(ipv4_floor->protid); ipv4_floor->protid = EPM_PROTOCOL_IP; ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr); hints.ai_flags = AI_NUMERICHOST; /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */ hints.ai_family = PF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_addrlen = 0; hints.ai_addr = NULL; hints.ai_canonname = NULL; hints.ai_next = NULL; ret = getaddrinfo(networkaddr, endpoint, &hints, &ai); if (ret) { ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai); if (ret) { ERR("getaddrinfo failed: %s\n", gai_strerror(ret)); return 0; } } if (ai->ai_family == PF_INET) { const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr; tcp_floor->port = sin->sin_port; ipv4_floor->ipv4addr = sin->sin_addr.s_addr; } else { ERR("unexpected protocol family %d\n", ai->ai_family); return 0; } freeaddrinfo(ai); return size;}static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint){ const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; const twr_ipv4_floor_t *ipv4_floor; struct in_addr in_addr; TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); if (tower_size < sizeof(*tcp_floor)) return EPT_S_NOT_REGISTERED; tower_data += sizeof(*tcp_floor); tower_size -= sizeof(*tcp_floor); if (tower_size < sizeof(*ipv4_floor)) return EPT_S_NOT_REGISTERED; ipv4_floor = (const twr_ipv4_floor_t *)tower_data; if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || (tcp_floor->protid != EPM_PROTOCOL_TCP) || (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || (ipv4_floor->protid != EPM_PROTOCOL_IP) || (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr))) return EPT_S_NOT_REGISTERED; if (endpoint) { *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */); if (!*endpoint) return RPC_S_OUT_OF_RESOURCES; sprintf(*endpoint, "%u", ntohs(tcp_floor->port)); } if (networkaddr) { *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN); if (!*networkaddr) { if (endpoint) { I_RpcFree(*endpoint); *endpoint = NULL; } return RPC_S_OUT_OF_RESOURCES; } in_addr.s_addr = ipv4_floor->ipv4addr; if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN)) { ERR("inet_ntop: %s\n", strerror(errno)); I_RpcFree(*networkaddr); *networkaddr = NULL; if (endpoint) { I_RpcFree(*endpoint); *endpoint = NULL; } return EPT_S_NOT_REGISTERED; } } return RPC_S_OK;}typedef struct _RpcServerProtseq_sock{ RpcServerProtseq common; int mgr_event_rcv; int mgr_event_snd;} RpcServerProtseq_sock;static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void){ RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); if (ps) { int fds[2]; u_long blocking; if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds)) { blocking = 1; ioctlsocket(fds[0], FIONBIO, &blocking); ioctlsocket(fds[1], FIONBIO, &blocking); ps->mgr_event_rcv = fds[0]; ps->mgr_event_snd = fds[1]; } else { ERR("socketpair failed with error %s\n", strerror(errno)); HeapFree(GetProcessHeap(), 0, ps); return NULL; } } return &ps->common;}static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq){ RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); char dummy = 1; write(sockps->mgr_event_snd, &dummy, sizeof(dummy));}static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count){ struct pollfd *poll_info = prev_array; RpcConnection_tcp *conn; RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); EnterCriticalSection(&protseq->cs); /* open and count connections */ *count = 1; conn = (RpcConnection_tcp *)protseq->conn; while (conn) { if (conn->sock != -1) (*count)++; conn = (RpcConnection_tcp *)conn->common.Next; } /* make array of connections */ if (poll_info) poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info)); else poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info)); if (!poll_info) { ERR("couldn't allocate poll_info\n"); LeaveCriticalSection(&protseq->cs); return NULL; } poll_info[0].fd = sockps->mgr_event_rcv; poll_info[0].events = POLLIN; *count = 1; conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); while (conn) { if (conn->sock != -1) { poll_info[*count].fd = conn->sock; poll_info[*count].events = POLLIN; (*count)++; } conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); } LeaveCriticalSection(&protseq->cs); return poll_info;}static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array){ HeapFree(GetProcessHeap(), 0, array);}static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array){ struct pollfd *poll_info = wait_array; int ret, i; RpcConnection *cconn; RpcConnection_tcp *conn; if (!poll_info) return -1; ret = poll(poll_info, count, -1); if (ret < 0) { ERR("poll failed with error %d\n", ret); return -1; } for (i = 0; i < count; i++) if (poll_info[i].revents & POLLIN) { /* RPC server event */ if (i == 0) { char dummy; read(poll_info[0].fd, &dummy, sizeof(dummy)); return 0; } /* find which connection got a RPC */ EnterCriticalSection(&protseq->cs); conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); while (conn) { if (poll_info[i].fd == conn->sock) break; conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); } cconn = NULL; if (conn) RPCRT4_SpawnConnection(&cconn, &conn->common); else ERR("failed to locate connection for fd %d\n", poll_info[i].fd); LeaveCriticalSection(&protseq->cs); if (cconn) RPCRT4_new_client(cconn); else return -1; } return 1;}static const struct connection_ops conn_protseq_list[] = { { "ncacn_np", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, rpcrt4_conn_np_alloc, rpcrt4_ncacn_np_open, rpcrt4_ncacn_np_handoff, rpcrt4_conn_np_read, rpcrt4_conn_np_write, rpcrt4_conn_np_close, rpcrt4_ncacn_np_get_top_of_tower, rpcrt4_ncacn_np_parse_top_of_tower, }, { "ncalrpc", { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, rpcrt4_conn_np_alloc, rpcrt4_ncalrpc_open, rpcrt4_ncalrpc_handoff, rpcrt4_conn_np_read, rpcrt4_conn_np_write, rpcrt4_conn_np_close, rpcrt4_ncalrpc_get_top_of_tower, rpcrt4_ncalrpc_parse_top_of_tower, }, { "ncacn_ip_tcp", { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, rpcrt4_conn_tcp_alloc, rpcrt4_ncacn_ip_tcp_open, rpcrt4_conn_tcp_handoff, rpcrt4_conn_tcp_read, rpcrt4_conn_tcp_write, rpcrt4_conn_tcp_close, rpcrt4_ncacn_ip_tcp_get_top_of_tower, rpcrt4_ncacn_ip_tcp_parse_top_of_tower, }};static const struct protseq_ops protseq_list[] ={ { "ncacn_np", rpcrt4_protseq_np_alloc, rpcrt4_protseq_np_signal_state_changed, rpcrt4_protseq_np_get_wait_array, rpcrt4_protseq_np_free_wait_array, rpcrt4_protseq_np_wait_for_new_connection, rpcrt4_protseq_ncacn_np_open_endpoint, }, { "ncalrpc", rpcrt4_protseq_np_alloc, rpcrt4_protseq_np_signal_state_changed, rpcrt4_protseq_np_get_wait_array, rpcrt4_protseq_np_free_wait_array, rpcrt4_protseq_np_wait_for_new_connection, rpcrt4_protseq_ncalrpc_open_endpoint, }, { "ncacn_ip_tcp", rpcrt4_protseq_sock_alloc, rpcrt4_protseq_sock_signal_state_changed, rpcrt4_protseq_sock_get_wait_array, rpcrt4_protseq_sock_free_wait_array, rpcrt4_protseq_sock_wait_for_new_connection, rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, },};#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -