| /* |
| * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| #include <windef.h> |
| #include <winsock.h> |
| |
| #include "hpi_impl.h" |
| |
| #include "mutex_md.h" |
| |
| struct sockaddr; |
| |
| #define FN_RECV 0 |
| #define FN_SEND 1 |
| #define FN_LISTEN 2 |
| #define FN_BIND 3 |
| #define FN_ACCEPT 4 |
| #define FN_RECVFROM 5 |
| #define FN_SENDTO 6 |
| #define FN_SELECT 7 |
| #define FN_CONNECT 8 |
| #define FN_CLOSESOCKET 9 |
| #define FN_SHUTDOWN 10 |
| #define FN_GETHOSTNAME 11 |
| #define FN_GETHOSTBYADDR 12 |
| #define FN_GETHOSTBYNAME 13 |
| #define FN_HTONS 14 |
| #define FN_HTONL 15 |
| #define FN_NTOHS 16 |
| #define FN_NTOHL 17 |
| #define FN_GETSOCKOPT 18 |
| #define FN_SETSOCKOPT 19 |
| #define FN_GETPROTOBYNAME 20 |
| #define FN_GETSOCKNAME 21 |
| #define FN_SOCKET 22 |
| #define FN_WSASENDDISCONNECT 23 |
| #define FN_SOCKETAVAILABLE 24 |
| |
| static int (PASCAL FAR *sockfnptrs[])() = |
| {NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, NULL, NULL, NULL, |
| NULL, NULL, NULL, NULL, NULL, |
| }; |
| |
| static bool_t sockfnptrs_initialized = FALSE; |
| static mutex_t sockFnTableMutex; |
| |
| /* is Winsock2 loaded? better to be explicit than to rely on sockfnptrs */ |
| static bool_t winsock2Available = FALSE; |
| |
| /* Winsock2 options at the IPPROTO_IP level |
| We need the following translation in order to deal with the multiple |
| definitions for IPPROTO_IP level options in different winsock versions. |
| |
| in winsock.h vs. ws2tcpip.h |
| #define IP_OPTIONS 1 1 |
| #define IP_MULTICAST_IF 2 9 |
| #define IP_MULTICAST_TTL 3 10 |
| #define IP_MULTICAST_LOOP 4 11 |
| #define IP_ADD_MEMBERSHIP 5 12 |
| #define IP_DROP_MEMBERSHIP 6 13 |
| #define IP_TTL 7 4 |
| #define IP_TOS 8 3 |
| #define IP_DONTFRAGMENT 9 14 |
| */ |
| static int IPPROTO_OPTIONS[] = {-1, 1, 9, 10, 11, 12, 13, 4, 3, 14}; |
| |
| /* IMPORTANT: whenever possible, we want to use Winsock2 (ws2_32.dll) |
| * instead of Winsock (wsock32.dll). Other than the fact that it is |
| * newer, less buggy and faster than Winsock, Winsock2 lets us to work |
| * around the following problem: |
| * |
| * Generally speaking, it is important to shutdown a socket before |
| * closing it, since failing to do so can sometimes result in a TCP |
| * RST (abortive close) which is disturbing to the peer of the |
| * connection. |
| * |
| * The Winsock way to shutdown a socket is the Berkeley call |
| * shutdown(). We do not want to call it on Win95, since it |
| * sporadically leads to an OS crash in IFS_MGR.VXD. Complete hull |
| * breach. Blue screen. Ugly. |
| * |
| * So, in initSockTable we look for Winsock 2, and if we find it we |
| * assign wsassendisconnectfn function pointer. When we close, we |
| * first check to see if it's bound, and if it is, we call it. Winsock |
| * 2 will always be there on NT, and we recommend that win95 user |
| * install it. |
| * |
| * - br 10/11/97 |
| */ |
| |
| static void |
| initSockFnTable() { |
| int (PASCAL FAR* WSAStartupPtr)(WORD, LPWSADATA); |
| WSADATA wsadata; |
| OSVERSIONINFO info; |
| |
| mutexInit(&sockFnTableMutex); |
| mutexLock(&sockFnTableMutex); |
| if (sockfnptrs_initialized == FALSE) { |
| HANDLE hWinsock; |
| |
| /* try to load Winsock2, and if that fails, load Winsock */ |
| hWinsock = LoadLibrary("ws2_32.dll"); |
| if (hWinsock == NULL) { |
| hWinsock = LoadLibrary("wsock32.dll"); |
| winsock2Available = FALSE; |
| } else { |
| winsock2Available = TRUE; |
| } |
| |
| if (hWinsock == NULL) { |
| VM_CALL(jio_fprintf)(stderr, "Could not load Winsock 1 or 2 (error: %d)\n", |
| GetLastError()); |
| } |
| |
| /* If we loaded a DLL, then we might as well initialize it. */ |
| WSAStartupPtr = (int (PASCAL FAR *)(WORD, LPWSADATA)) |
| GetProcAddress(hWinsock, "WSAStartup"); |
| if (WSAStartupPtr(MAKEWORD(1,1), &wsadata) != 0) { |
| VM_CALL(jio_fprintf)(stderr, "Could not initialize Winsock\n"); |
| } |
| |
| sockfnptrs[FN_RECV] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "recv"); |
| sockfnptrs[FN_SEND] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "send"); |
| sockfnptrs[FN_LISTEN] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "listen"); |
| sockfnptrs[FN_BIND] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "bind"); |
| sockfnptrs[FN_ACCEPT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "accept"); |
| sockfnptrs[FN_RECVFROM] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "recvfrom"); |
| sockfnptrs[FN_SENDTO] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "sendto"); |
| sockfnptrs[FN_SELECT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "select"); |
| sockfnptrs[FN_CONNECT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "connect"); |
| sockfnptrs[FN_CLOSESOCKET] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "closesocket"); |
| /* we don't use this */ |
| sockfnptrs[FN_SHUTDOWN] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "shutdown"); |
| sockfnptrs[FN_GETHOSTNAME] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "gethostname"); |
| sockfnptrs[FN_GETHOSTBYADDR] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "gethostbyaddr"); |
| sockfnptrs[FN_GETHOSTBYNAME] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "gethostbyname"); |
| sockfnptrs[FN_HTONS] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "htons"); |
| sockfnptrs[FN_HTONL] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "htonl"); |
| sockfnptrs[FN_NTOHS] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "ntohs"); |
| sockfnptrs[FN_NTOHL] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "ntohl"); |
| sockfnptrs[FN_GETSOCKOPT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "getsockopt"); |
| sockfnptrs[FN_SETSOCKOPT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "setsockopt"); |
| sockfnptrs[FN_GETPROTOBYNAME] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "getprotobyname"); |
| sockfnptrs[FN_GETSOCKNAME] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "getsockname"); |
| |
| sockfnptrs[FN_SOCKET] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, "socket"); |
| /* in winsock 1, this will simply be 0 */ |
| sockfnptrs[FN_WSASENDDISCONNECT] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, |
| "WSASendDisconnect"); |
| sockfnptrs[FN_SOCKETAVAILABLE] |
| = (int (PASCAL FAR *)())GetProcAddress(hWinsock, |
| "ioctlsocket"); |
| } |
| |
| sysAssert(sockfnptrs[FN_RECV] != NULL); |
| sysAssert(sockfnptrs[FN_SEND] != NULL); |
| sysAssert(sockfnptrs[FN_LISTEN] != NULL); |
| sysAssert(sockfnptrs[FN_BIND] != NULL); |
| sysAssert(sockfnptrs[FN_ACCEPT] != NULL); |
| sysAssert(sockfnptrs[FN_RECVFROM] != NULL); |
| sysAssert(sockfnptrs[FN_SENDTO] != NULL); |
| sysAssert(sockfnptrs[FN_SELECT] != NULL); |
| sysAssert(sockfnptrs[FN_CONNECT] != NULL); |
| sysAssert(sockfnptrs[FN_CLOSESOCKET] != NULL); |
| sysAssert(sockfnptrs[FN_SHUTDOWN] != NULL); |
| sysAssert(sockfnptrs[FN_GETHOSTNAME] != NULL); |
| sysAssert(sockfnptrs[FN_GETHOSTBYADDR] != NULL); |
| sysAssert(sockfnptrs[FN_GETHOSTBYNAME] != NULL); |
| sysAssert(sockfnptrs[FN_HTONS] != NULL); |
| sysAssert(sockfnptrs[FN_HTONL] != NULL); |
| sysAssert(sockfnptrs[FN_NTOHS] != NULL); |
| sysAssert(sockfnptrs[FN_NTOHL] != NULL); |
| sysAssert(sockfnptrs[FN_GETSOCKOPT] != NULL); |
| sysAssert(sockfnptrs[FN_SETSOCKOPT] != NULL); |
| sysAssert(sockfnptrs[FN_GETPROTOBYNAME] != NULL); |
| sysAssert(sockfnptrs[FN_GETSOCKNAME] != NULL); |
| sysAssert(sockfnptrs[FN_SOCKET] != NULL); |
| |
| if (winsock2Available) { |
| sysAssert(sockfnptrs[FN_WSASENDDISCONNECT] != NULL); |
| } |
| |
| sysAssert(sockfnptrs[FN_SOCKETAVAILABLE] != NULL); |
| |
| sockfnptrs_initialized = TRUE; |
| mutexUnlock(&sockFnTableMutex); |
| } |
| |
| /* |
| * If we get a nonnull function pointer it might still be the case |
| * that some other thread is in the process of initializing the socket |
| * function pointer table, but our pointer should still be good. |
| */ |
| int |
| sysListen(int fd, int count) { |
| int (PASCAL FAR *listenfn)(); |
| if ((listenfn = sockfnptrs[FN_LISTEN]) == NULL) { |
| initSockFnTable(); |
| listenfn = sockfnptrs[FN_LISTEN]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && listenfn != NULL); |
| return (*listenfn)(fd, (long)count); |
| } |
| |
| int |
| sysConnect(int fd, struct sockaddr *name, int namelen) { |
| int (PASCAL FAR *connectfn)(); |
| if ((connectfn = sockfnptrs[FN_CONNECT]) == NULL) { |
| initSockFnTable(); |
| connectfn = sockfnptrs[FN_CONNECT]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(connectfn != NULL); |
| return (*connectfn)(fd, name, namelen); |
| } |
| |
| int |
| sysBind(int fd, struct sockaddr *name, int namelen) { |
| int (PASCAL FAR *bindfn)(); |
| if ((bindfn = sockfnptrs[FN_BIND]) == NULL) { |
| initSockFnTable(); |
| bindfn = sockfnptrs[FN_BIND]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(bindfn != NULL); |
| return (*bindfn)(fd, name, namelen); |
| } |
| |
| int |
| sysAccept(int fd, struct sockaddr *name, int *namelen) { |
| int (PASCAL FAR *acceptfn)(); |
| if ((acceptfn = sockfnptrs[FN_ACCEPT]) == NULL) { |
| initSockFnTable(); |
| acceptfn = sockfnptrs[FN_ACCEPT]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && acceptfn != NULL); |
| return (*acceptfn)(fd, name, namelen); |
| } |
| |
| int |
| sysRecvFrom(int fd, char *buf, int nBytes, |
| int flags, struct sockaddr *from, int *fromlen) { |
| int (PASCAL FAR *recvfromfn)(); |
| if ((recvfromfn = sockfnptrs[FN_RECVFROM]) == NULL) { |
| initSockFnTable(); |
| recvfromfn = sockfnptrs[FN_RECVFROM]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && recvfromfn != NULL); |
| return (*recvfromfn)(fd, buf, nBytes, flags, from, fromlen); |
| } |
| |
| int |
| sysSendTo(int fd, char *buf, int len, |
| int flags, struct sockaddr *to, int tolen) { |
| int (PASCAL FAR *sendtofn)(); |
| if ((sendtofn = sockfnptrs[FN_SENDTO]) == NULL) { |
| initSockFnTable(); |
| sendtofn = sockfnptrs[FN_SENDTO]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && sendtofn != NULL); |
| return (*sendtofn)(fd, buf, len, flags, to, tolen); |
| } |
| |
| int |
| sysRecv(int fd, char *buf, int nBytes, int flags) { |
| int (PASCAL FAR *recvfn)(); |
| if ((recvfn = sockfnptrs[FN_RECV]) == NULL) { |
| initSockFnTable(); |
| recvfn = sockfnptrs[FN_RECV]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && recvfn != NULL); |
| return (*recvfn)(fd, buf, nBytes, flags); |
| } |
| |
| int |
| sysSend(int fd, char *buf, int nBytes, int flags) { |
| int (PASCAL FAR *sendfn)(); |
| if ((sendfn = sockfnptrs[FN_SEND]) == NULL) { |
| initSockFnTable(); |
| sendfn = sockfnptrs[FN_SEND]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && sendfn != NULL); |
| return (*sendfn)(fd, buf, nBytes, flags); |
| } |
| |
| |
| int |
| sysGetHostName(char *hostname, int namelen) { |
| int (PASCAL FAR *fn)(); |
| if ((fn = sockfnptrs[FN_GETHOSTNAME]) == NULL) { |
| initSockFnTable(); |
| fn = sockfnptrs[FN_GETHOSTNAME]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && fn != NULL); |
| return (*fn)(hostname, namelen); |
| } |
| |
| struct hostent * |
| sysGetHostByAddr(const char *hostname, int len, int type) { |
| struct hostent * (PASCAL FAR *fn)(); |
| if ((fn = (struct hostent * (PASCAL FAR *)()) sockfnptrs[FN_GETHOSTBYADDR]) == NULL) { |
| initSockFnTable(); |
| fn = (struct hostent * (PASCAL FAR *)()) sockfnptrs[FN_GETHOSTBYADDR]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && fn != NULL); |
| return (*fn)(hostname, len, type); |
| } |
| |
| struct hostent * |
| sysGetHostByName(char *hostname) { |
| struct hostent * (PASCAL FAR *fn)(); |
| if ((fn = (struct hostent * (PASCAL FAR *)()) sockfnptrs[FN_GETHOSTBYNAME]) == NULL) { |
| initSockFnTable(); |
| fn = (struct hostent * (PASCAL FAR *)()) sockfnptrs[FN_GETHOSTBYNAME]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && fn != NULL); |
| return (*fn)(hostname); |
| } |
| |
| int |
| sysSocket(int domain, int type, int protocol) { |
| int sock; |
| int (PASCAL FAR *socketfn)(); |
| if ((socketfn = sockfnptrs[FN_SOCKET]) == NULL) { |
| initSockFnTable(); |
| socketfn = sockfnptrs[FN_SOCKET]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && socketfn != NULL); |
| sock = (*socketfn)(domain, type, protocol); |
| if (sock != INVALID_SOCKET) { |
| SetHandleInformation((HANDLE)(uintptr_t)sock, HANDLE_FLAG_INHERIT, FALSE); |
| } |
| return sock; |
| } |
| |
| int sysSocketShutdown(int fd, int how) { |
| if (fd > 0) { |
| int (PASCAL FAR *shutdownfn)(); |
| if ((shutdownfn = sockfnptrs[FN_SHUTDOWN]) == NULL) { |
| initSockFnTable(); |
| shutdownfn = sockfnptrs[FN_SHUTDOWN]; |
| } |
| /* At this point we are guaranteed the sockfnptrs are initialized */ |
| sysAssert(sockfnptrs_initialized == TRUE && shutdownfn != NULL); |
| (void) (*shutdownfn)(fd, how); |
| } |
| return TRUE; |
| } |
| |
| /* |
| * This function is carefully designed to work around a bug in Windows |
| * 95's networking winsock. Please see the beginning of this file for |
| * a complete description of the problem. |
| */ |
| int sysSocketClose(int fd) { |
| |
| if (fd > 0) { |
| int (PASCAL FAR *closesocketfn)(); |
| int (PASCAL FAR *wsasenddisconnectfn)(); |
| int dynamic_ref = -1; |
| |
| if ((closesocketfn = sockfnptrs[FN_CLOSESOCKET]) == NULL) { |
| initSockFnTable(); |
| } |
| /* At this point we are guaranteed the sockfnptrs are initialized */ |
| sysAssert(sockfnptrs_initialized == TRUE); |
| |
| closesocketfn = sockfnptrs[FN_CLOSESOCKET]; |
| sysAssert(closesocketfn != NULL); |
| |
| if (winsock2Available) { |
| struct linger l; |
| int len = sizeof(l); |
| |
| if (sysGetSockOpt(fd, SOL_SOCKET, SO_LINGER, (char *)&l, &len) == 0) { |
| if (l.l_onoff == 0) { |
| wsasenddisconnectfn = sockfnptrs[FN_WSASENDDISCONNECT]; |
| (*wsasenddisconnectfn)(fd, NULL); |
| } |
| } |
| } |
| (void) (*closesocketfn)(fd); |
| } |
| return TRUE; |
| } |
| |
| /* |
| * Poll the fd for reading for timeout ms. Returns 1 if something's |
| * ready, 0 if it timed out, -1 on error, -2 if interrupted (although |
| * interruption isn't implemented yet). Timeout in milliseconds. */ |
| int |
| sysTimeout(int fd, long timeout) { |
| int res; |
| fd_set tbl; |
| struct timeval t; |
| int (PASCAL FAR *selectfn)(); |
| |
| t.tv_sec = timeout / 1000; |
| t.tv_usec = (timeout % 1000) * 1000; |
| FD_ZERO(&tbl); |
| FD_SET(fd, &tbl); |
| |
| if ((selectfn = sockfnptrs[FN_SELECT]) == NULL) { |
| initSockFnTable(); |
| selectfn = sockfnptrs[FN_SELECT]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && selectfn != NULL); |
| res = (*selectfn)(fd + 1, &tbl, 0, 0, &t); |
| return res; |
| } |
| |
| long |
| sysSocketAvailable(int fd, jint *pbytes) |
| { |
| int (PASCAL FAR *socketfn)(); |
| if ((socketfn = sockfnptrs[FN_SOCKETAVAILABLE]) == NULL) { |
| initSockFnTable(); |
| socketfn = sockfnptrs[FN_SOCKETAVAILABLE]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE && socketfn != NULL); |
| return (*socketfn)(fd, FIONREAD, pbytes); |
| } |
| |
| int |
| sysGetSockName(int fd, struct sockaddr *name, int *namelen) { |
| int (PASCAL FAR *getsocknamefn)(); |
| if ((getsocknamefn = sockfnptrs[FN_GETSOCKNAME]) == NULL) { |
| initSockFnTable(); |
| getsocknamefn = sockfnptrs[FN_GETSOCKNAME]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(getsocknamefn != NULL); |
| return (*getsocknamefn)(fd, name, namelen); |
| } |
| |
| int |
| sysGetSockOpt(int fd, int level, int optname, char *optval, int *optlen ) { |
| int (PASCAL FAR *getsockoptfn)(); |
| if ((getsockoptfn = sockfnptrs[FN_GETSOCKOPT]) == NULL) { |
| initSockFnTable(); |
| getsockoptfn = sockfnptrs[FN_GETSOCKOPT]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(getsockoptfn != NULL); |
| |
| /* We need the following translation in order to deal with the multiple |
| definitions for IPPROTO_IP level options in different winsock versions |
| */ |
| if (winsock2Available && level == IPPROTO_IP && |
| optname >= IP_OPTIONS && optname <= IP_DONTFRAGMENT) { |
| optname = IPPROTO_OPTIONS[optname]; |
| } |
| return (*getsockoptfn)(fd, level, optname, optval, optlen); |
| } |
| |
| int |
| sysSetSockOpt(int fd, int level, int optname, const char *optval, int optlen ) { |
| int (PASCAL FAR *setsockoptfn)(); |
| if ((setsockoptfn = sockfnptrs[FN_SETSOCKOPT]) == NULL) { |
| initSockFnTable(); |
| setsockoptfn = sockfnptrs[FN_SETSOCKOPT]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(setsockoptfn != NULL); |
| |
| /* We need the following translation in order to deal with the multiple |
| definitions for IPPROTO_IP level options in different winsock versions |
| */ |
| if (winsock2Available && level == IPPROTO_IP && |
| optname >= IP_OPTIONS && optname <= IP_DONTFRAGMENT) { |
| optname = IPPROTO_OPTIONS[optname]; |
| } |
| |
| return (*setsockoptfn)(fd, level, optname, optval, optlen); |
| } |
| |
| struct protoent * |
| sysGetProtoByName(char *name) { |
| struct protoent * (PASCAL FAR *getprotobynamefn)(); |
| if ((getprotobynamefn = (struct protoent * (PASCAL FAR *)()) sockfnptrs[FN_GETPROTOBYNAME]) == NULL) { |
| initSockFnTable(); |
| getprotobynamefn = (struct protoent * (PASCAL FAR *)()) sockfnptrs[FN_GETPROTOBYNAME]; |
| } |
| sysAssert(sockfnptrs_initialized == TRUE); |
| sysAssert(getprotobynamefn != NULL); |
| return (*getprotobynamefn)(name); |
| } |