0N/A/*
2362N/A * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A#include <windows.h>
0N/A#include <winsock2.h>
0N/A
0N/A#include "sysSocket.h"
0N/A#include "socketTransport.h"
0N/A
0N/Atypedef jboolean bool_t;
0N/A
0N/A/*
0N/A * Table of Windows Sockets errors, the specific exception we
0N/A * throw for the error, and the error text.
0N/A *
0N/A * Note that this table excludes OS dependent errors.
0N/A */
0N/Astatic struct {
0N/A int errCode;
0N/A const char *errString;
0N/A} const winsock_errors[] = {
0N/A { WSAEPROVIDERFAILEDINIT, "Provider initialization failed (check %SystemRoot%)" },
0N/A { WSAEACCES, "Permission denied" },
0N/A { WSAEADDRINUSE, "Address already in use" },
0N/A { WSAEADDRNOTAVAIL, "Cannot assign requested address" },
0N/A { WSAEAFNOSUPPORT, "Address family not supported by protocol family" },
0N/A { WSAEALREADY, "Operation already in progress" },
0N/A { WSAECONNABORTED, "Software caused connection abort" },
0N/A { WSAECONNREFUSED, "Connection refused" },
0N/A { WSAECONNRESET, "Connection reset by peer" },
0N/A { WSAEDESTADDRREQ, "Destination address required" },
0N/A { WSAEFAULT, "Bad address" },
0N/A { WSAEHOSTDOWN, "Host is down" },
0N/A { WSAEHOSTUNREACH, "No route to host" },
0N/A { WSAEINPROGRESS, "Operation now in progress" },
0N/A { WSAEINTR, "Interrupted function call" },
0N/A { WSAEINVAL, "Invalid argument" },
0N/A { WSAEISCONN, "Socket is already connected" },
0N/A { WSAEMFILE, "Too many open files" },
0N/A { WSAEMSGSIZE, "The message is larger than the maximum supported by the underlying transport" },
0N/A { WSAENETDOWN, "Network is down" },
0N/A { WSAENETRESET, "Network dropped connection on reset" },
0N/A { WSAENETUNREACH, "Network is unreachable" },
0N/A { WSAENOBUFS, "No buffer space available (maximum connections reached?)" },
0N/A { WSAENOPROTOOPT, "Bad protocol option" },
0N/A { WSAENOTCONN, "Socket is not connected" },
0N/A { WSAENOTSOCK, "Socket operation on nonsocket" },
0N/A { WSAEOPNOTSUPP, "Operation not supported" },
0N/A { WSAEPFNOSUPPORT, "Protocol family not supported" },
0N/A { WSAEPROCLIM, "Too many processes" },
0N/A { WSAEPROTONOSUPPORT, "Protocol not supported" },
0N/A { WSAEPROTOTYPE, "Protocol wrong type for socket" },
0N/A { WSAESHUTDOWN, "Cannot send after socket shutdown" },
0N/A { WSAESOCKTNOSUPPORT, "Socket type not supported" },
0N/A { WSAETIMEDOUT, "Connection timed out" },
0N/A { WSATYPE_NOT_FOUND, "Class type not found" },
0N/A { WSAEWOULDBLOCK, "Resource temporarily unavailable" },
0N/A { WSAHOST_NOT_FOUND, "Host not found" },
0N/A { WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available" },
0N/A { WSANOTINITIALISED, "Successful WSAStartup not yet performed" },
0N/A { WSANO_DATA, "Valid name, no data record of requested type" },
0N/A { WSANO_RECOVERY, "This is a nonrecoverable error" },
0N/A { WSASYSNOTREADY, "Network subsystem is unavailable" },
0N/A { WSATRY_AGAIN, "Nonauthoritative host not found" },
0N/A { WSAVERNOTSUPPORTED, "Winsock.dll version out of range" },
0N/A { WSAEDISCON, "Graceful shutdown in progress" },
0N/A { WSA_OPERATION_ABORTED, "Overlapped operation aborted" },
0N/A};
0N/A
0N/A
0N/A/*
0N/A * Initialize Windows Sockets API support
0N/A */
0N/ABOOL WINAPI
0N/ADllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
0N/A{
0N/A WSADATA wsadata;
0N/A
0N/A switch (reason) {
0N/A case DLL_PROCESS_ATTACH:
0N/A if (WSAStartup(MAKEWORD(2,2), &wsadata) != 0) {
0N/A return FALSE;
0N/A }
0N/A break;
0N/A
0N/A case DLL_PROCESS_DETACH:
0N/A WSACleanup();
0N/A break;
0N/A
0N/A default:
0N/A break;
0N/A }
0N/A return TRUE;
0N/A}
0N/A
0N/A/*
0N/A * If we get a nonnull function pointer it might still be the case
0N/A * that some other thread is in the process of initializing the socket
0N/A * function pointer table, but our pointer should still be good.
0N/A */
0N/Aint
439N/AdbgsysListen(int fd, int backlog) {
439N/A return listen(fd, backlog);
0N/A}
0N/A
0N/Aint
0N/AdbgsysConnect(int fd, struct sockaddr *name, int namelen) {
0N/A int rv = connect(fd, name, namelen);
0N/A if (rv == SOCKET_ERROR) {
0N/A if (WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) {
0N/A return DBG_EINPROGRESS;
0N/A }
0N/A }
0N/A return rv;
0N/A}
0N/A
0N/Aint dbgsysFinishConnect(int fd, long timeout) {
0N/A int rv;
0N/A struct timeval t;
0N/A fd_set wr, ex;
0N/A
0N/A t.tv_sec = timeout / 1000;
0N/A t.tv_usec = (timeout % 1000) * 1000;
0N/A
0N/A FD_ZERO(&wr);
0N/A FD_ZERO(&ex);
0N/A FD_SET((unsigned int)fd, &wr);
0N/A FD_SET((unsigned int)fd, &ex);
0N/A
0N/A rv = select(fd+1, 0, &wr, &ex, &t);
0N/A if (rv == 0) {
0N/A return SYS_ERR; /* timeout */
0N/A }
0N/A
0N/A /*
0N/A * Check if there was an error - this is preferable to check if
0N/A * the socket is writable because some versions of Windows don't
0N/A * report a connected socket as being writable.
0N/A */
0N/A if (!FD_ISSET(fd, &ex)) {
0N/A return SYS_OK;
0N/A }
0N/A
0N/A /*
0N/A * Unable to establish connection - to get the reason we must
0N/A * call getsockopt.
0N/A */
0N/A return SYS_ERR;
0N/A}
0N/A
0N/A
0N/Aint
0N/AdbgsysAccept(int fd, struct sockaddr *name, int *namelen) {
439N/A return (int)accept(fd, name, namelen);
0N/A}
0N/A
0N/Aint
0N/AdbgsysRecvFrom(int fd, char *buf, int nBytes,
0N/A int flags, struct sockaddr *from, int *fromlen) {
0N/A return recvfrom(fd, buf, nBytes, flags, from, fromlen);
0N/A}
0N/A
0N/Aint
0N/AdbgsysSendTo(int fd, char *buf, int len,
0N/A int flags, struct sockaddr *to, int tolen) {
0N/A return sendto(fd, buf, len, flags, to, tolen);
0N/A}
0N/A
0N/Aint
0N/AdbgsysRecv(int fd, char *buf, int nBytes, int flags) {
0N/A return recv(fd, buf, nBytes, flags);
0N/A}
0N/A
0N/Aint
0N/AdbgsysSend(int fd, char *buf, int nBytes, int flags) {
0N/A return send(fd, buf, nBytes, flags);
0N/A}
0N/A
0N/Astruct hostent *
0N/AdbgsysGetHostByName(char *hostname) {
0N/A return gethostbyname(hostname);
0N/A}
0N/A
0N/Aunsigned short
0N/AdbgsysHostToNetworkShort(unsigned short hostshort) {
0N/A return htons(hostshort);
0N/A}
0N/A
0N/Aint
0N/AdbgsysSocket(int domain, int type, int protocol) {
439N/A int fd = (int)socket(domain, type, protocol);
0N/A if (fd != SOCKET_ERROR) {
0N/A SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
0N/A }
0N/A return fd;
0N/A}
0N/A
0N/Aint
0N/AdbgsysSocketClose(int fd) {
0N/A struct linger l;
0N/A int len = sizeof(l);
0N/A
0N/A if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&l, &len) == 0) {
0N/A if (l.l_onoff == 0) {
0N/A WSASendDisconnect(fd, NULL);
0N/A }
0N/A }
0N/A return closesocket(fd);
0N/A}
0N/A
0N/A/* Additions to original follow */
0N/A
0N/Aint
0N/AdbgsysBind(int fd, struct sockaddr *name, int namelen) {
0N/A return bind(fd, name, namelen);
0N/A}
0N/A
0N/A
439N/Auint32_t
0N/AdbgsysInetAddr(const char* cp) {
439N/A return (uint32_t)inet_addr(cp);
0N/A}
0N/A
439N/Auint32_t
439N/AdbgsysHostToNetworkLong(uint32_t hostlong) {
439N/A return (uint32_t)htonl((u_long)hostlong);
0N/A}
0N/A
0N/Aunsigned short
0N/AdbgsysNetworkToHostShort(unsigned short netshort) {
0N/A return ntohs(netshort);
0N/A}
0N/A
0N/Aint
0N/AdbgsysGetSocketName(int fd, struct sockaddr *name, int *namelen) {
0N/A return getsockname(fd, name, namelen);
0N/A}
0N/A
439N/Auint32_t
439N/AdbgsysNetworkToHostLong(uint32_t netlong) {
439N/A return (uint32_t)ntohl((u_long)netlong);
0N/A}
0N/A
0N/A/*
0N/A * Below Adapted from PlainSocketImpl.c, win32 version 1.18. Changed exception
0N/A * throws to returns of SYS_ERR; we should improve the error codes
0N/A * eventually. Changed java objects to values the debugger back end can
0N/A * more easily deal with.
0N/A */
0N/A
0N/Aint
0N/AdbgsysSetSocketOption(int fd, jint cmd, jboolean on, jvalue value)
0N/A{
0N/A if (cmd == TCP_NODELAY) {
0N/A struct protoent *proto = getprotobyname("TCP");
0N/A int tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto);
0N/A long onl = (long)on;
0N/A
0N/A if (setsockopt(fd, tcp_level, TCP_NODELAY,
0N/A (char *)&onl, sizeof(long)) < 0) {
0N/A return SYS_ERR;
0N/A }
0N/A } else if (cmd == SO_LINGER) {
0N/A struct linger arg;
0N/A arg.l_onoff = on;
0N/A
0N/A if(on) {
0N/A arg.l_linger = (unsigned short)value.i;
0N/A if(setsockopt(fd, SOL_SOCKET, SO_LINGER,
0N/A (char*)&arg, sizeof(arg)) < 0) {
0N/A return SYS_ERR;
0N/A }
0N/A } else {
0N/A if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
0N/A (char*)&arg, sizeof(arg)) < 0) {
0N/A return SYS_ERR;
0N/A }
0N/A }
0N/A } else if (cmd == SO_SNDBUF) {
0N/A jint buflen = value.i;
0N/A if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
0N/A (char *)&buflen, sizeof(buflen)) < 0) {
0N/A return SYS_ERR;
0N/A }
0N/A } else if (cmd == SO_REUSEADDR) {
0N/A /*
0N/A * On Windows the SO_REUSEADDR socket option doesn't implement
0N/A * BSD semantics. Specifically, the socket option allows multiple
0N/A * processes to bind to the same address/port rather than allowing
0N/A * a process to bind with a previous connection in the TIME_WAIT
0N/A * state. Hence on Windows we never enable this option for TCP
0N/A * option.
0N/A */
0N/A int sotype, arglen=sizeof(sotype);
0N/A if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, &arglen) == SOCKET_ERROR) {
0N/A return SYS_ERR;
0N/A }
0N/A if (sotype != SOCK_STREAM) {
0N/A int oni = (int)on;
0N/A if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
0N/A (char *)&oni, sizeof(oni)) == SOCKET_ERROR) {
0N/A return SYS_ERR;
0N/A }
0N/A }
0N/A } else {
0N/A return SYS_ERR;
0N/A }
0N/A return SYS_OK;
0N/A}
0N/A
0N/Aint dbgsysConfigureBlocking(int fd, jboolean blocking) {
0N/A u_long argp;
0N/A int result = 0;
0N/A
0N/A if (blocking == JNI_FALSE) {
0N/A argp = 1;
0N/A } else {
0N/A argp = 0;
0N/A }
0N/A result = ioctlsocket(fd, FIONBIO, &argp);
0N/A if (result == SOCKET_ERROR) {
0N/A return SYS_ERR;
0N/A } else {
0N/A return SYS_OK;
0N/A }
0N/A}
0N/A
0N/Aint
0N/AdbgsysPoll(int fd, jboolean rd, jboolean wr, long timeout) {
0N/A int rv;
0N/A struct timeval t;
0N/A fd_set rd_tbl, wr_tbl;
0N/A
0N/A t.tv_sec = timeout / 1000;
0N/A t.tv_usec = (timeout % 1000) * 1000;
0N/A
0N/A FD_ZERO(&rd_tbl);
0N/A if (rd) {
0N/A FD_SET((unsigned int)fd, &rd_tbl);
0N/A }
0N/A
0N/A FD_ZERO(&wr_tbl);
0N/A if (wr) {
0N/A FD_SET((unsigned int)fd, &wr_tbl);
0N/A }
0N/A
0N/A rv = select(fd+1, &rd_tbl, &wr_tbl, 0, &t);
0N/A if (rv >= 0) {
0N/A rv = 0;
0N/A if (FD_ISSET(fd, &rd_tbl)) {
0N/A rv |= DBG_POLLIN;
0N/A }
0N/A if (FD_ISSET(fd, &wr_tbl)) {
0N/A rv |= DBG_POLLOUT;
0N/A }
0N/A }
0N/A return rv;
0N/A}
0N/A
0N/Aint
0N/AdbgsysGetLastIOError(char *buf, jint size) {
0N/A int table_size = sizeof(winsock_errors) /
0N/A sizeof(winsock_errors[0]);
0N/A int i;
0N/A int error = WSAGetLastError();
0N/A
0N/A /*
0N/A * Check table for known winsock errors
0N/A */
0N/A i=0;
0N/A while (i < table_size) {
0N/A if (error == winsock_errors[i].errCode) {
0N/A break;
0N/A }
0N/A i++;
0N/A }
0N/A
0N/A if (i < table_size) {
0N/A strcpy(buf, winsock_errors[i].errString);
0N/A } else {
0N/A sprintf(buf, "winsock error %d", error);
0N/A }
0N/A return 0;
0N/A}
0N/A
0N/A
0N/Aint
0N/AdbgsysTlsAlloc() {
0N/A return TlsAlloc();
0N/A}
0N/A
0N/Avoid
0N/AdbgsysTlsFree(int index) {
0N/A TlsFree(index);
0N/A}
0N/A
0N/Avoid
0N/AdbgsysTlsPut(int index, void *value) {
0N/A TlsSetValue(index, value);
0N/A}
0N/A
0N/Avoid *
0N/AdbgsysTlsGet(int index) {
0N/A return TlsGetValue(index);
0N/A}
0N/A
0N/A#define FT2INT64(ft) \
0N/A ((long)(ft).dwHighDateTime << 32 | (long)(ft).dwLowDateTime)
0N/A
0N/Along
0N/AdbgsysCurrentTimeMillis() {
0N/A static long fileTime_1_1_70 = 0; /* midnight 1/1/70 */
0N/A SYSTEMTIME st0;
0N/A FILETIME ft0;
0N/A
0N/A /* initialize on first usage */
0N/A if (fileTime_1_1_70 == 0) {
0N/A memset(&st0, 0, sizeof(st0));
0N/A st0.wYear = 1970;
0N/A st0.wMonth = 1;
0N/A st0.wDay = 1;
0N/A SystemTimeToFileTime(&st0, &ft0);
0N/A fileTime_1_1_70 = FT2INT64(ft0);
0N/A }
0N/A
0N/A GetSystemTime(&st0);
0N/A SystemTimeToFileTime(&st0, &ft0);
0N/A
0N/A return (FT2INT64(ft0) - fileTime_1_1_70) / 10000;
0N/A}