1 /* 2 * Copyright (c) 2014, 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 27 #include "SolarisSocketOptions.h" 28 29 static jfieldID sf_priority; 30 static jfieldID sf_bandwidth; 31 32 static int initialized = 0; 33 34 /* 35 * Declare library specific JNI_Onload entry if static build 36 */ 37 DEF_STATIC_JNI_OnLoad 38 39 /* 40 * Class: jdk_net_SolarisSocketOptions 41 * Method: init 42 * Signature: ()V 43 */ 44 JNIEXPORT void JNICALL Java_jdk_net_SolarisSocketOptions_init 45 (JNIEnv *env, jclass unused) 46 { 47 if (!initialized) { 48 jclass c = (*env)->FindClass(env, "jdk/net/SocketFlow"); 49 CHECK_NULL(c); 50 sf_priority = (*env)->GetFieldID(env, c, "priority", "I"); 51 CHECK_NULL(sf_priority); 52 sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J"); 53 CHECK_NULL(sf_bandwidth); 54 initialized = 1; 55 } 56 } 57 58 /** Return the Status value. */ 59 static jint toStatus(int errval) 60 { 61 switch (errval) { 62 case 0: return jdk_net_SocketFlow_OK_VALUE; 63 case EPERM: return jdk_net_SocketFlow_NO_PERMISSION_VALUE; 64 case ENOTCONN: return jdk_net_SocketFlow_NOT_CONNECTED_VALUE; 65 case EOPNOTSUPP: return jdk_net_SocketFlow_NOT_SUPPORTED_VALUE; 66 case EALREADY: return jdk_net_SocketFlow_ALREADY_CREATED_VALUE; 67 case EINPROGRESS: return jdk_net_SocketFlow_IN_PROGRESS_VALUE; 68 default: return jdk_net_SocketFlow_OTHER_VALUE; 69 } 70 } 71 72 void throwByNameWithLastError 73 (JNIEnv *env, const char *name, const char *defaultDetail) 74 { 75 char defaultMsg[255]; 76 sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail); 77 JNU_ThrowByNameWithLastError(env, name, defaultMsg); 78 } 79 80 /* 81 * Class: jdk_net_SolarisSocketOptions 82 * Method: setFlowOption0 83 * Signature: (IIJ)I 84 */ 85 JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_setFlowOption 86 (JNIEnv *env, jobject unused, jint fd, jint priority, jlong bandwidth) 87 { 88 int rv; 89 sock_flow_props_t props; 90 memset(&props, 0, sizeof(props)); 91 props.sfp_version = SOCK_FLOW_PROP_VERSION1; 92 93 if (priority != jdk_net_SocketFlow_UNSET) { 94 props.sfp_mask |= SFP_PRIORITY; 95 props.sfp_priority = priority; 96 } 97 if (bandwidth > jdk_net_SocketFlow_UNSET) { 98 props.sfp_mask |= SFP_MAXBW; 99 props.sfp_maxbw = (uint64_t) bandwidth; 100 } 101 102 rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); 103 104 if (rv < 0) { 105 if (errno == ENOPROTOOPT) { 106 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", 107 "unsupported socket option"); 108 } else if (errno == EACCES || errno == EPERM) { 109 JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); 110 } else { 111 throwByNameWithLastError(env, "java/net/SocketException", 112 "set option SO_FLOW_SLA failed"); 113 } 114 return 0; 115 } 116 return toStatus(props.sfp_status); 117 } 118 119 /* 120 * Class: jdk_net_SolarisSocketOptions 121 * Method: getFlowOption0 122 * Signature: (ILjdk/net/SocketFlow;)I 123 */ 124 JNIEXPORT jint JNICALL Java_jdk_net_SolarisSocketOptions_getFlowOption 125 (JNIEnv *env, jobject unused, jint fd, jobject flow) 126 { 127 sock_flow_props_t props; 128 socklen_t sz = sizeof(props); 129 130 int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz); 131 132 if (rv < 0) { 133 if (errno == ENOPROTOOPT) { 134 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", 135 "unsupported socket option"); 136 } else if (errno == EACCES || errno == EPERM) { 137 JNU_ThrowByName(env, "java/net/SocketException", "Permission denied"); 138 } else { 139 throwByNameWithLastError(env, "java/net/SocketException", 140 "get option SO_FLOW_SLA failed"); 141 } 142 return -1; 143 } 144 /* first check status to see if flow exists */ 145 if (props.sfp_status == 0) { /* OK */ 146 /* can set the other fields now */ 147 if (props.sfp_mask & SFP_PRIORITY) { 148 (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority); 149 } 150 if (props.sfp_mask & SFP_MAXBW) { 151 (*env)->SetLongField(env, flow, sf_bandwidth, 152 (jlong)props.sfp_maxbw); 153 } 154 } 155 return toStatus(props.sfp_status); 156 } 157 158 JNIEXPORT jboolean JNICALL Java_jdk_net_SolarisSocketOptions_flowSupported 159 (JNIEnv *env, jobject unused) 160 { 161 /* Do a simple dummy call, and try to figure out from that */ 162 sock_flow_props_t props; 163 int rv, s; 164 165 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 166 if (s < 0) { 167 return JNI_FALSE; 168 } 169 memset(&props, 0, sizeof(props)); 170 props.sfp_version = SOCK_FLOW_PROP_VERSION1; 171 props.sfp_mask |= SFP_PRIORITY; 172 props.sfp_priority = SFP_PRIO_NORMAL; 173 rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props)); 174 if (rv != 0 && errno == ENOPROTOOPT) { 175 rv = JNI_FALSE; 176 } else { 177 rv = JNI_TRUE; 178 } 179 close(s); 180 return rv; 181 }