mirror of
https://github.com/corda/corda.git
synced 2025-01-22 12:28:11 +00:00
Implement socket API
This commit is contained in:
parent
2800ffe826
commit
45ee25f68c
@ -9,33 +9,70 @@
|
|||||||
details. */
|
details. */
|
||||||
|
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include "jni-util.h"
|
#include "avian/machine.h"
|
||||||
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#include "sockets.h"
|
||||||
# include <winsock2.h>
|
|
||||||
# define ONLY_ON_WINDOWS(x) x
|
using namespace avian::classpath::sockets;
|
||||||
#else
|
|
||||||
# include <netdb.h>
|
|
||||||
# include <sys/socket.h>
|
|
||||||
# include <netinet/in.h>
|
|
||||||
# define ONLY_ON_WINDOWS(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
extern "C" JNIEXPORT void JNICALL
|
||||||
Java_java_net_Socket_init(JNIEnv* ONLY_ON_WINDOWS(e), jclass)
|
Java_java_net_Socket_init(JNIEnv* e, jclass) {
|
||||||
{
|
init(e);
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
static bool wsaInitialized = false;
|
|
||||||
if (not wsaInitialized) {
|
|
||||||
WSADATA data;
|
|
||||||
int r = WSAStartup(MAKEWORD(2, 2), &data);
|
|
||||||
if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) {
|
|
||||||
throwNew(e, "java/io/IOException", "WSAStartup failed");
|
|
||||||
} else {
|
|
||||||
wsaInitialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT SOCKET JNICALL
|
||||||
|
Java_java_net_Socket_create(JNIEnv* e, jclass) {
|
||||||
|
return create(e);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_connect(JNIEnv* e, jclass, SOCKET sock, long addr, short port) {
|
||||||
|
connect(e, sock, addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_bind(JNIEnv* e, jclass, SOCKET sock, long addr, short port) {
|
||||||
|
bind(e, sock, addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_abort(JNIEnv* e, jclass, SOCKET sock) {
|
||||||
|
abort(e, sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_close(JNIEnv* e, jclass, SOCKET sock) {
|
||||||
|
close(e, sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_closeOutput(JNIEnv* e, jclass, SOCKET sock) {
|
||||||
|
close_output(e, sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Java_java_net_Socket_closeInput(JNIEnv* e, jclass, SOCKET sock) {
|
||||||
|
close_input(e, sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT void JNICALL
|
||||||
|
Avian_java_net_Socket_send(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */
|
||||||
|
SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
|
||||||
|
vm::object buffer_obj = reinterpret_cast<vm::object>(arguments[2]);
|
||||||
|
int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
|
||||||
|
int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
|
||||||
|
char* buffer = reinterpret_cast<char*>(&vm::byteArrayBody(t, buffer_obj, start_pos));
|
||||||
|
avian::classpath::sockets::send((JNIEnv*)t, s, buffer, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" JNIEXPORT int64_t JNICALL
|
||||||
|
Avian_java_net_Socket_recv(vm::Thread* t, vm::object, uintptr_t* arguments) { /* SOCKET s, object buffer_obj, int start_pos, int count */
|
||||||
|
SOCKET& s = *(reinterpret_cast<SOCKET*>(&arguments[0]));
|
||||||
|
vm::object buffer_obj = reinterpret_cast<vm::object>(arguments[2]);
|
||||||
|
int32_t& start_pos = *(reinterpret_cast<int32_t*>(&arguments[3]));
|
||||||
|
int32_t& count = *(reinterpret_cast<int32_t*>(&arguments[4]));
|
||||||
|
char* buffer = reinterpret_cast<char*>(&vm::byteArrayBody(t, buffer_obj, start_pos));
|
||||||
|
return avian::classpath::sockets::recv((JNIEnv*)t, s, buffer, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT jint JNICALL
|
extern "C" JNIEXPORT jint JNICALL
|
||||||
@ -49,7 +86,7 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
|
|||||||
hostent* host = gethostbyname(chars);
|
hostent* host = gethostbyname(chars);
|
||||||
e->ReleaseStringUTFChars(name, chars);
|
e->ReleaseStringUTFChars(name, chars);
|
||||||
if (host) {
|
if (host) {
|
||||||
return htonl(reinterpret_cast<in_addr*>(host->h_addr_list[0])->s_addr);
|
return ntohl(reinterpret_cast<in_addr*>(host->h_addr_list[0])->s_addr);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "trouble %d\n", WSAGetLastError());
|
fprintf(stderr, "trouble %d\n", WSAGetLastError());
|
||||||
}
|
}
|
||||||
@ -67,7 +104,7 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
|
|||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
address = 0;
|
address = 0;
|
||||||
} else {
|
} else {
|
||||||
address = htonl
|
address = ntohl
|
||||||
(reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr);
|
(reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr);
|
||||||
|
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
@ -78,3 +115,4 @@ Java_java_net_InetAddress_ipv4AddressForName(JNIEnv* e,
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
classpath/java/lang/AutoCloseable.java
Normal file
15
classpath/java/lang/AutoCloseable.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* Copyright (c) 2008-2013, Avian Contributors
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
package java.lang;
|
||||||
|
|
||||||
|
public interface AutoCloseable {
|
||||||
|
void close() throws Exception;
|
||||||
|
}
|
@ -123,4 +123,7 @@ public class Throwable implements Serializable {
|
|||||||
trace = trace(0);
|
trace = trace(0);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addSuppressed(Throwable exception) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,41 +13,61 @@ package java.net;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class InetAddress {
|
public class InetAddress {
|
||||||
private final String address;
|
private final String name;
|
||||||
|
private final int ip;
|
||||||
|
|
||||||
private InetAddress(String address) {
|
private InetAddress(String name) throws UnknownHostException {
|
||||||
this.address = address;
|
this.name = name;
|
||||||
|
this.ip = ipv4AddressForName(name);
|
||||||
|
if (ip == 0) {
|
||||||
|
throw new UnknownHostException(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostName() {
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHostAddress() {
|
public String getHostAddress() {
|
||||||
return address;
|
try {
|
||||||
|
return new InetAddress(name).toString();
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
return null; // Strange case
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InetAddress getByName(String name)
|
public static InetAddress getByName(String name) throws UnknownHostException {
|
||||||
throws UnknownHostException
|
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
Socket.init();
|
Socket.init();
|
||||||
|
return new InetAddress(name);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
UnknownHostException uhe = new UnknownHostException(name);
|
UnknownHostException uhe = new UnknownHostException(name);
|
||||||
uhe.initCause(e);
|
uhe.initCause(e);
|
||||||
throw uhe;
|
throw uhe;
|
||||||
}
|
}
|
||||||
|
|
||||||
int address = ipv4AddressForName(name);
|
|
||||||
if (address == 0) {
|
|
||||||
throw new UnknownHostException(name);
|
|
||||||
} else {
|
|
||||||
return new InetAddress(ipv4AddressToString(address));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String ipv4AddressToString(int address) {
|
public byte[] getAddress() {
|
||||||
return (((address >>> 24) ) + "." +
|
byte[] res = new byte[4];
|
||||||
((address >>> 16) & 0xFF) + "." +
|
res[0] = (byte) ( ip >>> 24);
|
||||||
((address >>> 8 ) & 0xFF) + "." +
|
res[1] = (byte) ((ip >>> 16) & 0xFF);
|
||||||
((address ) & 0xFF));
|
res[2] = (byte) ((ip >>> 8 ) & 0xFF);
|
||||||
|
res[3] = (byte) ((ip ) & 0xFF);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native int ipv4AddressForName(String name);
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
byte[] addr = getAddress();
|
||||||
|
return (int)((addr[0] + 256) % 256) + "." +
|
||||||
|
(int)((addr[1] + 256) % 256) + "." +
|
||||||
|
(int)((addr[2] + 256) % 256) + "." +
|
||||||
|
(int)((addr[3] + 256) % 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getRawAddress() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static native int ipv4AddressForName(String name);
|
||||||
}
|
}
|
||||||
|
@ -11,16 +11,25 @@
|
|||||||
package java.net;
|
package java.net;
|
||||||
|
|
||||||
public class InetSocketAddress extends SocketAddress {
|
public class InetSocketAddress extends SocketAddress {
|
||||||
private final String host;
|
private final InetAddress address;
|
||||||
private final int port;
|
private final int port;
|
||||||
|
|
||||||
public InetSocketAddress(String host, int port) {
|
public InetSocketAddress(String host, int port) throws UnknownHostException {
|
||||||
this.host = host;
|
this.address = InetAddress.getByName(host);
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InetSocketAddress(InetAddress address, int port) {
|
||||||
|
this.address = address;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetAddress getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHostName() {
|
public String getHostName() {
|
||||||
return host;
|
return address.getHostName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
|
@ -10,10 +10,191 @@
|
|||||||
|
|
||||||
package java.net;
|
package java.net;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public abstract class Socket {
|
public class Socket implements Closeable, AutoCloseable {
|
||||||
|
|
||||||
|
private static final int SD_RECEIVE = 0x00;
|
||||||
|
private static final int SD_SEND = 0x01;
|
||||||
|
private static final int SD_BOTH = 0x02;
|
||||||
|
|
||||||
|
private static final int BUFFER_SIZE = 65535;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from all routines that depend on winsock in windows,
|
||||||
|
* so it has public visibility
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public static native void init() throws IOException;
|
public static native void init() throws IOException;
|
||||||
|
|
||||||
public abstract void setTcpNoDelay(boolean on) throws SocketException;
|
/**
|
||||||
|
* Creates the native socket object
|
||||||
|
* @return Handle to the native object
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static native /* SOCKET */long create() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects the native socket object to an address:port
|
||||||
|
* @param sock Native socket handler
|
||||||
|
* @param addr Address to connect to
|
||||||
|
* @param port Port to connect to
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private static native void connect(/* SOCKET */long sock, long addr, short port) throws IOException;
|
||||||
|
private static native void bind(/* SOCKET */long sock, long addr, short port) throws IOException;
|
||||||
|
|
||||||
|
private static native void send(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException;
|
||||||
|
private static native int recv(/* SOCKET */long sock, byte[] buffer, int start_pos, int count) throws IOException;
|
||||||
|
|
||||||
|
private static native void abort(/* SOCKET */long sock);
|
||||||
|
private static native void close(/* SOCKET */long sock);
|
||||||
|
private static native void closeOutput(/* SOCKET */long sock);
|
||||||
|
private static native void closeInput(/* SOCKET */long sock);
|
||||||
|
|
||||||
|
private class SocketInputStream extends InputStream {
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (!closed) {
|
||||||
|
closeInput(sock);
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
byte[] buffer = new byte[1];
|
||||||
|
int size = recv(sock, buffer, 0, 1);
|
||||||
|
if (size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buffer) throws IOException {
|
||||||
|
int fullSize = buffer.length;
|
||||||
|
int index = 0;
|
||||||
|
int size;
|
||||||
|
do {
|
||||||
|
size = recv(sock, buffer, index, Math.min(fullSize, Socket.BUFFER_SIZE));
|
||||||
|
fullSize -= size;
|
||||||
|
index += size;
|
||||||
|
} while (fullSize != 0 && size != 0);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SocketOutputStream extends OutputStream {
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (!closed) {
|
||||||
|
closeOutput(sock);
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int c) throws IOException {
|
||||||
|
byte[] res = new byte[1];
|
||||||
|
res[0] = (byte)c;
|
||||||
|
send(sock, res, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer) throws IOException {
|
||||||
|
int fullSize = buffer.length;
|
||||||
|
int index = 0;
|
||||||
|
int size;
|
||||||
|
do {
|
||||||
|
size = Math.min(fullSize, Socket.BUFFER_SIZE);
|
||||||
|
send(sock, buffer, index, size);
|
||||||
|
fullSize -= size;
|
||||||
|
index += size;
|
||||||
|
} while (fullSize != 0 && size != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private long sock;
|
||||||
|
private SocketInputStream inputStream;
|
||||||
|
private SocketOutputStream outputStream;
|
||||||
|
|
||||||
|
public Socket() throws IOException {
|
||||||
|
Socket.init();
|
||||||
|
sock = create();
|
||||||
|
inputStream = new SocketInputStream();
|
||||||
|
outputStream = new SocketOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketInputStream getInputStream() {
|
||||||
|
return inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SocketOutputStream getOutputStream() {
|
||||||
|
return outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket(InetAddress address, int port) throws IOException {
|
||||||
|
this();
|
||||||
|
connect(sock, address.getRawAddress(), (short)port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket(String host, int port) throws UnknownHostException, IOException {
|
||||||
|
this(InetAddress.getByName(host), port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(SocketAddress bindpoint) throws IOException {
|
||||||
|
if (bindpoint instanceof InetSocketAddress) {
|
||||||
|
InetSocketAddress inetBindpoint = (InetSocketAddress)bindpoint;
|
||||||
|
bind(sock, inetBindpoint.getAddress().getRawAddress(), (short) inetBindpoint.getPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTcpNoDelay(boolean on) throws SocketException {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
close(sock);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdownInput() throws IOException {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdownOutput() throws IOException {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,11 @@ public class SocketChannel extends SelectableChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Socket socket() {
|
public Socket socket() {
|
||||||
|
try {
|
||||||
return new Handle();
|
return new Handle();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean connect(SocketAddress address) throws IOException {
|
public boolean connect(SocketAddress address) throws IOException {
|
||||||
@ -165,6 +169,10 @@ public class SocketChannel extends SelectableChannel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Handle extends Socket {
|
public class Handle extends Socket {
|
||||||
|
public Handle() throws IOException {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public void setTcpNoDelay(boolean on) throws SocketException {
|
public void setTcpNoDelay(boolean on) throws SocketException {
|
||||||
natSetTcpNoDelay(socket, on);
|
natSetTcpNoDelay(socket, on);
|
||||||
}
|
}
|
||||||
|
184
classpath/sockets.cpp
Normal file
184
classpath/sockets.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/* Copyright (c) 2008-2013, Avian Contributors
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file implements a simple cross-platform JNI sockets API
|
||||||
|
* It is used from different classes of the default Avian classpath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sockets.h"
|
||||||
|
|
||||||
|
namespace avian {
|
||||||
|
namespace classpath {
|
||||||
|
namespace sockets {
|
||||||
|
|
||||||
|
int last_socket_error() {
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
int error = WSAGetLastError();
|
||||||
|
#else
|
||||||
|
int error = errno;
|
||||||
|
#endif
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void init(JNIEnv* ONLY_ON_WINDOWS(e)) {
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
static bool wsaInitialized = false;
|
||||||
|
if (not wsaInitialized) {
|
||||||
|
WSADATA data;
|
||||||
|
int r = WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (r or LOBYTE(data.wVersion) != 2 or HIBYTE(data.wVersion) != 2) {
|
||||||
|
throwNew(e, "java/io/IOException", "WSAStartup failed");
|
||||||
|
} else {
|
||||||
|
wsaInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET create(JNIEnv* e) {
|
||||||
|
SOCKET sock;
|
||||||
|
if (INVALID_SOCKET == (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't create a socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return 0; // This doesn't matter cause we have risen an exception
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(JNIEnv* e, SOCKET sock, long addr, short port) {
|
||||||
|
sockaddr_in adr;
|
||||||
|
adr.sin_family = AF_INET;
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
adr.sin_addr.S_un.S_addr = htonl(addr);
|
||||||
|
#else
|
||||||
|
adr.sin_addr.s_addr = htonl(addr);
|
||||||
|
#endif
|
||||||
|
adr.sin_port = htons (port);
|
||||||
|
|
||||||
|
if (SOCKET_ERROR == ::connect(sock, (sockaddr* )&adr, sizeof(adr)))
|
||||||
|
{
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't connect a socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(JNIEnv* e, SOCKET sock, long addr, short port) {
|
||||||
|
sockaddr_in adr;
|
||||||
|
adr.sin_family = AF_INET;
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
adr.sin_addr.S_un.S_addr = htonl(addr);
|
||||||
|
#else
|
||||||
|
adr.sin_addr.s_addr = htonl(addr);
|
||||||
|
#endif
|
||||||
|
adr.sin_port = htons (port);
|
||||||
|
|
||||||
|
if (SOCKET_ERROR == ::bind(sock, (sockaddr* )&adr, sizeof(adr)))
|
||||||
|
{
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't bind a socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port) {
|
||||||
|
sockaddr_in adr;
|
||||||
|
SOCKET client_socket = ::accept(sock, (sockaddr* )&adr, NULL);
|
||||||
|
if (INVALID_SOCKET == client_socket) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't accept the incoming connection. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client_addr != NULL) {
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
*client_addr = ntohl(adr.sin_addr.S_un.S_addr);
|
||||||
|
#else
|
||||||
|
*client_addr = ntohl(adr.sin_addr.s_addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client_port != NULL) {
|
||||||
|
*client_port = ntohs (adr.sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size) {
|
||||||
|
if (SOCKET_ERROR == ::send(sock, buff_ptr, buff_size, 0)) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't send data through the socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size) {
|
||||||
|
int length = ::recv(sock, buff_ptr, buff_size, 0);
|
||||||
|
if (SOCKET_ERROR == length) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't receive data through the socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
return 0; // This doesn't matter cause we have risen an exception
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort(JNIEnv* e, SOCKET sock) {
|
||||||
|
if (SOCKET_ERROR == ::closesocket(sock)) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't close the socket. System error: %d", last_socket_error());
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(JNIEnv* e, SOCKET sock) {
|
||||||
|
if (SOCKET_ERROR == ::shutdown(sock, SD_BOTH)) {
|
||||||
|
int errcode = last_socket_error();
|
||||||
|
if (errcode != ENOTCONN) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_input(JNIEnv* e, SOCKET sock) {
|
||||||
|
if (SOCKET_ERROR == ::shutdown(sock, SD_RECEIVE)) {
|
||||||
|
int errcode = last_socket_error();
|
||||||
|
if (errcode != ENOTCONN) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_output(JNIEnv* e, SOCKET sock) {
|
||||||
|
if (SOCKET_ERROR == ::shutdown(sock, SD_SEND)) {
|
||||||
|
int errcode = last_socket_error();
|
||||||
|
if (errcode != ENOTCONN) {
|
||||||
|
char buf[255];
|
||||||
|
sprintf(buf, "Can't shutdown the socket. System error: %d", errcode);
|
||||||
|
throwNew(e, "java/io/IOException", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
classpath/sockets.h
Normal file
72
classpath/sockets.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* Copyright (c) 2008-2013, Avian Contributors
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file represents a simple cross-platform JNI sockets API
|
||||||
|
* It is used from different classes of the default Avian classpath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SOCKETS_H_
|
||||||
|
#define SOCKETS_H_
|
||||||
|
|
||||||
|
#include "avian/common.h"
|
||||||
|
#include "jni.h"
|
||||||
|
#include "jni-util.h"
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
# include <winsock2.h>
|
||||||
|
|
||||||
|
# define ONLY_ON_WINDOWS(x) x
|
||||||
|
#else
|
||||||
|
# include <netdb.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
|
||||||
|
# define ONLY_ON_WINDOWS(x)
|
||||||
|
# define SOCKET int
|
||||||
|
# define INVALID_SOCKET -1
|
||||||
|
# define SOCKET_ERROR -1
|
||||||
|
# define closesocket(x) close(x)
|
||||||
|
|
||||||
|
# define SD_RECEIVE SHUT_RD
|
||||||
|
# define SD_SEND SHUT_WR
|
||||||
|
# define SD_BOTH SHUT_RDWR
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace avian {
|
||||||
|
namespace classpath {
|
||||||
|
namespace sockets {
|
||||||
|
|
||||||
|
// Library initialization
|
||||||
|
void init(JNIEnv* ONLY_ON_WINDOWS(e));
|
||||||
|
|
||||||
|
// Socket initialization
|
||||||
|
SOCKET create(JNIEnv* e);
|
||||||
|
void connect(JNIEnv* e, SOCKET sock, long addr, short port);
|
||||||
|
void bind(JNIEnv* e, SOCKET sock, long addr, short port);
|
||||||
|
SOCKET accept(JNIEnv* e, SOCKET sock, long* client_addr, short* client_port);
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
void send(JNIEnv* e, SOCKET sock, const char* buff_ptr, int buff_size);
|
||||||
|
int recv(JNIEnv* e, SOCKET sock, char* buff_ptr, int buff_size);
|
||||||
|
|
||||||
|
// Socket closing
|
||||||
|
void abort(JNIEnv* e, SOCKET sock);
|
||||||
|
void close(JNIEnv* e, SOCKET sock);
|
||||||
|
void close_input(JNIEnv* e, SOCKET sock);
|
||||||
|
void close_output(JNIEnv* e, SOCKET sock);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* SOCKETS_H_ */
|
37
test/Sockets.java
Normal file
37
test/Sockets.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
public class Sockets {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param args
|
||||||
|
* @throws IOException
|
||||||
|
* @throws UnknownHostException
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws UnknownHostException,
|
||||||
|
IOException {
|
||||||
|
System.out.print("Requesting...\n");
|
||||||
|
try (Socket sock = new Socket("www.google.com", 80)) {
|
||||||
|
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
|
||||||
|
String request = "GET /?gws_rd=cr HTTP/1.1\r\n"
|
||||||
|
+ "Host: www.google.com\r\n" + "Accept: */*\r\n"
|
||||||
|
+ "User-Agent: Java\r\n" + "Connection: close\r\n" + "\r\n";
|
||||||
|
bw.write(request);
|
||||||
|
bw.flush();
|
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
|
||||||
|
String read = null;
|
||||||
|
while ((read = br.readLine()) != null) {
|
||||||
|
System.out.println(read);
|
||||||
|
}
|
||||||
|
bw.close();
|
||||||
|
sock.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user