📄 natplainsocketimplposix.cc
字号:
/* Copyright (C) 2003 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>#ifdef HAVE_SYS_IOCTL_H#define BSD_COMP /* Get FIONREAD on Solaris2. */#include <sys/ioctl.h>#endif// Pick up FIONREAD on Solaris 2.5.#ifdef HAVE_SYS_FILIO_H#include <sys/filio.h>#endif#include <netinet/in.h>#include <netinet/tcp.h>#include <errno.h>#include <string.h>#if HAVE_BSTRING_H// Needed for bzero, implicitly used by FD_ZERO on IRIX 5.2 #include <bstring.h>#endif#include <gcj/cni.h>#include <gcj/javaprims.h>#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/io/InterruptedIOException.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){ int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0); if (sock < 0) { char* strerr = strerror (errno); throw new ::java::io::IOException (JvNewStringUTF (strerr)); } _Jv_platform_close_on_exec (sock); // We use native_fd in place of fd here. From leaving fd null we avoid // the double close problem in FileDescriptor.finalize. native_fd = sock;}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; int i = 1; 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")); // Enable SO_REUSEADDR, so that servers can reuse ports left in TIME_WAIT. ::setsockopt(native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i)); if (_Jv_bind (native_fd, ptr, len) == 0) { socklen_t addrlen = sizeof(u); if (lport != 0) localport = lport; else if (::getsockname (native_fd, (sockaddr*) &u, &addrlen) == 0) localport = ntohs (u.address.sin_port); else goto error; return; } error: char* strerr = strerror (errno); throw new ::java::net::BindException (JvNewStringUTF (strerr));}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(); 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) { int flags = ::fcntl (native_fd, F_GETFL); ::fcntl (native_fd, F_SETFL, flags | O_NONBLOCK); if ((_Jv_connect (native_fd, ptr, len) != 0) && (errno != EINPROGRESS)) goto error; fd_set fset; struct timeval tv; FD_ZERO(&fset); FD_SET(native_fd, &fset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int retval; if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0) goto error; else if (retval == 0) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("Connect timed out")); // Set the socket back into a blocking state. ::fcntl (native_fd, F_SETFL, flags); } else { if (_Jv_connect (native_fd, ptr, len) != 0) goto error; } address = host; port = rport; // 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) == 0) localport = ntohs (u.address.sin_port); else goto error; } return; error: char* strerr = strerror (errno); throw new ::java::net::ConnectException (JvNewStringUTF (strerr));}voidgnu::java::net::PlainSocketImpl::listen (jint backlog){ if (::listen (native_fd, backlog) != 0) { char* strerr = strerror (errno); throw new ::java::io::IOException (JvNewStringUTF (strerr)); }}voidgnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s){ union SockAddr u; socklen_t addrlen = sizeof(u); int new_socket = 0; // Do timeouts via select since SO_RCVTIMEO is not always available. if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE) { fd_set fset; struct timeval tv; FD_ZERO(&fset); FD_SET(native_fd, &fset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int retval; if ((retval = _Jv_select (native_fd + 1, &fset, &fset, NULL, &tv)) < 0) goto error; else if (retval == 0) throw new ::java::net::SocketTimeoutException ( JvNewStringUTF("Accept timed out")); } new_socket = _Jv_accept (native_fd, (sockaddr*) &u, &addrlen); if (new_socket < 0) goto error; _Jv_platform_close_on_exec (new_socket); 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 = new_socket; s->localport = localport; s->address = new ::java::net::InetAddress (raddr, NULL); s->port = rport; return; error: char* strerr = strerror (errno); throw new ::java::io::IOException (JvNewStringUTF (strerr));}// 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 = _Jv_close (native_fd); if (res == -1) { // These three errors are not errors according to tests performed // on the reference implementation. if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) throw new ::java::io::IOException (JvNewStringUTF (strerror (errno))); } // 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 = _Jv_write (this$0->native_fd, &d, 1); if (r == -1) { if (::java::lang::Thread::interrupted()) { ::java::io::InterruptedIOException *iioe = new ::java::io::InterruptedIOException (JvNewStringLatin1 (strerror (errno))); iioe->bytesTransferred = 0; throw iioe; } // Some errors should not cause exceptions. if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) throw new ::java::io::IOException (JvNewStringUTF (strerror (errno))); 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; jbyte *bytes = elements (b) + offset; int written = 0; while (len > 0) { int r = _Jv_write (this$0->native_fd, bytes, len); if (r == -1) { if (::java::lang::Thread::interrupted()) { ::java::io::InterruptedIOException *iioe = new ::java::io::InterruptedIOException (JvNewStringLatin1 (strerror (errno))); iioe->bytesTransferred = written; throw iioe; } // Some errors should not cause exceptions. if (errno != ENOTCONN && errno != ECONNRESET && errno != EBADF) throw new ::java::io::IOException (JvNewStringUTF (strerror (errno))); break; } written += r; len -= r; bytes += r; }}voidgnu::java::net::PlainSocketImpl::sendUrgentData (jint){ throw new ::java::net::SocketException (JvNewStringLatin1 ( "PlainSocketImpl: sending of urgent data not supported by this socket"));}// Read a single byte from the socket.jintgnu::java::net::PlainSocketImpl$SocketInputStream::read(void){ jbyte b; jint timeout = this$0->timeout; jint native_fd = this$0->native_fd; // Do timeouts via select. if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE) { // Create the file descriptor set. fd_set read_fds; FD_ZERO (&read_fds); FD_SET (native_fd,&read_fds); // Create the timeout struct based on our internal timeout value. struct timeval timeout_value; timeout_value.tv_sec = timeout / 1000; timeout_value.tv_usec = (timeout % 1000) * 1000; // Select on the fds. int sel_retval = _Jv_select (native_fd + 1, &read_fds, NULL, NULL, &timeout_value); // If select returns 0 we've waited without getting data... // that means we've timed out. if (sel_retval == 0) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("Read timed out") ); // If select returns ok we know we either got signalled or read some data... // either way we need to try to read. } int r = _Jv_read (native_fd, &b, 1); if (r == 0) return -1; if (::java::lang::Thread::interrupted()) { ::java::io::InterruptedIOException *iioe = new ::java::io::InterruptedIOException (JvNewStringUTF("Read interrupted")); iioe->bytesTransferred = r == -1 ? 0 : r; throw iioe; } else if (r == -1) { // Some errors cause us to return end of stream... if (errno == ENOTCONN) return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -