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 <jni.h>
27 #include <string.h>
28
29 #include "net_util.h"
30 #include "jdk_net_SocketFlow.h"
31
32 static jclass sf_status_class; /* Status enum type */
33
34 static jfieldID sf_status;
35 static jfieldID sf_priority;
36 static jfieldID sf_bandwidth;
37
38 static jfieldID sf_fd_fdID; /* FileDescriptor.fd */
39
40 /* References to the literal enum values */
41
42 static jobject sfs_NOSTATUS;
43 static jobject sfs_OK;
44 static jobject sfs_NOPERMISSION;
45 static jobject sfs_NOTCONNECTED;
46 static jobject sfs_NOTSUPPORTED;
47 static jobject sfs_ALREADYCREATED;
48 static jobject sfs_INPROGRESS;
49 static jobject sfs_OTHER;
50
51 static jobject getEnumField(JNIEnv *env, char *name);
52 static void setStatus(JNIEnv *env, jobject obj, int errval);
53
54 /* OS specific code is implemented in these three functions */
55
56 static jboolean flowSupported0() ;
57
58 /*
59 * Class: sun_net_ExtendedOptionsImpl
60 * Method: init
61 * Signature: ()V
62 */
63 JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_init
64 (JNIEnv *env, jclass UNUSED)
65 {
66 static int initialized = 0;
67 jclass c;
68
69 /* Global class references */
70
71 if (initialized) {
72 return;
73 }
74
75 c = (*env)->FindClass(env, "jdk/net/SocketFlow$Status");
76 CHECK_NULL(c);
77 sf_status_class = (*env)->NewGlobalRef(env, c);
78 CHECK_NULL(sf_status_class);
79
80 /* int "fd" field of java.io.FileDescriptor */
81
82 c = (*env)->FindClass(env, "java/io/FileDescriptor");
83 CHECK_NULL(c);
84 sf_fd_fdID = (*env)->GetFieldID(env, c, "fd", "I");
85 CHECK_NULL(sf_fd_fdID);
86
87
88 /* SocketFlow fields */
89
90 c = (*env)->FindClass(env, "jdk/net/SocketFlow");
91 CHECK_NULL(c);
92
93 /* status */
94
95 sf_status = (*env)->GetFieldID(env, c, "status",
96 "Ljdk/net/SocketFlow$Status;");
97 CHECK_NULL(sf_status);
98
99 /* priority */
100
101 sf_priority = (*env)->GetFieldID(env, c, "priority", "I");
102 CHECK_NULL(sf_priority);
103
104 /* bandwidth */
105
106 sf_bandwidth = (*env)->GetFieldID(env, c, "bandwidth", "J");
107 CHECK_NULL(sf_bandwidth);
108
109 /* Initialize the static enum values */
110
111 sfs_NOSTATUS = getEnumField(env, "NO_STATUS");
112 CHECK_NULL(sfs_NOSTATUS);
113 sfs_OK = getEnumField(env, "OK");
114 CHECK_NULL(sfs_OK);
115 sfs_NOPERMISSION = getEnumField(env, "NO_PERMISSION");
116 CHECK_NULL(sfs_NOPERMISSION);
117 sfs_NOTCONNECTED = getEnumField(env, "NOT_CONNECTED");
118 CHECK_NULL(sfs_NOTCONNECTED);
119 sfs_NOTSUPPORTED = getEnumField(env, "NOT_SUPPORTED");
120 CHECK_NULL(sfs_NOTSUPPORTED);
121 sfs_ALREADYCREATED = getEnumField(env, "ALREADY_CREATED");
122 CHECK_NULL(sfs_ALREADYCREATED);
123 sfs_INPROGRESS = getEnumField(env, "IN_PROGRESS");
124 CHECK_NULL(sfs_INPROGRESS);
125 sfs_OTHER = getEnumField(env, "OTHER");
126 CHECK_NULL(sfs_OTHER);
127 initialized = JNI_TRUE;
128 }
129
130 static jobject getEnumField(JNIEnv *env, char *name)
131 {
132 jobject f;
133 jfieldID fID = (*env)->GetStaticFieldID(env, sf_status_class, name,
134 "Ljdk/net/SocketFlow$Status;");
135 CHECK_NULL_RETURN(fID, NULL);
136
137 f = (*env)->GetStaticObjectField(env, sf_status_class, fID);
138 CHECK_NULL_RETURN(f, NULL);
139 f = (*env)->NewGlobalRef(env, f);
140 CHECK_NULL_RETURN(f, NULL);
141 return f;
142 }
143
144 /*
145 * Retrieve the int file-descriptor from a public socket type object.
146 * Gets impl, then the FileDescriptor from the impl, and then the fd
147 * from that.
148 */
149 static int getFD(JNIEnv *env, jobject fileDesc) {
150 return (*env)->GetIntField(env, fileDesc, sf_fd_fdID);
151 }
152
153 /**
154 * Sets the status field of a SocketFlow to one of the
155 * canned enum values
156 */
157 static void setStatus (JNIEnv *env, jobject obj, int errval)
158 {
159 switch (errval) {
160 case 0: /* OK */
161 (*env)->SetObjectField(env, obj, sf_status, sfs_OK);
162 break;
163 case EPERM:
164 (*env)->SetObjectField(env, obj, sf_status, sfs_NOPERMISSION);
165 break;
166 case ENOTCONN:
167 (*env)->SetObjectField(env, obj, sf_status, sfs_NOTCONNECTED);
168 break;
169 case EOPNOTSUPP:
170 (*env)->SetObjectField(env, obj, sf_status, sfs_NOTSUPPORTED);
171 break;
172 case EALREADY:
173 (*env)->SetObjectField(env, obj, sf_status, sfs_ALREADYCREATED);
174 break;
175 case EINPROGRESS:
176 (*env)->SetObjectField(env, obj, sf_status, sfs_INPROGRESS);
177 break;
178 default:
179 (*env)->SetObjectField(env, obj, sf_status, sfs_OTHER);
180 break;
181 }
182 }
183
184 #ifdef __solaris__
185
186 /*
187 * Class: sun_net_ExtendedOptionsImpl
188 * Method: setFlowOption
189 * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
190 */
191 JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
192 (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
193 {
194 int fd = getFD(env, fileDesc);
195
196 if (fd < 0) {
197 NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
198 return;
199 } else {
200 sock_flow_props_t props;
201 jlong bandwidth;
202 int rv;
203
204 jint priority = (*env)->GetIntField(env, flow, sf_priority);
205 memset(&props, 0, sizeof(props));
206 props.sfp_version = SOCK_FLOW_PROP_VERSION1;
207
208 if (priority != jdk_net_SocketFlow_UNSET) {
209 props.sfp_mask |= SFP_PRIORITY;
210 props.sfp_priority = priority;
211 }
212 bandwidth = (*env)->GetLongField(env, flow, sf_bandwidth);
213 if (bandwidth > -1) {
214 props.sfp_mask |= SFP_MAXBW;
215 props.sfp_maxbw = (uint64_t) bandwidth;
216 }
217 rv = setsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
218 if (rv < 0) {
219 if (errno == ENOPROTOOPT) {
220 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
221 "unsupported socket option");
222 } else if (errno == EACCES || errno == EPERM) {
223 NET_ERROR(env, JNU_JAVANETPKG "SocketException",
224 "Permission denied");
225 } else {
226 NET_ERROR(env, JNU_JAVANETPKG "SocketException",
227 "set option SO_FLOW_SLA failed");
228 }
229 return;
230 }
231 setStatus(env, flow, props.sfp_status);
232 }
233 }
234
235 /*
236 * Class: sun_net_ExtendedOptionsImpl
237 * Method: getFlowOption
238 * Signature: (Ljava/io/FileDescriptor;Ljdk/net/SocketFlow;)V
239 */
240 JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
241 (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
242 {
243 int fd = getFD(env, fileDesc);
244
245 if (fd < 0) {
246 NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed");
247 return;
248 } else {
249 sock_flow_props_t props;
250 int status;
251 socklen_t sz = sizeof(props);
252
253 int rv = getsockopt(fd, SOL_SOCKET, SO_FLOW_SLA, &props, &sz);
254 if (rv < 0) {
255 if (errno == ENOPROTOOPT) {
256 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
257 "unsupported socket option");
258 } else if (errno == EACCES || errno == EPERM) {
259 NET_ERROR(env, JNU_JAVANETPKG "SocketException",
260 "Permission denied");
261 } else {
262 NET_ERROR(env, JNU_JAVANETPKG "SocketException",
263 "set option SO_FLOW_SLA failed");
264 }
265 return;
266 }
267 /* first check status to see if flow exists */
268 status = props.sfp_status;
269 setStatus(env, flow, status);
270 if (status == 0) { /* OK */
271 /* can set the other fields now */
272 if (props.sfp_mask & SFP_PRIORITY) {
273 (*env)->SetIntField(env, flow, sf_priority, props.sfp_priority);
274 }
275 if (props.sfp_mask & SFP_MAXBW) {
276 (*env)->SetLongField(env, flow, sf_bandwidth,
277 (jlong)props.sfp_maxbw);
278 }
279 }
280 }
281 }
282
283 static jboolean flowsupported;
284 static jboolean flowsupported_set = JNI_FALSE;
285
286 static jboolean flowSupported0()
287 {
288 /* Do a simple dummy call, and try to figure out from that */
289 sock_flow_props_t props;
290 int rv, s;
291 if (flowsupported_set) {
292 return flowsupported;
293 }
294 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
295 if (s < 0) {
296 flowsupported = JNI_FALSE;
297 flowsupported_set = JNI_TRUE;
298 return JNI_FALSE;
299 }
300 memset(&props, 0, sizeof(props));
301 props.sfp_version = SOCK_FLOW_PROP_VERSION1;
302 props.sfp_mask |= SFP_PRIORITY;
303 props.sfp_priority = SFP_PRIO_NORMAL;
304 rv = setsockopt(s, SOL_SOCKET, SO_FLOW_SLA, &props, sizeof(props));
305 if (rv != 0 && errno == ENOPROTOOPT) {
306 rv = JNI_FALSE;
307 } else {
308 rv = JNI_TRUE;
309 }
310 close(s);
311 flowsupported = rv;
312 flowsupported_set = JNI_TRUE;
313 return flowsupported;
314 }
315
316 #else /* __solaris__ */
317
318 /* Non Solaris. Functionality is not supported. So, throw UnsupportedOpExc */
319
320 JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setFlowOption
321 (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
322 {
323 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
324 "unsupported socket option");
325 }
326
327 JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_getFlowOption
328 (JNIEnv *env, jclass UNUSED, jobject fileDesc, jobject flow)
329 {
330 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
331 "unsupported socket option");
332 }
333
334 static jboolean flowSupported0() {
335 return JNI_FALSE;
336 }
337
338 #endif /* __solaris__ */
339
340 JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported
341 (JNIEnv *env, jclass UNUSED)
342 {
343 return flowSupported0();
344 }
|
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 }
|