annotate src/solaris/native/java/net/PlainSocketImpl.c @ 3819:51ef29aafc1b

6835668: Use of /usr/include/linux/ files creates a dependence on kernel-headers Reviewed-by: chegar
author michaelm
date Thu, 24 Feb 2011 18:35:17 +0000
parents a06412e13bf7
children 241d5769859e 272483f6650b
rev   line source
duke@0 1 /*
ohair@3413 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2486 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2486 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2486 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2486 22 * or visit www.oracle.com if you need additional information or have any
ohair@2486 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include <errno.h>
duke@0 27 #include <string.h>
duke@0 28 #include <sys/types.h>
duke@0 29 #include <sys/socket.h>
duke@0 30 #if defined(__linux__) && !defined(USE_SELECT)
duke@0 31 #include <sys/poll.h>
duke@0 32 #endif
duke@0 33 #include <netinet/tcp.h> /* Defines TCP_NODELAY, needed for 2.6 */
duke@0 34 #include <netinet/in.h>
duke@0 35 #ifdef __linux__
duke@0 36 #include <netinet/ip.h>
duke@0 37 #endif
duke@0 38 #include <netdb.h>
duke@0 39 #include <stdlib.h>
duke@0 40
duke@0 41 #ifdef __solaris__
duke@0 42 #include <fcntl.h>
duke@0 43 #endif
duke@0 44 #ifdef __linux__
michaelm@3819 45 #include <unistd.h>
michaelm@3819 46 #include <sys/sysctl.h>
duke@0 47 #endif
duke@0 48
duke@0 49 #include "jvm.h"
duke@0 50 #include "jni_util.h"
duke@0 51 #include "net_util.h"
duke@0 52
duke@0 53 #include "java_net_SocketOptions.h"
duke@0 54 #include "java_net_PlainSocketImpl.h"
duke@0 55
duke@0 56 /************************************************************************
duke@0 57 * PlainSocketImpl
duke@0 58 */
duke@0 59
duke@0 60 static jfieldID IO_fd_fdID;
duke@0 61
duke@0 62 jfieldID psi_fdID;
duke@0 63 jfieldID psi_addressID;
duke@0 64 jfieldID psi_ipaddressID;
duke@0 65 jfieldID psi_portID;
duke@0 66 jfieldID psi_localportID;
duke@0 67 jfieldID psi_timeoutID;
duke@0 68 jfieldID psi_trafficClassID;
duke@0 69 jfieldID psi_serverSocketID;
duke@0 70 jfieldID psi_fdLockID;
duke@0 71 jfieldID psi_closePendingID;
duke@0 72
duke@0 73 /*
duke@0 74 * file descriptor used for dup2
duke@0 75 */
duke@0 76 static int marker_fd = -1;
duke@0 77
duke@0 78
duke@0 79 #define SET_NONBLOCKING(fd) { \
duke@0 80 int flags = fcntl(fd, F_GETFL); \
duke@0 81 flags |= O_NONBLOCK; \
duke@0 82 fcntl(fd, F_SETFL, flags); \
duke@0 83 }
duke@0 84
duke@0 85 #define SET_BLOCKING(fd) { \
duke@0 86 int flags = fcntl(fd, F_GETFL); \
duke@0 87 flags &= ~O_NONBLOCK; \
duke@0 88 fcntl(fd, F_SETFL, flags); \
duke@0 89 }
duke@0 90
duke@0 91 /*
duke@0 92 * Create the marker file descriptor by establishing a loopback connection
duke@0 93 * which we shutdown but do not close the fd. The result is an fd that
duke@0 94 * can be used for read/write.
duke@0 95 */
duke@0 96 static int getMarkerFD()
duke@0 97 {
jccollet@376 98 int sv[2];
duke@0 99
jccollet@376 100 #ifdef AF_UNIX
jccollet@376 101 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
jccollet@376 102 return -1;
duke@0 103 }
jccollet@376 104 #else
jccollet@376 105 return -1;
duke@0 106 #endif
duke@0 107
duke@0 108 /*
jccollet@376 109 * Finally shutdown sv[0] (any reads to this fd will get
duke@0 110 * EOF; any writes will get an error).
duke@0 111 */
jccollet@376 112 JVM_SocketShutdown(sv[0], 2);
jccollet@376 113 JVM_SocketClose(sv[1]);
duke@0 114
jccollet@376 115 return sv[0];
duke@0 116 }
duke@0 117
duke@0 118
duke@0 119 /*
duke@0 120 * Return the file descriptor given a PlainSocketImpl
duke@0 121 */
duke@0 122 static int getFD(JNIEnv *env, jobject this) {
duke@0 123 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 124 CHECK_NULL_RETURN(fdObj, -1);
duke@0 125 return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 126 }
duke@0 127
duke@0 128 /*
duke@0 129 * The initroto function is called whenever PlainSocketImpl is
duke@0 130 * loaded, to cache fieldIds for efficiency. This is called everytime
duke@0 131 * the Java class is loaded.
duke@0 132 *
duke@0 133 * Class: java_net_PlainSocketImpl
duke@0 134 * Method: initProto
duke@0 135 * Signature: ()V
duke@0 136 */
duke@0 137 JNIEXPORT void JNICALL
duke@0 138 Java_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {
duke@0 139 psi_fdID = (*env)->GetFieldID(env, cls , "fd",
duke@0 140 "Ljava/io/FileDescriptor;");
duke@0 141 CHECK_NULL(psi_fdID);
duke@0 142 psi_addressID = (*env)->GetFieldID(env, cls, "address",
duke@0 143 "Ljava/net/InetAddress;");
duke@0 144 CHECK_NULL(psi_addressID);
duke@0 145 psi_portID = (*env)->GetFieldID(env, cls, "port", "I");
duke@0 146 CHECK_NULL(psi_portID);
duke@0 147 psi_localportID = (*env)->GetFieldID(env, cls, "localport", "I");
duke@0 148 CHECK_NULL(psi_localportID);
duke@0 149 psi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
duke@0 150 CHECK_NULL(psi_timeoutID);
duke@0 151 psi_trafficClassID = (*env)->GetFieldID(env, cls, "trafficClass", "I");
duke@0 152 CHECK_NULL(psi_trafficClassID);
duke@0 153 psi_serverSocketID = (*env)->GetFieldID(env, cls, "serverSocket",
duke@0 154 "Ljava/net/ServerSocket;");
duke@0 155 CHECK_NULL(psi_serverSocketID);
duke@0 156 psi_fdLockID = (*env)->GetFieldID(env, cls, "fdLock",
duke@0 157 "Ljava/lang/Object;");
duke@0 158 CHECK_NULL(psi_fdLockID);
duke@0 159 psi_closePendingID = (*env)->GetFieldID(env, cls, "closePending", "Z");
duke@0 160 CHECK_NULL(psi_closePendingID);
duke@0 161 IO_fd_fdID = NET_GetFileDescriptorID(env);
duke@0 162 CHECK_NULL(IO_fd_fdID);
duke@0 163
duke@0 164 /* Create the marker fd used for dup2 */
duke@0 165 marker_fd = getMarkerFD();
duke@0 166 }
duke@0 167
duke@0 168 /* a global reference to the java.net.SocketException class. In
duke@0 169 * socketCreate, we ensure that this is initialized. This is to
duke@0 170 * prevent the problem where socketCreate runs out of file
duke@0 171 * descriptors, and is then unable to load the exception class.
duke@0 172 */
duke@0 173 static jclass socketExceptionCls;
duke@0 174
duke@0 175 /*
duke@0 176 * Class: java_net_PlainSocketImpl
duke@0 177 * Method: socketCreate
duke@0 178 * Signature: (Z)V */
duke@0 179 JNIEXPORT void JNICALL
duke@0 180 Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
duke@0 181 jboolean stream) {
duke@0 182 jobject fdObj, ssObj;
duke@0 183 int fd;
chegar@2796 184 int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
chegar@2796 185 #ifdef AF_INET6
chegar@2796 186 int domain = ipv6_available() ? AF_INET6 : AF_INET;
chegar@2796 187 #else
chegar@2796 188 int domain = AF_INET;
chegar@2796 189 #endif
duke@0 190
duke@0 191 if (socketExceptionCls == NULL) {
duke@0 192 jclass c = (*env)->FindClass(env, "java/net/SocketException");
duke@0 193 CHECK_NULL(c);
duke@0 194 socketExceptionCls = (jclass)(*env)->NewGlobalRef(env, c);
duke@0 195 CHECK_NULL(socketExceptionCls);
duke@0 196 }
duke@0 197 fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 198
duke@0 199 if (fdObj == NULL) {
duke@0 200 (*env)->ThrowNew(env, socketExceptionCls, "null fd object");
duke@0 201 return;
duke@0 202 }
chegar@2796 203
chegar@2796 204 if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) {
duke@0 205 /* note: if you run out of fds, you may not be able to load
duke@0 206 * the exception class, and get a NoClassDefFoundError
duke@0 207 * instead.
duke@0 208 */
duke@0 209 NET_ThrowNew(env, errno, "can't create socket");
duke@0 210 return;
duke@0 211 }
duke@0 212
chegar@2796 213 #ifdef AF_INET6
chegar@2796 214 /* Disable IPV6_V6ONLY to ensure dual-socket support */
chegar@2796 215 if (domain == AF_INET6) {
chegar@2796 216 int arg = 0;
chegar@2796 217 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
chegar@2796 218 sizeof(int)) < 0) {
chegar@2796 219 NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6");
chegar@2796 220 close(fd);
chegar@2796 221 return;
chegar@2796 222 }
chegar@2796 223 }
chegar@2796 224 #endif /* AF_INET6 */
chegar@2796 225
duke@0 226 /*
duke@0 227 * If this is a server socket then enable SO_REUSEADDR
duke@0 228 * automatically and set to non blocking.
duke@0 229 */
duke@0 230 ssObj = (*env)->GetObjectField(env, this, psi_serverSocketID);
duke@0 231 if (ssObj != NULL) {
duke@0 232 int arg = 1;
duke@0 233 SET_NONBLOCKING(fd);
chegar@2796 234 if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
chegar@2796 235 sizeof(arg)) < 0) {
chegar@2796 236 NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR");
chegar@2796 237 close(fd);
chegar@2796 238 return;
chegar@2796 239 }
duke@0 240 }
chegar@2796 241
chegar@2796 242 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
duke@0 243 }
duke@0 244
duke@0 245 /*
duke@0 246 * inetAddress is the address object passed to the socket connect
duke@0 247 * call.
duke@0 248 *
duke@0 249 * Class: java_net_PlainSocketImpl
duke@0 250 * Method: socketConnect
duke@0 251 * Signature: (Ljava/net/InetAddress;I)V
duke@0 252 */
duke@0 253 JNIEXPORT void JNICALL
duke@0 254 Java_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
duke@0 255 jobject iaObj, jint port,
duke@0 256 jint timeout)
duke@0 257 {
duke@0 258 jint localport = (*env)->GetIntField(env, this, psi_localportID);
duke@0 259 int len = 0;
duke@0 260
duke@0 261 /* fdObj is the FileDescriptor field on this */
duke@0 262 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 263 jobject fdLock;
duke@0 264
duke@0 265 jint trafficClass = (*env)->GetIntField(env, this, psi_trafficClassID);
duke@0 266
duke@0 267 /* fd is an int field on iaObj */
duke@0 268 jint fd;
duke@0 269
duke@0 270 SOCKADDR him;
duke@0 271 /* The result of the connection */
duke@0 272 int connect_rv = -1;
duke@0 273
duke@0 274 if (IS_NULL(fdObj)) {
duke@0 275 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
duke@0 276 return;
duke@0 277 } else {
duke@0 278 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 279 }
duke@0 280 if (IS_NULL(iaObj)) {
duke@0 281 JNU_ThrowNullPointerException(env, "inet address argument null.");
duke@0 282 return;
duke@0 283 }
duke@0 284
duke@0 285 /* connect */
duke@0 286 if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
duke@0 287 return;
duke@0 288 }
duke@0 289
duke@0 290 #ifdef AF_INET6
duke@0 291 if (trafficClass != 0 && ipv6_available()) {
duke@0 292 NET_SetTrafficClass((struct sockaddr *)&him, trafficClass);
duke@0 293 }
duke@0 294 #endif /* AF_INET6 */
duke@0 295 if (timeout <= 0) {
duke@0 296 connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len);
duke@0 297 #ifdef __solaris__
duke@0 298 if (connect_rv == JVM_IO_ERR && errno == EINPROGRESS ) {
duke@0 299
duke@0 300 /* This can happen if a blocking connect is interrupted by a signal.
duke@0 301 * See 6343810.
duke@0 302 */
duke@0 303 while (1) {
chegar@316 304 #ifndef USE_SELECT
chegar@316 305 {
chegar@316 306 struct pollfd pfd;
chegar@316 307 pfd.fd = fd;
chegar@316 308 pfd.events = POLLOUT;
duke@0 309
chegar@316 310 connect_rv = NET_Poll(&pfd, 1, -1);
chegar@316 311 }
chegar@316 312 #else
chegar@316 313 {
chegar@316 314 fd_set wr, ex;
duke@0 315
chegar@316 316 FD_ZERO(&wr);
chegar@316 317 FD_SET(fd, &wr);
chegar@316 318 FD_ZERO(&ex);
chegar@316 319 FD_SET(fd, &ex);
chegar@316 320
chegar@316 321 connect_rv = NET_Select(fd+1, 0, &wr, &ex, 0);
chegar@316 322 }
chegar@316 323 #endif
chegar@316 324
duke@0 325 if (connect_rv == JVM_IO_ERR) {
duke@0 326 if (errno == EINTR) {
duke@0 327 continue;
duke@0 328 } else {
duke@0 329 break;
duke@0 330 }
duke@0 331 }
duke@0 332 if (connect_rv > 0) {
duke@0 333 int optlen;
duke@0 334 /* has connection been established */
duke@0 335 optlen = sizeof(connect_rv);
duke@0 336 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
duke@0 337 (void*)&connect_rv, &optlen) <0) {
duke@0 338 connect_rv = errno;
duke@0 339 }
duke@0 340
duke@0 341 if (connect_rv != 0) {
duke@0 342 /* restore errno */
duke@0 343 errno = connect_rv;
duke@0 344 connect_rv = JVM_IO_ERR;
duke@0 345 }
duke@0 346 break;
duke@0 347 }
duke@0 348 }
duke@0 349 }
duke@0 350 #endif
duke@0 351 } else {
duke@0 352 /*
duke@0 353 * A timeout was specified. We put the socket into non-blocking
duke@0 354 * mode, connect, and then wait for the connection to be
duke@0 355 * established, fail, or timeout.
duke@0 356 */
duke@0 357 SET_NONBLOCKING(fd);
duke@0 358
duke@0 359 /* no need to use NET_Connect as non-blocking */
duke@0 360 connect_rv = connect(fd, (struct sockaddr *)&him, len);
duke@0 361
duke@0 362 /* connection not established immediately */
duke@0 363 if (connect_rv != 0) {
duke@0 364 int optlen;
duke@0 365 jlong prevTime = JVM_CurrentTimeMillis(env, 0);
duke@0 366
duke@0 367 if (errno != EINPROGRESS) {
duke@0 368 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
duke@0 369 "connect failed");
duke@0 370 SET_BLOCKING(fd);
duke@0 371 return;
duke@0 372 }
duke@0 373
duke@0 374 /*
duke@0 375 * Wait for the connection to be established or a
duke@0 376 * timeout occurs. poll/select needs to handle EINTR in
duke@0 377 * case lwp sig handler redirects any process signals to
duke@0 378 * this thread.
duke@0 379 */
duke@0 380 while (1) {
duke@0 381 jlong newTime;
duke@0 382 #ifndef USE_SELECT
duke@0 383 {
duke@0 384 struct pollfd pfd;
duke@0 385 pfd.fd = fd;
duke@0 386 pfd.events = POLLOUT;
duke@0 387
duke@0 388 errno = 0;
duke@0 389 connect_rv = NET_Poll(&pfd, 1, timeout);
duke@0 390 }
duke@0 391 #else
duke@0 392 {
duke@0 393 fd_set wr, ex;
duke@0 394 struct timeval t;
duke@0 395
duke@0 396 t.tv_sec = timeout / 1000;
duke@0 397 t.tv_usec = (timeout % 1000) * 1000;
duke@0 398
duke@0 399 FD_ZERO(&wr);
duke@0 400 FD_SET(fd, &wr);
duke@0 401 FD_ZERO(&ex);
duke@0 402 FD_SET(fd, &ex);
duke@0 403
duke@0 404 errno = 0;
duke@0 405 connect_rv = NET_Select(fd+1, 0, &wr, &ex, &t);
duke@0 406 }
duke@0 407 #endif
duke@0 408
duke@0 409 if (connect_rv >= 0) {
duke@0 410 break;
duke@0 411 }
duke@0 412 if (errno != EINTR) {
duke@0 413 break;
duke@0 414 }
duke@0 415
duke@0 416 /*
duke@0 417 * The poll was interrupted so adjust timeout and
duke@0 418 * restart
duke@0 419 */
duke@0 420 newTime = JVM_CurrentTimeMillis(env, 0);
duke@0 421 timeout -= (newTime - prevTime);
duke@0 422 if (timeout <= 0) {
duke@0 423 connect_rv = 0;
duke@0 424 break;
duke@0 425 }
duke@0 426 prevTime = newTime;
duke@0 427
duke@0 428 } /* while */
duke@0 429
duke@0 430 if (connect_rv == 0) {
duke@0 431 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
duke@0 432 "connect timed out");
duke@0 433
duke@0 434 /*
duke@0 435 * Timeout out but connection may still be established.
duke@0 436 * At the high level it should be closed immediately but
duke@0 437 * just in case we make the socket blocking again and
duke@0 438 * shutdown input & output.
duke@0 439 */
duke@0 440 SET_BLOCKING(fd);
duke@0 441 JVM_SocketShutdown(fd, 2);
duke@0 442 return;
duke@0 443 }
duke@0 444
duke@0 445 /* has connection been established */
duke@0 446 optlen = sizeof(connect_rv);
duke@0 447 if (JVM_GetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
duke@0 448 &optlen) <0) {
duke@0 449 connect_rv = errno;
duke@0 450 }
duke@0 451 }
duke@0 452
duke@0 453 /* make socket blocking again */
duke@0 454 SET_BLOCKING(fd);
duke@0 455
duke@0 456 /* restore errno */
duke@0 457 if (connect_rv != 0) {
duke@0 458 errno = connect_rv;
duke@0 459 connect_rv = JVM_IO_ERR;
duke@0 460 }
duke@0 461 }
duke@0 462
duke@0 463 /* report the appropriate exception */
duke@0 464 if (connect_rv < 0) {
duke@0 465
duke@0 466 #ifdef __linux__
duke@0 467 /*
duke@0 468 * Linux/GNU distribution setup /etc/hosts so that
duke@0 469 * InetAddress.getLocalHost gets back the loopback address
duke@0 470 * rather than the host address. Thus a socket can be
duke@0 471 * bound to the loopback address and the connect will
duke@0 472 * fail with EADDRNOTAVAIL. In addition the Linux kernel
duke@0 473 * returns the wrong error in this case - it returns EINVAL
duke@0 474 * instead of EADDRNOTAVAIL. We handle this here so that
duke@0 475 * a more descriptive exception text is used.
duke@0 476 */
duke@0 477 if (connect_rv == JVM_IO_ERR && errno == EINVAL) {
duke@0 478 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 479 "Invalid argument or cannot assign requested address");
duke@0 480 return;
duke@0 481 }
duke@0 482 #endif
duke@0 483 if (connect_rv == JVM_IO_INTR) {
duke@0 484 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
duke@0 485 "operation interrupted");
duke@0 486 } else if (errno == EPROTO) {
duke@0 487 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ProtocolException",
duke@0 488 "Protocol error");
duke@0 489 } else if (errno == ECONNREFUSED) {
duke@0 490 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
duke@0 491 "Connection refused");
duke@0 492 } else if (errno == ETIMEDOUT) {
duke@0 493 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
duke@0 494 "Connection timed out");
duke@0 495 } else if (errno == EHOSTUNREACH) {
duke@0 496 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
duke@0 497 "Host unreachable");
duke@0 498 } else if (errno == EADDRNOTAVAIL) {
duke@0 499 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "NoRouteToHostException",
duke@0 500 "Address not available");
duke@0 501 } else if ((errno == EISCONN) || (errno == EBADF)) {
duke@0 502 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 503 "Socket closed");
duke@0 504 } else {
duke@0 505 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "connect failed");
duke@0 506 }
duke@0 507 return;
duke@0 508 }
duke@0 509
duke@0 510 (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd);
duke@0 511
duke@0 512 /* set the remote peer address and port */
duke@0 513 (*env)->SetObjectField(env, this, psi_addressID, iaObj);
duke@0 514 (*env)->SetIntField(env, this, psi_portID, port);
duke@0 515
duke@0 516 /*
duke@0 517 * we need to initialize the local port field if bind was called
duke@0 518 * previously to the connect (by the client) then localport field
duke@0 519 * will already be initialized
duke@0 520 */
duke@0 521 if (localport == 0) {
duke@0 522 /* Now that we're a connected socket, let's extract the port number
duke@0 523 * that the system chose for us and store it in the Socket object.
duke@0 524 */
duke@0 525 len = SOCKADDR_LEN;
duke@0 526 if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
duke@0 527 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 528 "Error getting socket name");
duke@0 529 } else {
duke@0 530 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
duke@0 531 (*env)->SetIntField(env, this, psi_localportID, localport);
duke@0 532 }
duke@0 533 }
duke@0 534 }
duke@0 535
duke@0 536 /*
duke@0 537 * Class: java_net_PlainSocketImpl
duke@0 538 * Method: socketBind
duke@0 539 * Signature: (Ljava/net/InetAddress;I)V
duke@0 540 */
duke@0 541 JNIEXPORT void JNICALL
duke@0 542 Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,
duke@0 543 jobject iaObj, jint localport) {
duke@0 544
duke@0 545 /* fdObj is the FileDescriptor field on this */
duke@0 546 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 547 /* fd is an int field on fdObj */
duke@0 548 int fd;
duke@0 549 int len;
duke@0 550 SOCKADDR him;
duke@0 551
duke@0 552 if (IS_NULL(fdObj)) {
duke@0 553 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 554 "Socket closed");
duke@0 555 return;
duke@0 556 } else {
duke@0 557 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 558 }
duke@0 559 if (IS_NULL(iaObj)) {
duke@0 560 JNU_ThrowNullPointerException(env, "iaObj is null.");
duke@0 561 return;
duke@0 562 }
duke@0 563
duke@0 564 /* bind */
duke@0 565 if (NET_InetAddressToSockaddr(env, iaObj, localport, (struct sockaddr *)&him, &len, JNI_TRUE) != 0) {
duke@0 566 return;
duke@0 567 }
duke@0 568
duke@0 569 if (NET_Bind(fd, (struct sockaddr *)&him, len) < 0) {
duke@0 570 if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
duke@0 571 errno == EPERM || errno == EACCES) {
duke@0 572 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
duke@0 573 "Bind failed");
duke@0 574 } else {
duke@0 575 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 576 "Bind failed");
duke@0 577 }
duke@0 578 return;
duke@0 579 }
duke@0 580
duke@0 581 /* set the address */
duke@0 582 (*env)->SetObjectField(env, this, psi_addressID, iaObj);
duke@0 583
duke@0 584 /* intialize the local port */
duke@0 585 if (localport == 0) {
duke@0 586 /* Now that we're a connected socket, let's extract the port number
duke@0 587 * that the system chose for us and store it in the Socket object.
duke@0 588 */
duke@0 589 if (JVM_GetSockName(fd, (struct sockaddr *)&him, &len) == -1) {
duke@0 590 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 591 "Error getting socket name");
duke@0 592 return;
duke@0 593 }
duke@0 594 localport = NET_GetPortFromSockaddr((struct sockaddr *)&him);
duke@0 595 (*env)->SetIntField(env, this, psi_localportID, localport);
duke@0 596 } else {
duke@0 597 (*env)->SetIntField(env, this, psi_localportID, localport);
duke@0 598 }
duke@0 599 }
duke@0 600
duke@0 601 /*
duke@0 602 * Class: java_net_PlainSocketImpl
duke@0 603 * Method: socketListen
duke@0 604 * Signature: (I)V
duke@0 605 */
duke@0 606 JNIEXPORT void JNICALL
duke@0 607 Java_java_net_PlainSocketImpl_socketListen (JNIEnv *env, jobject this,
duke@0 608 jint count)
duke@0 609 {
duke@0 610 /* this FileDescriptor fd field */
duke@0 611 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 612 /* fdObj's int fd field */
duke@0 613 int fd;
duke@0 614
duke@0 615 if (IS_NULL(fdObj)) {
duke@0 616 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 617 "Socket closed");
duke@0 618 return;
duke@0 619 } else {
duke@0 620 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 621 }
duke@0 622
duke@0 623 /*
duke@0 624 * Workaround for bugid 4101691 in Solaris 2.6. See 4106600.
duke@0 625 * If listen backlog is Integer.MAX_VALUE then subtract 1.
duke@0 626 */
duke@0 627 if (count == 0x7fffffff)
duke@0 628 count -= 1;
duke@0 629
duke@0 630 if (JVM_Listen(fd, count) == JVM_IO_ERR) {
duke@0 631 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 632 "Listen failed");
duke@0 633 }
duke@0 634 }
duke@0 635
duke@0 636 /*
duke@0 637 * Class: java_net_PlainSocketImpl
duke@0 638 * Method: socketAccept
duke@0 639 * Signature: (Ljava/net/SocketImpl;)V
duke@0 640 */
duke@0 641 JNIEXPORT void JNICALL
duke@0 642 Java_java_net_PlainSocketImpl_socketAccept(JNIEnv *env, jobject this,
duke@0 643 jobject socket)
duke@0 644 {
duke@0 645 /* fields on this */
duke@0 646 int port;
duke@0 647 jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
duke@0 648 jlong prevTime = 0;
duke@0 649 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 650
duke@0 651 /* the FileDescriptor field on socket */
duke@0 652 jobject socketFdObj;
duke@0 653 /* the InetAddress field on socket */
duke@0 654 jobject socketAddressObj;
duke@0 655
duke@0 656 /* the ServerSocket fd int field on fdObj */
duke@0 657 jint fd;
duke@0 658
duke@0 659 /* accepted fd */
duke@0 660 jint newfd;
duke@0 661
duke@0 662 SOCKADDR him;
duke@0 663 int len;
duke@0 664
duke@0 665 len = SOCKADDR_LEN;
duke@0 666
duke@0 667 if (IS_NULL(fdObj)) {
duke@0 668 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 669 "Socket closed");
duke@0 670 return;
duke@0 671 } else {
duke@0 672 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 673 }
duke@0 674 if (IS_NULL(socket)) {
duke@0 675 JNU_ThrowNullPointerException(env, "socket is null");
duke@0 676 return;
duke@0 677 }
duke@0 678
duke@0 679 /*
duke@0 680 * accept connection but ignore ECONNABORTED indicating that
duke@0 681 * connection was eagerly accepted by the OS but was reset
duke@0 682 * before accept() was called.
duke@0 683 *
duke@0 684 * If accept timeout in place and timeout is adjusted with
duke@0 685 * each ECONNABORTED or EWOULDBLOCK to ensure that semantics
duke@0 686 * of timeout are preserved.
duke@0 687 */
duke@0 688 for (;;) {
duke@0 689 int ret;
duke@0 690
duke@0 691 /* first usage pick up current time */
duke@0 692 if (prevTime == 0 && timeout > 0) {
duke@0 693 prevTime = JVM_CurrentTimeMillis(env, 0);
duke@0 694 }
duke@0 695
duke@0 696 /* passing a timeout of 0 to poll will return immediately,
duke@0 697 but in the case of ServerSocket 0 means infinite. */
duke@0 698 if (timeout <= 0) {
duke@0 699 ret = NET_Timeout(fd, -1);
duke@0 700 } else {
duke@0 701 ret = NET_Timeout(fd, timeout);
duke@0 702 }
duke@0 703
duke@0 704 if (ret == 0) {
duke@0 705 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
duke@0 706 "Accept timed out");
duke@0 707 return;
duke@0 708 } else if (ret == JVM_IO_ERR) {
duke@0 709 if (errno == EBADF) {
duke@0 710 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
duke@0 711 } else {
duke@0 712 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");
duke@0 713 }
duke@0 714 return;
duke@0 715 } else if (ret == JVM_IO_INTR) {
duke@0 716 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
duke@0 717 "operation interrupted");
duke@0 718 return;
duke@0 719 }
duke@0 720
duke@0 721 newfd = NET_Accept(fd, (struct sockaddr *)&him, (jint*)&len);
duke@0 722
duke@0 723 /* connection accepted */
duke@0 724 if (newfd >= 0) {
duke@0 725 SET_BLOCKING(newfd);
duke@0 726 break;
duke@0 727 }
duke@0 728
duke@0 729 /* non (ECONNABORTED or EWOULDBLOCK) error */
duke@0 730 if (!(errno == ECONNABORTED || errno == EWOULDBLOCK)) {
duke@0 731 break;
duke@0 732 }
duke@0 733
duke@0 734 /* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
duke@0 735 if (timeout) {
duke@0 736 jlong currTime = JVM_CurrentTimeMillis(env, 0);
duke@0 737 timeout -= (currTime - prevTime);
duke@0 738
duke@0 739 if (timeout <= 0) {
duke@0 740 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
duke@0 741 "Accept timed out");
duke@0 742 return;
duke@0 743 }
duke@0 744 prevTime = currTime;
duke@0 745 }
duke@0 746 }
duke@0 747
duke@0 748 if (newfd < 0) {
duke@0 749 if (newfd == -2) {
duke@0 750 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
duke@0 751 "operation interrupted");
duke@0 752 } else {
duke@0 753 if (errno == EINVAL) {
duke@0 754 errno = EBADF;
duke@0 755 }
duke@0 756 if (errno == EBADF) {
duke@0 757 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
duke@0 758 } else {
duke@0 759 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Accept failed");
duke@0 760 }
duke@0 761 }
duke@0 762 return;
duke@0 763 }
duke@0 764
duke@0 765 /*
duke@0 766 * fill up the remote peer port and address in the new socket structure.
duke@0 767 */
duke@0 768 socketAddressObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
duke@0 769 if (socketAddressObj == NULL) {
duke@0 770 /* should be pending exception */
duke@0 771 close(newfd);
duke@0 772 return;
duke@0 773 }
duke@0 774
duke@0 775 /*
duke@0 776 * Populate SocketImpl.fd.fd
duke@0 777 */
duke@0 778 socketFdObj = (*env)->GetObjectField(env, socket, psi_fdID);
duke@0 779 (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, newfd);
duke@0 780
duke@0 781 (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
duke@0 782 (*env)->SetIntField(env, socket, psi_portID, port);
duke@0 783 /* also fill up the local port information */
duke@0 784 port = (*env)->GetIntField(env, this, psi_localportID);
duke@0 785 (*env)->SetIntField(env, socket, psi_localportID, port);
duke@0 786 }
duke@0 787
duke@0 788
duke@0 789 /*
duke@0 790 * Class: java_net_PlainSocketImpl
duke@0 791 * Method: socketAvailable
duke@0 792 * Signature: ()I
duke@0 793 */
duke@0 794 JNIEXPORT jint JNICALL
duke@0 795 Java_java_net_PlainSocketImpl_socketAvailable(JNIEnv *env, jobject this) {
duke@0 796
duke@0 797 jint ret = -1;
duke@0 798 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 799 jint fd;
duke@0 800
duke@0 801 if (IS_NULL(fdObj)) {
duke@0 802 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 803 "Socket closed");
duke@0 804 return -1;
duke@0 805 } else {
duke@0 806 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 807 }
duke@0 808 /* JVM_SocketAvailable returns 0 for failure, 1 for success */
duke@0 809 if (!JVM_SocketAvailable(fd, &ret)){
duke@0 810 if (errno == ECONNRESET) {
duke@0 811 JNU_ThrowByName(env, "sun/net/ConnectionResetException", "");
duke@0 812 } else {
duke@0 813 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 814 "ioctl FIONREAD failed");
duke@0 815 }
duke@0 816 }
duke@0 817 return ret;
duke@0 818 }
duke@0 819
duke@0 820 /*
duke@0 821 * Class: java_net_PlainSocketImpl
duke@0 822 * Method: socketClose0
duke@0 823 * Signature: (Z)V
duke@0 824 */
duke@0 825 JNIEXPORT void JNICALL
duke@0 826 Java_java_net_PlainSocketImpl_socketClose0(JNIEnv *env, jobject this,
duke@0 827 jboolean useDeferredClose) {
duke@0 828
duke@0 829 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 830 jint fd;
duke@0 831
duke@0 832 if (IS_NULL(fdObj)) {
duke@0 833 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 834 "socket already closed");
duke@0 835 return;
duke@0 836 } else {
duke@0 837 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 838 }
duke@0 839 if (fd != -1) {
duke@0 840 if (useDeferredClose && marker_fd >= 0) {
duke@0 841 NET_Dup2(marker_fd, fd);
duke@0 842 } else {
duke@0 843 (*env)->SetIntField(env, fdObj, IO_fd_fdID, -1);
duke@0 844 NET_SocketClose(fd);
duke@0 845 }
duke@0 846 }
duke@0 847 }
duke@0 848
duke@0 849 /*
duke@0 850 * Class: java_net_PlainSocketImpl
duke@0 851 * Method: socketShutdown
duke@0 852 * Signature: (I)V
duke@0 853 */
duke@0 854 JNIEXPORT void JNICALL
duke@0 855 Java_java_net_PlainSocketImpl_socketShutdown(JNIEnv *env, jobject this,
duke@0 856 jint howto)
duke@0 857 {
duke@0 858
duke@0 859 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 860 jint fd;
duke@0 861
duke@0 862 /*
duke@0 863 * WARNING: THIS NEEDS LOCKING. ALSO: SHOULD WE CHECK for fd being
duke@0 864 * -1 already?
duke@0 865 */
duke@0 866 if (IS_NULL(fdObj)) {
duke@0 867 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 868 "socket already closed");
duke@0 869 return;
duke@0 870 } else {
duke@0 871 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 872 }
duke@0 873 JVM_SocketShutdown(fd, howto);
duke@0 874 }
duke@0 875
duke@0 876
duke@0 877 /*
duke@0 878 * Class: java_net_PlainSocketImpl
duke@0 879 * Method: socketSetOption
duke@0 880 * Signature: (IZLjava/lang/Object;)V
duke@0 881 */
duke@0 882 JNIEXPORT void JNICALL
duke@0 883 Java_java_net_PlainSocketImpl_socketSetOption(JNIEnv *env, jobject this,
duke@0 884 jint cmd, jboolean on,
duke@0 885 jobject value) {
duke@0 886 int fd;
duke@0 887 int level, optname, optlen;
duke@0 888 union {
duke@0 889 int i;
duke@0 890 struct linger ling;
duke@0 891 } optval;
duke@0 892
duke@0 893 /*
duke@0 894 * Check that socket hasn't been closed
duke@0 895 */
duke@0 896 fd = getFD(env, this);
duke@0 897 if (fd < 0) {
duke@0 898 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 899 "Socket closed");
duke@0 900 return;
duke@0 901 }
duke@0 902
duke@0 903 /*
duke@0 904 * SO_TIMEOUT is a no-op on Solaris/Linux
duke@0 905 */
duke@0 906 if (cmd == java_net_SocketOptions_SO_TIMEOUT) {
duke@0 907 return;
duke@0 908 }
duke@0 909
duke@0 910 /*
duke@0 911 * Map the Java level socket option to the platform specific
duke@0 912 * level and option name.
duke@0 913 */
duke@0 914 if (NET_MapSocketOption(cmd, &level, &optname)) {
duke@0 915 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
duke@0 916 return;
duke@0 917 }
duke@0 918
duke@0 919 switch (cmd) {
duke@0 920 case java_net_SocketOptions_SO_SNDBUF :
duke@0 921 case java_net_SocketOptions_SO_RCVBUF :
duke@0 922 case java_net_SocketOptions_SO_LINGER :
duke@0 923 case java_net_SocketOptions_IP_TOS :
duke@0 924 {
duke@0 925 jclass cls;
duke@0 926 jfieldID fid;
duke@0 927
duke@0 928 cls = (*env)->FindClass(env, "java/lang/Integer");
duke@0 929 CHECK_NULL(cls);
duke@0 930 fid = (*env)->GetFieldID(env, cls, "value", "I");
duke@0 931 CHECK_NULL(fid);
duke@0 932
duke@0 933 if (cmd == java_net_SocketOptions_SO_LINGER) {
duke@0 934 if (on) {
duke@0 935 optval.ling.l_onoff = 1;
duke@0 936 optval.ling.l_linger = (*env)->GetIntField(env, value, fid);
duke@0 937 } else {
duke@0 938 optval.ling.l_onoff = 0;
duke@0 939 optval.ling.l_linger = 0;
duke@0 940 }
duke@0 941 optlen = sizeof(optval.ling);
duke@0 942 } else {
duke@0 943 optval.i = (*env)->GetIntField(env, value, fid);
duke@0 944 optlen = sizeof(optval.i);
duke@0 945 }
duke@0 946
duke@0 947 break;
duke@0 948 }
duke@0 949
duke@0 950 /* Boolean -> int */
duke@0 951 default :
duke@0 952 optval.i = (on ? 1 : 0);
duke@0 953 optlen = sizeof(optval.i);
duke@0 954
duke@0 955 }
duke@0 956
duke@0 957 if (NET_SetSockOpt(fd, level, optname, (const void *)&optval, optlen) < 0) {
duke@0 958 #ifdef __solaris__
duke@0 959 if (errno == EINVAL) {
duke@0 960 // On Solaris setsockopt will set errno to EINVAL if the socket
duke@0 961 // is closed. The default error message is then confusing
duke@0 962 char fullMsg[128];
duke@0 963 jio_snprintf(fullMsg, sizeof(fullMsg), "Invalid option or socket reset by remote peer");
duke@0 964 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", fullMsg);
duke@0 965 return;
duke@0 966 }
duke@0 967 #endif /* __solaris__ */
duke@0 968 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 969 "Error setting socket option");
duke@0 970 }
duke@0 971 }
duke@0 972
duke@0 973 /*
duke@0 974 * Class: java_net_PlainSocketImpl
duke@0 975 * Method: socketGetOption
duke@0 976 * Signature: (I)I
duke@0 977 */
duke@0 978 JNIEXPORT jint JNICALL
duke@0 979 Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
duke@0 980 jint cmd, jobject iaContainerObj) {
duke@0 981
duke@0 982 int fd;
duke@0 983 int level, optname, optlen;
duke@0 984 union {
duke@0 985 int i;
duke@0 986 struct linger ling;
duke@0 987 } optval;
duke@0 988
duke@0 989 /*
duke@0 990 * Check that socket hasn't been closed
duke@0 991 */
duke@0 992 fd = getFD(env, this);
duke@0 993 if (fd < 0) {
duke@0 994 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
duke@0 995 "Socket closed");
duke@0 996 return -1;
duke@0 997 }
duke@0 998
duke@0 999 /*
duke@0 1000 * SO_BINDADDR isn't a socket option
duke@0 1001 */
duke@0 1002 if (cmd == java_net_SocketOptions_SO_BINDADDR) {
duke@0 1003 SOCKADDR him;
jccollet@376 1004 socklen_t len = 0;
duke@0 1005 int port;
duke@0 1006 jobject iaObj;
duke@0 1007 jclass iaCntrClass;
duke@0 1008 jfieldID iaFieldID;
duke@0 1009
duke@0 1010 len = SOCKADDR_LEN;
duke@0 1011
duke@0 1012 if (getsockname(fd, (struct sockaddr *)&him, &len) < 0) {
duke@0 1013 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 1014 "Error getting socket name");
duke@0 1015 return -1;
duke@0 1016 }
duke@0 1017 iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);
duke@0 1018 CHECK_NULL_RETURN(iaObj, -1);
duke@0 1019
duke@0 1020 iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
duke@0 1021 iaFieldID = (*env)->GetFieldID(env, iaCntrClass, "addr", "Ljava/net/InetAddress;");
duke@0 1022 CHECK_NULL_RETURN(iaFieldID, -1);
duke@0 1023 (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
duke@0 1024 return 0; /* notice change from before */
duke@0 1025 }
duke@0 1026
duke@0 1027 /*
duke@0 1028 * Map the Java level socket option to the platform specific
duke@0 1029 * level and option name.
duke@0 1030 */
duke@0 1031 if (NET_MapSocketOption(cmd, &level, &optname)) {
duke@0 1032 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
duke@0 1033 return -1;
duke@0 1034 }
duke@0 1035
duke@0 1036 /*
duke@0 1037 * Args are int except for SO_LINGER
duke@0 1038 */
duke@0 1039 if (cmd == java_net_SocketOptions_SO_LINGER) {
duke@0 1040 optlen = sizeof(optval.ling);
duke@0 1041 } else {
duke@0 1042 optlen = sizeof(optval.i);
duke@0 1043 }
duke@0 1044
duke@0 1045 if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
duke@0 1046 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
duke@0 1047 "Error getting socket option");
duke@0 1048 return -1;
duke@0 1049 }
duke@0 1050
duke@0 1051 switch (cmd) {
duke@0 1052 case java_net_SocketOptions_SO_LINGER:
duke@0 1053 return (optval.ling.l_onoff ? optval.ling.l_linger: -1);
duke@0 1054
duke@0 1055 case java_net_SocketOptions_SO_SNDBUF:
duke@0 1056 case java_net_SocketOptions_SO_RCVBUF:
duke@0 1057 case java_net_SocketOptions_IP_TOS:
duke@0 1058 return optval.i;
duke@0 1059
duke@0 1060 default :
duke@0 1061 return (optval.i == 0) ? -1 : 1;
duke@0 1062 }
duke@0 1063 }
duke@0 1064
duke@0 1065
duke@0 1066 /*
duke@0 1067 * Class: java_net_PlainSocketImpl
duke@0 1068 * Method: socketSendUrgentData
duke@0 1069 * Signature: (B)V
duke@0 1070 */
duke@0 1071 JNIEXPORT void JNICALL
duke@0 1072 Java_java_net_PlainSocketImpl_socketSendUrgentData(JNIEnv *env, jobject this,
duke@0 1073 jint data) {
duke@0 1074 /* The fd field */
duke@0 1075 jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
duke@0 1076 int n, fd;
duke@0 1077 unsigned char d = data & 0xFF;
duke@0 1078
duke@0 1079 if (IS_NULL(fdObj)) {
duke@0 1080 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
duke@0 1081 return;
duke@0 1082 } else {
duke@0 1083 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
duke@0 1084 /* Bug 4086704 - If the Socket associated with this file descriptor
duke@0 1085 * was closed (sysCloseFD), the the file descriptor is set to -1.
duke@0 1086 */
duke@0 1087 if (fd == -1) {
duke@0 1088 JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
duke@0 1089 return;
duke@0 1090 }
duke@0 1091
duke@0 1092 }
duke@0 1093 n = JVM_Send(fd, (char *)&d, 1, MSG_OOB);
duke@0 1094 if (n == JVM_IO_ERR) {
duke@0 1095 NET_ThrowByNameWithLastError(env, "java/io/IOException", "Write failed");
duke@0 1096 return;
duke@0 1097 }
duke@0 1098 if (n == JVM_IO_INTR) {
duke@0 1099 JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
duke@0 1100 return;
duke@0 1101 }
duke@0 1102 }