Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <errno.h>
     28 #include <string.h>
     29 #include <sys/types.h>
     30 #include <sys/socket.h>
     31 
     32 #include "jvm.h"
     33 #include "jni_util.h"
     34 #include "net_util.h"
     35 
     36 #include <nativehelper/JNIHelp.h>
     37 
     38 #define NATIVE_METHOD(className, functionName, signature) \
     39 { #functionName, signature, (void*)(className ## _ ## functionName) }
     40 
     41 
     42 /************************************************************************
     43  * SocketInputStream
     44  */
     45 
     46 static jfieldID IO_fd_fdID;
     47 
     48 /*
     49  * Class:     java_net_SocketInputStream
     50  * Method:    socketRead0
     51  * Signature: (Ljava/io/FileDescriptor;[BIII)I
     52  */
     53 JNIEXPORT jint JNICALL
     54 SocketInputStream_socketRead0(JNIEnv *env, jobject this,
     55                                             jobject fdObj, jbyteArray data,
     56                                             jint off, jint len, jint timeout)
     57 {
     58     char BUF[MAX_BUFFER_LEN];
     59     char *bufP;
     60     jint fd, nread;
     61 
     62     if (IS_NULL(fdObj)) {
     63         /* shouldn't this be a NullPointerException? -br */
     64         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
     65                         "Socket closed");
     66         return -1;
     67     } else {
     68         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
     69         /* Bug 4086704 - If the Socket associated with this file descriptor
     70          * was closed (sysCloseFD), then the file descriptor is set to -1.
     71          */
     72         if (fd == -1) {
     73             JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
     74             return -1;
     75         }
     76     }
     77 
     78     /*
     79      * If the read is greater than our stack allocated buffer then
     80      * we allocate from the heap (up to a limit)
     81      */
     82     if (len > MAX_BUFFER_LEN) {
     83         if (len > MAX_HEAP_BUFFER_LEN) {
     84             len = MAX_HEAP_BUFFER_LEN;
     85         }
     86         bufP = (char *)malloc((size_t)len);
     87         if (bufP == NULL) {
     88             bufP = BUF;
     89             len = MAX_BUFFER_LEN;
     90         }
     91     } else {
     92         bufP = BUF;
     93     }
     94 
     95     if (timeout) {
     96         nread = NET_Timeout(fd, timeout);
     97         if (nread <= 0) {
     98             if (nread == 0) {
     99                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
    100                             "Read timed out");
    101             } else if (nread == JVM_IO_ERR) {
    102                 if (errno == EBADF) {
    103                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
    104                  } else {
    105                      NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
    106                                                   "select/poll failed");
    107                  }
    108             } else if (nread == JVM_IO_INTR) {
    109                 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    110                             "Operation interrupted");
    111             }
    112             if (bufP != BUF) {
    113                 free(bufP);
    114             }
    115             return -1;
    116         }
    117     }
    118 
    119     nread = NET_Read(fd, bufP, len);
    120 
    121     if (nread <= 0) {
    122         if (nread < 0) {
    123 
    124             switch (errno) {
    125                 case ECONNRESET:
    126                 case EPIPE:
    127                     JNU_ThrowByName(env, "sun/net/ConnectionResetException",
    128                         "Connection reset");
    129                     break;
    130 
    131                 case EBADF:
    132                     JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
    133                         "Socket closed");
    134                     break;
    135 
    136                 case EINTR:
    137                      JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
    138                            "Operation interrupted");
    139                      break;
    140 
    141                 default:
    142                     NET_ThrowByNameWithLastError(env,
    143                         JNU_JAVANETPKG "SocketException", "Read failed");
    144             }
    145         }
    146     } else {
    147         (*env)->SetByteArrayRegion(env, data, off, nread, (jbyte *)bufP);
    148     }
    149 
    150     if (bufP != BUF) {
    151         free(bufP);
    152     }
    153     return nread;
    154 }
    155 
    156 static JNINativeMethod gMethods[] = {
    157   NATIVE_METHOD(SocketInputStream, socketRead0, "(Ljava/io/FileDescriptor;[BIII)I"),
    158 };
    159 
    160 void register_java_net_SocketInputStream(JNIEnv* env) {
    161   jniRegisterNativeMethods(env, "java/net/SocketInputStream", gMethods, NELEM(gMethods));
    162 
    163   // Init field ids
    164   IO_fd_fdID = NET_GetFileDescriptorID(env);
    165 }
    166