26
27 #include "jvm.h"
28 #include "net_util.h"
29
30 #include "java_net_SocketOptions.h"
31 #include "java_net_PlainSocketImpl.h"
32
33 /************************************************************************
34 * PlainSocketImpl
35 */
36
37 static jfieldID IO_fd_fdID;
38
39 jfieldID psi_fdID;
40 jfieldID psi_addressID;
41 jfieldID psi_ipaddressID;
42 jfieldID psi_portID;
43 jfieldID psi_localportID;
44 jfieldID psi_timeoutID;
45 jfieldID psi_trafficClassID;
46 jfieldID psi_serverSocketID;
47 jfieldID psi_fdLockID;
48 jfieldID psi_closePendingID;
49
50 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
51
52 /*
53 * file descriptor used for dup2
54 */
55 static int marker_fd = -1;
56
57
58 #define SET_NONBLOCKING(fd) { \
59 int flags = fcntl(fd, F_GETFL); \
60 flags |= O_NONBLOCK; \
61 fcntl(fd, F_SETFL, flags); \
62 }
63
64 #define SET_BLOCKING(fd) { \
65 int flags = fcntl(fd, F_GETFL); \
66 flags &= ~O_NONBLOCK; \
111 * Class: java_net_PlainSocketImpl
112 * Method: initProto
113 * Signature: ()V
114 */
115 JNIEXPORT void JNICALL
116 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
117 psi_fdID = (*env)->GetFieldID(env, cls , "fd",
118 "Ljava/io/FileDescriptor;");
119 CHECK_NULL(psi_fdID);
120 psi_addressID = (*env)->GetFieldID(env, cls, "address",
121 "Ljava/net/InetAddress;");
122 CHECK_NULL(psi_addressID);
123 psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
124 CHECK_NULL(psi_portID);
125 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
126 CHECK_NULL(psi_localportID);
127 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
128 CHECK_NULL(psi_timeoutID);
129 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
130 CHECK_NULL(psi_trafficClassID);
131 psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
132 "Ljava/net/ServerSocket;");
133 CHECK_NULL(psi_serverSocketID);
134 psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
135 "Ljava/lang/Object;");
136 CHECK_NULL(psi_fdLockID);
137 psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
138 CHECK_NULL(psi_closePendingID);
139 IO_fd_fdID = NET_GetFileDescriptorID(env);
140 CHECK_NULL(IO_fd_fdID);
141
142 initInetAddressIDs(env);
143 JNU_CHECK_EXCEPTION(env);
144
145 /* Create the marker fd used for dup2 */
146 marker_fd = getMarkerFD();
147 }
148
149 /* a global reference to the java.net.SocketException class. In
150 * socketCreate, we ensure that this is initialized. This is to
151 * prevent the problem where socketCreate runs out of file
152 * descriptors, and is then unable to load the exception class.
153 */
154 static jclass socketExceptionCls;
155
156 /*
157 * Class: java_net_PlainSocketImpl
158 * Method: socketCreate
159 * Signature: (Z)V */
160 JNIEXPORT void JNICALL
161 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
162 jboolean stream) {
163 jobject fdObj, ssObj;
164 int fd;
165 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
166 int domain = ipv6_available() ? AF_INET6 : AF_INET;
167
168 if (socketExceptionCls == NULL) {
169 jclass c = (*env)->FindClass(env, "java/net/SocketException");
170 CHECK_NULL(c);
171 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
172 CHECK_NULL(socketExceptionCls);
173 }
174 fdObj = (*env)->GetObjectField(env, this, psi_fdID);
175
176 if (fdObj == NULL) {
177 (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
178 return;
179 }
180
181 if ((fd = socket(domain, type, 0)) == -1) {
182 /* note: if you run out of fds, you may not be able to load
185 */
186 NET_ThrowNew(env, errno, "can't create socket");
187 return;
188 }
189
190 /* Disable IPV6_V6ONLY to ensure dual-socket support */
191 if (domain == AF_INET6) {
192 int arg = 0;
193 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
194 sizeof(int)) < 0) {
195 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
196 close(fd);
197 return;
198 }
199 }
200
201 /*
202 * If this is a server socket then enable SO_REUSEADDR
203 * automatically and set to non blocking.
204 */
205 ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
206 if (ssObj != NULL) {
207 int arg = 1;
208 SET_NONBLOCKING(fd);
209 if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
210 sizeof(arg)) < 0) {
211 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
212 close(fd);
213 return;
214 }
215 }
216
217 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
218 }
219
220 /*
221 * inetAddress is the address object passed to the socket connect
222 * call.
223 *
224 * Class: java_net_PlainSocketImpl
225 * Method: socketConnect
226 * Signature: (Ljava/net/InetAddress;I)V
|
26
27 #include "jvm.h"
28 #include "net_util.h"
29
30 #include "java_net_SocketOptions.h"
31 #include "java_net_PlainSocketImpl.h"
32
33 /************************************************************************
34 * PlainSocketImpl
35 */
36
37 static jfieldID IO_fd_fdID;
38
39 jfieldID psi_fdID;
40 jfieldID psi_addressID;
41 jfieldID psi_ipaddressID;
42 jfieldID psi_portID;
43 jfieldID psi_localportID;
44 jfieldID psi_timeoutID;
45 jfieldID psi_trafficClassID;
46 jfieldID psi_fdLockID;
47 jfieldID psi_closePendingID;
48
49 extern void setDefaultScopeID(JNIEnv *env, struct sockaddr *him);
50
51 /*
52 * file descriptor used for dup2
53 */
54 static int marker_fd = -1;
55
56
57 #define SET_NONBLOCKING(fd) { \
58 int flags = fcntl(fd, F_GETFL); \
59 flags |= O_NONBLOCK; \
60 fcntl(fd, F_SETFL, flags); \
61 }
62
63 #define SET_BLOCKING(fd) { \
64 int flags = fcntl(fd, F_GETFL); \
65 flags &= ~O_NONBLOCK; \
110 * Class: java_net_PlainSocketImpl
111 * Method: initProto
112 * Signature: ()V
113 */
114 JNIEXPORT void JNICALL
115 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
116 psi_fdID = (*env)->GetFieldID(env, cls , "fd",
117 "Ljava/io/FileDescriptor;");
118 CHECK_NULL(psi_fdID);
119 psi_addressID = (*env)->GetFieldID(env, cls, "address",
120 "Ljava/net/InetAddress;");
121 CHECK_NULL(psi_addressID);
122 psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
123 CHECK_NULL(psi_portID);
124 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
125 CHECK_NULL(psi_localportID);
126 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
127 CHECK_NULL(psi_timeoutID);
128 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
129 CHECK_NULL(psi_trafficClassID);
130 psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
131 "Ljava/lang/Object;");
132 CHECK_NULL(psi_fdLockID);
133 psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
134 CHECK_NULL(psi_closePendingID);
135 IO_fd_fdID = NET_GetFileDescriptorID(env);
136 CHECK_NULL(IO_fd_fdID);
137
138 initInetAddressIDs(env);
139 JNU_CHECK_EXCEPTION(env);
140
141 /* Create the marker fd used for dup2 */
142 marker_fd = getMarkerFD();
143 }
144
145 /* a global reference to the java.net.SocketException class. In
146 * socketCreate, we ensure that this is initialized. This is to
147 * prevent the problem where socketCreate runs out of file
148 * descriptors, and is then unable to load the exception class.
149 */
150 static jclass socketExceptionCls;
151
152 /*
153 * Class: java_net_PlainSocketImpl
154 * Method: socketCreate
155 * Signature: (ZZ)V */
156 JNIEXPORT void JNICALL
157 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
158 jboolean stream, jboolean server) {
159 jobject fdObj, ssObj;
160 int fd;
161 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
162 int domain = ipv6_available() ? AF_INET6 : AF_INET;
163
164 if (socketExceptionCls == NULL) {
165 jclass c = (*env)->FindClass(env, "java/net/SocketException");
166 CHECK_NULL(c);
167 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
168 CHECK_NULL(socketExceptionCls);
169 }
170 fdObj = (*env)->GetObjectField(env, this, psi_fdID);
171
172 if (fdObj == NULL) {
173 (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
174 return;
175 }
176
177 if ((fd = socket(domain, type, 0)) == -1) {
178 /* note: if you run out of fds, you may not be able to load
181 */
182 NET_ThrowNew(env, errno, "can't create socket");
183 return;
184 }
185
186 /* Disable IPV6_V6ONLY to ensure dual-socket support */
187 if (domain == AF_INET6) {
188 int arg = 0;
189 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
190 sizeof(int)) < 0) {
191 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
192 close(fd);
193 return;
194 }
195 }
196
197 /*
198 * If this is a server socket then enable SO_REUSEADDR
199 * automatically and set to non blocking.
200 */
201 if (server) {
202 int arg = 1;
203 SET_NONBLOCKING(fd);
204 if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
205 sizeof(arg)) < 0) {
206 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
207 close(fd);
208 return;
209 }
210 }
211
212 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
213 }
214
215 /*
216 * inetAddress is the address object passed to the socket connect
217 * call.
218 *
219 * Class: java_net_PlainSocketImpl
220 * Method: socketConnect
221 * Signature: (Ljava/net/InetAddress;I)V
|