rktio: dup and socket addresses

This commit is contained in:
Matthew Flatt 2017-06-11 16:47:14 -06:00
parent 9461c0e72a
commit e9d5260295
5 changed files with 171 additions and 154 deletions

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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 */
/*************************************************************/