void en_socket_datagram_connect (EIF_INTEGER fd, EIF_INTEGER fd1, EIF_POINTER sockaddr) { SOCKETADDRESS* him; int family; EIF_INTEGER fdc = -1; int ipv6_supported; int connect_res; EIF_NET_INITIALIZE; ipv6_supported = en_ipv6_available(); him = (SOCKETADDRESS*) sockaddr; family = him->him.sa_family; if (family == AF_INET6 && !ipv6_supported) { eraise ("Protocol family not supported", EN_PROG); return; } fdc = (family == AF_INET? fd: fd1); connect_res = connect(fdc, (struct sockaddr *)him, SOCKETADDRESS_LEN(him)); if ( connect_res == -1) { eraise("Unable to establish connection", EN_PROG); } }
JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind* b) { int fd=-1, ofd=-1, rv, len; /* need to defer close until new sockets created */ int close_fd=-1, close_ofd=-1; SOCKETADDRESS oaddr; /* other address to bind */ int family = b->addr->him.sa_family; int ofamily; u_short port; /* requested port parameter */ u_short bound_port; if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY)) { /* bind to v4 only */ int ret; ret = NET_Bind (b->ipv4_fd, (struct sockaddr *)b->addr, sizeof (struct sockaddr_in)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv6_fd); b->ipv6_fd = -1; return 0; } if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->him6.sin6_addr))) { /* bind to v6 only */ int ret; ret = NET_Bind (b->ipv6_fd, (struct sockaddr *)b->addr, sizeof (struct SOCKADDR_IN6)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv4_fd); b->ipv4_fd = -1; return 0; } /* We need to bind on both stacks, with the same port number */ memset (&oaddr, 0, sizeof(oaddr)); if (family == AF_INET) { ofamily = AF_INET6; fd = b->ipv4_fd; ofd = b->ipv6_fd; port = (u_short)GET_PORT (b->addr); IN6ADDR_SETANY (&oaddr.him6); oaddr.him6.sin6_port = port; } else { ofamily = AF_INET; ofd = b->ipv4_fd; fd = b->ipv6_fd; port = (u_short)GET_PORT (b->addr); oaddr.him4.sin_family = AF_INET; oaddr.him4.sin_port = port; oaddr.him4.sin_addr.s_addr = INADDR_ANY; } rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* get the port and set it in the other address */ len = SOCKETADDRESS_LEN(b->addr); if (getsockname(fd, (struct sockaddr *)b->addr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = GET_PORT (b->addr); SET_PORT (&oaddr, bound_port); if ((rv=NET_Bind (ofd, (struct sockaddr *) &oaddr, SOCKETADDRESS_LEN (&oaddr))) == SOCKET_ERROR) { int retries; int sotype, arglen=sizeof(sotype); /* no retries unless, the request was for any free port */ if (port != 0) { CLOSE_SOCKETS_AND_RETURN; } getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen); #define SOCK_RETRIES 50 /* 50 is an arbitrary limit, just to ensure that this * cannot be an endless loop. Would expect socket creation to * succeed sooner. */ for (retries = 0; retries < SOCK_RETRIES; retries ++) { int len; close_fd = fd; fd = -1; close_ofd = ofd; ofd = -1; b->ipv4_fd = SOCKET_ERROR; b->ipv6_fd = SOCKET_ERROR; /* create two new sockets */ fd = socket (family, sotype, 0); if (fd == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } ofd = socket (ofamily, sotype, 0); if (ofd == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* bind random port on first socket */ SET_PORT (&oaddr, 0); rv = NET_Bind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* close the original pair of sockets before continuing */ closesocket (close_fd); closesocket (close_ofd); close_fd = close_ofd = -1; /* bind new port on second socket */ len = SOCKETADDRESS_LEN(&oaddr); if (getsockname(ofd, (struct sockaddr *)&oaddr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = GET_PORT (&oaddr); SET_PORT (b->addr, bound_port); rv = NET_Bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv != SOCKET_ERROR) { if (family == AF_INET) { b->ipv4_fd = fd; b->ipv6_fd = ofd; } else { b->ipv4_fd = ofd; b->ipv6_fd = fd; } return 0; } } CLOSE_SOCKETS_AND_RETURN; } return 0; }
EIF_INTEGER en_socket_datagram_send_to (EIF_INTEGER fd, EIF_INTEGER fd1, EIF_POINTER buf, EIF_INTEGER len, EIF_INTEGER flags, SOCKETADDRESS *him) { int result = -1; int fduse = -1; if (him->him.sa_family == AF_INET) { fduse = fd; } else if (him->him.sa_family == AF_INET6) { fduse = fd1; } if (fduse != -1) { result = sendto ((SOCKET) fduse, (char *) buf, (int) len, (int) flags, (struct sockaddr *) him, SOCKETADDRESS_LEN(him)); eif_net_check (result); } return (EIF_INTEGER) result; }
void en_socket_stream_bind (EIF_INTEGER *a_fd, EIF_INTEGER *a_fd1, EIF_INTEGER *a_local_port, EIF_POINTER sockaddr) { SOCKETADDRESS* him; int family; SOCKET fd, fd1; int ipv6_supported; int localport; int rv; EIF_NET_INITIALIZE; ipv6_supported = en_ipv6_available(); him = (SOCKETADDRESS*) sockaddr; family = him->him.sa_family; localport = ntohs (GET_PORT (him)); fd = (SOCKET) *a_fd; fd1 = (SOCKET) *a_fd1; if (ipv6_supported) { struct ipv6bind v6bind; v6bind.addr = him; v6bind.ipv4_fd = fd; v6bind.ipv6_fd = fd1; rv = net_bindV6(&v6bind); if (rv != -1) { /* check if the fds have changed */ if (v6bind.ipv4_fd != fd) { fd = v6bind.ipv4_fd; if (fd == INVALID_SOCKET) { /* socket is closed. */ *a_fd = -1; } else { /* socket was re-created */ *a_fd = (EIF_INTEGER) fd; } } if (v6bind.ipv6_fd != fd1) { fd1 = v6bind.ipv6_fd; if (fd1 == INVALID_SOCKET) { /* socket is closed. */ *a_fd1 = -1; } else { /* socket was re-created */ *a_fd1 = (EIF_INTEGER) fd1; } } } } else { rv = net_bind(fd, (struct sockaddr *)him, SOCKETADDRESS_LEN(him)); } if (rv == -1) { eraise("bind error", EN_PROG); return; } /* intialize the local port */ if (localport == 0) { /* Now that we're a bound socket, let's extract the port number * that the system chose for us and store it in the Socket object. */ int len = SOCKETADDRESS_LEN(him); u_short port; fd = him->him.sa_family == AF_INET? fd: fd1; if ((rv=getsockname(fd, (struct sockaddr *)him, &len)) == -1) { eif_net_check(rv); return; } port = ntohs (GET_PORT (him)); *a_local_port = port; } else { *a_local_port = localport; } }
void en_socket_stream_connect (EIF_INTEGER *a_fd, EIF_INTEGER *a_fd1, EIF_INTEGER *a_local_port, EIF_POINTER sockaddr, EIF_INTEGER timeout, EIF_BOOLEAN is_blocking) { SOCKETADDRESS* him; int family; SOCKET fd, fd1 = INVALID_SOCKET; int ipv6_supported; int connect_res; EIF_NET_INITIALIZE; ipv6_supported = en_ipv6_available(); fd = (SOCKET) *a_fd; if (ipv6_supported) { fd1 = *a_fd1; } him = (SOCKETADDRESS*) sockaddr; family = him->him.sa_family; if (family == AF_INET6) { if (!ipv6_supported) { eraise ("Protocol family not supported", EN_PROG); return; } else { if (fd1 == -1) { eraise ("Destination unreachable", EN_PROG); return; } /* close the v4 socket, and set fd to be the v6 socket */ *a_fd = (EIF_INTEGER) fd1; *a_fd1 = -1; net_socket_close(fd); fd = fd1; } } else { if (fd1 != -1) { /* close the v6 socket */ *a_fd1 = -1; net_socket_close(fd1); } if (fd == INVALID_SOCKET) { eraise ("Destination unreachable", EN_PROG); return; } } if (timeout <= 0) { connect_res = connect(fd, (struct sockaddr *) him, SOCKETADDRESS_LEN(him)); if (connect_res == SOCKET_ERROR) { connect_res = WSAGetLastError(); if ((connect_res == WSAEWOULDBLOCK) || (connect_res == WSAEINPROGRESS)) { connect_res = 0; errno = 0; } } } else { u_long optval; int optlen = sizeof(int); /* make socket non-blocking */ if (is_blocking) { optval = 1; ioctlsocket( fd, FIONBIO, &optval ); } /* initiate the connect */ connect_res = connect(fd, (struct sockaddr *) him, SOCKETADDRESS_LEN(him)); if (connect_res == SOCKET_ERROR) { if (WSAGetLastError() == WSAEWOULDBLOCK) { fd_set wr, ex; struct timeval t; FD_ZERO(&wr); FD_ZERO(&ex); FD_SET(fd, &wr); FD_SET(fd, &ex); t.tv_sec = timeout / 1000; t.tv_usec = (timeout % 1000) * 1000; /* Wait for timout, connection established or * connection failed. */ connect_res = select((int) fd+1, 0, &wr, &ex, &t); /* Timeout before connection is established/failed so * we throw exception and shutdown input/output to prevent * socket from being used. * The socket should be closed immediately by the caller. */ if (connect_res == 0) { shutdown( fd, SD_BOTH ); if (is_blocking) { /* make socket blocking again - just in case */ optval = 0; ioctlsocket( fd, FIONBIO, &optval ); } eraise("connect timed out", EN_PROG); return; } /* We must now determine if the connection has been established * or if it has failed. The logic here is designed to work around * bug on Windows NT whereby using getsockopt to obtain the * last error (SO_ERROR) indicates there is no error. The workaround * on NT is to allow winsock to be scheduled and this is done by * yielding and retrying. As yielding is problematic in heavy * load conditions we attempt up to 3 times to get the error reason. */ if (!FD_ISSET(fd, &ex)) { connect_res = 0; } else { int retry; for (retry=0; retry<3; retry++) { net_get_sock_opt(fd, SOL_SOCKET, SO_ERROR, (char*)&connect_res, &optlen); if (connect_res) { break; } Sleep(0); } if (connect_res == 0) { eraise("Unable to establish connection", EN_PROG); return; } } } } if (is_blocking) { /* make socket blocking again */ optval = 0; ioctlsocket(fd, FIONBIO, &optval); } } if (connect_res) { if (connect_res == WSAEADDRNOTAVAIL) { eraise("Address is invalid on local machine, or port is not valid on remote machine", EN_PROG); } else { eraise("Unable to establish connection", EN_PROG); } return; } *a_fd = (EIF_INTEGER) fd; /* we need to initialize the local port field if bind was called * previously to the connect (by the client) then localport field * will already be initialized. */ if (*a_local_port == 0) { /* Now that we're a connected socket, let's extract the port number * that the system chose for us and store it in the Socket object. */ u_short port; int len = SOCKETADDRESS_LEN(him); if (getsockname(fd, (struct sockaddr *)him, &len) == -1) { if (WSAGetLastError() == WSAENOTSOCK) { eraise("Socket closed", EN_PROG); } else { eraise("getsockname failed", EN_PROG); } return; } port = ntohs (GET_PORT(him)); *a_local_port = port; } }
static int net_bindV6(struct ipv6bind* b) { SOCKET fd=INVALID_SOCKET, ofd=INVALID_SOCKET, rv; int len; /* need to defer close until new sockets created */ SOCKET close_fd=INVALID_SOCKET, close_ofd=INVALID_SOCKET; SOCKETADDRESS oaddr; /* other address to bind */ int family = b->addr->him.sa_family; int ofamily; u_short port; /* requested port parameter */ u_short bound_port; /* We only bind to only IPv4 or IPv6 if the listen address is different from the ANY IP address or * the LOOPBACK IP address. */ if (family == AF_INET && (b->addr->him4.sin_addr.s_addr != INADDR_ANY) && (b->addr->him4.sin_addr.s_addr != htonl (INADDR_LOOPBACK))) { /* bind to v4 only */ int ret; ret = net_bind (b->ipv4_fd, (struct sockaddr *)b->addr, sizeof (struct sockaddr_in)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv6_fd); b->ipv6_fd = INVALID_SOCKET; return 0; } if (family == AF_INET6 && (!NET_IN6ADDR_ISANY(&b->addr->him6)) && !NET_IN6ADDR_ISLOOPBACK(&b->addr->him6)) { /* bind to v6 only */ int ret; ret = net_bind (b->ipv6_fd, (struct sockaddr *)b->addr, sizeof (struct sockaddr_in6)); if (ret == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } closesocket (b->ipv4_fd); b->ipv4_fd = INVALID_SOCKET; return 0; } /* We need to bind on both stacks, with the same port number */ memset (&oaddr, 0, sizeof(oaddr)); if (family == AF_INET) { ofamily = AF_INET6; fd = b->ipv4_fd; ofd = b->ipv6_fd; port = ntohs (GET_PORT (b->addr)); if (b->addr->him4.sin_addr.s_addr == htonl (INADDR_LOOPBACK)) { NET_IN6ADDR_SETLOOPBACK (&oaddr.him6); } else { NET_IN6ADDR_SETANY (&oaddr.him6); } oaddr.him6.sin6_port = port; } else { ofamily = AF_INET; ofd = b->ipv4_fd; fd = b->ipv6_fd; port = ntohs (GET_PORT (b->addr)); oaddr.him4.sin_family = AF_INET; oaddr.him4.sin_port = port; if (NET_IN6ADDR_ISLOOPBACK(&b->addr->him6)) { oaddr.him4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); } else { oaddr.him4.sin_addr.s_addr = INADDR_ANY; } } rv = net_bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* get the port and set it in the other address */ len = SOCKETADDRESS_LEN(b->addr); if (getsockname(fd, (struct sockaddr *)b->addr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = ntohs (GET_PORT (b->addr)); SET_PORT (&oaddr, htons (bound_port)); len = SOCKETADDRESS_LEN (&oaddr); if ((rv=net_bind (ofd, (struct sockaddr *) &oaddr, len)) == SOCKET_ERROR) { int retries; int sotype, arglen=sizeof(sotype); /* no retries unless, the request was for any free port */ if (port != 0) { CLOSE_SOCKETS_AND_RETURN; } getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen); #define SOCK_RETRIES 50 /* 50 is an arbitrary limit, just to ensure that this * cannot be an endless loop. Would expect socket creation to * succeed sooner. */ for (retries = 0; retries < SOCK_RETRIES; retries ++) { int len; close_fd = fd; fd = INVALID_SOCKET; close_ofd = ofd; ofd = INVALID_SOCKET; b->ipv4_fd = INVALID_SOCKET; b->ipv6_fd = INVALID_SOCKET; /* create two new sockets */ fd = check_socket_bounds (socket (family, sotype, 0)); if (fd == INVALID_SOCKET) { CLOSE_SOCKETS_AND_RETURN; } ofd = check_socket_bounds (socket (ofamily, sotype, 0)); if (ofd == INVALID_SOCKET) { CLOSE_SOCKETS_AND_RETURN; } /* bind random port on first socket */ SET_PORT (&oaddr, 0); rv = net_bind (ofd, (struct sockaddr *)&oaddr, SOCKETADDRESS_LEN(&oaddr)); if (rv == SOCKET_ERROR) { CLOSE_SOCKETS_AND_RETURN; } /* close the original pair of sockets before continuing */ closesocket (close_fd); closesocket (close_ofd); close_fd = close_ofd = INVALID_SOCKET; /* bind new port on second socket */ len = SOCKETADDRESS_LEN(&oaddr); if (getsockname(ofd, (struct sockaddr *)&oaddr, &len) == -1) { CLOSE_SOCKETS_AND_RETURN; } bound_port = ntohs (GET_PORT (&oaddr)); SET_PORT (b->addr, htons (bound_port)); rv = net_bind (fd, (struct sockaddr *)b->addr, SOCKETADDRESS_LEN(b->addr)); if (rv != SOCKET_ERROR) { if (family == AF_INET) { b->ipv4_fd = fd; b->ipv6_fd = ofd; } else { b->ipv4_fd = ofd; b->ipv6_fd = fd; } return 0; } } CLOSE_SOCKETS_AND_RETURN; } return 0; }