diff --git a/netcon/NetconEthernetTap.cpp b/netcon/NetconEthernetTap.cpp index afb91fdbc..0ef3a6f04 100644 --- a/netcon/NetconEthernetTap.cpp +++ b/netcon/NetconEthernetTap.cpp @@ -442,7 +442,7 @@ void NetconEthernetTap::phyOnUnixData(PhySocket *sock,void **uptr,void *data,uns } /* - * Send a return value to the client for an RPC + * Send a 'retval' and 'errno' to the client for an RPC over connection->rpcSock */ int NetconEthernetTap::send_return_value(TcpConnection *conn, int retval, int _errno = 0) { @@ -642,8 +642,6 @@ void NetconEthernetTap::nc_err(void *arg, err_t err) if(l->conn) { switch(err) { - // FIXME: Check if connection is pending first? - case ERR_MEM: fprintf(stderr, "nc_err(): ERR_MEM->ENOMEM\n"); l->tap->send_return_value(l->conn, -1, ENOMEM); @@ -818,7 +816,7 @@ void NetconEthernetTap::handle_retval(PhySocket *sock, void **uptr, unsigned cha [X] EINVAL - The socket is already bound to an address. [I] ENOTSOCK - sockfd is a descriptor for a file, not a socket. - [X] ENOMEM - Insufficient kernel memory was available. ??? + [X] ENOMEM - Insufficient kernel memory was available. - The following errors are specific to UNIX domain (AF_UNIX) sockets: @@ -857,9 +855,9 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st if(err == ERR_USE) send_return_value(conn, -1, EADDRINUSE); if(err == ERR_MEM) - send_return_value(conn, -1, ENOMEM); // FIXME: Likely won't happen - if(err == ERR_BUF) send_return_value(conn, -1, ENOMEM); + if(err == ERR_BUF) + send_return_value(conn, -1, ENOMEM); // FIXME: Closest match } else { send_return_value(conn, ERR_OK, ERR_OK); // Success @@ -870,10 +868,10 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st send_return_value(conn, -1, EINVAL); } } - //else { - // fprintf(stderr, "handle_bind(): can't locate connection for PCB\n"); - // send_return_value(conn, -1, EBADF); // FIXME: This makes no sense - //} + else { + fprintf(stderr, "handle_bind(): can't locate connection for PCB\n"); + send_return_value(conn, -1, EBADF); + } } /* @@ -890,7 +888,7 @@ void NetconEthernetTap::handle_bind(PhySocket *sock, void **uptr, struct bind_st - := Not needed [?] EADDRINUSE - Another socket is already listening on the same port. -[I] EBADF - The argument sockfd is not a valid descriptor. +[IX] EBADF - The argument sockfd is not a valid descriptor. [I] ENOTSOCK - The argument sockfd is not a socket. [I] EOPNOTSUPP - The socket is not of a type that supports the listen() operation. @@ -923,7 +921,13 @@ void NetconEthernetTap::handle_listen(PhySocket *sock, void **uptr, struct liste } else { fprintf(stderr, "handle_listen(): unable to allocate memory for new listening PCB\n"); - send_return_value(conn, -1, ENOMEM); // FIXME: This does not have an equivalent errno value + // FIXME: This does not have an equivalent errno value + // lwip will reclaim space with a tcp_listen call since a PCB in a LISTEN + // state takes up less space. If something goes wrong during the creation of a + // new listening socket we should return an error that implies we can't use this + // socket, even if the reason isn't describing what really happened internally. + // See: http://lwip.wikia.com/wiki/Raw/TCP + send_return_value(conn, -1, EBADF); } } else { @@ -963,12 +967,13 @@ void NetconEthernetTap::handle_listen(PhySocket *sock, void **uptr, struct liste */ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socket_st* socket_rpc) { + int rpc_fd = _phy.getDescriptor(sock); struct tcp_pcb *newpcb = lwipstack->tcp_new(); if(newpcb != NULL) { ZT_PHY_SOCKFD_TYPE fds[2]; if(socketpair(PF_LOCAL, SOCK_STREAM, 0, fds) < 0) { if(errno < 0) { - send_return_value(_phy.getDescriptor(sock), -1, errno); + send_return_value(rpc_fd, -1, errno); return; } } @@ -984,7 +989,6 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke new_conn->pending = true; } else { - int rpc_fd = _phy.getDescriptor(sock); sock_fd_write(rpc_fd, -1); // Send a bad fd, to signal error fprintf(stderr, "handle_socket(): Memory not available for new PCB\n"); send_return_value(rpc_fd, -1, ENOMEM); @@ -1008,20 +1012,22 @@ void NetconEthernetTap::handle_socket(PhySocket *sock, void **uptr, struct socke [-] EACCES - For UNIX domain sockets, which are identified by pathname: Write permission is denied ... [?] EACCES, EPERM - The user tried to connect to a broadcast address without having the socket broadcast flag enabled ... - [i] EADDRINUSE - Local address is already in use. + [X] EADDRINUSE - Local address is already in use. [I] EAFNOSUPPORT - The passed address didn't have the correct address family in its sa_family field. - [?] EAGAIN - No more free local ports or insufficient entries in the routing cache. + [X] EAGAIN - No more free local ports or insufficient entries in the routing cache. [ ] EALREADY - The socket is nonblocking and a previous connection attempt has not yet been completed. - [I] EBADF - The file descriptor is not a valid index in the descriptor table. + [IX] EBADF - The file descriptor is not a valid index in the descriptor table. [ ] ECONNREFUSED - No-one listening on the remote address. [i] EFAULT - The socket structure address is outside the user's address space. [ ] EINPROGRESS - The socket is nonblocking and the connection cannot be completed immediately. [-] EINTR - The system call was interrupted by a signal that was caught. [X] EISCONN - The socket is already connected. - [?] ENETUNREACH - Network is unreachable. + [X] ENETUNREACH - Network is unreachable. [I] ENOTSOCK - The file descriptor is not associated with a socket. [X] ETIMEDOUT - Timeout while attempting connection. + [X] EINVAL - Invalid argument, SVr4, generally makes sense to set this + * */ void NetconEthernetTap::handle_connect(PhySocket *sock, void **uptr, struct connect_st* connect_rpc) @@ -1033,7 +1039,7 @@ void NetconEthernetTap::handle_connect(PhySocket *sock, void **uptr, struct conn ip_addr_t conn_addr = convert_ip((struct sockaddr_in *)&connect_rpc->__addr); if(conn != NULL) { - lwipstack->tcp_sent(conn->pcb, nc_sent); // FIXME: Move? + lwipstack->tcp_sent(conn->pcb, nc_sent); lwipstack->tcp_recv(conn->pcb, nc_recved); lwipstack->tcp_err(conn->pcb, nc_err); lwipstack->tcp_poll(conn->pcb, nc_poll, APPLICATION_POLL_FREQ); @@ -1042,25 +1048,41 @@ void NetconEthernetTap::handle_connect(PhySocket *sock, void **uptr, struct conn int err = 0; if((err = lwipstack->tcp_connect(conn->pcb,&conn_addr,conn_port, nc_connected)) < 0) { + if(err == ERR_ISCONN) { + send_return_value(conn, -1, EISCONN); // Already in connected state + return; + } if(err == ERR_USE) { - send_return_value(conn, -1, EISCONN); // Already in use + send_return_value(conn, -1, EADDRINUSE); // Already in use return; } if(err == ERR_VAL) { - send_return_value(conn, -1, EAFNOSUPPORT); // FIXME: Invalid arguments? + send_return_value(conn, -1, EINVAL); // Invalid ipaddress parameter return; } if(err == ERR_RTE) { - send_return_value(conn, -1, ENETUNREACH); // FIXME: Host unreachable + send_return_value(conn, -1, ENETUNREACH); // No route to host return; } - if(err == ERR_BUF) - { - // FIXME + if(err == ERR_BUF) { + send_return_value(conn, -1, EAGAIN); // No more ports available + return; } if(err == ERR_MEM) { - // FIXME: return value originates from tcp_enqueue_flags() + /* Can occur for the following reasons: tcp_enqueue_flags() + + 1) tcp_enqueue_flags is always called with either SYN or FIN in flags. + We need one available snd_buf byte to do that. + This means we can't send FIN while snd_buf==0. A better fix would be to + not include SYN and FIN sequence numbers in the snd_buf count. + + 2) Cannot allocate new pbuf + 3) Cannot allocate new TCP segment + + */ + send_return_value(conn, -1, EAGAIN); // FIXME: Doesn't describe the problem well, but closest match + return; } // We should only return a value if failure happens immediately @@ -1071,13 +1093,14 @@ void NetconEthernetTap::handle_connect(PhySocket *sock, void **uptr, struct conn // - Most instances of a retval for a connect() should happen // in the nc_connect() and nc_err() callbacks! fprintf(stderr, "handle_connect(): unable to connect\n"); - send_return_value(conn, -1, err); // FIXME: Only catch unhandled errors + send_return_value(conn, -1, EAGAIN); } // Everything seems to be ok, but we don't have enough info to retval conn->pending=true; } else { fprintf(stderr, "could not locate PCB based on their fd\n"); + send_return_value(conn, -1, EBADF); } } diff --git a/netcon/libintercept.so.1.0 b/netcon/libintercept.so.1.0 new file mode 100755 index 000000000..f8a460236 Binary files /dev/null and b/netcon/libintercept.so.1.0 differ