-/* Copyright (C) 2003, 2004, 2005 Free Software Foundation
+/* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
#include <java/lang/NullPointerException.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/IllegalArgumentException.h>
+#include <java/net/UnknownHostException.h>
union SockAddr
{
void
gnu::java::net::PlainSocketImpl::create (jboolean stream)
{
+ // We might already have been create()d in the nio case.
+ if (native_fd != -1)
+ return;
+
int sock = _Jv_socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
if (sock < 0)
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;
int len = haddress->length;
int i = 1;
+ // The following is needed for OS X/PPC, otherwise bind() fails with an
+ // error. I found the issue and following fix on some mailing list, but
+ // no explanation was given as to why this solved the problem.
+ memset (&u, 0, sizeof (u));
+
if (len == 4)
{
u.address.sin_family = AF_INET;
void
gnu::java::net::PlainSocketImpl::connect (::java::net::SocketAddress *addr,
- jint timeout)
+ jint timeout)
{
::java::net::InetSocketAddress *tmp = (::java::net::InetSocketAddress*) addr;
::java::net::InetAddress *host = tmp->getAddress();
+ if (! host)
+ throw new ::java::net::UnknownHostException(tmp->toString());
+
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;
goto error;
}
- address = host;
- port = rport;
-
// A bind may not have been done on this socket; if so, set localport now.
if (localport == 0)
{
}
}
+static void
+throw_on_sock_closed (gnu::java::net::PlainSocketImpl *soc_impl)
+{
+ // Avoid races from asynchronous close().
+ JvSynchronize sync (soc_impl);
+ if (soc_impl->native_fd == -1)
+ {
+ using namespace java::net;
+ // Socket was closed.
+ SocketException *se =
+ new SocketException (JvNewStringUTF ("Socket Closed"));
+ throw se;
+ }
+}
+
void
gnu::java::net::PlainSocketImpl::accept (gnu::java::net::PlainSocketImpl *s)
{
if (new_socket < 0)
goto error;
- _Jv_platform_close_on_exec (new_socket);
-
jbyteArray raddr;
jint rport;
if (u.address.sin_family == AF_INET)
s->native_fd = new_socket;
s->localport = localport;
- s->address = new ::java::net::InetAddress (raddr, NULL);
+ s->address = ::java::net::InetAddress::getByAddress (raddr);
s->port = rport;
return;
error:
char* strerr = strerror (errno);
+ throw_on_sock_closed (this);
throw new ::java::io::IOException (JvNewStringUTF (strerr));
}
// Avoid races from asynchronous finalization.
JvSynchronize sync (this);
- // should we use shutdown here? how would that effect so_linger?
+ // Should we use shutdown here? Yes.
+ // How would that effect so_linger? Uncertain.
+ ::shutdown (native_fd, 2);
+ // Ignore errors in shutdown as we are closing and all the same
+ // errors are handled in the close.
int res = _Jv_close (native_fd);
if (res == -1)
if (offset < 0 || len < 0 || offset + len > JvGetArrayLength (b))
throw new ::java::lang::ArrayIndexOutOfBoundsException;
- write_helper (this$0->native_fd, elements (b) + offset * sizeof (jbyte), len);
+ write_helper (this$0->native_fd, elements (b) + offset, len);
}
static void
}
static jint
-read_helper (jint native_fd, jint timeout, jbyte *bytes, jint count);
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count);
// Read a single byte from the socket.
jint
{
jbyte data;
- if (read_helper (this$0->native_fd, this$0->timeout, &data, 1) == 1)
+ if (read_helper (this$0, &data, 1) == 1)
return data & 0xFF;
return -1;
// Read count bytes into the buffer, starting at offset.
jint
-gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer, jint offset,
- jint count)
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
+ jint offset,
+ jint count)
{
if (! buffer)
throw new ::java::lang::NullPointerException;
if (offset < 0 || count < 0 || offset + count > bsize)
throw new ::java::lang::ArrayIndexOutOfBoundsException;
- return read_helper (this$0->native_fd, this$0->timeout,
- elements (buffer) + offset * sizeof (jbyte), count);
+ return read_helper (this$0, elements (buffer) + offset, count);
}
static jint
-read_helper (jint native_fd, jint timeout, jbyte *bytes, jint count)
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count)
{
// If zero bytes were requested, short circuit so that recv
// doesn't signal EOF.
return 0;
// Do timeouts via select.
- if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
+ if (soc_impl->timeout > 0
+ && soc_impl->native_fd >= 0
+ && soc_impl->native_fd < FD_SETSIZE)
{
// Create the file descriptor set.
fd_set read_fds;
FD_ZERO (&read_fds);
- FD_SET (native_fd, &read_fds);
+ FD_SET (soc_impl->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;
+ timeout_value.tv_sec = soc_impl->timeout / 1000;
+ timeout_value.tv_usec =(soc_impl->timeout % 1000) * 1000;
// Select on the fds.
int sel_retval =
- _Jv_select (native_fd + 1, &read_fds, NULL, NULL, &timeout_value);
+ _Jv_select (soc_impl->native_fd + 1,
+ &read_fds, NULL, NULL, &timeout_value);
// We're only interested in the 0 return.
// error returns still require us to try to read
// the socket to see what happened.
}
// Read the socket.
- int r = ::recv (native_fd, (char *) bytes, count, 0);
+ int r = ::recv (soc_impl->native_fd, (char *) bytes, count, 0);
if (r == 0)
- return -1;
+ {
+ throw_on_sock_closed (soc_impl);
+ return -1;
+ }
if (::java::lang::Thread::interrupted())
{
}
else if (r == -1)
{
+ throw_on_sock_closed (soc_impl);
// Some errors cause us to return end of stream...
if (errno == ENOTCONN)
return -1;
if (::setsockopt (native_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &val,
val_len) != 0)
goto error;
+ return;
#else
throw new ::java::lang::InternalError (
JvNewStringUTF ("SO_REUSEADDR not supported"));
else
throw new ::java::net::SocketException
(JvNewStringUTF ("invalid family"));
- localAddress = new ::java::net::InetAddress (laddr, NULL);
+ localAddress = ::java::net::InetAddress::getByAddress (laddr);
}
return localAddress;