From 6b1a38f14c6d30510d3332039accdc43b5bd5032 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Mon, 12 Oct 2015 16:38:08 -0400 Subject: [PATCH] Better retval+errno handling --- netcon/NetconEthernetTap.cpp | 33 +++++++++++--------- netcon/intercept.c | 57 ++++++++++++++++++++--------------- netcon/libintercept.so.1.0 | Bin 0 -> 51688 bytes 3 files changed, 50 insertions(+), 40 deletions(-) create mode 100755 netcon/libintercept.so.1.0 diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index 1e74084fa..276d481a8 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/netcon/NetconEthernetTap.cpp @@ -447,13 +447,13 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns */ int NetconEthernetTap::send_return_value(TcpConnection *conn, int retval, int _errno = 0) { - char retmsg[sizeof(retval) + sizeof(_errno)]; + int sz = sizeof(char) + sizeof(retval) + sizeof(errno); + char retmsg[sz]; memset(&retmsg, '\0', sizeof(retmsg)); retmsg[0]=RPC_RETVAL; - memcpy(&retmsg[1], &retval, sizeof(retval)); + memcpy(&retmsg[1], &retval, sizeof(retval)); memcpy(&retmsg[1]+sizeof(retval), &_errno, sizeof(_errno)); - fprintf(stderr, "errno = %d\n", _errno); - int n = write(_phy.getDescriptor(conn->rpcSock), &retmsg, sizeof(retmsg)); + int n = write(_phy.getDescriptor(conn->rpcSock), &retmsg, sz); if(n > 0) conn->pending = false; else { @@ -695,8 +695,8 @@ err_t NetconEthernetTap::nc_connected(void *arg, struct tcp_pcb *tpcb, err_t err [ ] EACCES - The address is protected, and the user is not the superuser. [X] EADDRINUSE - The given address is already in use. - [ ] EBADF - sockfd is not a valid descriptor. - [ ] EINVAL - The socket is already bound to an address. + [X] EBADF - sockfd is not a valid descriptor. + [X] EINVAL - The socket is already bound to an address. [ ] ENOTSOCK - sockfd is a descriptor for a file, not a socket. [ ] The following errors are specific to UNIX domain (AF_UNIX) sockets: [ ] EACCES - Search permission is denied on a component of the path prefix. (See also path_resolution(7).) @@ -704,16 +704,15 @@ err_t NetconEthernetTap::nc_connected(void *arg, struct tcp_pcb *tpcb, err_t err [ ] EFAULT - addr points outside the user's accessible address space. [ ] EINVAL - The addrlen is wrong, or the socket was not in the AF_UNIX family. [ ] ELOOP - Too many symbolic links were encountered in resolving addr. - [ ] ENAMETOOLONG -s addr is too long. + [ ] ENAMETOOLONG - s addr is too long. [ ] ENOENT - The file does not exist. - [ ] ENOMEM - Insufficient kernel memory was available. + [X] ENOMEM - Insufficient kernel memory was available. [ ] ENOTDIR - A component of the path prefix is not a directory. [ ] EROFS - The socket inode would reside on a read-only file system. */ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st *bind_rpc) { - int _errno; struct sockaddr_in *connaddr; connaddr = (struct sockaddr_in *) &bind_rpc->addr; int conn_port = lwipstack->ntohs(connaddr->sin_port); @@ -725,11 +724,6 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st if(conn) { if(conn->pcb->state == CLOSED){ int err = lwipstack->tcp_bind(conn->pcb, &conn_addr, conn_port); - send_return_value(conn, err, -99); - if(err == ERR_USE) { - _errno = EADDRINUSE; - send_return_value(conn, err, -99); - } if(err != ERR_OK) { int ip = connaddr->sin_addr.s_addr; unsigned char d[4]; @@ -738,11 +732,20 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st d[2] = (ip >> 16) & 0xFF; d[3] = (ip >> 24) & 0xFF; fprintf(stderr, "handle_bind(): error binding to %d.%d.%d.%d : %d\n", d[0],d[1],d[2],d[3], conn_port); - } + if(err == ERR_USE) + send_return_value(conn, -1, EADDRINUSE); + if(err == ERR_MEM) + send_return_value(conn, -1, ENOMEM); + } + else { + send_return_value(conn, ERR_OK, 0); // OK + } } else fprintf(stderr, "handle_bind(): PCB not in CLOSED state. Ignoring BIND request.\n"); + send_return_value(conn, -1, EINVAL); } else fprintf(stderr, "handle_bind(): can't locate connection for PCB\n"); + send_return_value(conn, -1, EBADF); } /* diff --git a/netcon/intercept.c b/netcon/intercept.c index d7caf1012..b3e919059 100755 --- a/netcon/intercept.c +++ b/netcon/intercept.c @@ -139,6 +139,11 @@ static char* af_sock_name = "/tmp/.ztnc_e5cd7a9e1c5311ab"; static int thispid; +/* +* +* Check for forking +* +*/ int checkpid() { if(thispid != getpid()) { printf("clone/fork detected. re-initializing this instance.\n"); @@ -149,6 +154,31 @@ int checkpid() { return 0; } +/* +* +* Reads a return value from the service and sets errno (if applicable) +* +*/ +int get_retval() +{ + if(fdret_sock >= 0) { + int retval; + int sz = sizeof(char) + sizeof(retval) + sizeof(errno); + char retbuf[BUF_SZ]; + memset(&retbuf, '\0', sz); + int n_read = read(fdret_sock, &retbuf, sz); + if(n_read > 0) { + memcpy(&retval, &retbuf[1], sizeof(retval)); + memcpy(&errno, &retbuf[1+sizeof(retval)], sizeof(errno)); + return retval; + } + else { + dwr("unable to read connect: return value\n"); + return -1; + } + } +} + #define SLEEP_TIME 0 /*------------------------------------------------------------------------------ @@ -474,7 +504,6 @@ int socket(SOCKET_SIG) { #ifdef DUMMY dwr("socket(fam=%d, type=%d, prot=%d)\n", socket_family, socket_type, protocol); - //usleep(DUMMY_WAIT); return realsocket(socket_family, socket_type, protocol); #else @@ -676,33 +705,11 @@ int bind(BIND_SIG) write(fdret_sock, cmd, BUF_SZ); pthread_mutex_unlock(&lock); - /* - If we successfully wrote the RPC, try to read a return value - - Also get errno value - */ - if(fdret_sock >= 0) { - int retval; - int _errno; - char mynewbuf[BUF_SZ]; - memset(&mynewbuf, '\0', sizeof(mynewbuf)); - int n_read = read(fdret_sock, &mynewbuf, sizeof(mynewbuf)); - if(n_read > 0) { - memcpy(&retval, &mynewbuf[1], sizeof(retval)); - memcpy(&_errno, &mynewbuf[1]+sizeof(retval), sizeof(_errno)); - dwr("errno = %d\n", _errno); - errno = _errno; - pthread_mutex_unlock(&lock); - return retval; - } - else { - pthread_mutex_unlock(&lock); - dwr("unable to read connect: return value\n"); - } - } - return 0; /* FIXME: get real return value */ + return get_retval(); #endif } + /*------------------------------------------------------------------------------ ----------------------------------- accept4() ---------------------------------- ------------------------------------------------------------------------------*/ diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 new file mode 100755 index 0000000000000000000000000000000000000000..f4034ee29a0d2e4ff6cb511d4bd78c1e8ca41f65 GIT binary patch literal 51688 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 literal 0 HcmV?d00001