/* {INET_PROPERTIES}.is_ipv6_available */ EIF_TYPED_VALUE F157_8694 (EIF_REFERENCE Current) { GTCX char *l_feature_name = "is_ipv6_available"; RTEX; EIF_BOOLEAN Result = ((EIF_BOOLEAN) 0); RTSN; RTDA; RTLD; RTLI(1); RTLR(0,Current); RTLU (SK_BOOL, &Result); RTLU (SK_REF, &Current); RTEAA(l_feature_name, 156, Current, 0, 0, 2264); RTSA(Dtype(Current)); RTSC; RTME(Dtype(Current), 1); RTDBGEAA(156, Current, 2264); RTIV(Current, RTAL);Result = (EIF_BOOLEAN) EIF_TEST(en_ipv6_available()); RTVI(Current, RTAL); RTRS; RTHOOK(1); RTDBGLE; RTMD(1); RTLE; RTLO(2); RTEE; { EIF_TYPED_VALUE r; r.type = SK_BOOL; r.it_b = Result; return r; } }
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); } }
void en_socket_stream_create (EIF_INTEGER *a_fd, EIF_INTEGER *a_fd1) { SOCKET fd, fd1; EIF_NET_INITIALIZE; fd = check_socket_bounds(socket(AF_INET, SOCK_STREAM, 0)); if (fd == INVALID_SOCKET) { *a_fd = -1; eif_net_check ((int)fd); return; } else { /* Set socket attribute so it is not passed to any child process */ SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, FALSE); *a_fd = (EIF_INTEGER) fd; } if (en_ipv6_available()) { fd1 = check_socket_bounds(socket(AF_INET6, SOCK_STREAM, 0)); if (fd1 == INVALID_SOCKET) { *a_fd = -1; *a_fd1 = -1; net_socket_close((int)fd); eif_net_check ((int)fd1); return; } else { /* Set socket attribute so it is not passed to any child process */ SetHandleInformation((HANDLE)fd1, HANDLE_FLAG_INHERIT, FALSE); *a_fd1 = (EIF_INTEGER) fd1; } } else { *a_fd1 = -1; } }
EIF_INTEGER en_socket_datagram_rcv_from (EIF_INTEGER fd, EIF_INTEGER fd1, EIF_INTEGER *a_last_fd, EIF_POINTER buf, EIF_INTEGER len, EIF_INTEGER flags, EIF_INTEGER timeout, SOCKETADDRESS *him) { int nsockets = 0; int fduse = 0; int result; int lenn = sizeof(SOCKETADDRESS); int ipv6_supported = en_ipv6_available(); if (fd > 0) { nsockets++; } if (fd1 > 0) { nsockets++; } if (nsockets == 2) { /* need to choose one of them */ int ret, t = (timeout == 0) ? -1: timeout; ret = net_timeout2 (fd, fd1, t, &fduse); if (ret == 2) { fduse = check_last_fd (a_last_fd, fd, fd1); } else if (ret == 0) { if (ret == 0) { eraise("Receive timed out", EN_PROG); } else { eraise("Receive error", EN_PROG); } return -1; } } else if (!ipv6_supported) { fduse = fd; } else if (fd >= 0) { /* ipv6 supported: and this socket bound to an IPV6 only address */ fduse = fd1; } else { /* ipv6 supported: and this socket bound to an IPV4 only address */ fduse = fd; } if (timeout && nsockets == 1) { int ret; ret = net_timeout(fduse, timeout); if (ret <= 0) { if (ret == 0) { eraise("Receive timed out", EN_PROG); } else { eraise("Receive error", EN_PROG); } return -1; } } result = recvfrom ((SOCKET) fduse, (char *) buf, (int) len, (int) flags, (struct sockaddr *) him, &lenn); eif_net_check (result); return (EIF_INTEGER) result; }
void en_socket_datagram_create (EIF_INTEGER *a_fd, EIF_INTEGER *a_fd1) { SOCKET fd, fd1; BOOL t = TRUE; DWORD x1, x2; /* ignored result codes */ EIF_NET_INITIALIZE; fd = check_socket_bounds(socket (AF_INET, SOCK_DGRAM, 0)); if (fd == INVALID_SOCKET) { *a_fd = -1; eif_net_check ((int)fd); return; } else { /* Set socket attribute so it is not passed to any child process */ SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, FALSE); *a_fd = (EIF_INTEGER) fd; net_set_sock_opt((int) fd, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL)); } if (en_ipv6_available()) { /* SIO_UDP_CONNRESET fixes a bug introduced in Windows 2000, which * returns connection reset errors un connected UDP sockets (as well * as connected sockets. The solution is to only enable this feature * when the socket is connected */ t = FALSE; WSAIoctl(fd,SIO_UDP_CONNRESET,&t,sizeof(BOOL),&x1,sizeof(x1),&x2,0,0); t = TRUE; fd1 = check_socket_bounds(socket (AF_INET6, SOCK_DGRAM, 0)); if (fd1 == INVALID_SOCKET) { *a_fd = -1; *a_fd1 = -1; eif_net_check ((int)fd1); return; } else { net_set_sock_opt((int)fd1, SOL_SOCKET, SO_BROADCAST, (char*)&t, sizeof(BOOL)); t = FALSE; WSAIoctl(fd1,SIO_UDP_CONNRESET,&t,sizeof(BOOL),&x1,sizeof(x1),&x2,0,0); SetHandleInformation((HANDLE)fd1, HANDLE_FLAG_INHERIT, FALSE); *a_fd1 = (EIF_INTEGER) fd1; } } else { *a_fd1 = -1; } }
void en_socket_stream_listen (EIF_INTEGER *a_fd, EIF_INTEGER *a_fd1, EIF_POINTER sockaddr, EIF_INTEGER count) { int fd, fd1; SOCKETADDRESS *addr; int ipv6_supported; int res; EIF_NET_INITIALIZE; addr = (SOCKETADDRESS*) sockaddr; ipv6_supported = en_ipv6_available(); fd = *a_fd; if (addr->him.sa_family == AF_INET || NET_IN6ADDR_ISANY(&addr->him6) || NET_IN6ADDR_ISLOOPBACK(&addr->him6)) { /* listen on v4 */ if ((res=listen(fd, count)) == -1) { eif_net_check(res); } } else { net_socket_close(fd); *a_fd = -1; } if (ipv6_supported) { fd1 = *a_fd1; if ((addr->him.sa_family == AF_INET6) || (addr->him4.sin_addr.s_addr == INADDR_ANY) || (addr->him4.sin_addr.s_addr == htonl (INADDR_LOOPBACK))) { /* listen on v6 */ if ((res=listen(fd1, count)) == -1) { eif_net_check(res); } } else { net_socket_close(fd1); *a_fd1 = -1; } } }
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; } }