2014-04-21 02:14:48 +00:00
|
|
|
/* Copyright (c) 2008-2014, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2011-06-01 19:56:03 +00:00
|
|
|
#include "jni.h"
|
2007-10-24 17:24:19 +00:00
|
|
|
#include "jni-util.h"
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
# include <winsock2.h>
|
2010-06-14 22:09:56 +00:00
|
|
|
# include <ws2tcpip.h>
|
2007-10-23 17:22:48 +00:00
|
|
|
# include <errno.h>
|
2009-08-27 00:26:44 +00:00
|
|
|
# ifdef _MSC_VER
|
|
|
|
# define snprintf sprintf_s
|
|
|
|
# else
|
|
|
|
# include <unistd.h>
|
|
|
|
# endif
|
2007-10-05 21:32:56 +00:00
|
|
|
#else
|
2009-08-27 00:26:44 +00:00
|
|
|
# include <unistd.h>
|
2007-10-05 21:32:56 +00:00
|
|
|
# include <fcntl.h>
|
|
|
|
# include <errno.h>
|
|
|
|
# include <netdb.h>
|
|
|
|
# include <sys/select.h>
|
2012-08-02 16:36:16 +00:00
|
|
|
# include <arpa/inet.h>
|
|
|
|
# include <netinet/in.h>
|
2012-07-18 00:21:17 +00:00
|
|
|
# include <netinet/ip.h>
|
2008-11-22 22:32:53 +00:00
|
|
|
# include <netinet/tcp.h>
|
2009-08-06 17:52:36 +00:00
|
|
|
# include <sys/socket.h>
|
2007-10-24 17:24:19 +00:00
|
|
|
#endif
|
2007-10-05 21:32:56 +00:00
|
|
|
|
|
|
|
#define java_nio_channels_SelectionKey_OP_READ 1L
|
|
|
|
#define java_nio_channels_SelectionKey_OP_WRITE 4L
|
2009-10-08 22:26:20 +00:00
|
|
|
#define java_nio_channels_SelectionKey_OP_CONNECT 8L
|
2007-10-05 21:32:56 +00:00
|
|
|
#define java_nio_channels_SelectionKey_OP_ACCEPT 16L
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-23 17:22:48 +00:00
|
|
|
typedef int socklen_t;
|
|
|
|
#endif
|
|
|
|
|
2008-10-10 17:49:07 +00:00
|
|
|
inline void* operator new(size_t, void* p) throw() { return p; }
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-10-23 17:22:48 +00:00
|
|
|
inline jbyteArray
|
|
|
|
charsToArray(JNIEnv* e, const char* s)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2007-10-23 17:22:48 +00:00
|
|
|
unsigned length = strlen(s);
|
|
|
|
jbyteArray a = e->NewByteArray(length + 1);
|
|
|
|
e->SetByteArrayRegion(a, 0, length + 1, reinterpret_cast<const jbyte*>(s));
|
|
|
|
return a;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
inline void
|
2010-06-05 00:45:13 +00:00
|
|
|
doClose(int socket)
|
2009-08-27 00:26:44 +00:00
|
|
|
{
|
2010-06-05 00:45:13 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2009-08-27 00:26:44 +00:00
|
|
|
closesocket(socket);
|
2010-06-05 00:45:13 +00:00
|
|
|
#else
|
|
|
|
close(socket);
|
2009-08-27 00:26:44 +00:00
|
|
|
#endif
|
2010-06-05 00:45:13 +00:00
|
|
|
}
|
2009-08-27 00:26:44 +00:00
|
|
|
|
2007-10-23 17:22:48 +00:00
|
|
|
inline jbyteArray
|
|
|
|
errorString(JNIEnv* e, int n)
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
const unsigned size = 128;
|
|
|
|
char buffer[size];
|
|
|
|
strerror_s(buffer, size, n);
|
|
|
|
return charsToArray(e, buffer);
|
|
|
|
#else
|
2007-10-23 17:22:48 +00:00
|
|
|
return charsToArray(e, strerror(n));
|
2009-08-27 00:26:44 +00:00
|
|
|
#endif
|
2007-10-23 17:22:48 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 23:41:27 +00:00
|
|
|
inline jbyteArray
|
|
|
|
socketErrorString(JNIEnv* e, int n)
|
|
|
|
{
|
|
|
|
#ifdef PLATFORM_WINDOWS
|
|
|
|
const unsigned size = 64;
|
|
|
|
char buffer[size];
|
|
|
|
snprintf(buffer, size, "wsa code: %d", n);
|
|
|
|
return charsToArray(e, buffer);
|
|
|
|
#else
|
|
|
|
return errorString(e, n);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-10-23 17:22:48 +00:00
|
|
|
inline jbyteArray
|
|
|
|
errorString(JNIEnv* e)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
const unsigned size = 64;
|
|
|
|
char buffer[size];
|
|
|
|
snprintf(buffer, size, "wsa code: %d", WSAGetLastError());
|
2007-10-23 17:22:48 +00:00
|
|
|
return charsToArray(e, buffer);
|
2007-10-05 21:32:56 +00:00
|
|
|
#else
|
2007-10-23 23:22:42 +00:00
|
|
|
return errorString(e, errno);
|
2007-10-05 21:32:56 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-10-23 17:22:48 +00:00
|
|
|
void
|
|
|
|
throwIOException(JNIEnv* e, const char* s)
|
|
|
|
{
|
|
|
|
throwNew(e, "java/io/IOException", s);
|
|
|
|
}
|
|
|
|
|
2014-04-24 21:10:35 +00:00
|
|
|
void throwIOException(JNIEnv* e, jbyteArray a)
|
2007-10-23 17:22:48 +00:00
|
|
|
{
|
2014-04-24 21:10:35 +00:00
|
|
|
size_t length = e->GetArrayLength(a);
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
|
|
|
|
if (buf) {
|
|
|
|
e->GetByteArrayRegion(a, 0, length, reinterpret_cast<jbyte*>(buf));
|
|
|
|
throwIOException(e, reinterpret_cast<const char*>(buf));
|
|
|
|
free(buf);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
2007-10-23 17:22:48 +00:00
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
void
|
|
|
|
throwIOException(JNIEnv* e)
|
|
|
|
{
|
2007-10-23 17:22:48 +00:00
|
|
|
throwIOException(e, errorString(e));
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2008-11-22 22:32:53 +00:00
|
|
|
void
|
|
|
|
throwSocketException(JNIEnv* e, const char* s)
|
|
|
|
{
|
|
|
|
throwNew(e, "java/net/SocketException", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
throwSocketException(JNIEnv* e, jbyteArray a)
|
|
|
|
{
|
|
|
|
jbyte* s = static_cast<jbyte*>(e->GetPrimitiveArrayCritical(a, 0));
|
|
|
|
throwSocketException(e, reinterpret_cast<const char*>(s));
|
|
|
|
e->ReleasePrimitiveArrayCritical(a, s, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
throwSocketException(JNIEnv* e)
|
|
|
|
{
|
|
|
|
throwSocketException(e, errorString(e));
|
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
void init(sockaddr_in* address, jint host, jint port)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2014-03-28 18:30:20 +00:00
|
|
|
memset(address, 0, sizeof(sockaddr_in));
|
|
|
|
address->sin_family = AF_INET;
|
|
|
|
address->sin_port = htons(port);
|
|
|
|
address->sin_addr.s_addr = htonl(host);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-12 15:28:04 +00:00
|
|
|
inline bool
|
|
|
|
einProgress(int error)
|
|
|
|
{
|
|
|
|
#ifdef PLATFORM_WINDOWS
|
|
|
|
return error == WSAEINPROGRESS
|
|
|
|
or error == WSAEWOULDBLOCK;
|
|
|
|
#else
|
|
|
|
return error == EINPROGRESS;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
inline bool
|
|
|
|
einProgress()
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
return WSAGetLastError() == WSAEINPROGRESS
|
|
|
|
or WSAGetLastError() == WSAEWOULDBLOCK;
|
|
|
|
#else
|
|
|
|
return errno == EINPROGRESS;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
eagain()
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
return WSAGetLastError() == WSAEINPROGRESS
|
|
|
|
or WSAGetLastError() == WSAEWOULDBLOCK;
|
|
|
|
#else
|
|
|
|
return errno == EAGAIN;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2009-08-03 14:58:56 +00:00
|
|
|
setBlocking(JNIEnv* e, int d, bool blocking)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2009-08-03 14:58:56 +00:00
|
|
|
u_long a = (blocking ? 0 : 1);
|
2007-10-05 21:32:56 +00:00
|
|
|
int r = ioctlsocket(d, FIONBIO, &a);
|
2007-10-23 17:22:48 +00:00
|
|
|
if (r != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
#else
|
2009-08-03 14:58:56 +00:00
|
|
|
int r = fcntl(d, F_SETFL, (blocking
|
|
|
|
? (fcntl(d, F_GETFL) & (~O_NONBLOCK))
|
|
|
|
: (fcntl(d, F_GETFL) | O_NONBLOCK)));
|
2007-10-05 21:32:56 +00:00
|
|
|
if (r < 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
2007-10-23 17:22:48 +00:00
|
|
|
return true;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2008-11-22 22:32:53 +00:00
|
|
|
bool
|
|
|
|
setTcpNoDelay(JNIEnv* e, int d, bool on)
|
|
|
|
{
|
|
|
|
int flag = on;
|
|
|
|
int r = setsockopt
|
|
|
|
(d, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&flag), sizeof(int));
|
|
|
|
if (r < 0) {
|
|
|
|
throwSocketException(e);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
void
|
2012-07-03 17:24:05 +00:00
|
|
|
doBind(JNIEnv* e, int s, sockaddr_in* address)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2013-03-18 17:43:00 +00:00
|
|
|
{ int opt = 1;
|
|
|
|
int r = ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
reinterpret_cast<char*>(&opt), sizeof(int));
|
|
|
|
if (r != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2013-03-18 17:43:00 +00:00
|
|
|
#ifdef SO_NOSIGPIPE
|
|
|
|
{ int opt = 1;
|
|
|
|
int r = ::setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE,
|
|
|
|
reinterpret_cast<char*>(&opt), sizeof(int));
|
|
|
|
if (r != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
{ int r = ::bind
|
|
|
|
(s, reinterpret_cast<sockaddr*>(address), sizeof(sockaddr_in));
|
|
|
|
if (r != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
2012-07-03 17:24:05 +00:00
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
|
2012-07-03 17:24:05 +00:00
|
|
|
void
|
|
|
|
doListen(JNIEnv* e, int s)
|
|
|
|
{
|
|
|
|
int r = ::listen(s, 100);
|
2007-10-05 21:32:56 +00:00
|
|
|
if (r != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-12 01:29:48 +00:00
|
|
|
void
|
2010-02-19 23:41:27 +00:00
|
|
|
doFinishConnect(JNIEnv* e, int socket)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
socklen_t size = sizeof(int);
|
|
|
|
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
|
|
|
|
reinterpret_cast<char*>(&error), &size);
|
|
|
|
|
|
|
|
if (r != 0 or size != sizeof(int)) {
|
|
|
|
throwIOException(e);
|
2011-01-12 01:29:48 +00:00
|
|
|
} else if (error and not einProgress(error)) {
|
2010-02-19 23:41:27 +00:00
|
|
|
throwIOException(e, socketErrorString(e, error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
bool
|
|
|
|
doConnect(JNIEnv* e, int s, sockaddr_in* address)
|
|
|
|
{
|
|
|
|
int r = ::connect(s, reinterpret_cast<sockaddr*>(address),
|
|
|
|
sizeof(sockaddr_in));
|
|
|
|
if (r == 0) {
|
|
|
|
return true;
|
|
|
|
} else if (not einProgress()) {
|
|
|
|
throwIOException(e);
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
doAccept(JNIEnv* e, int s)
|
|
|
|
{
|
|
|
|
sockaddr address;
|
|
|
|
socklen_t length = sizeof(address);
|
|
|
|
int r = ::accept(s, &address, &length);
|
|
|
|
if (r >= 0) {
|
|
|
|
return r;
|
2009-11-17 00:23:09 +00:00
|
|
|
} else if (errno != EINTR) {
|
2007-10-05 21:32:56 +00:00
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
doRead(int fd, void* buffer, size_t count)
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
return recv(fd, static_cast<char*>(buffer), count, 0);
|
|
|
|
#else
|
|
|
|
return read(fd, buffer, count);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-07-10 20:09:14 +00:00
|
|
|
int
|
|
|
|
doRecv(int fd, void* buffer, size_t count, int32_t* host, int32_t* port)
|
|
|
|
{
|
|
|
|
sockaddr address;
|
|
|
|
socklen_t length = sizeof(address);
|
|
|
|
int r = recvfrom
|
|
|
|
(fd, static_cast<char*>(buffer), count, 0, &address, &length);
|
|
|
|
|
|
|
|
if (r > 0) {
|
|
|
|
sockaddr_in a; memcpy(&a, &address, length);
|
|
|
|
*host = ntohl(a.sin_addr.s_addr);
|
|
|
|
*port = ntohs(a.sin_port);
|
|
|
|
} else {
|
|
|
|
*host = 0;
|
|
|
|
*port = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
int
|
|
|
|
doWrite(int fd, const void* buffer, size_t count)
|
|
|
|
{
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
return send(fd, static_cast<const char*>(buffer), count, 0);
|
|
|
|
#else
|
|
|
|
return write(fd, buffer, count);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
int doSend(int fd, sockaddr_in* address, const void* buffer, size_t count)
|
|
|
|
{
|
|
|
|
return sendto(fd,
|
|
|
|
static_cast<const char*>(buffer),
|
|
|
|
count,
|
|
|
|
0,
|
|
|
|
reinterpret_cast<sockaddr*>(address),
|
|
|
|
sizeof(sockaddr_in));
|
|
|
|
}
|
|
|
|
|
|
|
|
int makeSocket(JNIEnv* e, int type = SOCK_STREAM, int protocol = IPPROTO_TCP)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2012-07-03 17:24:05 +00:00
|
|
|
int s = ::socket(AF_INET, type, protocol);
|
2008-07-21 21:35:14 +00:00
|
|
|
if (s < 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return s;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace <anonymous>
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_ServerSocketChannel_natDoAccept(JNIEnv *e, jclass, jint socket)
|
|
|
|
{
|
|
|
|
return ::doAccept(e, socket);
|
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_ServerSocketChannel_natDoListen(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port)
|
|
|
|
{
|
2007-10-05 21:32:56 +00:00
|
|
|
sockaddr_in address;
|
2014-03-28 18:30:20 +00:00
|
|
|
init(&address, host, port);
|
2007-10-05 21:32:56 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
::doBind(e, socket, &address);
|
|
|
|
if (e->ExceptionCheck())
|
|
|
|
return;
|
2012-07-03 17:24:05 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
::doListen(e, socket);
|
2012-07-03 17:24:05 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_bind(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port)
|
|
|
|
{
|
2012-07-03 17:24:05 +00:00
|
|
|
sockaddr_in address;
|
2014-03-28 18:30:20 +00:00
|
|
|
init(&address, host, port);
|
2012-07-03 17:24:05 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
::doBind(e, socket, &address);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_bind(JNIEnv* e,
|
|
|
|
jclass c,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port)
|
|
|
|
{
|
|
|
|
Java_java_nio_channels_SocketChannel_bind(e, c, socket, host, port);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_configureBlocking(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
setBlocking(e, socket, blocking);
|
|
|
|
}
|
|
|
|
|
2012-07-03 17:24:05 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_configureBlocking(JNIEnv* e,
|
|
|
|
jclass c,
|
|
|
|
jint socket,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
return Java_java_nio_channels_SocketChannel_configureBlocking
|
|
|
|
(e, c, socket, blocking);
|
|
|
|
}
|
|
|
|
|
2008-11-22 22:32:53 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natSetTcpNoDelay(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jboolean on)
|
|
|
|
{
|
|
|
|
setTcpNoDelay(e, socket, on);
|
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT jboolean JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natDoConnect(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port)
|
2007-10-05 21:32:56 +00:00
|
|
|
{
|
2014-03-28 18:30:20 +00:00
|
|
|
sockaddr_in address;
|
|
|
|
init(&address, host, port);
|
2008-07-21 21:35:14 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
return ::doConnect(e, socket, &address);
|
|
|
|
}
|
2009-08-03 14:58:56 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_makeSocket(JNIEnv* e, jclass)
|
|
|
|
{
|
|
|
|
return makeSocket(e);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2012-07-03 17:24:05 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
2014-03-28 18:30:20 +00:00
|
|
|
Java_java_nio_channels_DatagramChannel_makeSocket(JNIEnv* e, jclass)
|
2012-07-03 17:24:05 +00:00
|
|
|
{
|
2014-03-28 18:30:20 +00:00
|
|
|
return makeSocket(e, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
}
|
2012-07-03 17:24:05 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT jboolean JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_connect(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port)
|
|
|
|
{
|
2012-07-03 17:24:05 +00:00
|
|
|
sockaddr_in address;
|
2014-03-28 18:30:20 +00:00
|
|
|
init(&address, host, port);
|
|
|
|
|
|
|
|
return ::doConnect(e, socket, &address);
|
2012-07-03 17:24:05 +00:00
|
|
|
}
|
|
|
|
|
2011-01-12 01:29:48 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
2009-10-08 22:26:20 +00:00
|
|
|
Java_java_nio_channels_SocketChannel_natFinishConnect(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket)
|
|
|
|
{
|
2011-01-12 01:29:48 +00:00
|
|
|
doFinishConnect(e, socket);
|
2009-10-08 22:26:20 +00:00
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natRead(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jbyteArray buffer,
|
|
|
|
jint offset,
|
2010-06-04 21:37:22 +00:00
|
|
|
jint length,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
if (blocking) {
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
|
|
|
|
if (buf) {
|
|
|
|
r = ::doRead(socket, buf, length);
|
|
|
|
if (r > 0) {
|
|
|
|
e->SetByteArrayRegion
|
|
|
|
(buffer, offset, r, reinterpret_cast<jbyte*>(buf));
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
jboolean isCopy;
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>
|
|
|
|
(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
|
|
|
|
|
|
|
r = ::doRead(socket, buf + offset, length);
|
|
|
|
|
|
|
|
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
if (r < 0) {
|
|
|
|
if (eagain()) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
2007-10-05 21:51:06 +00:00
|
|
|
} else if (r == 0) {
|
|
|
|
return -1;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-07-03 17:24:05 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
2012-07-10 20:09:14 +00:00
|
|
|
Java_java_nio_channels_DatagramChannel_receive(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jbyteArray buffer,
|
|
|
|
jint offset,
|
|
|
|
jint length,
|
|
|
|
jboolean blocking,
|
|
|
|
jintArray address)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
int32_t host;
|
|
|
|
int32_t port;
|
|
|
|
if (blocking) {
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
|
|
|
|
if (buf) {
|
|
|
|
r = ::doRecv(socket, buf, length, &host, &port);
|
|
|
|
if (r > 0) {
|
|
|
|
e->SetByteArrayRegion
|
|
|
|
(buffer, offset, r, reinterpret_cast<jbyte*>(buf));
|
|
|
|
}
|
|
|
|
free(buf);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
jboolean isCopy;
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>
|
|
|
|
(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
|
|
|
|
|
|
|
r = ::doRecv(socket, buf + offset, length, &host, &port);
|
|
|
|
|
|
|
|
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
if (eagain()) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
} else if (r == 0) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
2012-07-24 22:50:24 +00:00
|
|
|
jint jhost = host; e->SetIntArrayRegion(address, 0, 1, &jhost);
|
|
|
|
jint jport = port; e->SetIntArrayRegion(address, 1, 1, &jport);
|
2012-07-10 20:09:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
2012-07-03 17:24:05 +00:00
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natWrite(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jbyteArray buffer,
|
|
|
|
jint offset,
|
2010-06-04 21:37:22 +00:00
|
|
|
jint length,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
if (blocking) {
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
|
|
|
|
if (buf) {
|
|
|
|
e->GetByteArrayRegion
|
|
|
|
(buffer, offset, length, reinterpret_cast<jbyte*>(buf));
|
|
|
|
r = ::doWrite(socket, buf, length);
|
|
|
|
free(buf);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
jboolean isCopy;
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>
|
|
|
|
(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
|
|
|
|
|
|
|
r = ::doWrite(socket, buf + offset, length);
|
|
|
|
|
|
|
|
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
if (r < 0) {
|
|
|
|
if (eagain()) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-07-03 17:24:05 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_write(JNIEnv* e,
|
|
|
|
jclass c,
|
|
|
|
jint socket,
|
|
|
|
jbyteArray buffer,
|
|
|
|
jint offset,
|
|
|
|
jint length,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
return Java_java_nio_channels_SocketChannel_natWrite
|
|
|
|
(e, c, socket, buffer, offset, length, blocking);
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_send(JNIEnv* e,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint host,
|
|
|
|
jint port,
|
|
|
|
jbyteArray buffer,
|
|
|
|
jint offset,
|
|
|
|
jint length,
|
|
|
|
jboolean blocking)
|
|
|
|
{
|
|
|
|
sockaddr_in address;
|
|
|
|
init(&address, host, port);
|
|
|
|
|
|
|
|
int r;
|
|
|
|
if (blocking) {
|
|
|
|
uint8_t* buf = static_cast<uint8_t*>(allocate(e, length));
|
|
|
|
if (buf) {
|
|
|
|
e->GetByteArrayRegion(
|
|
|
|
buffer, offset, length, reinterpret_cast<jbyte*>(buf));
|
|
|
|
r = ::doSend(socket, &address, buf, length);
|
|
|
|
free(buf);
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
jboolean isCopy;
|
|
|
|
uint8_t* buf
|
|
|
|
= static_cast<uint8_t*>(e->GetPrimitiveArrayCritical(buffer, &isCopy));
|
|
|
|
|
|
|
|
r = ::doSend(socket, &address, buf + offset, length);
|
|
|
|
|
|
|
|
e->ReleasePrimitiveArrayCritical(buffer, buf, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
if (eagain()) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natThrowWriteError(JNIEnv *e,
|
|
|
|
jclass,
|
|
|
|
jint socket)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
socklen_t size = sizeof(int);
|
|
|
|
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
|
|
|
|
reinterpret_cast<char*>(&error), &size);
|
2010-02-19 23:41:27 +00:00
|
|
|
if (r != 0 or size != sizeof(int)) {
|
|
|
|
throwIOException(e);
|
|
|
|
} else if (error != 0) {
|
|
|
|
throwIOException(e, socketErrorString(e, error));
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketChannel_natCloseSocket(JNIEnv *,
|
|
|
|
jclass,
|
|
|
|
jint socket)
|
|
|
|
{
|
2010-06-05 00:45:13 +00:00
|
|
|
doClose(socket);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2014-03-28 18:30:20 +00:00
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_DatagramChannel_close(JNIEnv *,
|
|
|
|
jclass,
|
|
|
|
jint socket)
|
|
|
|
{
|
|
|
|
doClose(socket);
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class Pipe {
|
|
|
|
public:
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-05 21:32:56 +00:00
|
|
|
// The Windows socket API only accepts socket file descriptors, not
|
|
|
|
// pipe descriptors or others. Thus, to implement
|
|
|
|
// Selector.wakeup(), we make a socket connection via the loopback
|
|
|
|
// interface and use it as a pipe.
|
2007-10-23 17:22:48 +00:00
|
|
|
Pipe(JNIEnv* e): connected_(false), listener_(-1), reader_(-1), writer_(-1) {
|
2007-10-05 21:32:56 +00:00
|
|
|
sockaddr_in address;
|
|
|
|
address.sin_family = AF_INET;
|
|
|
|
address.sin_port = 0;
|
|
|
|
address.sin_addr.s_addr = inet_addr("127.0.0.1"); //INADDR_LOOPBACK;
|
2012-07-03 17:24:05 +00:00
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
listener_ = makeSocket(e);
|
2012-07-03 17:24:05 +00:00
|
|
|
if (e->ExceptionCheck()) return;
|
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
setBlocking(e, listener_, false);
|
2012-07-03 17:24:05 +00:00
|
|
|
|
|
|
|
::doBind(e, listener_, &address);
|
|
|
|
if (e->ExceptionCheck()) return;
|
|
|
|
|
|
|
|
::doListen(e, listener_);
|
|
|
|
if (e->ExceptionCheck()) return;
|
2007-10-05 21:32:56 +00:00
|
|
|
|
|
|
|
socklen_t length = sizeof(sockaddr_in);
|
|
|
|
int r = getsockname(listener_, reinterpret_cast<sockaddr*>(&address),
|
|
|
|
&length);
|
|
|
|
if (r) {
|
2007-10-23 17:22:48 +00:00
|
|
|
throwIOException(e);
|
2012-07-03 17:24:05 +00:00
|
|
|
return;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
writer_ = makeSocket(e);
|
2012-07-03 17:24:05 +00:00
|
|
|
if (e->ExceptionCheck()) return;
|
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
setBlocking(e, writer_, true);
|
2007-10-23 17:22:48 +00:00
|
|
|
connected_ = ::doConnect(e, writer_, &address);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2007-10-23 17:22:48 +00:00
|
|
|
void dispose() {
|
2010-06-05 00:45:13 +00:00
|
|
|
if (listener_ >= 0) ::doClose(listener_);
|
|
|
|
if (reader_ >= 0) ::doClose(reader_);
|
|
|
|
if (writer_ >= 0) ::doClose(writer_);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool connected() {
|
|
|
|
return connected_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setConnected(bool v) {
|
|
|
|
connected_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
int listener() {
|
|
|
|
return listener_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setListener(int v) {
|
|
|
|
listener_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
int reader() {
|
|
|
|
return reader_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setReader(int v) {
|
|
|
|
reader_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
int writer() {
|
|
|
|
return writer_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool connected_;
|
|
|
|
int listener_;
|
|
|
|
int reader_;
|
|
|
|
int writer_;
|
|
|
|
#else
|
|
|
|
Pipe(JNIEnv* e) {
|
|
|
|
if (::pipe(pipe) != 0) {
|
|
|
|
throwIOException(e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-03 14:58:56 +00:00
|
|
|
if (setBlocking(e, pipe[0], false)) {
|
|
|
|
setBlocking(e, pipe[1], false);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
2009-10-05 15:23:53 +00:00
|
|
|
|
|
|
|
open_ = true;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2007-10-08 19:05:56 +00:00
|
|
|
void dispose() {
|
2010-06-05 00:45:13 +00:00
|
|
|
::doClose(pipe[0]);
|
|
|
|
::doClose(pipe[1]);
|
2009-10-05 15:23:53 +00:00
|
|
|
open_ = false;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool connected() {
|
2009-10-05 15:23:53 +00:00
|
|
|
return open_;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int reader() {
|
|
|
|
return pipe[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
int writer() {
|
|
|
|
return pipe[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
int pipe[2];
|
2009-10-05 15:23:53 +00:00
|
|
|
bool open_;
|
2007-10-05 21:32:56 +00:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SelectorState {
|
|
|
|
fd_set read;
|
|
|
|
fd_set write;
|
|
|
|
fd_set except;
|
|
|
|
Pipe control;
|
|
|
|
SelectorState(JNIEnv* e) : control(e) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jlong JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natInit(JNIEnv* e, jclass)
|
|
|
|
{
|
2007-10-08 19:05:56 +00:00
|
|
|
void *mem = malloc(sizeof(SelectorState));
|
|
|
|
if (mem) {
|
|
|
|
SelectorState *s = new (mem) SelectorState(e);
|
2012-07-03 17:24:05 +00:00
|
|
|
if (e->ExceptionCheck()) return 0;
|
2007-10-08 19:05:56 +00:00
|
|
|
|
|
|
|
if (s) {
|
|
|
|
FD_ZERO(&(s->read));
|
|
|
|
FD_ZERO(&(s->write));
|
|
|
|
FD_ZERO(&(s->except));
|
|
|
|
return reinterpret_cast<jlong>(s);
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
2007-10-08 19:05:56 +00:00
|
|
|
throwNew(e, "java/lang/OutOfMemoryError", 0);
|
|
|
|
return 0;
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natWakeup(JNIEnv *e, jclass, jlong state)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
|
|
|
if (s->control.connected()) {
|
|
|
|
const char c = 1;
|
|
|
|
int r = ::doWrite(s->control.writer(), &c, 1);
|
|
|
|
if (r != 1) {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natClose(JNIEnv *, jclass, jlong state)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
2007-10-08 19:05:56 +00:00
|
|
|
s->control.dispose();
|
|
|
|
free(s);
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT void JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natSelectClearAll(JNIEnv *, jclass,
|
|
|
|
jint socket,
|
|
|
|
jlong state)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->read));
|
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->write));
|
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->except));
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natSelectUpdateInterestSet(JNIEnv *,
|
|
|
|
jclass,
|
|
|
|
jint socket,
|
|
|
|
jint interest,
|
|
|
|
jlong state,
|
|
|
|
jint max)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
|
|
|
if (interest & (java_nio_channels_SelectionKey_OP_READ |
|
|
|
|
java_nio_channels_SelectionKey_OP_ACCEPT)) {
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->read));
|
2007-10-05 21:32:56 +00:00
|
|
|
if (max < socket) max = socket;
|
|
|
|
} else {
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->read));
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-08 22:26:20 +00:00
|
|
|
if (interest & (java_nio_channels_SelectionKey_OP_WRITE |
|
|
|
|
java_nio_channels_SelectionKey_OP_CONNECT)) {
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->write));
|
2010-02-19 23:41:27 +00:00
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->except));
|
2007-10-05 21:32:56 +00:00
|
|
|
if (max < socket) max = socket;
|
|
|
|
} else {
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->write));
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
|
|
|
return max;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natDoSocketSelect(JNIEnv *e, jclass,
|
|
|
|
jlong state,
|
|
|
|
jint max,
|
|
|
|
jlong interval)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
|
|
|
if (s->control.reader() >= 0) {
|
|
|
|
int socket = s->control.reader();
|
2007-10-23 17:22:48 +00:00
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->read));
|
2007-10-05 21:32:56 +00:00
|
|
|
if (max < socket) max = socket;
|
|
|
|
}
|
2007-10-27 00:04:55 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-27 00:04:55 +00:00
|
|
|
if (s->control.listener() >= 0) {
|
|
|
|
int socket = s->control.listener();
|
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->read));
|
|
|
|
if (max < socket) max = socket;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not s->control.connected()) {
|
|
|
|
int socket = s->control.writer();
|
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->write));
|
|
|
|
FD_SET(static_cast<unsigned>(socket), &(s->except));
|
|
|
|
if (max < socket) max = socket;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-07-23 19:08:41 +00:00
|
|
|
timeval time;
|
|
|
|
if (interval > 0) {
|
|
|
|
time.tv_sec = interval / 1000;
|
|
|
|
time.tv_usec = (interval % 1000) * 1000;
|
|
|
|
} else if (interval < 0) {
|
|
|
|
time.tv_sec = 0;
|
|
|
|
time.tv_usec = 0;
|
|
|
|
} else {
|
2012-07-03 17:17:51 +00:00
|
|
|
time.tv_sec = 24 * 60 * 60 * 1000;
|
2009-07-23 19:08:41 +00:00
|
|
|
time.tv_usec = 0;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
int r = ::select(max + 1, &(s->read), &(s->write), &(s->except), &time);
|
2007-10-27 00:04:55 +00:00
|
|
|
|
2008-03-25 22:17:29 +00:00
|
|
|
if (r < 0) {
|
|
|
|
if (errno != EINTR) {
|
|
|
|
throwIOException(e);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2007-10-27 00:04:55 +00:00
|
|
|
if (FD_ISSET(s->control.writer(), &(s->write)) or
|
|
|
|
FD_ISSET(s->control.writer(), &(s->except)))
|
|
|
|
{
|
2010-05-13 22:38:58 +00:00
|
|
|
int socket = s->control.writer();
|
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->write));
|
|
|
|
FD_CLR(static_cast<unsigned>(socket), &(s->except));
|
2007-10-27 00:04:55 +00:00
|
|
|
|
|
|
|
int error;
|
|
|
|
socklen_t size = sizeof(int);
|
|
|
|
int r = getsockopt(socket, SOL_SOCKET, SO_ERROR,
|
|
|
|
reinterpret_cast<char*>(&error), &size);
|
2010-02-19 23:41:27 +00:00
|
|
|
if (r != 0 or size != sizeof(int)) {
|
2007-10-27 00:04:55 +00:00
|
|
|
throwIOException(e);
|
2010-02-19 23:41:27 +00:00
|
|
|
} else if (error != 0) {
|
|
|
|
throwIOException(e, socketErrorString(e, error));
|
2007-10-27 00:04:55 +00:00
|
|
|
}
|
|
|
|
s->control.setConnected(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->control.listener() >= 0 and
|
|
|
|
FD_ISSET(s->control.listener(), &(s->read)))
|
|
|
|
{
|
|
|
|
FD_CLR(static_cast<unsigned>(s->control.listener()), &(s->read));
|
|
|
|
|
|
|
|
s->control.setReader(::doAccept(e, s->control.listener()));
|
|
|
|
s->control.setListener(-1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (s->control.reader() >= 0 and
|
|
|
|
FD_ISSET(s->control.reader(), &(s->read)))
|
|
|
|
{
|
|
|
|
FD_CLR(static_cast<unsigned>(s->control.reader()), &(s->read));
|
|
|
|
|
|
|
|
char c;
|
|
|
|
int r = 1;
|
|
|
|
while (r == 1) {
|
|
|
|
r = ::doRead(s->control.reader(), &c, 1);
|
|
|
|
}
|
|
|
|
if (r < 0 and not eagain()) {
|
|
|
|
throwIOException(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" JNIEXPORT jint JNICALL
|
|
|
|
Java_java_nio_channels_SocketSelector_natUpdateReadySet(JNIEnv *, jclass,
|
|
|
|
jint socket,
|
|
|
|
jint interest,
|
|
|
|
jlong state)
|
|
|
|
{
|
|
|
|
SelectorState* s = reinterpret_cast<SelectorState*>(state);
|
|
|
|
jint ready = 0;
|
|
|
|
|
|
|
|
if (FD_ISSET(socket, &(s->read))) {
|
|
|
|
if (interest & java_nio_channels_SelectionKey_OP_READ) {
|
|
|
|
ready |= java_nio_channels_SelectionKey_OP_READ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interest & java_nio_channels_SelectionKey_OP_ACCEPT) {
|
|
|
|
ready |= java_nio_channels_SelectionKey_OP_ACCEPT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-19 23:41:27 +00:00
|
|
|
if (FD_ISSET(socket, &(s->write)) or FD_ISSET(socket, &(s->except))) {
|
2009-10-08 22:26:20 +00:00
|
|
|
if (interest & java_nio_channels_SelectionKey_OP_WRITE) {
|
|
|
|
ready |= java_nio_channels_SelectionKey_OP_WRITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interest & java_nio_channels_SelectionKey_OP_CONNECT) {
|
|
|
|
ready |= java_nio_channels_SelectionKey_OP_CONNECT;
|
|
|
|
}
|
2007-10-05 21:32:56 +00:00
|
|
|
}
|
2009-10-08 22:26:20 +00:00
|
|
|
|
2007-10-05 21:32:56 +00:00
|
|
|
return ready;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-11 05:04:11 +00:00
|
|
|
extern "C" JNIEXPORT jboolean JNICALL
|
|
|
|
Java_java_nio_ByteOrder_isNativeBigEndian(JNIEnv *, jclass)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
uint32_t i;
|
|
|
|
char c[4];
|
|
|
|
} u = {0x01020304};
|
|
|
|
|
|
|
|
if (u.c[0] == 1)
|
|
|
|
return JNI_TRUE;
|
|
|
|
return JNI_FALSE;
|
|
|
|
}
|