1 /*
   2  * Copyright (c) 2017, 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 #include <sys/socket.h>
  26 #include <string.h>
  27 #include <errno.h>
  28 #include <unistd.h>
  29 
  30 #include <jni.h>
  31 #include <netinet/tcp.h>
  32 #include "jni_util.h"
  33 
  34 static void throwByNameWithLastError(JNIEnv *env, const char *name,
  35         const char *defaultDetail) {
  36     char defaultMsg[255];
  37     sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail);
  38     JNU_ThrowByNameWithLastError(env, name, defaultMsg);
  39 }
  40 
  41 /*
  42  * Class:     jdk_net_LinuxSocketOptions
  43  * Method:    setQuickAck
  44  * Signature: (II)V
  45  */
  46 JNIEXPORT void JNICALL Java_jdk_net_LinuxSocketOptions_setQuickAck
  47 (JNIEnv *env, jobject unused, jint fd, jboolean on) {
  48     int optval;
  49     int rv;
  50     optval = (on ? 1 : 0);
  51     rv = setsockopt(fd, SOL_SOCKET, TCP_QUICKACK, &optval, sizeof (optval));
  52     if (rv < 0) {
  53         if (errno == ENOPROTOOPT) {
  54             JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
  55                             "unsupported socket option");
  56         } else {
  57             throwByNameWithLastError(env, "java/net/SocketException",
  58                                     "set option SO_QUICKACK failed");
  59         }
  60     }
  61 }
  62 
  63 /*
  64  * Class:     jdk_net_LinuxSocketOptions
  65  * Method:    getQuickAck
  66  * Signature: (I)I;
  67  */
  68 JNIEXPORT jint JNICALL Java_jdk_net_LinuxSocketOptions_getQuickAck0
  69 (JNIEnv *env, jobject unused, jint fd) {
  70     int on;
  71     socklen_t sz = sizeof (on);
  72     int rv = getsockopt(fd, SOL_SOCKET, TCP_QUICKACK, &on, &sz);
  73     if (rv < 0) {
  74         if (errno == ENOPROTOOPT) {
  75             JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
  76                             "unsupported socket option");
  77         } else {
  78             throwByNameWithLastError(env, "java/net/SocketException",
  79                                     "get option SO_QUICKACK failed");
  80         }
  81     }
  82     return on;
  83 }
  84 
  85 /*
  86  * Class:     jdk_net_LinuxSocketOptions
  87  * Method:    quickAckSupported
  88  * Signature: ()Z
  89  */
  90 JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_quickAckSupported
  91 (JNIEnv *env, jobject unused) {
  92     int one = 1;
  93     int rv, s;
  94     s = socket(PF_INET, SOCK_STREAM, 0);
  95     if (s < 0) {
  96         return JNI_FALSE;
  97     }
  98     rv = setsockopt(s, SOL_SOCKET, TCP_QUICKACK, (void *) &one, sizeof (one));
  99     if (rv != 0 && errno == ENOPROTOOPT) {
 100         rv = JNI_FALSE;
 101     } else {
 102         rv = JNI_TRUE;
 103     }
 104     close(s);
 105     return rv;
 106 }