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