📄 pcsl_ip.c
字号:
/* * * * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program 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. * * This program 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 at /legal/license.txt). * * 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 or visit www.sun.com if you need additional * information or have any questions. *//** * @file * * Implementation of IP functions in pcsl_network.h for platforms that * support the winsock API. * */#include <stdio.h>#include <winsock2.h>#include <windows.h>#include <pcsl_memory.h>#include <pcsl_network.h>#include <pcsl_network_notifier.h>#include <pcsl_socket.h>/* #include <win32app_export.h>, will a pcsl_event header file later. */extern HANDLE win32app_get_window_handle();#define WM_DEBUGGER (WM_USER)#define WM_HOST_RESOLVED (WM_USER + 1)#define WM_NETWORK (WM_USER + 2)typedef struct _AddrContext { struct _AddrContext* next; HANDLE asyncHandle; /* host must be last because it is variable length. */ struct hostent host; } AddrContext;/* For use by pcsl_network_error. */int lastError;/* * To reduce complexity, a whole struct is used a root instead of a just a * pointer. The root host field never has any real data. */static AddrContext rootAddrContext;static void addAddrContext(AddrContext* pContext) { pContext->next = rootAddrContext.next; rootAddrContext.next = pContext;}static AddrContext* removeAddrContext(HANDLE asyncHandle) { AddrContext* prev = &rootAddrContext; AddrContext* current = rootAddrContext.next; // Start after the root, because the root struct has no data. while (NULL != current) { if (current->asyncHandle == asyncHandle) { prev->next = current->next; return current; } prev = current; current = current->next; } return NULL;}/** * See pcsl_network.h for definition. */int pcsl_network_gethostbyname_start( char *hostname, unsigned char *pAddress, int maxLen, int *pLen, void **pHandle, void **pContext){ AddrContext* pAddrContext; HANDLE asyncHandle; (void)pAddress; (void)pLen; (void)maxLen; pAddrContext = (AddrContext*) pcsl_mem_malloc((sizeof (AddrContext) + MAXGETHOSTSTRUCT)); if (NULL == pAddrContext) { return PCSL_NET_IOERROR; } asyncHandle = WSAAsyncGetHostByName(win32app_get_window_handle(), WM_HOST_RESOLVED, hostname, (char*)(&pAddrContext->host), MAXGETHOSTSTRUCT); lastError = WSAGetLastError(); if (0 == asyncHandle) { pcsl_mem_free(pAddrContext); return PCSL_NET_IOERROR; } *pHandle = (void*)asyncHandle; pAddrContext->asyncHandle = asyncHandle; addAddrContext(pAddrContext); return PCSL_NET_WOULDBLOCK;}/** * See pcsl_network.h for definition. * * Since the start function never returns PCSL_NET_WOULDBLOCK, this * function should never be called. */int pcsl_network_gethostbyname_finish( unsigned char *pAddress, int maxLen, int *pLen, void *handle, void *context){ AddrContext* pAddrContext = removeAddrContext((HANDLE)handle); int addrLen; lastError = (int)context; if (NULL == pAddrContext) { return PCSL_NET_IOERROR; } if ((0 != lastError) || (AF_INET != pAddrContext->host.h_addrtype && AF_INET6 != pAddrContext->host.h_addrtype)) { pcsl_mem_free(pAddrContext); return PCSL_NET_IOERROR; } addrLen = pAddrContext->host.h_length; if (addrLen > maxLen) { pcsl_mem_free(pAddrContext); return PCSL_NET_INVALID; } *pLen = addrLen; memcpy(pAddress, pAddrContext->host.h_addr, addrLen); pcsl_mem_free(pAddrContext); return PCSL_NET_SUCCESS;}/** * See pcsl_network.h for definition. */int pcsl_network_getsockopt( void *handle, int flag, int *pOptval){ SOCKET s = (SOCKET)handle; int level = SOL_SOCKET; int optname; int optsize = sizeof(optname); struct linger lbuf ; void * opttarget = (void *) pOptval ; switch (flag) { case 0: /* DELAY */ level = IPPROTO_TCP; optname = TCP_NODELAY; break; case 1: /* LINGER */ opttarget = (void *) &lbuf ; optsize = sizeof (struct linger); optname = SO_LINGER; break; case 2: /* KEEPALIVE */ optname = SO_KEEPALIVE; break; case 3: /* RCVBUF */ optname = SO_RCVBUF; break; case 4: /* SNDBUF */ optname = SO_SNDBUF; break; default: /* Illegal Argument */ return PCSL_NET_INVALID; } if (0 == getsockopt(s, level, optname, opttarget, &optsize)) { if (SO_LINGER == optname) { /* If linger is on return the number of seconds. */ *pOptval = (lbuf.l_onoff == 0 ? 0 : lbuf.l_linger) ; } lastError = 0; return 0; } lastError = WSAGetLastError(); return PCSL_NET_IOERROR;}/** * See pcsl_network.h for definition. */int pcsl_network_setsockopt( void *handle, int flag, int optval){ SOCKET s = (SOCKET)handle; int level = SOL_SOCKET; int optsize = sizeof(optval); int optname; struct linger lbuf ; void * opttarget = (void *) & optval ; switch (flag) { case 0: /* DELAY */ level = IPPROTO_TCP; optname = TCP_NODELAY; break; case 1: /* LINGER */ opttarget = (void *) &lbuf ; optsize = sizeof (struct linger); optname = SO_LINGER; lbuf.l_linger = (unsigned short) optval; if (flag <= 0) { lbuf.l_onoff = 0; /* lbuf.l_linger would be ignored */ } else { lbuf.l_onoff = 1; } break; case 2: /* KEEPALIVE */ optname = SO_KEEPALIVE; break; case 3: /* RCVBUF */ optname = SO_RCVBUF; break; case 4: /* SNDBUF */ optname = SO_SNDBUF; /* * Linux sets the SO_SND buffer size in TCP to 2048 even if * there is an explicite request to set it to 0 through * setsockopt() system call. This is because TCP reserves a minimum * size buffer for administrative purposes and internal kernel * structures. * However, in windows, it has been found that buffer size is actually * set to 0 upon setsockopt() with value = 0. It causes one of the TCK * tests, viz, SecureConnection0011, to block indefinitely. A * workaround for this problem is to set the SO_SND buffer size to * a minimum value like 2048 bytes as in linux. Ideally, it is not * advisable to set the buffer sizes to 0 as it causes calling * application process to sleep if there is a need to send TCP data * from this socket. */ if (optval == 0) { optval = 2048; opttarget = (void *) & optval ; } break; default: /* Illegal Argument */ return PCSL_NET_INVALID; } if (0 == setsockopt(s, level, optname, opttarget, optsize)){ lastError = 0; return PCSL_NET_SUCCESS; } lastError = WSAGetLastError(); return PCSL_NET_INVALID;}/** * See pcsl_network.h for definition. */int pcsl_socket_getlocaladdr( void *handle, char *pAddress){ SOCKET s = (SOCKET)handle; int status; struct sockaddr_in sa; int saLen = sizeof (sa); sa.sin_family = AF_INET; status = getsockname(s, (struct sockaddr*)&sa, &saLen); lastError = WSAGetLastError(); if (SOCKET_ERROR == status) { return PCSL_NET_IOERROR; } /* * The string returned from inet_ntoa is only valid until the next * winsock API call. The string should not be freed. */ strcpy(pAddress, inet_ntoa(sa.sin_addr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -