int udp_attach(PNATState pData, struct socket *so) { struct sockaddr_in *addr; struct sockaddr sa_addr; socklen_t socklen = sizeof(struct sockaddr); int status; int opt = 1; /* We attaching some olready attched socket ??? */ Assert(so->so_type == 0); if ((so->s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) goto error; /* * Here, we bind() the socket. Although not really needed * (sendto() on an unbound socket will bind it), it's done * here so that emulation of ytalk etc. don't have to do it */ memset(&sa_addr, 0, sizeof(struct sockaddr)); addr = (struct sockaddr_in *)&sa_addr; #ifdef RT_OS_DARWIN addr->sin_len = sizeof(struct sockaddr_in); #endif addr->sin_family = AF_INET; addr->sin_addr.s_addr = pData->bindIP.s_addr; fd_nonblock(so->s); if (bind(so->s, &sa_addr, sizeof(struct sockaddr_in)) < 0) { int lasterrno = errno; closesocket(so->s); so->s = -1; #ifdef RT_OS_WINDOWS WSASetLastError(lasterrno); #else errno = lasterrno; #endif goto error; } /* success, insert in queue */ so->so_expire = curtime + SO_EXPIRE; /* enable broadcast for later use */ setsockopt(so->s, SOL_SOCKET, SO_BROADCAST, (const char *)&opt, sizeof(opt)); status = getsockname(so->s, &sa_addr, &socklen); Assert(status == 0 && sa_addr.sa_family == AF_INET); so->so_hlport = ((struct sockaddr_in *)&sa_addr)->sin_port; so->so_hladdr.s_addr = ((struct sockaddr_in *)&sa_addr)->sin_addr.s_addr; SOCKET_LOCK_CREATE(so); QSOCKET_LOCK(udb); insque(pData, so, &udb); NSOCK_INC(); QSOCKET_UNLOCK(udb); so->so_type = IPPROTO_UDP; return so->s; error: Log2(("NAT: can't create datagramm socket\n")); return -1; }
void udp_detach(PNATState pData, struct socket *so) { if (so != &pData->icmp_socket) { Assert(so->so_type == IPPROTO_UDP); QSOCKET_LOCK(udb); SOCKET_LOCK(so); QSOCKET_UNLOCK(udb); closesocket(so->s); sofree(pData, so); SOCKET_UNLOCK(so); } }
int udp_attach(PNATState pData, struct socket *so) { struct sockaddr sa_addr; socklen_t socklen = sizeof(struct sockaddr); int status; int opt = 1; AssertReturn(so->so_type == 0, -1); so->so_type = IPPROTO_UDP; so->s = socket(AF_INET, SOCK_DGRAM, 0); if (so->s == -1) goto error; fd_nonblock(so->s); so->so_sottl = 0; so->so_sotos = 0; so->so_sodf = -1; status = sobind(pData, so); if (status != 0) return status; /* success, insert in queue */ so->so_expire = curtime + SO_EXPIRE; /* enable broadcast for later use */ setsockopt(so->s, SOL_SOCKET, SO_BROADCAST, (const char *)&opt, sizeof(opt)); status = getsockname(so->s, &sa_addr, &socklen); if (status == 0) { Assert(sa_addr.sa_family == AF_INET); so->so_hlport = ((struct sockaddr_in *)&sa_addr)->sin_port; so->so_hladdr.s_addr = ((struct sockaddr_in *)&sa_addr)->sin_addr.s_addr; } SOCKET_LOCK_CREATE(so); QSOCKET_LOCK(udb); insque(pData, so, &udb); NSOCK_INC(); QSOCKET_UNLOCK(udb); return so->s; error: Log2(("NAT: can't create datagram socket\n")); return -1; }
void udp_detach(PNATState pData, struct socket *so) { if (so != &pData->icmp_socket) { Assert(so->so_type == IPPROTO_UDP); QSOCKET_LOCK(udb); SOCKET_LOCK(so); QSOCKET_UNLOCK(udb); #ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE if (so->so_cloneOf) so->so_cloneOf->so_cCloneCounter--; else if (so->so_cCloneCounter > 0) { /* we can't close socket yet */ SOCKET_UNLOCK(so); return; } #endif closesocket(so->s); sofree(pData, so); SOCKET_UNLOCK(so); } }
/* * Read from so's socket into sb_snd, updating all relevant sbuf fields * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ int soread(PNATState pData, struct socket *so) { int n, nn, lss, total; struct sbuf *sb = &so->so_snd; u_int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; int sockerr; STAM_PROFILE_START(&pData->StatIOread, a); STAM_COUNTER_RESET(&pData->StatIORead_in_1); STAM_COUNTER_RESET(&pData->StatIORead_in_2); QSOCKET_LOCK(tcb); SOCKET_LOCK(so); QSOCKET_UNLOCK(tcb); LogFlow(("soread: so = %R[natsock]\n", so)); Log2(("%s: so = %R[natsock] so->so_snd = %R[sbuf]\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, so, sb)); /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; iov[1].iov_base = 0; iov[1].iov_len = 0; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_rptr - sb->sb_data; if (iov[1].iov_len > len) iov[1].iov_len = len; total = iov[0].iov_len + iov[1].iov_len; if (total > mss) { lss = total % mss; if (iov[1].iov_len > lss) { iov[1].iov_len -= lss; n = 2; } else { lss -= iov[1].iov_len; iov[0].iov_len -= lss; n = 1; } } else n = 2; } else { if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } } #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); #else nn = recv(so->s, iov[0].iov_base, iov[0].iov_len, (so->so_tcpcb->t_force? MSG_OOB:0)); #endif if (nn < 0) sockerr = errno; /* save it, as it may be clobbered by logging */ else sockerr = 0; Log2(("%s: read(1) nn = %d bytes\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, nn)); Log2(("%s: so = %R[natsock] so->so_snd = %R[sbuf]\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, so, sb)); if (nn <= 0) { #ifdef RT_OS_WINDOWS /* * Windows reports ESHUTDOWN after SHUT_RD (SD_RECEIVE) * instead of just returning EOF indication. */ if (nn < 0 && sockerr == ESHUTDOWN) { nn = 0; sockerr = 0; } #endif if (nn == 0) /* XXX: should this be inside #if defined(RT_OS_WINDOWS)? */ { /* * Special case for WSAEnumNetworkEvents: If we receive 0 bytes that * _could_ mean that the connection is closed. But we will receive an * FD_CLOSE event later if the connection was _really_ closed. With * www.youtube.com I see this very often. Closing the socket too early * would be dangerous. */ int status; unsigned long pending = 0; status = ioctlsocket(so->s, FIONREAD, &pending); if (status < 0) Log(("NAT:%s: error in WSAIoctl: %d\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, errno)); if (pending != 0) { SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return 0; } } if ( nn < 0 && soIgnorableErrorCode(sockerr)) { SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return 0; } else { int fUninitializedTemplate = 0; int shuterr; fUninitializedTemplate = RT_BOOL(( sototcpcb(so) && ( sototcpcb(so)->t_template.ti_src.s_addr == INADDR_ANY || sototcpcb(so)->t_template.ti_dst.s_addr == INADDR_ANY))); /* nn == 0 means peer has performed an orderly shutdown */ Log2(("%s: disconnected, nn = %d, errno = %d (%s)\n", RT_GCC_EXTENSION __PRETTY_FUNCTION__, nn, sockerr, strerror(sockerr))); shuterr = sofcantrcvmore(so); if (!sockerr && !shuterr && !fUninitializedTemplate) tcp_sockclosed(pData, sototcpcb(so)); else { LogRel2(("NAT: sockerr %d, shuterr %d - %R[natsock]\n", sockerr, shuterr, so)); tcp_drop(pData, sototcpcb(so), sockerr); } SOCKET_UNLOCK(so); STAM_PROFILE_STOP(&pData->StatIOread, a); return -1; } } STAM_STATS( if (n == 1) { STAM_COUNTER_INC(&pData->StatIORead_in_1); STAM_COUNTER_ADD(&pData->StatIORead_in_1_bytes, nn); } else { STAM_COUNTER_INC(&pData->StatIORead_in_2); STAM_COUNTER_ADD(&pData->StatIORead_in_2_1st_bytes, nn); } );
struct socket * udp_listen(PNATState pData, u_int32_t bind_addr, u_int port, u_int32_t laddr, u_int lport, int flags) { struct sockaddr_in addr; struct socket *so; socklen_t addrlen = sizeof(struct sockaddr_in); int opt = 1; LogFlowFunc(("ENTER: bind_addr:%RTnaipv4, port:%d, laddr:%RTnaipv4, lport:%d, flags:%x\n", bind_addr, RT_N2H_U16(port), laddr, RT_N2H_U16(lport), flags)); if ((so = socreate()) == NULL) { LogFlowFunc(("LEAVE: NULL\n")); return NULL; } so->s = socket(AF_INET, SOCK_DGRAM, 0); if (so->s == -1) { LogRel(("NAT: can't create datagram socket\n")); RTMemFree(so); LogFlowFunc(("LEAVE: NULL\n")); return NULL; } so->so_expire = curtime + SO_EXPIRE; so->so_type = IPPROTO_UDP; fd_nonblock(so->s); so->so_sottl = 0; so->so_sotos = 0; so->so_sodf = -1; SOCKET_LOCK_CREATE(so); QSOCKET_LOCK(udb); insque(pData, so, &udb); NSOCK_INC(); QSOCKET_UNLOCK(udb); memset(&addr, 0, sizeof(addr)); #ifdef RT_OS_DARWIN addr.sin_len = sizeof(addr); #endif addr.sin_family = AF_INET; addr.sin_addr.s_addr = bind_addr; addr.sin_port = port; if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { LogRel(("NAT: udp bind to %RTnaipv4:%d failed, error %d\n", addr.sin_addr, RT_N2H_U16(port), errno)); udp_detach(pData, so); LogFlowFunc(("LEAVE: NULL\n")); return NULL; } setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR,(char *)&opt, sizeof(int)); /* setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE,(char *)&opt, sizeof(int)); */ getsockname(so->s,(struct sockaddr *)&addr,&addrlen); so->so_hladdr = addr.sin_addr; so->so_hlport = addr.sin_port; /* XXX: wtf are we setting so_faddr/so_fport here? */ so->so_fport = addr.sin_port; #if 0 /* The original check was completely broken, as the commented out * if statement was always true (INADDR_ANY=0). */ /** @todo vvl - alias_addr should be set (if required) * later by liabalias module. */ if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) so->so_faddr = alias_addr; else #endif so->so_faddr = addr.sin_addr; so->so_lport = lport; so->so_laddr.s_addr = laddr; if (flags != SS_FACCEPTONCE) so->so_expire = 0; so->so_state = SS_ISFCONNECTED; LogFlowFunc(("LEAVE: %R[natsock]\n", so)); return so; }