📄 natplainsocketimplwin32.cc
字号:
/* Copyright (C) 2003, 2004, 2005 Free Software Foundation This file is part of libgcj.This software is copyrighted work licensed under the terms of theLibgcj License. Please consult the file "LIBGCJ_LICENSE" fordetails. */#include <config.h>#include <platform.h>#undef STRICT#undef MAX_PRIORITY#undef MIN_PRIORITY#include <gnu/java/net/PlainSocketImpl.h>#include <gnu/java/net/PlainSocketImpl$SocketInputStream.h>#include <gnu/java/net/PlainSocketImpl$SocketOutputStream.h>#include <java/io/IOException.h>#include <java/net/BindException.h>#include <java/net/ConnectException.h>#include <java/net/InetAddress.h>#include <java/net/InetSocketAddress.h>#include <java/net/SocketException.h>#include <java/net/SocketTimeoutException.h>#include <java/lang/InternalError.h>#include <java/lang/Object.h>#include <java/lang/Boolean.h>#include <java/lang/Class.h>#include <java/lang/Integer.h>#include <java/lang/Thread.h>#include <java/lang/NullPointerException.h>#include <java/lang/ArrayIndexOutOfBoundsException.h>#include <java/lang/IllegalArgumentException.h>union SockAddr{ struct sockaddr_in address;#ifdef HAVE_INET6 struct sockaddr_in6 address6;#endif};voidgnu::java::net::PlainSocketImpl::create (jboolean stream){ SOCKET sock = ::socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) { _Jv_ThrowIOException (); } // Cast this to a HANDLE so we can make // it non-inheritable via _Jv_platform_close_on_exec. HANDLE hSocket = (HANDLE) sock; _Jv_platform_close_on_exec (hSocket); // We use native_fd in place of fd here. From leaving fd null we avoid // the double close problem in FileDescriptor.finalize. native_fd = (jint) hSocket;}voidgnu::java::net::PlainSocketImpl::bind (::java::net::InetAddress *host, jint lport){ union SockAddr u; struct sockaddr *ptr = (struct sockaddr *) &u.address; jbyteArray haddress = host->addr; jbyte *bytes = elements (haddress); int len = haddress->length; if (len == 4) { u.address.sin_family = AF_INET; if (host != NULL) memcpy (&u.address.sin_addr, bytes, len); else u.address.sin_addr.s_addr = htonl (INADDR_ANY); len = sizeof (struct sockaddr_in); u.address.sin_port = htons (lport); }#ifdef HAVE_INET6 else if (len == 16) { u.address6.sin6_family = AF_INET6; memcpy (&u.address6.sin6_addr, bytes, len); len = sizeof (struct sockaddr_in6); u.address6.sin6_port = htons (lport); }#endif else throw new ::java::net::SocketException (JvNewStringUTF ("invalid length")); if (::bind (native_fd, ptr, len) != SOCKET_ERROR) { socklen_t addrlen = sizeof(u); if (lport != 0) localport = lport; else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != SOCKET_ERROR) localport = ntohs (u.address.sin_port); else goto error; return; }error: DWORD dwErrorCode = WSAGetLastError (); throw new ::java::net::BindException (_Jv_WinStrError (dwErrorCode));}static voidthrowConnectException (DWORD dwErrorCode){ throw new ::java::net::ConnectException (_Jv_WinStrError (dwErrorCode));}static voidthrowConnectException (){ throwConnectException (WSAGetLastError ());}voidgnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr, jint timeout){ ::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr; ::java::net::InetAddress *host = tmp->getAddress(); jint rport = tmp->getPort(); // Set the SocketImpl's address and port fields before we try to // connect. Note that the fact that these are set doesn't imply // that we're actually connected to anything. We need to record // this data before we attempt the connect, since non-blocking // SocketChannels will use this and almost certainly throw timeout // exceptions. address = host; port = rport; union SockAddr u; socklen_t addrlen = sizeof(u); jbyteArray haddress = host->addr; jbyte *bytes = elements (haddress); int len = haddress->length; struct sockaddr *ptr = (struct sockaddr *) &u.address; if (len == 4) { u.address.sin_family = AF_INET; memcpy (&u.address.sin_addr, bytes, len); len = sizeof (struct sockaddr_in); u.address.sin_port = htons (rport); }#ifdef HAVE_INET6 else if (len == 16) { u.address6.sin6_family = AF_INET6; memcpy (&u.address6.sin6_addr, bytes, len); len = sizeof (struct sockaddr_in6); u.address6.sin6_port = htons (rport); }#endif else throw new ::java::net::SocketException (JvNewStringUTF ("invalid length")); if (timeout > 0) { // FIXME: we're creating a fresh WSAEVENT for each connect(). WSAEventWrapper aWSAEventWrapper(native_fd, FD_CONNECT); WSAEVENT hEvent = aWSAEventWrapper.getEventHandle (); if (::connect (native_fd, ptr, len) == SOCKET_ERROR) { if (WSAGetLastError () != WSAEWOULDBLOCK) throwConnectException (); DWORD dwRet = WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false); // use true, false instead of TRUE, FALSE because the // MS constants got undefined // Reset and ignore our thread's interrupted flag. // It's not possible to interrupt these sort of // operations on Win32 anyway. ::java::lang::Thread::interrupted(); if (dwRet == WSA_WAIT_FAILED) throwConnectException (); else if (dwRet == WSA_WAIT_TIMEOUT) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("connect timed out")); // If we get here, we still need to check whether the actual // connect() succeeded. Use any socket-specific error code // instead of the thread-based one. int nErrCode; int nErrLen=sizeof(nErrCode); if (::getsockopt(native_fd, SOL_SOCKET, SO_ERROR, (char*) &nErrCode, &nErrLen) == SOCKET_ERROR) { throwConnectException (); } if (nErrCode != NO_ERROR) { throwConnectException (nErrCode); } } } else { if (::connect (native_fd, ptr, len) == SOCKET_ERROR) throwConnectException(); } // A bind may not have been done on this socket; if so, set localport now. if (localport == 0) { if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) != SOCKET_ERROR) localport = ntohs (u.address.sin_port); else throwConnectException(); }}voidgnu::java::net::PlainSocketImpl::listen (jint backlog){ if (::listen (native_fd, backlog) == SOCKET_ERROR) { _Jv_ThrowIOException (); }}voidgnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s){ union SockAddr u; socklen_t addrlen = sizeof(u); HANDLE hSocket = 0; SOCKET new_socket = 0; if (timeout > 0) { // FIXME: we're creating a fresh WSAEVENT for each accept(). // One possible alternative would be that native_fd really points // to an extended structure consisting of the SOCKET, its // associated WSAEVENT, etc. WSAEventWrapper aWSAEventWrapper(native_fd, FD_ACCEPT); WSAEVENT hEvent = aWSAEventWrapper.getEventHandle (); for (;;) { new_socket = ::accept (native_fd, (sockaddr*) &u, &addrlen); if (new_socket != INVALID_SOCKET) { // This new child socket is nonblocking because the parent // socket became nonblocking via the WSAEventSelect() call, // so we set its mode back to blocking. WSAEventSelect (new_socket, hEvent, 0); // undo the hEvent <-> FD_ACCEPT association inherited // inherited from our parent socket unsigned long lSockOpt = 0L; // blocking mode if (ioctlsocket(new_socket, FIONBIO, &lSockOpt) == SOCKET_ERROR) { goto error; } break; } else if (WSAGetLastError () != WSAEWOULDBLOCK) { goto error; } DWORD dwRet = WSAWaitForMultipleEvents (1, &hEvent, true, timeout, false); // use true, false instead of TRUE, FALSE because the // MS constants got undefined // Reset and ignore our thread's interrupted flag. ::java::lang::Thread::interrupted(); if (dwRet == WSA_WAIT_FAILED) goto error; else if (dwRet == WSA_WAIT_TIMEOUT) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("Accept timed out")); } } else { new_socket = ::accept (native_fd, (sockaddr*) &u, &addrlen); } if (new_socket == INVALID_SOCKET) goto error; // Cast this to a HANDLE so we can make // it non-inheritable via _Jv_platform_close_on_exec. hSocket = (HANDLE) new_socket; _Jv_platform_close_on_exec (hSocket); jbyteArray raddr; jint rport; if (u.address.sin_family == AF_INET) { raddr = JvNewByteArray (4); memcpy (elements (raddr), &u.address.sin_addr, 4); rport = ntohs (u.address.sin_port); }#ifdef HAVE_INET6 else if (u.address.sin_family == AF_INET6) { raddr = JvNewByteArray (16); memcpy (elements (raddr), &u.address6.sin6_addr, 16); rport = ntohs (u.address6.sin6_port); }#endif else throw new ::java::net::SocketException (JvNewStringUTF ("invalid family")); s->native_fd = (jint) hSocket; s->localport = localport; s->address = new ::java::net::InetAddress (raddr, NULL); s->port = rport; return; error: _Jv_ThrowIOException ();}// Close(shutdown) the socket.voidgnu::java::net::PlainSocketImpl::close(){ // Avoid races from asynchronous finalization. JvSynchronize sync (this); // should we use shutdown here? how would that effect so_linger? int res = ::closesocket (native_fd); if (res == -1) { // These three errors are not errors according to tests performed // on the reference implementation. DWORD dwErr = WSAGetLastError(); if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET && dwErr != WSAENOTSOCK) _Jv_ThrowIOException (); } // Safe place to reset the file pointer. native_fd = -1; timeout = 0;}// Write a byte to the socket.voidgnu::java::net::PlainSocketImpl$SocketOutputStream::write(jint b){ jbyte d =(jbyte) b; int r = 0; while (r != 1) { r = ::send (this$0->native_fd, (char*) &d, 1, 0); if (r == -1) { DWORD dwErr = WSAGetLastError(); // Reset and ignore our thread's interrupted flag. // It's not possible to interrupt these sort of // operations on Win32 anyway. ::java::lang::Thread::interrupted(); // Some errors should not cause exceptions. if (dwErr != WSAENOTCONN && dwErr != WSAECONNRESET && dwErr != WSAENOTSOCK) _Jv_ThrowIOException (); break; } }}// Write some bytes to the socket.voidgnu::java::net::PlainSocketImpl$SocketOutputStream::write(jbyteArray b, jint offset, jint len){ if (! b) throw new ::java::lang::NullPointerException; if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b)) throw new ::java::lang::ArrayIndexOutOfBoundsException;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -