1 /*
   2  * Copyright (c) 2000, 2018, 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 <netdb.h>
  27 #include <sys/types.h>
  28 #include <rdma/rsocket.h>
  29 #include <stdlib.h>
  30 #include <errno.h>
  31 #include <string.h>
  32 #include <poll.h>
  33 
  34 #include <netinet/in.h>
  35 
  36 #include "jni.h"
  37 #include "jni_util.h"
  38 #include "net_util.h"
  39 #include "jvm.h"
  40 #include "jlong.h"
  41 #include "rdma_ch_RdmaSocketChannelImpl.h"
  42 #include "nio_util.h"
  43 #include "nio.h"
  44 
  45 static jfieldID fd_fdID;
  46 
  47 JNIEXPORT void JNICALL
  48 Java_rdma_ch_RdmaSocketChannelImpl_initIDs(JNIEnv *env, jclass clazz)
  49 {
  50     CHECK_NULL(clazz = (*env)->FindClass(env, "java/io/FileDescriptor"));
  51     CHECK_NULL(fd_fdID = (*env)->GetFieldID(env, clazz, "fd", "I"));
  52 }
  53 
  54 jint fdVal(JNIEnv *env, jobject fdo)
  55 {
  56     return (*env)->GetIntField(env, fdo, fd_fdID);
  57 }
  58 
  59 JNIEXPORT jint JNICALL
  60 Java_rdma_ch_RdmaSocketChannelImpl_checkConnect(JNIEnv *env, jobject this,
  61                                                jobject fdo, jboolean block)
  62 {
  63     int error = 0;
  64     socklen_t n = sizeof(int);
  65     jint fd = fdVal(env, fdo);
  66     int result = 0;
  67     struct pollfd poller;
  68 
  69     poller.fd = fd;
  70     poller.events = POLLOUT;
  71     poller.revents = 0;
  72     result = rpoll(&poller, 1, block ? -1 : 0);
  73 
  74     if (result < 0) {
  75         if (errno == EINTR) {
  76             return IOS_INTERRUPTED;
  77         } else {
  78             JNU_ThrowIOExceptionWithLastError(env, "poll failed");
  79             return IOS_THROWN;
  80         }
  81     }
  82     if (!block && (result == 0))
  83         return IOS_UNAVAILABLE;
  84 
  85     if (result > 0) {
  86         errno = 0;
  87         result = rgetsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
  88         if (result < 0) {
  89             return handleSocketError(env, errno);
  90         } else if (error) {
  91             return handleSocketError(env, error);
  92         } else if ((poller.revents & POLLHUP) != 0) {
  93             return handleSocketError(env, ENOTCONN);
  94         }
  95         // connected
  96         return 1;
  97     }
  98     return 0;
  99 }
 100 
 101 JNIEXPORT jint JNICALL
 102 Java_rdma_ch_RdmaSocketChannelImpl_sendOutOfBandData(JNIEnv* env, jclass this,
 103                                                     jobject fdo, jbyte b)
 104 {
 105     int n = rsend(fdVal(env, fdo), (const void*)&b, 1, MSG_OOB);
 106     return convertReturnVal(env, n, JNI_FALSE);
 107 }