├── .gitignore ├── src ├── main │ ├── java │ │ └── com │ │ │ └── savarese │ │ │ └── rocksaw │ │ │ ├── overview.html │ │ │ └── net │ │ │ └── RawSocket.java │ └── native │ │ ├── Makefile.win32 │ │ ├── Makefile │ │ ├── RawSocket.h │ │ └── RawSocket.c └── test │ └── java │ └── rocksaw │ └── TestPing.java ├── .editorconfig ├── .travis.yml ├── NOTICE ├── Dockerfile ├── README.md ├── CHANGES ├── pom.xml └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .settings 3 | .classpath 4 | .project 5 | .scala_dependencies 6 | *.iml 7 | .idea 8 | build -------------------------------------------------------------------------------- /src/main/java/com/savarese/rocksaw/overview.html: -------------------------------------------------------------------------------- 1 | 2 | The RockSaw library contains packages implementing an API for 3 | using raw sockets from Java. 4 | 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | indent_style = space 7 | indent_size = 2 8 | 9 | end_of_line = lf 10 | 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [Makefile] 15 | insert_final_newline = false 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | services: 4 | - docker 5 | 6 | cache: 7 | directories: 8 | - $HOME/.m2 9 | 10 | before_install: 11 | - docker build -t mlaccetti/rocksaw:develop . 12 | 13 | script: 14 | - docker run --rm -v $(pwd):/opt/rocksaw -v $HOME/.m2:/root/.m2 mlaccetti/rocksaw:develop 15 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | RockSaw 2 | Copyright 2004-2007 Daniel F. Savarese 3 | Copyright 2007-2009 Savarese Software Research Corporation 4 | 5 | This product includes software developed by 6 | Daniel F. Savarese (http://www.savarese.org/). 7 | 8 | This product includes software developed by 9 | Savarese Software Research Corporation (http://www.savarese.com/). 10 | -------------------------------------------------------------------------------- /src/main/native/Makefile.win32: -------------------------------------------------------------------------------- 1 | # Copyright 2004-2005 Daniel F. Savarese 2 | # Copyright 2009 Savarese Software Research Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.savarese.com/software/ApacheLicense-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | JAVA_INCDIR = $(JDK_HOME)\include 17 | JAVA_INCDIR_PLAF = $(JAVA_INCDIR)\win32 18 | 19 | CC = cl 20 | CFLAGS = -TC 21 | CPPFLAGS = -I$(JAVA_INCDIR) -I$(JAVA_INCDIR_PLAF) 22 | WINSOCK = ws2_32 23 | LDFLAGS = $(WINSOCK).lib 24 | 25 | SRC = RawSocket.c 26 | OBJ = $(SRC:.c=.obj) 27 | 28 | LIBNAME = rocksaw 29 | LIBEXTENSION = dll 30 | LIBROCKSAW = $(LIBNAME).$(LIBEXTENSION) 31 | CLEAN_EXTENSIONS = *.obj *.$(LIBEXTENSION) *.lib *.exp 32 | 33 | all: $(LIBROCKSAW) 34 | 35 | .c.obj: 36 | $(CC) -nologo $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 37 | 38 | $(LIBROCKSAW): $(OBJ) 39 | $(CC) -nologo -MD -LD -o $@ $** $(LDFLAGS) 40 | 41 | clean: 42 | del $(CLEAN_EXTENSIONS) 43 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # RockSaw Testing Container Container 3 | # 4 | # Runs a super-tiny container with Java/Maven/gcc for building/testing RockSaw. 5 | # 6 | # Building the container: 7 | # $ docker build -t mlaccetti/rocksaw-dev . 8 | # 9 | # Interactive usage: 10 | # $ docker run -v $(pwd):/opt/rocksaw -it --rm mlaccetti/rocksaw-dev /bin/bash 11 | # 12 | # If you want to cache Maven dependencies between runs, you can change the run command: 13 | # $ docker run -v $(pwd):/opt/rocksaw -v ~/.m2:/root/.m2 -it --rm mlaccetti/rocksaw-dev /bin/bash 14 | # 15 | # Automated build usage: 16 | # $ docker run -v $(pwd):/opt/rocksaw --rm mlaccetti/rocksaw-dev 17 | # 18 | # Automated build usage with Maven cache: 19 | # $ docker run -v $(pwd):/opt/rocksaw -v ~/.m2:/root/.m2 --rm mlaccetti/rocksaw-dev 20 | 21 | FROM anapsix/alpine-java:jdk8 22 | 23 | MAINTAINER Michael Laccetti "michael@laccetti.com" 24 | 25 | ENV MAVEN_HOME="/opt/maven" 26 | ENV MAVEN_VERSION="3.3.9" 27 | 28 | RUN echo "http://mirror.leaseweb.com/alpine/v3.3/main" | tee /etc/apk/repositories 29 | 30 | RUN apk update && \ 31 | apk upgrade --update && \ 32 | apk add build-base curl vim && \ 33 | cd /opt && \ 34 | curl -LS "http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz" -o apache-maven-$MAVEN_VERSION-bin.tar.gz && \ 35 | tar xvzf apache-maven-$MAVEN_VERSION-bin.tar.gz && \ 36 | mv apache-maven-$MAVEN_VERSION /opt/maven && \ 37 | ln -s /opt/maven/bin/mvn /usr/bin/mvn && \ 38 | rm /opt/apache-maven-$MAVEN_VERSION-bin.tar.gz 39 | 40 | WORKDIR /opt/rocksaw 41 | 42 | CMD ["mvn", "clean", "test"] 43 | -------------------------------------------------------------------------------- /src/main/native/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2004-2006 Daniel F. Savarese 2 | # Copyright 2009 Savarese Software Research Corporation 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.savarese.com/software/ApacheLicense-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | UNAME := $(shell uname) 17 | CYGWIN := $(findstring CYGWIN,$(UNAME)) 18 | DARWIN := $(findstring Darwin,$(UNAME)) 19 | 20 | MKDIR_P = mkdir -p 21 | CC = gcc 22 | SHARED = -shared 23 | CFLAGS = -Wall -O2 -pipe -pthread 24 | WINSOCK = ws2_32 25 | EXTRA_LDFLAGS = -fPIC 26 | EXTRA_CPPFLAGS = 27 | LDFLAGS = $(EXTRA_LDFLAGS) 28 | CPPFLAGS = $(EXTRA_CPPFLAGS) 29 | LIBNAME = librocksaw 30 | LIBEXTENSION = so 31 | OUT_DIR = ../../../target/native 32 | 33 | ifeq ($(DARWIN),Darwin) 34 | LIBEXTENSION = jnilib 35 | CPPFLAGS += -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin 36 | LDFLAGS += -dynamiclib -framework JavaVM 37 | SHARED = 38 | else 39 | ifeq ($(CYGWIN),CYGWIN) 40 | override CC += -mno-cygwin 41 | CPPFLAGS += -D__int64="long long" 42 | LDFLAGS += -Wl,--kill-at -l$(WINSOCK) 43 | JDK_HOME := $(shell cygpath $(JDK_HOME)) 44 | LIBNAME = rocksaw 45 | LIBEXTENSION = dll 46 | endif 47 | 48 | JAVA_INCDIR = $(JAVA_HOME)/include 49 | JAVA_INCDIR_PLAF = $(dir $(wildcard $(JAVA_INCDIR)/*/jni_md.h)) 50 | CPPFLAGS += -I$(JAVA_INCDIR) -I$(JAVA_INCDIR_PLAF) 51 | CFLAGS += -ansi -pthread -DPIC -fPIC 52 | endif 53 | 54 | SRC := $(shell find . -name "*.c" -print) 55 | OBJ := $(SRC:%.c=%.o) 56 | 57 | CLEAN_EXTENSIONS = o $(LIBEXTENSION) 58 | 59 | LIBROCKSAW = $(LIBNAME).$(LIBEXTENSION) 60 | 61 | .PHONY: clean directories move_target 62 | 63 | all: directories $(LIBROCKSAW) move_target 64 | 65 | directories: 66 | $(MKDIR_P) $(OUT_DIR) 67 | 68 | %.o: %.c 69 | $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ 70 | 71 | $(LIBROCKSAW): $(OBJ) 72 | $(CC) $(SHARED) $(LDFLAGS) -o $@ $^ 73 | 74 | move_target: $(OBJ) 75 | mv $(OBJ) $(OUT_DIR) 76 | mv $(LIBROCKSAW) $(OUT_DIR) 77 | 78 | clean: 79 | rm -fR $(OUT_DIR) 80 | rm -f *.$(LIBEXTENSION) *.o -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## RockSaw 2 | 3 | TravisCI: [![Build Status](https://travis-ci.org/mlaccetti/rocksaw.png?branch=master)](https://travis-ci.org/mlaccetti/rocksaw) 4 | 5 | A fork of RockSaw (http://www.savarese.com/software/rocksaw/) that includes Maven support. 6 | 7 | Please note that the JNI stuff needs a bit of love to build - the Makefile was mangled (by me/Michael Laccetti). 8 | 9 | ### About 10 | 11 | RockSaw is a simple API for performing network I/O with raw 12 | sockets in Java. 13 | 14 | IPv6 support was graciously funded by ByteSphere Technologies 15 | (www.bytesphere.com). 16 | 17 | Commercial support is provided by Savarese Software Research 18 | Corporation (www.savarese.com). 19 | 20 | ### Requirements 21 | 22 | The 1.1.0 version of RockSaw has been compiled and tested on Linux, 23 | Win32 with Cygwin/MinGW/Winsock or Visual C++, and Mac OS X 10.11.4. It 24 | should compile on other POSIX systems using the GNU tool chain. 25 | 26 | No binary distributions are presently released; you will have to compile 27 | for yourself. 28 | 29 | Java 1.8 or greater is required to compile/run. 30 | 31 | ### Compiling 32 | 33 | You must have the JAVA_HOME environment variable set and pointing to 34 | the directory where the Java Development Kit is installed. Otherwise, 35 | the JNI headers will not be found. 36 | 37 | The project requires `maven` to build; The command `mvn clean package` 38 | should be sufficient to compile the JAR and associated library. 39 | 40 | There are very few files in the source tree: 41 | 42 | - src/main/java Java source code 43 | - src/main/native The C JNI source and Makefile 44 | 45 | #### Note about make 46 | 47 | The default Makefile requires GNU make. 48 | 49 | #### Win32: Visual C++ (Outdated Instructions) 50 | 51 | To compile using Visual C++, you have to override the default 52 | compiler command, make command, and makefile properties: 53 | 54 | jni.cc 55 | jni.make 56 | jni.makefile 57 | 58 | You can override these on the command line or in build.properties. 59 | For example, to compile using Visual C++, you would use the 60 | following command: 61 | 62 | ant -Djni.cc=cl -Djni.make=nmake -Djni.makefile=Makefile.win32 jar 63 | 64 | Make sure your JDK_HOME environment variable is set and that 65 | you've run either the vcvars.bat or vsvars32.bat command 66 | (depending on the version of Visual C++ you're using) to set 67 | your paths for the command line tools. 68 | 69 | #### Mac OS X 70 | 71 | Be sure to set JAVA_HOME to the right location. It will typically be 72 | something like 73 | `/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home`. 74 | 75 | ``` 76 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home 77 | mvn clean pacakge 78 | ``` 79 | 80 | ### Licensing 81 | 82 | RockSaw is 83 | Copyright 2004-2007 by Daniel F. Savarese 84 | Copyright 2007-2009 by Savarese Software Research Corporation 85 | and licensed under the Apache License 2.0 as described in the files: 86 | 87 | LICENSE 88 | NOTICE 89 | 90 | ### Notes 91 | 92 | On most operating systems, you must have root access or administrative 93 | privileges to use raw sockets. If you are running a firewall, you will have to make sure it allows ICMP requests through. 94 | 95 | The API is minimalist, yet functional. Don't hesitate to submit patches 96 | that enhance the functionality. 97 | 98 | 99 | ### Contact 100 | 101 | http://www.savarese.com/contact.html 102 | -------------------------------------------------------------------------------- /src/main/native/RawSocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2005 Daniel F. Savarese 3 | * Copyright 2009 Savarese Software Research Corporation 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.savarese.com/software/ApacheLicense-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef __ROCKSAW_RAW_SOCKET_H 18 | #define __ROCKSAW_RAW_SOCKET_H 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | JNIEXPORT void JNICALL 27 | Java_com_savarese_rocksaw_net_RawSocket__1_1getErrorMessage 28 | (JNIEnv *, jclass, jobject); 29 | 30 | JNIEXPORT jint JNICALL 31 | Java_com_savarese_rocksaw_net_RawSocket__1_1RockSawStartup 32 | (JNIEnv *, jclass); 33 | 34 | JNIEXPORT void JNICALL 35 | Java_com_savarese_rocksaw_net_RawSocket__1_1RockSawShutdown 36 | (JNIEnv *, jclass); 37 | 38 | JNIEXPORT jint JNICALL 39 | Java_com_savarese_rocksaw_net_RawSocket__1_1PF_1INET 40 | (JNIEnv *, jclass); 41 | 42 | JNIEXPORT jint JNICALL 43 | Java_com_savarese_rocksaw_net_RawSocket__1_1PF_1INET6 44 | (JNIEnv *, jclass); 45 | 46 | JNIEXPORT jint JNICALL 47 | Java_com_savarese_rocksaw_net_RawSocket__1_1select 48 | (JNIEnv *env, jclass cls, jint, jboolean, jint); 49 | 50 | JNIEXPORT jint JNICALL 51 | Java_com_savarese_rocksaw_net_RawSocket__1_1socket 52 | (JNIEnv *, jclass, jint, jint); 53 | 54 | JNIEXPORT jint JNICALL 55 | Java_com_savarese_rocksaw_net_RawSocket__1_1bind 56 | (JNIEnv *, jclass, jint, jint, jbyteArray, jint); 57 | 58 | JNIEXPORT jint JNICALL 59 | Java_com_savarese_rocksaw_net_RawSocket__1_1bindDevice 60 | (JNIEnv *, jclass, jint, jstring); 61 | 62 | JNIEXPORT jint JNICALL 63 | Java_com_savarese_rocksaw_net_RawSocket_getProtocolByName 64 | (JNIEnv *, jclass, jstring); 65 | 66 | JNIEXPORT jint JNICALL 67 | Java_com_savarese_rocksaw_net_RawSocket__1_1query_1routing_1interface 68 | (JNIEnv *, jclass, jint, jint, jbyteArray, jbyteArray); 69 | 70 | JNIEXPORT jint JNICALL 71 | Java_com_savarese_rocksaw_net_RawSocket__1_1close 72 | (JNIEnv *, jclass, jint); 73 | 74 | JNIEXPORT jint JNICALL 75 | Java_com_savarese_rocksaw_net_RawSocket__1_1recvfrom1 76 | (JNIEnv *, jclass, jint, jbyteArray, jint, jint, jint); 77 | 78 | JNIEXPORT jint JNICALL 79 | Java_com_savarese_rocksaw_net_RawSocket__1_1recvfrom2 80 | (JNIEnv *, jclass, jint, jbyteArray, jint, jint, jint, jbyteArray); 81 | 82 | JNIEXPORT jint JNICALL 83 | Java_com_savarese_rocksaw_net_RawSocket__1_1sendto 84 | (JNIEnv *, jclass, jint, jbyteArray, jint, jint, jint, jbyteArray, jint); 85 | 86 | JNIEXPORT jboolean JNICALL 87 | Java_com_savarese_rocksaw_net_RawSocket__1_1isErrorEAGAIN 88 | (JNIEnv *, jclass); 89 | 90 | JNIEXPORT jint JNICALL 91 | Java_com_savarese_rocksaw_net_RawSocket__1_1setIPHeaderInclude 92 | (JNIEnv *, jclass, jint, jboolean); 93 | 94 | JNIEXPORT jint JNICALL 95 | Java_com_savarese_rocksaw_net_RawSocket__1_1getIPHeaderInclude 96 | (JNIEnv *env, jclass cls, jint socket); 97 | 98 | JNIEXPORT jint JNICALL 99 | Java_com_savarese_rocksaw_net_RawSocket__1_1setSendBufferSize 100 | (JNIEnv *, jclass, jint, jint); 101 | 102 | JNIEXPORT jint JNICALL 103 | Java_com_savarese_rocksaw_net_RawSocket__1_1getSendBufferSize 104 | (JNIEnv *, jclass, jint); 105 | 106 | JNIEXPORT jint JNICALL 107 | Java_com_savarese_rocksaw_net_RawSocket__1_1setReceiveBufferSize 108 | (JNIEnv *, jclass, jint, jint); 109 | 110 | JNIEXPORT jint JNICALL 111 | Java_com_savarese_rocksaw_net_RawSocket__1_1getReceiveBufferSize 112 | (JNIEnv *, jclass, jint); 113 | 114 | JNIEXPORT jint JNICALL 115 | Java_com_savarese_rocksaw_net_RawSocket__1_1setSendTimeout 116 | (JNIEnv *, jclass, jint, jint); 117 | 118 | JNIEXPORT jint JNICALL 119 | Java_com_savarese_rocksaw_net_RawSocket__1_1getSendTimeout 120 | (JNIEnv *, jclass, jint); 121 | 122 | JNIEXPORT jint JNICALL 123 | Java_com_savarese_rocksaw_net_RawSocket__1_1setReceiveTimeout 124 | (JNIEnv *, jclass, jint, jint); 125 | 126 | JNIEXPORT jint JNICALL 127 | Java_com_savarese_rocksaw_net_RawSocket__1_1getReceiveTimeout 128 | (JNIEnv *, jclass, jint); 129 | 130 | #ifdef __cplusplus 131 | } 132 | #endif 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | Release Notes - RockSaw - Version 1.0.1 2 | 3 | ** Task 4 | * [No Issue] - Copy librocksaw.jnilib to lib/ on Mac OS X 5 | * [No Issue] - Change default make command from gmake to make 6 | 7 | Release Notes - RockSaw - Version 1.0.0 8 | 9 | ** Task 10 | * [No Issue] - Change org.savarese.rocksaw to com.savarese.rocksaw 11 | 12 | Release Notes - RockSaw - Version 0.6.2 13 | 14 | ** Improvement 15 | * [SBX-14] - Refactor Ping example to clarify difference between 16 | IPv4 and IPv6 cases 17 | 18 | Release Notes - RockSaw - Version 0.6.1 19 | 20 | ** Bug 21 | * [SBX-13] - Fix Darwin/MacOS X jni compilation 22 | 23 | Release Notes - RockSaw - Version 0.6.0 24 | 25 | ** Bug 26 | * [SBX-12] - Fix address parameter in RawSocket.read to return source 27 | address 28 | ** New Feature 29 | * [SBX-11] - Add IPv6 read/write/bind support 30 | 31 | Release Notes - RockSaw - Version 0.5.0 32 | 33 | ** New Feature 34 | * [SBX-9] - Implement binding local IP address to raw socket 35 | * [SBX-10] - Implement binding local network device to raw socket (Linux) 36 | 37 | Version 0.4.6 (unreleased) 38 | o Added -D_REENTRANT for systems where this isn't the default, so that 39 | a per-thread errno will be used. 40 | 41 | Version 0.4.5 42 | o Added jni compilation support for Darwin. 43 | 44 | Version 0.4.4 45 | 46 | o Added separate default source/target values for library and example 47 | code(1.3 and 1.5 respectively). 48 | 49 | o Fixed a race condition in the Ping.java example program that was 50 | introduced after converting it from synchronous to asynchronous 51 | send/receives. 52 | 53 | Version 0.4.3 54 | 55 | o On Win32, if a RawSocket was created and used before any java.net 56 | classes/methods, the JVM would crash. This is resolved by having 57 | RawSocket call WSAStartup in its static class initializer and 58 | adding a shutdown hook that calls WSACleanup. Unfortunately, the 59 | shutdown hook makes J2SE 1.3 the new compatibility baseline. 60 | 61 | o Eliminated compiler warnings related to signedness in JNI code. 62 | 63 | Version 0.4.2 64 | 65 | o Made minor improvements to GNU Makefile under Cygwin. JDK_HOME is 66 | adjusted with cygpath and uname is used to detect Cygwin environment. 67 | 68 | o Renamed compilation properties to use javac as prefix (e.g., source 69 | becomes javac.source). Also added javac.target compilation 70 | property to set the version of the targeted JVM class file format. 71 | 72 | o Added compile.classes and jar.only build targets to build only the 73 | Java source code without also compiling the JNI code. 74 | 75 | o Improved error messages on Win32 (now use FormatMessage instead of 76 | strerror). 77 | 78 | Version 0.4.1 79 | 80 | o Added socket send/receive timeout emulation using select() if the 81 | platform does not support SO_RCVTIMEO and SO_SNDTIMEO (e.g., Solaris). 82 | See RawSocket.setUseSelectTimeout(boolean) for details. 83 | 84 | o Changed argument checks in RawSocket.write and RawSocket.read 85 | so that zero-length packets can be written or read. 86 | 87 | Version 0.4.0 88 | 89 | o Corrected cygwin compilation problem. The -mno-cygwin option for gcc 90 | wasn't being enabled when the JNI Makefile was executed by Ant. 91 | 92 | o Added instructions for compiling with J2SE 1.4/1.3/1.2 93 | 94 | o Added socket option setters and getters for send/receive timeout, 95 | send/receive buffer size, and IP header include. 96 | 97 | o Changed default Winsock (wsock32) linking to Winsock2 (ws2_32) and 98 | added jni.winsock property to specify which library to use. 99 | 100 | Version 0.3.1 101 | 102 | o Corrected minor errors in build documentation. 103 | 104 | Version 0.3.0 105 | 106 | o Added support for building with Visual C++. 107 | 108 | o Added jni.make, jni.cc, and jni.makefile properties to 109 | build.properties. These can be used to configure the commands 110 | used to build the JNI source code. 111 | 112 | Version 0.2.2 113 | 114 | o Corrected error in license information embedded in source code. 115 | 116 | Version 0.2.1 117 | 118 | o Corrected packaging mistake that omitted NOTICE file. 119 | 120 | Version 0.2.0 121 | 122 | o Adjusted JNI code to compile on Win32 with Cygwin/MinGW. You 123 | must have both Cygwin and MinGW installed with support for 124 | the Cygwin gcc -mno-cygwin option. Visual C++ support will 125 | be added in a future release. 126 | 127 | o Changed Ping.java example to wait until first echo request is 128 | sent before trying to receive echo replies. Otherwise, Windows 129 | will produce WSAETIMEDOUT errors, causing IOExceptions. 130 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.mlaccetti 5 | rocksaw 6 | 1.1.0 7 | 8 | RockSaw Raw Socket Library 9 | RockSaw is a simple API for performing network I/O with IPv4 and IPv6 raw sockets in Java 10 | https://github.com/mlaccetti/rocksaw 11 | 12 | 13 | UTF-8 14 | 8 15 | 16 | 17 | 18 | 19 | 20 | org.codehaus.mojo 21 | exec-maven-plugin 22 | 1.4.0 23 | 24 | 25 | 26 | buildlib 27 | compile 28 | 29 | exec 30 | 31 | 32 | make 33 | ${basedir}/src/main/native 34 | 35 | clean 36 | all 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.sonatype.plugins 44 | nexus-staging-maven-plugin 45 | 1.6.7 46 | true 47 | 48 | ossrh 49 | https://oss.sonatype.org/ 50 | true 51 | 52 | 53 | 54 | org.apache.maven.plugins 55 | maven-compiler-plugin 56 | 3.5.1 57 | 58 | 1.8 59 | 1.8 60 | UTF-8 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-surefire-plugin 66 | 2.19.1 67 | 68 | once 69 | -Djava.library.path=${project.basedir}/target/native 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-failsafe-plugin 75 | 2.19.1 76 | 77 | 78 | 79 | integration-test 80 | verify 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-source-plugin 88 | 3.0.0 89 | 90 | 91 | attach-sources 92 | 93 | jar-no-fork 94 | 95 | 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-javadoc-plugin 101 | 2.10.3 102 | 103 | 104 | attach-javadocs 105 | 106 | jar 107 | 108 | 109 | 110 | 111 | -Xdoclint:none 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-gpg-plugin 117 | 1.6 118 | 119 | 120 | sign-artifacts 121 | verify 122 | 123 | sign 124 | 125 | 126 | 127 | 128 | 129 | org.apache.maven.plugins 130 | maven-release-plugin 131 | 2.5.3 132 | 133 | true 134 | false 135 | release 136 | deploy 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-assembly-plugin 142 | 2.6 143 | 144 | 145 | jar-with-dependencies 146 | 147 | 148 | 149 | 150 | make-assembly 151 | package 152 | 153 | single 154 | 155 | 156 | 157 | 158 | 159 | 160 | maven-resources-plugin 161 | 3.0.2 162 | 163 | 164 | copy-resources 165 | process-classes 166 | 167 | copy-resources 168 | 169 | 170 | ${project.build.outputDirectory} 171 | 172 | 173 | ${basedir}/target/native 174 | false 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | org.codehaus.mojo 189 | findbugs-maven-plugin 190 | 3.0.3 191 | 192 | true 193 | ${artifactTargetPath} 194 | ${artifactTargetPath} 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | net.java.dev.jna 203 | jna 204 | 4.2.2 205 | 206 | 207 | com.github.mlaccetti 208 | vserv-tcpip 209 | 0.9.2.1 210 | 211 | 212 | org.slf4j 213 | slf4j-simple 214 | 1.7.19 215 | test 216 | 217 | 218 | junit 219 | junit 220 | 4.12 221 | test 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/test/java/rocksaw/TestPing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2004-2007 Daniel F. Savarese 3 | * Copyright 2009 Savarese Software Research Corporation 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.savarese.com/software/ApacheLicense-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package rocksaw; 18 | 19 | import com.savarese.rocksaw.net.RawSocket; 20 | import org.junit.Test; 21 | import org.savarese.vserv.tcpip.ICMPEchoPacket; 22 | import org.savarese.vserv.tcpip.ICMPPacket; 23 | import org.savarese.vserv.tcpip.IPPacket; 24 | import org.savarese.vserv.tcpip.OctetConverter; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import java.io.IOException; 29 | import java.net.Inet6Address; 30 | import java.net.InetAddress; 31 | import java.net.SocketException; 32 | import java.util.concurrent.CountDownLatch; 33 | import java.util.concurrent.ScheduledThreadPoolExecutor; 34 | import java.util.concurrent.TimeUnit; 35 | 36 | import static com.savarese.rocksaw.net.RawSocket.PF_INET; 37 | import static com.savarese.rocksaw.net.RawSocket.PF_INET6; 38 | import static com.savarese.rocksaw.net.RawSocket.getProtocolByName; 39 | import static org.savarese.vserv.tcpip.ICMPPacket.OFFSET_ICMP_CHECKSUM; 40 | 41 | /** 42 | *

43 | * The Ping class is a simple demo showing how you can send ICMP echo requests 44 | * and receive echo replies using raw sockets. It has been updated to work with 45 | * both IPv4 and IPv6. 46 | *

47 | *

48 | * Note, this is not a model of good programming. The point of the example is to 49 | * show how the RawSocket API calls work. There is much kluginess surrounding 50 | * the actual packet and protocol handling, all of which is outside of the scope 51 | * of what RockSaw does. 52 | *

53 | * 54 | * @author Daniel F. Savarese 55 | */ 56 | public class TestPing { 57 | private static final Logger log = LoggerFactory.getLogger(TestPing.class); 58 | 59 | @Test 60 | public void testPingLocalhost() { 61 | final String localhost = "localhost"; 62 | final int pingCount = 5; 63 | 64 | final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2); 65 | 66 | try { 67 | final InetAddress address = InetAddress.getByName(localhost); 68 | final String hostname = address.getCanonicalHostName(); 69 | final String hostaddr = address.getHostAddress(); 70 | 71 | // Ping programs usually use the process ID for the identifier, 72 | // but we can't get it and this is only a demo. 73 | final int id = 65535; 74 | final Pinger ping; 75 | 76 | if (address instanceof Inet6Address) { 77 | ping = new PingerIPv6(id); 78 | } else { 79 | ping = new Pinger(id); 80 | } 81 | 82 | ping.setEchoReplyListener(new EchoReplyListener() { 83 | StringBuffer buffer = new StringBuffer(128); 84 | 85 | public void notifyEchoReply(final ICMPEchoPacket packet, final byte[] data, final int dataOffset, final byte[] srcAddress) throws IOException { 86 | final long end = System.nanoTime(); 87 | final long start = OctetConverter.octetsToLong(data, dataOffset); 88 | // Note: Java and JNI overhead will be noticeable (100-200 89 | // microseconds) for sub-millisecond transmission times. 90 | // The first ping may even show several seconds of delay 91 | // because of initial JIT compilation overhead. 92 | final double rtt = (double) (end - start) / 1e6; 93 | 94 | buffer.setLength(0); 95 | buffer.append(packet.getICMPPacketByteLength()).append(" bytes from ").append(hostname).append(" ("); 96 | buffer.append(InetAddress.getByAddress(srcAddress).toString()); 97 | buffer.append("): icmp_seq=").append(packet.getSequenceNumber()).append(" ttl=").append(packet.getTTL()).append(" time=").append(rtt).append(" ms"); 98 | log.debug(buffer.toString()); 99 | } 100 | }); 101 | 102 | log.debug("PING {} ({}) {} ({}) bytes of data).", hostname, hostaddr, ping.getRequestDataLength(), ping.getRequestPacketLength()); 103 | 104 | final CountDownLatch latch = new CountDownLatch(1); 105 | 106 | executor.scheduleAtFixedRate(new Runnable() { 107 | int counter = pingCount; 108 | 109 | public void run() { 110 | try { 111 | if (counter > 0) { 112 | ping.sendEchoRequest(address); 113 | if (counter == pingCount) { 114 | latch.countDown(); 115 | } 116 | --counter; 117 | } else { 118 | executor.shutdown(); 119 | } 120 | } catch (final IOException ioe) { 121 | ioe.printStackTrace(); 122 | } 123 | } 124 | }, 0, 1, TimeUnit.SECONDS); 125 | 126 | // We wait for first ping to be sent because Windows times out 127 | // with WSAETIMEDOUT if echo request hasn't been sent first. 128 | // POSIX does the right thing and just blocks on the first receive. 129 | // An alternative is to bind the socket first, which should allow a 130 | // receive to be performed first on Windows. 131 | latch.await(); 132 | 133 | for (int i = 0; i < pingCount; ++i) { 134 | ping.receiveEchoReply(); 135 | } 136 | 137 | ping.close(); 138 | } catch (final Exception e) { 139 | executor.shutdown(); 140 | e.printStackTrace(); 141 | } 142 | } 143 | 144 | public interface EchoReplyListener { 145 | void notifyEchoReply(ICMPEchoPacket packet, byte[] data, int dataOffset, byte[] srcAddress) throws IOException; 146 | } 147 | 148 | public static class Pinger { 149 | private static final int TIMEOUT = 10000; 150 | 151 | protected RawSocket socket; 152 | protected ICMPEchoPacket sendPacket, recvPacket; 153 | protected int offset, length, dataOffset; 154 | protected int requestType, replyType; 155 | protected byte[] sendData, recvData, srcAddress; 156 | protected int sequence, identifier; 157 | protected EchoReplyListener listener; 158 | 159 | protected Pinger(final int id, final int protocolFamily, final int protocol) throws IOException { 160 | sequence = 0; 161 | identifier = id; 162 | setEchoReplyListener(null); 163 | 164 | sendPacket = new ICMPEchoPacket(1); 165 | recvPacket = new ICMPEchoPacket(1); 166 | sendData = new byte[84]; 167 | recvData = new byte[84]; 168 | 169 | sendPacket.setData(sendData); 170 | recvPacket.setData(recvData); 171 | sendPacket.setIPHeaderLength(5); 172 | recvPacket.setIPHeaderLength(5); 173 | sendPacket.setICMPDataByteLength(56); 174 | recvPacket.setICMPDataByteLength(56); 175 | 176 | offset = sendPacket.getIPHeaderByteLength(); 177 | dataOffset = offset + sendPacket.getICMPHeaderByteLength(); 178 | length = sendPacket.getICMPPacketByteLength(); 179 | 180 | socket = new RawSocket(); 181 | socket.open(protocolFamily, protocol); 182 | 183 | try { 184 | socket.setSendTimeout(TIMEOUT); 185 | socket.setReceiveTimeout(TIMEOUT); 186 | } catch (final SocketException se) { 187 | socket.setUseSelectTimeout(true); 188 | socket.setSendTimeout(TIMEOUT); 189 | socket.setReceiveTimeout(TIMEOUT); 190 | } 191 | } 192 | 193 | public Pinger(final int id) throws IOException { 194 | this(id, PF_INET, getProtocolByName("icmp")); 195 | 196 | srcAddress = new byte[4]; 197 | requestType = ICMPPacket.TYPE_ECHO_REQUEST; 198 | replyType = ICMPPacket.TYPE_ECHO_REPLY; 199 | } 200 | 201 | protected void computeSendChecksum(final InetAddress host) 202 | throws IOException { 203 | sendPacket.computeICMPChecksum(); 204 | } 205 | 206 | public void setEchoReplyListener(final EchoReplyListener l) { 207 | listener = l; 208 | } 209 | 210 | /** 211 | * Closes the raw socket opened by the constructor. After calling 212 | * this method, the object cannot be used. 213 | */ 214 | public void close() throws IOException { 215 | socket.close(); 216 | } 217 | 218 | public void sendEchoRequest(final InetAddress host) throws IOException { 219 | sendPacket.setType(requestType); 220 | sendPacket.setCode(0); 221 | sendPacket.setIdentifier(identifier); 222 | sendPacket.setSequenceNumber(sequence++); 223 | 224 | OctetConverter.longToOctets(System.nanoTime(), sendData, dataOffset); 225 | 226 | computeSendChecksum(host); 227 | 228 | socket.write(host, sendData, offset, length); 229 | } 230 | 231 | public void receive() throws IOException { 232 | socket.read(recvData, srcAddress); 233 | } 234 | 235 | public void receiveEchoReply() throws IOException { 236 | do { 237 | receive(); 238 | } while (recvPacket.getType() != replyType || recvPacket.getIdentifier() != identifier); 239 | 240 | if (listener != null) { 241 | listener.notifyEchoReply(recvPacket, recvData, dataOffset, srcAddress); 242 | } 243 | } 244 | 245 | /** 246 | * @return The number of bytes in the data portion of the ICMP ping request 247 | * packet. 248 | */ 249 | public int getRequestDataLength() { 250 | return sendPacket.getICMPDataByteLength(); 251 | } 252 | 253 | /** 254 | * @return The number of bytes in the entire IP ping request packet. 255 | */ 256 | public int getRequestPacketLength() { 257 | return sendPacket.getIPPacketLength(); 258 | } 259 | } 260 | 261 | public static class PingerIPv6 extends Pinger { 262 | private static final int IPPROTO_ICMPV6 = 58; 263 | private static final int ICMPv6_TYPE_ECHO_REQUEST = 128; 264 | private static final int ICMPv6_TYPE_ECHO_REPLY = 129; 265 | private final byte[] localAddress; 266 | private final ICMPv6ChecksumCalculator icmpv6Checksummer; 267 | 268 | public PingerIPv6(final int id) throws IOException { 269 | super(id, PF_INET6, IPPROTO_ICMPV6 /*getProtocolByName("ipv6-icmp")*/); 270 | 271 | icmpv6Checksummer = new ICMPv6ChecksumCalculator(); 272 | srcAddress = new byte[16]; 273 | localAddress = new byte[16]; 274 | requestType = ICMPv6_TYPE_ECHO_REQUEST; 275 | replyType = ICMPv6_TYPE_ECHO_REPLY; 276 | } 277 | 278 | protected void computeSendChecksum(final InetAddress host) 279 | throws IOException { 280 | // This is necessary only for Windows, which doesn't implement 281 | // RFC 2463 correctly. 282 | socket.getSourceAddressForDestination(host, localAddress); 283 | icmpv6Checksummer.computeChecksum(sendData, sendPacket, 284 | host.getAddress(), localAddress); 285 | } 286 | 287 | public void receive() throws IOException { 288 | socket.read(recvData, offset, length, srcAddress); 289 | } 290 | 291 | public int getRequestPacketLength() { 292 | return (getRequestDataLength() + 40); 293 | } 294 | 295 | /** 296 | * Operating system kernels are supposed to calculate the ICMPv6 297 | * checksum for the sender, but Microsoft's IPv6 stack does not do 298 | * this. Nor does it support the IPV6_CHECKSUM socket option. 299 | * Therefore, in order to work on the Windows family of operating 300 | * systems, we have to calculate the ICMPv6 checksum. 301 | */ 302 | private static class ICMPv6ChecksumCalculator extends IPPacket { 303 | ICMPv6ChecksumCalculator() { 304 | super(1); 305 | } 306 | 307 | private int computeVirtualHeaderTotal(final byte[] destination, final byte[] source, final int icmpLength) { 308 | int total = 0; 309 | 310 | for (int i = 0; i < source.length; ) { 311 | total += (((source[i++] & 0xff) << 8) | (source[i++] & 0xff)); 312 | } 313 | for (int i = 0; i < destination.length; ) { 314 | total += (((destination[i++] & 0xff) << 8) | (destination[i++] & 0xff)); 315 | } 316 | 317 | total += (icmpLength >>> 16); 318 | total += (icmpLength & 0xffff); 319 | total += IPPROTO_ICMPV6; 320 | 321 | return total; 322 | } 323 | 324 | int computeChecksum(final byte[] data, final ICMPPacket packet, final byte[] destination, final byte[] source) { 325 | final int startOffset = packet.getIPHeaderByteLength(); 326 | final int checksumOffset = startOffset + OFFSET_ICMP_CHECKSUM; 327 | final int ipLength = packet.getIPPacketLength(); 328 | final int icmpLength = packet.getICMPPacketByteLength(); 329 | 330 | setData(data); 331 | 332 | return _computeChecksum_(startOffset, checksumOffset, ipLength, computeVirtualHeaderTotal(destination, source, icmpLength), true); 333 | } 334 | } 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /src/main/native/RawSocket.c: -------------------------------------------------------------------------------- 1 | /* Copyright 2004-2008 Daniel F. Savarese 2 | * Copyright 2009-2014 Savarese Software Research Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.savarese.com/software/ApacheLicense-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #if defined(_WIN32) 21 | 22 | # include 23 | # include 24 | 25 | # if !defined(close) 26 | # define close(fd) closesocket(fd) 27 | # endif 28 | 29 | #else 30 | 31 | # include 32 | # include 33 | # include 34 | # include 35 | # include 36 | 37 | # ifdef ROCKSAW_USE_POLL 38 | 39 | # include 40 | 41 | # endif 42 | 43 | #endif 44 | 45 | #include "RawSocket.h" 46 | 47 | /* 48 | * Empty main 49 | */ 50 | int main (void) { return 0; } 51 | 52 | /* 53 | * Utility functions. 54 | */ 55 | static int setintsockopt(int socket, int level, int option, int value); 56 | static int getintsockopt(int socket, int level, int option); 57 | static int settimeout(int socket, int option, int timeout); 58 | static int gettimeout(int socket, int option); 59 | 60 | static int setintsockopt(int socket, int level, int option, int value) { 61 | return setsockopt(socket, level, option, (void*)&value, sizeof(value)); 62 | } 63 | 64 | static int getintsockopt(int socket, int level, int option) { 65 | int value = -1; 66 | socklen_t size = sizeof(value); 67 | int result = getsockopt(socket, level, option, (void*)&value, &size); 68 | 69 | if(result < 0) { 70 | return result; 71 | } 72 | 73 | return value; 74 | } 75 | 76 | static void milliseconds_to_timeval(int milliseconds, struct timeval *value) { 77 | int seconds = milliseconds / 1000; 78 | 79 | if(seconds > 0) { 80 | milliseconds-=(seconds*1000); 81 | } 82 | 83 | value->tv_sec = seconds; 84 | value->tv_usec = milliseconds * 1000; 85 | } 86 | 87 | static int settimeout(int socket, int option, int timeout) { 88 | #if defined(_WIN32) 89 | return setintsockopt(socket, SOL_SOCKET, option, timeout); 90 | #else 91 | struct timeval value; 92 | 93 | milliseconds_to_timeval(timeout, &value); 94 | 95 | return setsockopt(socket, SOL_SOCKET, option, (void*)&value, sizeof(value)); 96 | #endif 97 | } 98 | 99 | static int gettimeout(int socket, int option) { 100 | int result; 101 | struct timeval value; 102 | socklen_t size = sizeof(value); 103 | 104 | result = getsockopt(socket, SOL_SOCKET, option, (void*)&value, &size); 105 | 106 | if(result < 0) 107 | return result; 108 | 109 | return (value.tv_sec * 1000 + value.tv_usec / 1000); 110 | } 111 | 112 | static struct sockaddr* 113 | init_sockaddr_in(JNIEnv *env, struct sockaddr_in *sin, jbyteArray address) { 114 | jbyte *buf; 115 | 116 | memset(sin, 0, sizeof(struct sockaddr_in)); 117 | sin->sin_family = PF_INET; 118 | buf = (*env)->GetByteArrayElements(env, address, NULL); 119 | memcpy(&sin->sin_addr, buf, sizeof(sin->sin_addr)); 120 | (*env)->ReleaseByteArrayElements(env, address, buf, JNI_ABORT); 121 | return (struct sockaddr *)sin; 122 | } 123 | 124 | static struct sockaddr* 125 | init_sockaddr_in6(JNIEnv *env, struct sockaddr_in6 *sin6, jbyteArray address, 126 | int scope_id) 127 | { 128 | jbyte *buf; 129 | 130 | memset(sin6, 0, sizeof(struct sockaddr_in6)); 131 | sin6->sin6_family = PF_INET6; 132 | sin6->sin6_scope_id = scope_id; 133 | buf = (*env)->GetByteArrayElements(env, address, NULL); 134 | memcpy(&sin6->sin6_addr, buf, sizeof(sin6->sin6_addr)); 135 | (*env)->ReleaseByteArrayElements(env, address, buf, JNI_ABORT); 136 | 137 | return (struct sockaddr *)sin6; 138 | } 139 | 140 | /* 141 | * Class: com_savarese_rocksaw_net_RawSocket 142 | * Method: __RockSawInit(); 143 | * Signature: ()I 144 | */ 145 | JNIEXPORT jint JNICALL 146 | Java_com_savarese_rocksaw_net_RawSocket__1_1RockSawStartup 147 | (JNIEnv *env, jclass cls) 148 | { 149 | #if defined(_WIN32) 150 | WORD version = MAKEWORD(2, 0); 151 | WSADATA data; 152 | return (errno = WSAStartup(version, &data)); 153 | #else 154 | return 0; 155 | #endif 156 | } 157 | 158 | /* 159 | * Class: com_savarese_rocksaw_net_RawSocket 160 | * Method: __RockSawShutdown(); 161 | * Signature: ()V 162 | */ 163 | JNIEXPORT void JNICALL 164 | Java_com_savarese_rocksaw_net_RawSocket__1_1RockSawShutdown 165 | (JNIEnv *env, jclass cls) 166 | { 167 | #if defined(_WIN32) 168 | WSACleanup(); 169 | #endif 170 | } 171 | 172 | /* 173 | * Class: com_savarese_rocksaw_net_RawSocket 174 | * Method: __getErrorMessage 175 | * Signature: (Ljava/lang/StringBuffer;)V 176 | */ 177 | JNIEXPORT void JNICALL 178 | Java_com_savarese_rocksaw_net_RawSocket__1_1getErrorMessage 179 | (JNIEnv *env, jclass cls, jobject buffer) 180 | { 181 | jclass sbc; 182 | jstring str; 183 | jmethodID mid; 184 | 185 | if(errno) { 186 | char *message = NULL; 187 | 188 | #if defined(_WIN32) 189 | int formatted = 190 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 191 | FORMAT_MESSAGE_FROM_SYSTEM | 192 | FORMAT_MESSAGE_IGNORE_INSERTS, 193 | NULL, errno, 194 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 195 | (LPTSTR) &message, 0, NULL ); 196 | if(!formatted) 197 | message = strerror(errno); 198 | #else 199 | message = strerror(errno); 200 | #endif 201 | 202 | str = (*env)->NewStringUTF(env, message); 203 | 204 | #if defined(_WIN32) 205 | if(formatted) 206 | LocalFree(message); 207 | #endif 208 | 209 | sbc = (*env)->GetObjectClass(env, buffer); 210 | mid = 211 | (*env)->GetMethodID(env, sbc, "append", 212 | "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); 213 | (*env)->CallObjectMethod(env, buffer, mid, str); 214 | } 215 | } 216 | 217 | 218 | /* 219 | * Class: com_savarese_rocksaw_net_RawSocket 220 | * Method: __select 221 | * Signature: (IZII)I 222 | * 223 | * Returns zero if the socket is ready for I/O. 224 | */ 225 | #ifndef ROCKSAW_USE_POLL 226 | JNIEXPORT jint JNICALL 227 | Java_com_savarese_rocksaw_net_RawSocket__1_1select 228 | (JNIEnv *env, jclass cls, jint socket, jboolean read, jint milliseconds) 229 | { 230 | int result; 231 | 232 | struct timeval timeout; 233 | fd_set *rset = NULL, *wset = NULL, errset, fdset; 234 | 235 | FD_ZERO(&fdset); 236 | FD_ZERO(&errset); 237 | FD_SET(socket, &fdset); 238 | FD_SET(socket, &errset); 239 | 240 | milliseconds_to_timeval(milliseconds, &timeout); 241 | 242 | if(read) 243 | rset = &fdset; 244 | else 245 | wset = &fdset; 246 | 247 | result = select(socket + 1, rset, wset, &errset, &timeout); 248 | 249 | if(result >= 0) { 250 | if(FD_ISSET(socket, &errset)) 251 | result = -1; 252 | else if(FD_ISSET(socket, &fdset)) 253 | result = 0; 254 | else { 255 | # if defined(_WIN32) 256 | errno = WSAETIMEDOUT; 257 | # else 258 | errno = EAGAIN; 259 | # endif 260 | result = -1; 261 | } 262 | } 263 | 264 | return result; 265 | } 266 | 267 | #else 268 | 269 | JNIEXPORT jint JNICALL 270 | Java_com_savarese_rocksaw_net_RawSocket__1_1select 271 | (JNIEnv *env, jclass cls, jint socket, jboolean read, jint milliseconds) 272 | { 273 | int result; 274 | 275 | struct pollfd fds[1]; 276 | int timeout = milliseconds; 277 | 278 | if(timeout == 0) { 279 | timeout = -1; 280 | } 281 | 282 | fds[0].fd = socket; 283 | fds[0].events = (read ? POLLIN : POLLOUT); 284 | fds[0].revents = 0; 285 | 286 | result = poll(fds, 1, timeout); 287 | 288 | if(result == 1) { 289 | result = 0; 290 | } else if(result == -1) { 291 | errno = EAGAIN; 292 | } 293 | 294 | return result; 295 | } 296 | 297 | #endif 298 | 299 | /* 300 | * Class: com_savarese_rocksaw_net_RawSocket 301 | * Method: __PF_INET 302 | * Signature: ()I 303 | */ 304 | JNIEXPORT jint JNICALL 305 | Java_com_savarese_rocksaw_net_RawSocket__1_1PF_1INET 306 | (JNIEnv *env, jclass cls) 307 | { 308 | return PF_INET; 309 | } 310 | 311 | /* 312 | * Class: com_savarese_rocksaw_net_RawSocket 313 | * Method: __PF_INET6 314 | * Signature: ()I 315 | */ 316 | JNIEXPORT jint JNICALL 317 | Java_com_savarese_rocksaw_net_RawSocket__1_1PF_1INET6 318 | (JNIEnv *env, jclass cls) 319 | { 320 | return PF_INET6; 321 | } 322 | 323 | /* 324 | * Class: com_savarese_rocksaw_net_RawSocket 325 | * Method: __socket 326 | * Signature: (II)I 327 | */ 328 | JNIEXPORT jint JNICALL 329 | Java_com_savarese_rocksaw_net_RawSocket__1_1socket 330 | (JNIEnv *env, jclass cls, jint family, jint protocol) 331 | { 332 | return socket(family, SOCK_RAW, protocol); 333 | } 334 | 335 | /* 336 | * Class: com_savarese_rocksaw_net_RawSocket 337 | * Method: __bind 338 | * Signature: (II[B)I 339 | */ 340 | JNIEXPORT jint JNICALL 341 | Java_com_savarese_rocksaw_net_RawSocket__1_1bind 342 | (JNIEnv *env, jclass cls, jint socket, jint family, jbyteArray address, 343 | jint scope_id) 344 | { 345 | struct sockaddr *saddr; 346 | socklen_t socklen; 347 | union { 348 | struct sockaddr_in sin; 349 | struct sockaddr_in6 sin6; 350 | } sin; 351 | 352 | if(family == PF_INET) { 353 | socklen = sizeof(sin.sin); 354 | saddr = init_sockaddr_in(env, &sin.sin, address); 355 | } else if(family == PF_INET6) { 356 | socklen = sizeof(sin.sin6); 357 | saddr = init_sockaddr_in6(env, &sin.sin6, address, scope_id); 358 | } else 359 | return -1; 360 | 361 | return bind(socket, saddr, socklen); 362 | } 363 | 364 | /* 365 | * Class: com_savarese_rocksaw_net_RawSocket 366 | * Method: __bindDevice 367 | * Signature: (ILjava/lang/String;)I 368 | */ 369 | JNIEXPORT jint JNICALL 370 | Java_com_savarese_rocksaw_net_RawSocket__1_1bindDevice 371 | (JNIEnv *env, jclass cls, jint socket, jstring device) 372 | { 373 | #if defined(SO_BINDTODEVICE) 374 | const char *utf = (*env)->GetStringUTFChars(env, device, NULL); 375 | int result = setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, 376 | (void*)utf, (*env)->GetStringLength(env, device)); 377 | 378 | (*env)->ReleaseStringUTFChars(env, device, utf); 379 | 380 | return result; 381 | #else 382 | return 1; 383 | #endif 384 | } 385 | 386 | /* 387 | * Class: com_savarese_rocksaw_net_RawSocket 388 | * Method: getProtocolByName 389 | * Signature: (Ljava/lang/String;)I 390 | */ 391 | JNIEXPORT jint JNICALL 392 | Java_com_savarese_rocksaw_net_RawSocket_getProtocolByName 393 | (JNIEnv *env, jclass cls, jstring name) 394 | { 395 | const char *utf = (*env)->GetStringUTFChars(env, name, NULL); 396 | struct protoent *proto = getprotobyname(utf); 397 | 398 | (*env)->ReleaseStringUTFChars(env, name, utf); 399 | 400 | return proto->p_proto; 401 | } 402 | 403 | 404 | /* 405 | * Class: com_savarese_rocksaw_net_RawSocket 406 | * Method: __query_routing_interface 407 | * Signature: (II[B[B)I 408 | */ 409 | JNIEXPORT jint JNICALL 410 | Java_com_savarese_rocksaw_net_RawSocket__1_1query_1routing_1interface 411 | (JNIEnv *env, jclass cls, jint socket, jint family, 412 | jbyteArray destination, jbyteArray source) 413 | { 414 | int result = 0; 415 | #if defined(_WIN32) 416 | struct sockaddr_storage ifc; 417 | DWORD size; 418 | struct sockaddr *saddr; 419 | socklen_t socklen; 420 | union { 421 | struct sockaddr_in sin; 422 | struct sockaddr_in6 sin6; 423 | } sin; 424 | 425 | if(family == PF_INET) { 426 | socklen = sizeof(sin.sin); 427 | saddr = init_sockaddr_in(env, &sin.sin, destination); 428 | } else if(family == PF_INET6) { 429 | socklen = sizeof(sin.sin6); 430 | saddr = init_sockaddr_in6(env, &sin.sin6, destination, 0); 431 | } else 432 | return -1; 433 | 434 | result = 435 | WSAIoctl(socket, SIO_ROUTING_INTERFACE_QUERY, saddr, socklen, 436 | (struct sockaddr *)&ifc, sizeof(ifc), &size, NULL, NULL); 437 | 438 | if(result != SOCKET_ERROR) { 439 | jbyte *buf = (*env)->GetByteArrayElements(env, source, NULL); 440 | 441 | if(ifc.ss_family == PF_INET6) { 442 | memcpy(buf, &((struct sockaddr_in6*)&ifc)->sin6_addr, 443 | sizeof(struct in6_addr)); 444 | } else { 445 | memcpy(buf, &((struct sockaddr_in*)&ifc)->sin_addr, 446 | sizeof(struct in_addr)); 447 | } 448 | 449 | (*env)->ReleaseByteArrayElements(env, source, buf, 0); 450 | } 451 | 452 | #endif 453 | return result; 454 | } 455 | 456 | /* 457 | * Class: com_savarese_rocksaw_net_RawSocket 458 | * Method: __close 459 | * Signature: (I)V 460 | */ 461 | JNIEXPORT jint JNICALL 462 | Java_com_savarese_rocksaw_net_RawSocket__1_1close 463 | (JNIEnv *env, jclass cls, jint socket) 464 | { 465 | return close(socket); 466 | } 467 | 468 | /* 469 | * Class: com_savarese_rocksaw_net_RawSocket 470 | * Method: __recvfrom 471 | * Signature: (I[BIII)I 472 | */ 473 | JNIEXPORT jint JNICALL 474 | Java_com_savarese_rocksaw_net_RawSocket__1_1recvfrom1 475 | (JNIEnv *env, jclass cls, jint socket, 476 | jbyteArray data, jint offset, jint len, jint family) 477 | { 478 | int result; 479 | jbyte *buf; 480 | 481 | if(family != PF_INET && family != PF_INET6) { 482 | errno = EINVAL; 483 | return errno; 484 | } 485 | 486 | buf = (*env)->GetByteArrayElements(env, data, NULL); 487 | 488 | result = recvfrom(socket, buf+offset, len, 0, NULL, NULL); 489 | 490 | (*env)->ReleaseByteArrayElements(env, data, buf, 0); 491 | 492 | #if defined(_WIN32) 493 | if(result < 0) 494 | errno = WSAGetLastError(); 495 | #endif 496 | 497 | return result; 498 | } 499 | 500 | /* 501 | * Class: com_savarese_rocksaw_net_RawSocket 502 | * Method: __recvfrom 503 | * Signature: (I[BIII[B)I 504 | */ 505 | JNIEXPORT jint JNICALL 506 | Java_com_savarese_rocksaw_net_RawSocket__1_1recvfrom2 507 | (JNIEnv *env, jclass cls, jint socket, 508 | jbyteArray data, jint offset, jint len, jint family, jbyteArray address) 509 | { 510 | int result; 511 | jbyte *buf; 512 | union { 513 | struct sockaddr_in sin; 514 | struct sockaddr_in6 sin6; 515 | } sin; 516 | struct sockaddr *saddr; 517 | void *addr; 518 | socklen_t socklen; 519 | size_t addrlen; 520 | 521 | if(family == PF_INET) { 522 | socklen = sizeof(sin.sin); 523 | addrlen = sizeof(sin.sin.sin_addr); 524 | memset(&sin, 0, sizeof(struct sockaddr_in)); 525 | sin.sin.sin_family = PF_INET; 526 | saddr = (struct sockaddr *)&sin.sin; 527 | addr = &sin.sin.sin_addr; 528 | } else if(family == PF_INET6) { 529 | socklen = sizeof(sin.sin6); 530 | addrlen = sizeof(sin.sin6.sin6_addr); 531 | memset(&sin.sin6, 0, sizeof(struct sockaddr_in6)); 532 | sin.sin6.sin6_family = PF_INET6; 533 | addr = &sin.sin6.sin6_addr; 534 | saddr = (struct sockaddr *)&sin.sin6; 535 | } else { 536 | errno = EINVAL; 537 | return errno; 538 | } 539 | 540 | buf = (*env)->GetByteArrayElements(env, data, NULL); 541 | 542 | result = recvfrom(socket, buf+offset, len, 0, saddr, &socklen); 543 | 544 | (*env)->ReleaseByteArrayElements(env, data, buf, 0); 545 | 546 | buf = (*env)->GetByteArrayElements(env, address, NULL); 547 | memcpy(buf, addr, addrlen); 548 | (*env)->ReleaseByteArrayElements(env, address, buf, 0); 549 | 550 | #if defined(_WIN32) 551 | if(result < 0) 552 | errno = WSAGetLastError(); 553 | #endif 554 | 555 | return result; 556 | } 557 | 558 | /* 559 | * Class: com_savarese_rocksaw_net_RawSocket 560 | * Method: __sendto 561 | * Signature: (I[BIII[B)I 562 | */ 563 | JNIEXPORT jint JNICALL 564 | Java_com_savarese_rocksaw_net_RawSocket__1_1sendto 565 | (JNIEnv *env, jclass cls, jint socket, 566 | jbyteArray data, jint offset, jint len, jint family, jbyteArray address, 567 | jint scope_id) 568 | { 569 | int result; 570 | jbyte *buf; 571 | union { 572 | struct sockaddr_in sin; 573 | struct sockaddr_in6 sin6; 574 | } sin; 575 | struct sockaddr *saddr; 576 | socklen_t socklen; 577 | 578 | if(family == PF_INET) { 579 | socklen = sizeof(sin.sin); 580 | saddr = init_sockaddr_in(env, &sin.sin, address); 581 | } else if(family == PF_INET6) { 582 | socklen = sizeof(sin.sin6); 583 | saddr = init_sockaddr_in6(env, &sin.sin6, address, scope_id); 584 | } else { 585 | errno = EINVAL; 586 | return errno; 587 | } 588 | 589 | buf = (*env)->GetByteArrayElements(env, data, NULL); 590 | 591 | result = sendto(socket, buf+offset, len, 0, saddr, socklen); 592 | 593 | (*env)->ReleaseByteArrayElements(env, data, buf, JNI_ABORT); 594 | 595 | #if defined(_WIN32) 596 | if(result < 0) 597 | errno = WSAGetLastError(); 598 | #endif 599 | 600 | return result; 601 | } 602 | 603 | 604 | /* 605 | * Class: com_savarese_rocksaw_net_RawSocket 606 | * Method: __isErrorEAGAIN 607 | * Signature: ()Z 608 | */ 609 | JNIEXPORT jboolean JNICALL 610 | Java_com_savarese_rocksaw_net_RawSocket__1_1isErrorEAGAIN 611 | (JNIEnv *env, jclass cls) 612 | { 613 | #if defined(_WIN32) 614 | return (errno == WSAETIMEDOUT); 615 | #else 616 | return (errno == EAGAIN || errno == EWOULDBLOCK); 617 | #endif 618 | } 619 | 620 | 621 | /* 622 | * Class: com_savarese_rocksaw_net_RawSocket 623 | * Method: __setIPHeaderInclude 624 | * Signature: (IZ)I 625 | */ 626 | JNIEXPORT jint JNICALL 627 | Java_com_savarese_rocksaw_net_RawSocket__1_1setIPHeaderInclude 628 | (JNIEnv *env, jclass cls, jint socket, jboolean on) 629 | { 630 | return setintsockopt(socket, IPPROTO_IP, IP_HDRINCL, on); 631 | } 632 | 633 | 634 | /* 635 | * Class: com_savarese_rocksaw_net_RawSocket 636 | * Method: __getIPHeaderInclude 637 | * Signature: (I)I 638 | */ 639 | JNIEXPORT jint JNICALL 640 | Java_com_savarese_rocksaw_net_RawSocket__1_1getIPHeaderInclude 641 | (JNIEnv *env, jclass cls, jint socket) 642 | { 643 | return getintsockopt(socket, IPPROTO_IP, IP_HDRINCL); 644 | } 645 | 646 | 647 | /* 648 | * Class: com_savarese_rocksaw_net_RawSocket 649 | * Method: __setSendBufferSize 650 | * Signature: (II)I 651 | */ 652 | JNIEXPORT jint JNICALL 653 | Java_com_savarese_rocksaw_net_RawSocket__1_1setSendBufferSize 654 | (JNIEnv *env, jclass cls, jint socket, jint size) 655 | { 656 | return setintsockopt(socket, SOL_SOCKET, SO_SNDBUF, size); 657 | } 658 | 659 | 660 | /* 661 | * Class: com_savarese_rocksaw_net_RawSocket 662 | * Method: __getSendBufferSize 663 | * Signature: (I)I 664 | */ 665 | JNIEXPORT jint JNICALL 666 | Java_com_savarese_rocksaw_net_RawSocket__1_1getSendBufferSize 667 | (JNIEnv *env, jclass cls, jint socket) 668 | { 669 | return getintsockopt(socket, SOL_SOCKET, SO_SNDBUF); 670 | } 671 | 672 | 673 | /* 674 | * Class: com_savarese_rocksaw_net_RawSocket 675 | * Method: __setReceiveBufferSize 676 | * Signature: (II)I 677 | */ 678 | JNIEXPORT jint JNICALL 679 | Java_com_savarese_rocksaw_net_RawSocket__1_1setReceiveBufferSize 680 | (JNIEnv *env, jclass cls, jint socket, jint size) 681 | { 682 | return setintsockopt(socket, SOL_SOCKET, SO_RCVBUF, size); 683 | } 684 | 685 | 686 | /* 687 | * Class: com_savarese_rocksaw_net_RawSocket 688 | * Method: __getReceiveBufferSize 689 | * Signature: (I)I 690 | */ 691 | JNIEXPORT jint JNICALL 692 | Java_com_savarese_rocksaw_net_RawSocket__1_1getReceiveBufferSize 693 | (JNIEnv *env, jclass cls, jint socket) 694 | { 695 | return getintsockopt(socket, SOL_SOCKET, SO_RCVBUF); 696 | } 697 | 698 | 699 | /* 700 | * Class: com_savarese_rocksaw_net_RawSocket 701 | * Method: __setSendTimeout 702 | * Signature: (II)I 703 | */ 704 | JNIEXPORT jint JNICALL 705 | Java_com_savarese_rocksaw_net_RawSocket__1_1setSendTimeout 706 | (JNIEnv *env, jclass cls, jint socket, jint timeout) 707 | { 708 | return settimeout(socket, SO_SNDTIMEO, timeout); 709 | } 710 | 711 | 712 | /* 713 | * Class: com_savarese_rocksaw_net_RawSocket 714 | * Method: __getSendTimeout 715 | * Signature: (I)I 716 | */ 717 | JNIEXPORT jint JNICALL 718 | Java_com_savarese_rocksaw_net_RawSocket__1_1getSendTimeout 719 | (JNIEnv *env, jclass cls, jint socket) 720 | { 721 | return gettimeout(socket, SO_SNDTIMEO); 722 | } 723 | 724 | 725 | /* 726 | * Class: com_savarese_rocksaw_net_RawSocket 727 | * Method: __setReceiveTimeout 728 | * Signature: (II)I 729 | */ 730 | JNIEXPORT jint JNICALL 731 | Java_com_savarese_rocksaw_net_RawSocket__1_1setReceiveTimeout 732 | (JNIEnv *env, jclass cls, jint socket, jint timeout) 733 | { 734 | return settimeout(socket, SO_RCVTIMEO, timeout); 735 | } 736 | 737 | 738 | /* 739 | * Class: com_savarese_rocksaw_net_RawSocket 740 | * Method: __getReceiveTimeout 741 | * Signature: (I)I 742 | */ 743 | JNIEXPORT jint JNICALL 744 | Java_com_savarese_rocksaw_net_RawSocket__1_1getReceiveTimeout 745 | (JNIEnv *env, jclass cls, jint socket) 746 | { 747 | return gettimeout(socket, SO_RCVTIMEO); 748 | } 749 | -------------------------------------------------------------------------------- /src/main/java/com/savarese/rocksaw/net/RawSocket.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2004-2008 Daniel F. Savarese 2 | * Copyright 2009-2014 Savarese Software Research Corporation 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.savarese.com/software/ApacheLicense-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.savarese.rocksaw.net; 18 | 19 | import java.io.IOException; 20 | import java.io.InterruptedIOException; 21 | import java.net.InetAddress; 22 | import java.net.Inet6Address; 23 | import java.net.SocketException; 24 | 25 | /** 26 | *

The RawSocket class provides a strictly utilitarian API for 27 | * performing I/O with IPv4 and IPv6 raw sockets. The API is 28 | * minimalist, yet functional.

29 | * 30 | *

We throw java.io.InterruptedIOException when read/write 31 | * operations time out because java.net.SocketTimeoutException is 32 | * present only in J2SE 1.4 and up. By using InterruptedIOException, 33 | * we allow programmers to use the software with J2SE 1.2 and 1.3.

34 | * 35 | *

Socket options should not be set until the socket has been 36 | * opened.

37 | * 38 | *

Important! On most operating systems, you must have root 39 | * access or administrative privileges to use raw sockets.

40 | */ 41 | public class RawSocket { 42 | 43 | private native static int __PF_INET(); 44 | private native static int __PF_INET6(); 45 | 46 | /** 47 | * A protocol family constant for {@link #open} indicating IPv4. 48 | * This should be moved to another class. 49 | */ 50 | public static final int PF_INET; 51 | 52 | /** 53 | * A protocol family constant for {@link #open} indicating IPv6. 54 | * This should be moved to another class. 55 | */ 56 | public static final int PF_INET6; 57 | 58 | /** 59 | * Initializes any system resources used by the RockSaw library. 60 | * Really, all it does is call WSAStartup on Win32. It may be 61 | * called multiple times (only the first call has any effect), but 62 | * each call must be matched with a corresponding call to 63 | * RockSawShutdown(). 64 | * 65 | * @return zero if successful, otherwise some non-zero value. 66 | */ 67 | private native static int __RockSawStartup(); 68 | 69 | /** 70 | * Deallocates any system resources used by the RockSaw library. 71 | * Really, all it does is call WSACleanup on Win32. 72 | */ 73 | private native static void __RockSawShutdown(); 74 | 75 | static { 76 | System.loadLibrary("rocksaw"); 77 | if(__RockSawStartup() != 0) 78 | throw new UnsatisfiedLinkError(__getErrorMessage()); 79 | 80 | Runtime.getRuntime().addShutdownHook(new Thread() { 81 | public void run() { 82 | __RockSawShutdown(); 83 | } 84 | }); 85 | 86 | PF_INET = __PF_INET(); 87 | PF_INET6 = __PF_INET6(); 88 | } 89 | 90 | private static final int __UNDEFINED = -1; 91 | 92 | private int __socket; 93 | private int __family; 94 | private int __stimeout, __rtimeout; 95 | private boolean __useSelectTimeout; 96 | 97 | /** 98 | * Creates an uninitialized socket. If the {@code os.name} system 99 | * property starts with the string "SunOS", 100 | * {@link #setUseSelectTimeout} is set to true (because Solaris does not 101 | * support socket send and receive timeouts), otherwise it is false 102 | * by default. 103 | */ 104 | public RawSocket() { 105 | __socket = __UNDEFINED; 106 | __family = __UNDEFINED; 107 | __stimeout = 0; 108 | __rtimeout = 0; 109 | 110 | String os = System.getProperty("os.name"); 111 | 112 | if(os != null && os.startsWith("SunOS")) { 113 | setUseSelectTimeout(true); 114 | } else { 115 | setUseSelectTimeout(false); 116 | } 117 | } 118 | 119 | 120 | /** 121 | * Tests if the socket has been opened. 122 | * 123 | * @return True if the socket is open. 124 | */ 125 | public boolean isOpen() { 126 | return (__socket > 0); 127 | } 128 | 129 | 130 | /** 131 | * Writes a system error message into a StringBuffer. 132 | * The message is appended to the supplied StringBuffer argument. 133 | * This is a thread safe call on systems that support per-thread 134 | * instances of errno. 135 | * 136 | * @param buffer The buffer in which to store the error message. 137 | */ 138 | private native static void __getErrorMessage(StringBuffer buffer); 139 | 140 | private static String __getErrorMessage() { 141 | StringBuffer buf = new StringBuffer(); 142 | __getErrorMessage(buf); 143 | return buf.toString(); 144 | } 145 | 146 | private static void __throwIOException() throws IOException { 147 | throw new IOException(__getErrorMessage()); 148 | } 149 | 150 | private static void __throwSocketException() throws SocketException { 151 | throw new SocketException(__getErrorMessage()); 152 | } 153 | 154 | private static void __throwInterruptedIOException() 155 | throws InterruptedIOException 156 | { 157 | throw new InterruptedIOException(__getErrorMessage()); 158 | } 159 | 160 | private int __getScopeId(InetAddress address) { 161 | if(__family == PF_INET6 && address instanceof Inet6Address) { 162 | return ((Inet6Address)address).getScopeId(); 163 | } 164 | return 0; 165 | } 166 | 167 | private native static int __socket(int protocolFamily, int protocol); 168 | 169 | 170 | /** 171 | *

Returns the protocol number corresponding to the given protocol name. 172 | * For example, {@code getProtocolByName("icmp");} should return 1 and 173 | * {@code getProtocolByName("udp");} should return 17. The native system 174 | * protocol database is used to look up the protocol numbers.

175 | * 176 | *

This method really belongs in another class, probably in 177 | * vserv-tcpip, but is currently included here as a convenience. It 178 | * may be moved elsewhere in the 1.0 release API.

179 | * 180 | * @return The protocol number corresponding to the given protocol name. 181 | * If the protocol name cannot be found, returns a negative value. 182 | */ 183 | public native static final int getProtocolByName(String name); 184 | 185 | private native static 186 | int __query_routing_interface(int socket, int family, 187 | byte[] destination, byte[] source); 188 | 189 | /** 190 | *

Returns by out parameter the address of the network interface that 191 | * will be used to send a packet to the given destination. This 192 | * works on Windows only and is necessary in order to compute ICMPv6 193 | * checksums.

194 | * 195 | *

This method really belongs in another class,, but is 196 | * currently included here for expediency. It may be moved 197 | * elsewhere in the 1.0 release API.

198 | * 199 | * @param destination The address of the destination. 200 | * @param source A byte array in which to store the returned source 201 | * address. On platforms other than Microsoft Windows, the array is 202 | * left unchanged. 203 | * @exception IOException If an I/O error occurs. 204 | */ 205 | public void 206 | getSourceAddressForDestination(InetAddress destination, byte[] source) 207 | throws IOException 208 | { 209 | if(__query_routing_interface(__socket, __family, 210 | destination.getAddress(), source) < 0) 211 | __throwIOException(); 212 | } 213 | 214 | /** 215 | * Opens a raw socket. 216 | * 217 | * @param protocolFamily The protocol family of the socket (e.g., 218 | * {@link #PF_INET} or {@link #PF_INET6}). 219 | * @param protocol The protocol within the protocol family. {@link 220 | * #getProtocolByName} should be used to obtain protocol numbers. 221 | * @exception IllegalStateException If the object instance is 222 | * already open. 223 | * @exception IOException If an error occurs while opening the socket. 224 | */ 225 | public void open(int protocolFamily, int protocol) 226 | throws IllegalStateException, IOException 227 | { 228 | if(isOpen()) 229 | throw new IllegalStateException(); 230 | __socket = __socket(protocolFamily, protocol); 231 | 232 | if(__socket < 0) { 233 | __socket = __UNDEFINED; 234 | __throwIOException(); 235 | } 236 | 237 | __family = protocolFamily; 238 | } 239 | 240 | 241 | private native static int __bind(int socket, int family, byte[] address, 242 | int scope_id); 243 | 244 | /** 245 | * Binds a local network address to a previously opened raw socket. 246 | * On most operating systems, binding a raw socket to an address 247 | * causes only packets with a destination matching the address to be 248 | * delivered to the socket. Also, the kernel will set the source 249 | * address of outbound packets to the bound address (unless {@link 250 | * #setIPHeaderInclude setIPHeaderInclude(true)} has been called). 251 | * 252 | * @param address The address to bind. 253 | * @exception IllegalStateException If the socket has not been opened first. 254 | * @exception IOException If the address cannot be bound. 255 | */ 256 | public void bind(InetAddress address) 257 | throws IllegalStateException, IOException 258 | { 259 | int scope_id = __getScopeId(address); 260 | 261 | if(!isOpen()) { 262 | throw new IllegalStateException(); 263 | } 264 | 265 | if(__bind(__socket, __family, address.getAddress(), scope_id) != 0) { 266 | __throwIOException(); 267 | } 268 | } 269 | 270 | // Returns a positive value if unsupported operation. 271 | private native static int __bindDevice(int socket, String device); 272 | 273 | /** 274 | * Binds a network device (e.g., eth0) to a previously opened raw socket. 275 | * This is implemented currently only for Linux using the SO_BINDTODEVICE 276 | * socket option. Sent packets will leave through the bound device and 277 | * only packets arriving via the device will be delivered to the socket. 278 | * 279 | * @param device The name of the device to bind (e.g., "eth0"). 280 | * Passing a zero-length string will remove the current binding. 281 | * The loopback interface ("lo") and device aliases (e.g., "eth0:1") 282 | * cannot be bound. 283 | * @exception IllegalStateException If the socket has not been opened first. 284 | * @exception UnsupportedOperationException If binding a device 285 | * name is not supported on the runtime platform. 286 | * @exception IOException If the device cannot be bound. 287 | */ 288 | public void bindDevice(String device) 289 | throws UnsupportedOperationException, IllegalStateException, IOException 290 | { 291 | if(!isOpen()) 292 | throw new IllegalStateException(); 293 | 294 | int result = __bindDevice(__socket, device); 295 | 296 | if(result < 0) 297 | __throwIOException(); 298 | else if(result > 0) 299 | throw new UnsupportedOperationException(); 300 | } 301 | 302 | private native static int __close(int socket); 303 | 304 | /** 305 | * Closes the socket. 306 | * 307 | * @exception IOException If an I/O error occurs. 308 | */ 309 | public void close() throws IOException { 310 | int result = __close(__socket); 311 | __socket = __UNDEFINED; 312 | __family = __UNDEFINED; 313 | 314 | if(result != 0) 315 | __throwIOException(); 316 | } 317 | 318 | /** 319 | * @return True if errno equals EAGAIN or EWOULDBLOCK. 320 | */ 321 | private native boolean __isErrorEAGAIN(); 322 | 323 | private native static int __setIPHeaderInclude(int socket, boolean on); 324 | 325 | /** 326 | * @return A negative value if an error occurs, else zero for false and 327 | * a positive value for true. 328 | */ 329 | private native static int __getIPHeaderInclude(int socket); 330 | 331 | 332 | /** 333 | * Sets or unsets the IP_HDRINCL socket option. Setting this option 334 | * causes IPv4 packet writes to expect the entire IP packet, 335 | * starting from the header. The default behavior is to only expect 336 | * the data payload. This option is valid only for IPv4 sockets. 337 | * 338 | * @param on True if headers should be included, false if not. 339 | * @exception SocketException If the option setting could not be altered. 340 | */ 341 | public void setIPHeaderInclude(boolean on) throws SocketException { 342 | int result = __setIPHeaderInclude(__socket, on); 343 | 344 | if(result < 0) 345 | __throwSocketException(); 346 | } 347 | 348 | 349 | /** 350 | * Retrieves the current setting of the IP_HDRINCL option. 351 | * 352 | * @return True if the IP_HDRINCL option is set, false if not. 353 | * @exception SocketException If the option value could not be retrieved. 354 | */ 355 | public boolean getIPHeaderInclude() throws SocketException { 356 | int result = __getIPHeaderInclude(__socket); 357 | 358 | if(result < 0) 359 | __throwSocketException(); 360 | 361 | return (result > 0); 362 | } 363 | 364 | 365 | private native static int __setSendBufferSize(int socket, int size); 366 | 367 | /** 368 | * Sets the send buffer size (SO_SNDBUF). 369 | * 370 | * @param size The size of the send buffer. 371 | * @exception SocketException If the option value could not be set. 372 | */ 373 | public void setSendBufferSize(int size) throws SocketException { 374 | int result = __setSendBufferSize(__socket, size); 375 | 376 | if(result < 0) 377 | __throwSocketException(); 378 | } 379 | 380 | 381 | private native static int __getSendBufferSize(int __socket); 382 | 383 | /** 384 | * Retrieves the send buffer size (SO_SNDBUF). 385 | * 386 | * @return The size of the send buffer. 387 | * @exception SocketException If the option value could not be retrieved. 388 | */ 389 | public int getSendBufferSize() throws SocketException { 390 | int result = __getSendBufferSize(__socket); 391 | 392 | if(result < 0) 393 | __throwSocketException(); 394 | 395 | return result; 396 | } 397 | 398 | 399 | private native static int __setReceiveBufferSize(int socket, int size); 400 | 401 | /** 402 | * Sets the receive buffer size (SO_RCVBUF). 403 | * 404 | * @param size The size of the receive buffer. 405 | * @exception SocketException If the option value could not be set. 406 | */ 407 | public void setReceiveBufferSize(int size) throws SocketException { 408 | int result = __setReceiveBufferSize(__socket, size); 409 | 410 | if(result < 0) 411 | __throwSocketException(); 412 | } 413 | 414 | 415 | private native static int __getReceiveBufferSize(int socket); 416 | 417 | /** 418 | * Retrieves the receive buffer size (SO_RCVBUF). 419 | * 420 | * @return The size of the receive buffer. 421 | * @exception SocketException If the option value could not be retrieved. 422 | */ 423 | public int getReceiveBufferSize() throws SocketException { 424 | int result = __getReceiveBufferSize(__socket); 425 | 426 | if(result < 0) 427 | __throwSocketException(); 428 | 429 | return result; 430 | } 431 | 432 | /** 433 | * @return Zero if the socket is ready for I/O, negative value if 434 | * timed out or error occurred. 435 | */ 436 | private native static 437 | int __select(int socket, boolean read, int milliseconds); 438 | 439 | 440 | /** 441 | *

Sets whether or not socket send/receive timeouts should be 442 | * emulated by using the POSIX {@code select} function. Not all 443 | * platforms support socket send/receive timeouts and this method 444 | * provides a means to reproduce the same effect.

445 | * 446 | * @param useSelect true if {@code select} should be used to 447 | * implement timeouts, false if not. 448 | */ 449 | public void setUseSelectTimeout(boolean useSelect) { 450 | __useSelectTimeout = useSelect; 451 | } 452 | 453 | 454 | /** 455 | *

Determines whether or not socket send/receive timeouts are 456 | * emulated by using the POSIX {@code select} system function. 457 | * Not all platforms support socket send/receive timeouts. The 458 | * default value is false except for platforms where the {@code 459 | * os.name} property starts with the string "SunOS".

460 | * 461 | * @return True if send/receive timeouts are emulated with select, 462 | * false if not. 463 | */ 464 | public boolean getUseSelectTimeout() { 465 | return __useSelectTimeout; 466 | } 467 | 468 | 469 | private native static int __setSendTimeout(int socket, int timeout); 470 | 471 | /** 472 | * Sets the send timeout (SO_SNDTIMEO). A timeout of zero indicates 473 | * an infinite timeout. A negative timeout is undefined. 474 | * 475 | * @param timeout The send timeout in milliseconds. 476 | * @exception SocketException If the option value could not be set. 477 | */ 478 | public void setSendTimeout(int timeout) throws SocketException { 479 | __stimeout = timeout; 480 | 481 | if(!getUseSelectTimeout()) { 482 | int result = __setSendTimeout(__socket, timeout); 483 | 484 | if(result < 0) { 485 | __throwSocketException(); 486 | } 487 | } 488 | } 489 | 490 | 491 | private native static int __getSendTimeout(int socket); 492 | 493 | /** 494 | * Retrieves the send timeout (SO_SNDTIMEO). 495 | * 496 | * @return The send timeout in milliseconds. 497 | * @exception SocketException If the option value could not be set. 498 | */ 499 | public int getSendTimeout() throws SocketException { 500 | int result; 501 | 502 | if(getUseSelectTimeout()) { 503 | result = __stimeout; 504 | } else { 505 | result = __getSendTimeout(__socket); 506 | 507 | if(result < 0) { 508 | __throwSocketException(); 509 | } 510 | } 511 | 512 | return result; 513 | } 514 | 515 | 516 | private native static int __setReceiveTimeout(int socket, int timeout); 517 | 518 | /** 519 | * Sets the receive timeout (SO_RCVTIMEO). A timeout of zero indicates 520 | * an infinite timeout. A negative timeout is undefined. 521 | * 522 | * @param timeout The receive timeout in milliseconds. 523 | * @exception SocketException If the option value could not be set. 524 | */ 525 | public void setReceiveTimeout(int timeout) throws SocketException { 526 | __rtimeout = timeout; 527 | 528 | if(!getUseSelectTimeout()) { 529 | int result = __setReceiveTimeout(__socket, timeout); 530 | 531 | if(result < 0) { 532 | __throwSocketException(); 533 | } 534 | } 535 | } 536 | 537 | 538 | private native static int __getReceiveTimeout(int socket); 539 | 540 | /** 541 | * Retrieves the receive timeout (SO_RCVTIMEO). 542 | * 543 | * @return The receive timeout in milliseconds. 544 | * @exception SocketException If the option value could not be set. 545 | */ 546 | public int getReceiveTimeout() throws SocketException { 547 | int result; 548 | 549 | if(getUseSelectTimeout()) { 550 | result = __rtimeout; 551 | } else { 552 | result = __getReceiveTimeout(__socket); 553 | 554 | if(result < 0) { 555 | __throwSocketException(); 556 | } 557 | } 558 | 559 | return result; 560 | } 561 | 562 | 563 | private native static int __recvfrom1(int socket, byte[] data, int offset, 564 | int length, int family); 565 | private native static int __recvfrom2(int socket, byte[] data, int offset, 566 | int length, int family, 567 | byte[] address); 568 | 569 | /** 570 | * Reads packet data from the socket. IPv4 ({@link #PF_INET}) 571 | * packets will be delivered in their entirety, including the IP 572 | * header. IPv6 ({@link #PF_INET6}) packet data will not include 573 | * the IPV6 header. 574 | * 575 | * @param data The buffer in which to store the packet data. 576 | * @param offset The offset into the buffer where the data should 577 | * be stored. 578 | * @param length The number of bytes to read. 579 | * @param address A byte array in which to store the source address 580 | * of the received packet. It may be null if you don't want to 581 | * retrieve the source address. Otherwise, it must be the right 582 | * size to store the address (e.g., 4 bytes for an IPv4 address). 583 | * @exception IllegalArgumentException If the offset or lengths are 584 | * invalid or if the address parameter is the wrong length. 585 | * @exception IOException If an I/O error occurs. 586 | * @exception InterruptedIOException If the read operation times out. 587 | * @return The number of bytes read. 588 | */ 589 | public int read(byte[] data, int offset, int length, byte[] address) 590 | throws IllegalArgumentException, IOException, InterruptedIOException 591 | { 592 | if(offset < 0 || length < 0 || length > data.length - offset) 593 | throw new IllegalArgumentException("Invalid offset or length."); 594 | 595 | if(address != null && 596 | ((__family == PF_INET && address.length != 4) || 597 | (__family == PF_INET6 && address.length != 16))) 598 | throw new IllegalArgumentException("Invalid address length."); 599 | 600 | int result = 0; 601 | 602 | if(getUseSelectTimeout() && __rtimeout > 0) { 603 | result = __select(__socket, true, __rtimeout); 604 | } 605 | 606 | if(result == 0) 607 | result = 608 | (address == null ? 609 | __recvfrom1(__socket, data, offset, length, __family) : 610 | __recvfrom2(__socket, data, offset, length, __family, address)); 611 | 612 | if(result < 0) { 613 | if(__isErrorEAGAIN()) 614 | __throwInterruptedIOException(); 615 | else 616 | __throwIOException(); 617 | } 618 | 619 | return result; 620 | } 621 | 622 | /** Same as {@code read(data, 0, length, null);} */ 623 | public int read(byte[] data, int offset, int length) 624 | throws IllegalArgumentException, IOException, InterruptedIOException 625 | { 626 | return read(data, offset, length, null); 627 | } 628 | 629 | /** Same as {@code read(data, 0, data.length, address);} */ 630 | public int read(byte[] data, byte[] address) 631 | throws IOException, InterruptedIOException 632 | { 633 | return read(data, 0, data.length, address); 634 | } 635 | 636 | /** Same as {@code read(address, data, 0, data.length, null);} */ 637 | public int read(byte[] data) 638 | throws IOException, InterruptedIOException 639 | { 640 | return read(data, 0, data.length, null); 641 | } 642 | 643 | private native static int __sendto(int socket, byte[] data, int offset, 644 | int length, int family, byte[] address, 645 | int scope_id); 646 | 647 | /** 648 | * Writes packet data to the socket. The data should not include 649 | * the IP header. IPv4 ({@link #PF_INET}) sockets may set the 650 | * IP_HDRINCL option with {@link #setIPHeaderInclude}, in which case the 651 | * packet data should include the IP header. 652 | * 653 | * @param address The destination to write to. 654 | * @param data The buffer from which to copy the packet data. 655 | * @param offset The offset into the buffer where the data starts. 656 | * @param length The number of bytes to write. 657 | * @exception IllegalArgumentException If the offset or lengths are invalid. 658 | * @exception IOException If an I/O error occurs. 659 | * @exception InterruptedIOException If the write operation times out. 660 | * @return The number of bytes written. 661 | */ 662 | public int write(InetAddress address, byte[] data, int offset, int length) 663 | throws IllegalArgumentException, IOException, InterruptedIOException 664 | { 665 | int scope_id = __getScopeId(address); 666 | 667 | if(offset < 0 || length < 0 || length > data.length - offset) { 668 | throw new IllegalArgumentException("Invalid offset or length."); 669 | } 670 | 671 | int result = 0; 672 | 673 | if(getUseSelectTimeout() && __stimeout > 0) { 674 | result = __select(__socket, false, __stimeout); 675 | } 676 | 677 | if(result == 0) 678 | result = __sendto(__socket, data, offset, length, __family, 679 | address.getAddress(), scope_id); 680 | 681 | if(result < 0) { 682 | if(__isErrorEAGAIN()) { 683 | __throwInterruptedIOException(); 684 | } else { 685 | __throwIOException(); 686 | } 687 | } 688 | 689 | return result; 690 | } 691 | 692 | /** Same as {@code write(address, data, 0, data.length);} */ 693 | public int write(InetAddress address, byte[] data) 694 | throws IOException, InterruptedIOException 695 | { 696 | return write(address, data, 0, data.length); 697 | } 698 | 699 | } 700 | --------------------------------------------------------------------------------