From e9d52602957b215a74543809767850370f7e5860 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sun, 11 Jun 2017 16:47:14 -0600 Subject: [PATCH] rktio: dup and socket addresses --- racket/src/rktio/demo.c | 33 ++++ racket/src/rktio/rktio.h | 9 ++ racket/src/rktio/rktio_network.c | 233 ++++++++++------------------ racket/src/rktio/rktio_private.h | 2 + racket/src/rktio/rktio_read_write.c | 48 +++++- 5 files changed, 171 insertions(+), 154 deletions(-) diff --git a/racket/src/rktio/demo.c b/racket/src/rktio/demo.c index 5a9f8634fe..c7c477ed44 100644 --- a/racket/src/rktio/demo.c +++ b/racket/src/rktio/demo.c @@ -557,6 +557,39 @@ int main() check_valid(fd2); check_valid(!rktio_poll_accept_ready(rktio, lnr)); + { + /* Dup'ing and closing old should work as well as using directly */ + rktio_fd_t *fdx; + + fdx = rktio_dup(rktio, fd); + check_valid(fdx); + check_valid(rktio_close(rktio, fd)); + fd = fdx; + + fdx = rktio_dup(rktio, fd2); + check_valid(fdx); + check_valid(rktio_close(rktio, fd2)); + fd2 = fdx; + } + + { + char **strs; + + strs = rktio_socket_address(rktio, fd2); + check_valid(strs); + printf("client: %s %s\n", strs[0], strs[1]); + free(strs[0]); + free(strs[1]); + free(strs); + + strs = rktio_socket_peer_address(rktio, fd2); + check_valid(strs); + printf("server: %s %s\n", strs[0], strs[1]); + free(strs[0]); + free(strs[1]); + free(strs); + } + check_read_write_pair(rktio, fd, fd2); rktio_listen_stop(rktio, lnr); diff --git a/racket/src/rktio/rktio.h b/racket/src/rktio/rktio.h index d9337c0867..bd745acadd 100644 --- a/racket/src/rktio/rktio.h +++ b/racket/src/rktio/rktio.h @@ -38,6 +38,9 @@ int rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd); rktio_fd_t *rktio_open(rktio_t *rktio, char *src, int modes); int rktio_close(rktio_t *rktio, rktio_fd_t *fd); +rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd); +void rktio_forget(rktio_t *rktio, rktio_fd_t *fd); + #define RKTIO_READ_EOF (-1) #define RKTIO_READ_ERROR (-2) #define RKTIO_WRITE_ERROR (-2) @@ -89,9 +92,15 @@ int rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn); int rktio_socket_shutdown(rktio_t *rktio, rktio_fd_t *rfd, int mode); +char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd); +char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd); + /*************************************************/ /* File-descriptor sets for polling */ +/* A poll set is intended for a single use or few uses, as opposed to + "long-term" poll sets. */ + typedef struct rktio_poll_set_t rktio_poll_set_t; #define RKTIO_POLL_READ RKTIO_OPEN_READ diff --git a/racket/src/rktio/rktio_network.c b/racket/src/rktio/rktio_network.c index 5e76303e16..dd7c0b3e00 100644 --- a/racket/src/rktio/rktio_network.c +++ b/racket/src/rktio/rktio_network.c @@ -191,7 +191,7 @@ struct rktio_addrinfo_t { int ai_socktype; int ai_protocol; size_t ai_addrlen; - struct sockaddr *ai_addr; + struct sockaddr *ai_addr; struct rktio_addrinfo_t *ai_next; }; # define RKTIO_AS_ADDRINFO(x) x @@ -884,11 +884,23 @@ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd) #ifdef RKTIO_SYSTEM_WINDOWS UNREGISTER_SOCKET(rfd->sock); closesocket(rfd->sock); + free(rfd); return 1; #endif } +void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd) +{ +#ifdef RKTIO_SYSTEM_UNIX + rktio_forget(rktio, rfd); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + UNREGISTER_SOCKET(rfd->sock); + closesocket(rfd->sock); +#endif +} + int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd) { #ifdef RKTIO_SYSTEM_UNIX @@ -970,6 +982,30 @@ static void init_socket(rktio_socket_t s) #endif } +rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd) +{ +#ifdef RKTIO_SYSTEM_UNIX + return rktio_dup(rktio, rfd); +#endif +#ifdef RKTIO_SYSTEM_WINDOWS + intptr_t nsocket; + intptr_t rc; + WSAPROTOCOL_INFO protocolInfo; + rc = WSADuplicateSocket(rfd->sock, GetCurrentProcessId(), &protocolInfo); + if (rc) { + get_socket_error(); + return NULL; + } + nsocket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocolInfo, 0, WSA_FLAG_OVERLAPPED); + if (nsocket == INVALID_SOCKET) { + get_socket_error(); + return NULL; + } + REGISTER_SOCKET(nsocket); + return rktio_system_fd(nsocket, rfd->modes); +#endif +} + intptr_t rktio_socket_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len) { rktio_socket_t s = rktio_fd_system_fd(rktio, rfd); @@ -1530,179 +1566,70 @@ rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener) } } -#if 0 - -static void mz_getnameinfo(void *sa, int salen, - char *host, int hostlen, - char *serv, int servlen) +static char **get_numeric_strings(rktio_t *rktio, void *sa, unsigned int salen) { + char **r; #ifdef HAVE_GETADDRINFO - getnameinfo(sa, salen, host, hostlen, serv, servlen, - NI_NUMERICHOST | NI_NUMERICSERV); + char host[NI_MAXHOST], serv[NI_MAXSERV]; + int err; + + err = getnameinfo(sa, salen, host, sizeof(host), serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); #else - if (host) { + char host[128], serv[32]; + { unsigned char *b; b = (unsigned char *)&((struct sockaddr_in *)sa)->sin_addr; sprintf(host, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]); } - if (serv) { + { int id; id = ntohs(((struct sockaddr_in *)sa)->sin_port); sprintf(serv, "%d", id); } + err = 0; #endif + + if (!err) { + r = malloc(sizeof(char*) * 2); + r[0] = strdup(host); + r[1] = strdup(serv); + return r; + } else { + set_gai_error(err); + return NULL; + } } -char **rktio_get_addresses() +char **rktio_socket_address(rktio_t *rktio, rktio_fd_t *rfd) { + char name[RKTIO_SOCK_NAME_MAX_LEN]; + unsigned int name_len; + + name_len = sizeof(name); + if (getsockname(rktio_fd_system_fd(rktio, rfd), (struct sockaddr *)name, &name_len)) { + get_socket_error(); + return NULL; + } + + return get_numeric_strings(rktio, name, name_len); } -static int extract_svc_value(char *svc_buf) +char **rktio_socket_peer_address(rktio_t *rktio, rktio_fd_t *rfd) { - int id = 0, j; - for (j = 0; svc_buf[j]; j++) { - id = (id * 10) + (svc_buf[j] - '0'); + char name[RKTIO_SOCK_NAME_MAX_LEN]; + unsigned int name_len; + + name_len = sizeof(name); + if (getpeername(rktio_fd_system_fd(rktio, rfd), (struct sockaddr *)name, &name_len)) { + get_socket_error(); + return NULL; } - return id; + + return get_numeric_strings(rktio, name, name_len); } -#define SCHEME_LISTEN_PORTP(p) SAME_TYPE(SCHEME_TYPE(p), scheme_listener_type) -#define SCHEME_UDP_PORTP(p) SAME_TYPE(SCHEME_TYPE(p), scheme_udp_type) - -static Scheme_Object *tcp_addresses(int argc, Scheme_Object *argv[]) -{ -#ifdef USE_TCP - rktio_socket_t socket = 0; - Scheme_Tcp *tcp = NULL; - int closed = 0; - Scheme_Object *result[4]; - int with_ports = 0; - int listener = 0; - int udp = 0; - - if (SCHEME_OUTPUT_PORTP(argv[0])) { - Scheme_Output_Port *op; - op = scheme_output_port_record(argv[0]); - if (op->sub_type == scheme_tcp_output_port_type) - tcp = op->port_data; - closed = op->closed; - } else if (SCHEME_INPUT_PORTP(argv[0])) { - Scheme_Input_Port *ip; - ip = scheme_input_port_record(argv[0]); - if (ip->sub_type == scheme_tcp_input_port_type) - tcp = ip->port_data; - closed = ip->closed; - } - - if (argc > 1) - with_ports = SCHEME_TRUEP(argv[1]); - - if (tcp) { - socket = tcp->tcp; - } - else { - if (SCHEME_LISTEN_PORTP(argv[0])) { - listener = 1; - socket = ((listener_t *)argv[0])->s[0]; - } else if (SCHEME_UDP_PORTP(argv[0])) { - udp = 1; - socket = ((Scheme_UDP *)argv[0])->s; - } else { - scheme_wrong_contract("tcp-addresses", "tcp-port?", 0, argc, argv); - } - } - - if (closed) - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: port is closed"); - - { - unsigned int l; - char here[RKTIO_SOCK_NAME_MAX_LEN], there[RKTIO_SOCK_NAME_MAX_LEN]; - char host_buf[RKTIO_SOCK_HOST_NAME_MAX_LEN]; - char svc_buf[RKTIO_SOCK_SVC_NAME_MAX_LEN]; - unsigned int here_len; - unsigned int there_len = 0; - int peerrc = 0; - - l = sizeof(here); - if (getsockname(socket, (struct sockaddr *)here, &l)) { - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: could not get local address\n" - " system error: %E", - SOCK_ERRNO()); - } - here_len = l; - - if (!listener) { - l = sizeof(there); - peerrc = getpeername(socket, (struct sockaddr *)there, &l); - if (peerrc && !udp) { - scheme_raise_exn(MZEXN_FAIL_NETWORK, - "tcp-addresses: could not get peer address\n" - " system error: %E", - SOCK_ERRNO()); - } - there_len = l; - } - - scheme_getnameinfo((struct sockaddr *)here, here_len, - host_buf, sizeof(host_buf), - (with_ports ? svc_buf : NULL), - (with_ports ? sizeof(svc_buf) : 0)); - result[0] = scheme_make_utf8_string(host_buf); - if (with_ports) { - l = extract_svc_value(svc_buf); - result[1] = scheme_make_integer(l); - } - - if (listener || (udp && peerrc)) { - result[with_ports ? 2 : 1] = scheme_make_utf8_string("0.0.0.0"); - result[3] = scheme_make_integer(0); - } - else { - scheme_getnameinfo((struct sockaddr *)there, there_len, - host_buf, sizeof(host_buf), - (with_ports ? svc_buf : NULL), - (with_ports ? sizeof(svc_buf) : 0)); - result[with_ports ? 2 : 1] = scheme_make_utf8_string(host_buf); - if (with_ports) { - l = extract_svc_value(svc_buf); - result[3] = scheme_make_integer(l); - } - } - } - - return scheme_values(with_ports ? 4 : 2, result); -#else - /* First arg can't possibly be right! */ - scheme_wrong_contract("tcp-addresses", "tcp-port?", 0, argc, argv); -#endif -} - -intptr_t scheme_dup_socket(intptr_t fd) { -#ifdef USE_TCP -# ifdef RKTIO_SYSTEM_WINDOWS - intptr_t nsocket; - intptr_t rc; - WSAPROTOCOL_INFO protocolInfo; - rc = WSADuplicateSocket(fd, GetCurrentProcessId(), &protocolInfo); - if (rc) - return rc; - nsocket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &protocolInfo, 0, WSA_FLAG_OVERLAPPED); - REGISTER_SOCKET(nsocket); - return nsocket; -# else - intptr_t nfd; - do { - nfd = dup(fd); - } while (nfd == -1 && errno == EINTR); - return nfd; -# endif -#else - return -1; -#endif -} +#if 0 /*========================================================================*/ /* UDP */ diff --git a/racket/src/rktio/rktio_private.h b/racket/src/rktio/rktio_private.h index 98b5521bf1..b9ec641a8f 100644 --- a/racket/src/rktio/rktio_private.h +++ b/racket/src/rktio/rktio_private.h @@ -153,6 +153,8 @@ struct pollfd *rktio_get_poll_fd_array(rktio_poll_set_t *fds); /*========================================================================*/ int rktio_socket_close(rktio_t *rktio, rktio_fd_t *rfd); +void rktio_socket_forget(rktio_t *rktio, rktio_fd_t *rfd); +rktio_fd_t *rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd); int rktio_socket_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); int rktio_socket_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd); diff --git a/racket/src/rktio/rktio_read_write.c b/racket/src/rktio/rktio_read_write.c index 4ef291b7e8..c27945fdc8 100644 --- a/racket/src/rktio/rktio_read_write.c +++ b/racket/src/rktio/rktio_read_write.c @@ -83,7 +83,7 @@ static void init_read_fd(rktio_fd_t *rfd) th->checking = 0; sm = CreateSemaphore(NULL, 0, 1, NULL); - th->checking_sema = sm; +v th->checking_sema = sm; sm = CreateSemaphore(NULL, 0, 1, NULL); th->ready_sema = sm; sm = CreateSemaphore(NULL, 1, 1, NULL); @@ -153,6 +153,41 @@ int rktio_fd_is_socket(rktio_t *rktio, rktio_fd_t *rfd) return (rfd->modes & RKTIO_OPEN_SOCKET); } +rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd) { +#ifdef RKTIO_SYSTEM_UNIX + intptr_t nfd; + + do { + nfd = dup(rfd->fd); + } while (nfd == -1 && errno == EINTR); + + if (nfd == -1) { + get_posix_error(); + return NULL; + } else + return rktio_system_fd(rktio, nfd, rfd->modes); +#endif +#ifdef WINDOWS_FILE_HANDLES + if (rfd->modes & RKTIO_OPEN_SOCKET) { + return rktio_socket_dup(rktio_t *rktio, rktio_fd_t *rfd) + } else { + HANDLE newhandle; + BOOL rc; + + rc = DuplicateHandle(GetCurrentProcess(), rfd->fd, + GetCurrentProcess(), &newhandle, + 0, FALSE, DUPLICATE_SAME_ACCESS); + + if (rc == FALSE) { + get_windows_error(); + return NULL; + } else { + return rktio_system_fd(rktio, (intptr_t)newhandle, rfd->modes); + } + } +#endif +} + /*************************************************************/ /* opening a file fd */ /*************************************************************/ @@ -475,6 +510,17 @@ int rktio_close(rktio_t *rktio, rktio_fd_t *rfd) return 1; } +void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd) +{ +#ifdef RKTIO_SYSTEM_WINDOWS + if (rfd->modes & RKTIO_OPEN_SOCKET) { + rktio_socket_forget(rktio, rfd); + return; + } +#endif + free(rfd); +} + /*************************************************************/ /* polling */ /*************************************************************/