📄 natplaindatagramsocketimplposix.cc
字号:
/* Copyright (C) 2003, 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>#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#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 <gnu/java/net/PlainDatagramSocketImpl.h>#include <java/io/IOException.h>#include <java/io/InterruptedIOException.h>#include <java/net/BindException.h>#include <java/net/SocketException.h>#include <java/net/SocketTimeoutException.h>#include <java/net/InetAddress.h>#include <java/net/NetworkInterface.h>#include <java/net/DatagramPacket.h>#include <java/net/PortUnreachableException.h>#include <java/lang/InternalError.h>#include <java/lang/Object.h>#include <java/lang/Boolean.h>#include <java/lang/Integer.h>union SockAddr{ struct sockaddr_in address;#ifdef HAVE_INET6 struct sockaddr_in6 address6;#endif};union McastReq{#if HAVE_STRUCT_IP_MREQ struct ip_mreq mreq;#endif#if HAVE_STRUCT_IPV6_MREQ struct ipv6_mreq mreq6;#endif};union InAddr{ struct in_addr addr;#ifdef HAVE_INET6 struct in6_addr addr6;#endif};// FIXME: routines here and/or in natPlainSocketImpl.cc could throw// NoRouteToHostException; also consider UnknownHostException, ConnectException.voidgnu::java::net::PlainDatagramSocketImpl::create (){ int sock = _Jv_socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { char* strerr = strerror (errno); throw new ::java::net::SocketException (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::PlainDatagramSocketImpl::bind (jint lport, ::java::net::InetAddress *host){ union SockAddr u; struct sockaddr *ptr = (struct sockaddr *) &u.address; // FIXME: Use getaddrinfo() to get actual protocol instead of assuming ipv4. 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 (_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; /* Allow broadcast by default. */ int broadcast = 1; if (::setsockopt (native_fd, SOL_SOCKET, SO_BROADCAST, (char *) &broadcast, sizeof (broadcast)) != 0) goto error; return; } error: char* strerr = strerror (errno); throw new ::java::net::BindException (JvNewStringUTF (strerr));}voidgnu::java::net::PlainDatagramSocketImpl::connect (::java::net::InetAddress *, jint){ throw new ::java::lang::InternalError (JvNewStringLatin1 ( "PlainDatagramSocketImpl::connect: not implemented yet"));}voidgnu::java::net::PlainDatagramSocketImpl::disconnect (){ throw new ::java::lang::InternalError (JvNewStringLatin1 ( "PlainDatagramSocketImpl::disconnect: not implemented yet"));}jintgnu::java::net::PlainDatagramSocketImpl::peek (::java::net::InetAddress *i){ // FIXME: Deal with Multicast and if the socket is connected. union SockAddr u; socklen_t addrlen = sizeof(u); ssize_t retlen = ::recvfrom (native_fd, (char *) NULL, 0, MSG_PEEK, (sockaddr*) &u, &addrlen); if (retlen < 0) goto error; // FIXME: Deal with Multicast addressing and if the socket is connected. 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")); i->addr = raddr; return rport; error: char* strerr = strerror (errno); if (errno == ECONNREFUSED) throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr)); throw new ::java::io::IOException (JvNewStringUTF (strerr));}jintgnu::java::net::PlainDatagramSocketImpl::peekData (::java::net::DatagramPacket *p){ // FIXME: Deal with Multicast and if the socket is connected. union SockAddr u; socklen_t addrlen = sizeof(u); jbyte *dbytes = elements (p->getData()) + p->getOffset(); jint maxlen = p->maxlen - p->getOffset(); ssize_t retlen = 0; // Do timeouts via select since SO_RCVTIMEO is not always available. if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE) { fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(native_fd, &rset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int retval; if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0) goto error; else if (retval == 0) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("PeekData timed out") ); } retlen = ::recvfrom (native_fd, (char *) dbytes, maxlen, MSG_PEEK, (sockaddr*) &u, &addrlen); if (retlen < 0) goto error; // FIXME: Deal with Multicast addressing and if the socket is connected. 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")); p->setAddress (new ::java::net::InetAddress (raddr, NULL)); p->setPort (rport); p->length = (int) retlen; return rport; error: char* strerr = strerror (errno); if (errno == ECONNREFUSED) throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr)); throw new ::java::io::IOException (JvNewStringUTF (strerr));}// Close(shutdown) the socket.voidgnu::java::net::PlainDatagramSocketImpl::close (){ // Avoid races from asynchronous finalization. JvSynchronize sync (this); // The method isn't declared to throw anything, so we disregard // the return value. _Jv_close (native_fd); native_fd = -1; timeout = 0;}voidgnu::java::net::PlainDatagramSocketImpl::send (::java::net::DatagramPacket *p){ JvSynchronize lock (SEND_LOCK); // FIXME: Deal with Multicast and if the socket is connected. jint rport = p->getPort(); union SockAddr u; jbyteArray haddress = p->getAddress()->addr; jbyte *bytes = elements (haddress); int len = haddress->length; struct sockaddr *ptr = (struct sockaddr *) &u.address; jbyte *dbytes = elements (p->getData()) + p->getOffset(); 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 (::sendto (native_fd, (char *) dbytes, p->getLength(), 0, ptr, len) >= 0) return; char* strerr = strerror (errno); if (errno == ECONNREFUSED) throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr)); throw new ::java::io::IOException (JvNewStringUTF (strerr));}voidgnu::java::net::PlainDatagramSocketImpl::receive (::java::net::DatagramPacket *p){ JvSynchronize lock (RECEIVE_LOCK); // FIXME: Deal with Multicast and if the socket is connected. union SockAddr u; socklen_t addrlen = sizeof(u); jbyte *dbytes = elements (p->getData()) + p->getOffset(); jint maxlen = p->maxlen - p->getOffset(); ssize_t retlen = 0; // Do timeouts via select since SO_RCVTIMEO is not always available. if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE) { fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(native_fd, &rset); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int retval; if ((retval = _Jv_select (native_fd + 1, &rset, NULL, NULL, &tv)) < 0) goto error; else if (retval == 0) throw new ::java::net::SocketTimeoutException (JvNewStringUTF ("Receive timed out") ); } retlen = ::recvfrom (native_fd, (char *) dbytes, maxlen, 0, (sockaddr*) &u, &addrlen); if (retlen < 0) goto error; // FIXME: Deal with Multicast addressing and if the socket is connected. 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")); p->setAddress (new ::java::net::InetAddress (raddr, NULL)); p->setPort (rport); p->length = (jint) retlen; return; error: char* strerr = strerror (errno); if (errno == ECONNREFUSED) throw new ::java::net::PortUnreachableException (JvNewStringUTF (strerr)); throw new ::java::io::IOException (JvNewStringUTF (strerr));}voidgnu::java::net::PlainDatagramSocketImpl::setTimeToLive (jint ttl){ // Assumes IPPROTO_IP rather than IPPROTO_IPV6 since socket created is IPv4. char val = (char) ttl; socklen_t val_len = sizeof(val); if (::setsockopt (native_fd, IPPROTO_IP, IP_MULTICAST_TTL, &val, val_len) == 0) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -