jdk/src/solaris/native/sun/nio/ch/SctpNet.c
changeset 12128 09f5d262e329
parent 12127 eab1e4be8495
parent 11872 c51754cddc03
child 12129 561811d8ba18
equal deleted inserted replaced
12127:eab1e4be8495 12128:09f5d262e329
     1 /*
       
     2  * Copyright (c) 2009, 2010, 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 <stdlib.h>
       
    27 #include <string.h>
       
    28 #include <dlfcn.h>
       
    29 
       
    30 #include "Sctp.h"
       
    31 #include "jni.h"
       
    32 #include "jni_util.h"
       
    33 #include "nio_util.h"
       
    34 #include "nio.h"
       
    35 #include "net_util.h"
       
    36 #include "net_util_md.h"
       
    37 #include "sun_nio_ch_SctpNet.h"
       
    38 #include "sun_nio_ch_SctpStdSocketOption.h"
       
    39 
       
    40 static jclass isaCls = 0;
       
    41 static jmethodID isaCtrID = 0;
       
    42 
       
    43 static const char* nativeSctpLib = "libsctp.so.1";
       
    44 static jboolean funcsLoaded = JNI_FALSE;
       
    45 
       
    46 JNIEXPORT jint JNICALL JNI_OnLoad
       
    47   (JavaVM *vm, void *reserved) {
       
    48     return JNI_VERSION_1_2;
       
    49 }
       
    50 
       
    51 static int preCloseFD = -1;     /* File descriptor to which we dup other fd's
       
    52                                    before closing them for real */
       
    53 
       
    54 /**
       
    55  * Loads the native sctp library that contains the socket extension
       
    56  * functions, as well as locating the individual functions.
       
    57  * There will be a pending exception if this method returns false.
       
    58  */
       
    59 jboolean loadSocketExtensionFuncs
       
    60   (JNIEnv* env) {
       
    61     if (dlopen(nativeSctpLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) {
       
    62         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    63               dlerror());
       
    64         return JNI_FALSE;
       
    65     }
       
    66 
       
    67     if ((nio_sctp_getladdrs = (sctp_getladdrs_func*)
       
    68             dlsym(RTLD_DEFAULT, "sctp_getladdrs")) == NULL) {
       
    69         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    70               dlerror());
       
    71         return JNI_FALSE;
       
    72     }
       
    73 
       
    74     if ((nio_sctp_freeladdrs = (sctp_freeladdrs_func*)
       
    75             dlsym(RTLD_DEFAULT, "sctp_freeladdrs")) == NULL) {
       
    76         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    77               dlerror());
       
    78         return JNI_FALSE;
       
    79     }
       
    80 
       
    81     if ((nio_sctp_getpaddrs = (sctp_getpaddrs_func*)
       
    82             dlsym(RTLD_DEFAULT, "sctp_getpaddrs")) == NULL) {
       
    83         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    84               dlerror());
       
    85         return JNI_FALSE;
       
    86     }
       
    87 
       
    88     if ((nio_sctp_freepaddrs = (sctp_freepaddrs_func*)
       
    89             dlsym(RTLD_DEFAULT, "sctp_freepaddrs")) == NULL) {
       
    90         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    91               dlerror());
       
    92         return JNI_FALSE;
       
    93     }
       
    94 
       
    95     if ((nio_sctp_bindx = (sctp_bindx_func*)
       
    96             dlsym(RTLD_DEFAULT, "sctp_bindx")) == NULL) {
       
    97         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
    98               dlerror());
       
    99         return JNI_FALSE;
       
   100     }
       
   101 
       
   102     if ((nio_sctp_peeloff = (sctp_peeloff_func*)
       
   103             dlsym(RTLD_DEFAULT, "sctp_peeloff")) == NULL) {
       
   104         JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
       
   105               dlerror());
       
   106         return JNI_FALSE;
       
   107     }
       
   108 
       
   109     funcsLoaded = JNI_TRUE;
       
   110     return JNI_TRUE;
       
   111 }
       
   112 
       
   113 jint
       
   114 handleSocketError(JNIEnv *env, jint errorValue)
       
   115 {
       
   116     char *xn;
       
   117     switch (errorValue) {
       
   118         case EINPROGRESS:     /* Non-blocking connect */
       
   119             return 0;
       
   120         case EPROTO:
       
   121             xn= JNU_JAVANETPKG "ProtocolException";
       
   122             break;
       
   123         case ECONNREFUSED:
       
   124             xn = JNU_JAVANETPKG "ConnectException";
       
   125             break;
       
   126         case ETIMEDOUT:
       
   127             xn = JNU_JAVANETPKG "ConnectException";
       
   128             break;
       
   129         case EHOSTUNREACH:
       
   130             xn = JNU_JAVANETPKG "NoRouteToHostException";
       
   131             break;
       
   132         case EADDRINUSE:  /* Fall through */
       
   133         case EADDRNOTAVAIL:
       
   134             xn = JNU_JAVANETPKG "BindException";
       
   135             break;
       
   136         default:
       
   137             xn = JNU_JAVANETPKG "SocketException";
       
   138             break;
       
   139     }
       
   140     errno = errorValue;
       
   141     JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
       
   142     return IOS_THROWN;
       
   143 }
       
   144 
       
   145 /*
       
   146  * Class:     sun_nio_ch_SctpNet
       
   147  * Method:    init
       
   148  * Signature: ()V
       
   149  */
       
   150 JNIEXPORT void JNICALL
       
   151 Java_sun_nio_ch_SctpNet_init
       
   152   (JNIEnv *env, jclass cl) {
       
   153     int sp[2];
       
   154     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
       
   155         JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
       
   156         return;
       
   157     }
       
   158     preCloseFD = sp[0];
       
   159     close(sp[1]);
       
   160 }
       
   161 
       
   162 /*
       
   163  * Class:     sun_nio_ch_SctpNet
       
   164  * Method:    socket0
       
   165  * Signature: (Z)I
       
   166  */
       
   167 JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpNet_socket0
       
   168   (JNIEnv *env, jclass klass, jboolean oneToOne) {
       
   169     int fd;
       
   170     struct sctp_event_subscribe event;
       
   171 #ifdef AF_INET6
       
   172     int domain = ipv6_available() ? AF_INET6 : AF_INET;
       
   173 #else
       
   174     int domain = AF_INET;
       
   175 #endif
       
   176 
       
   177     /* Try to load the socket API extension functions */
       
   178     if (!funcsLoaded && !loadSocketExtensionFuncs(env)) {
       
   179         return 0;
       
   180     }
       
   181 
       
   182     fd = socket(domain, (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
       
   183 
       
   184     if (fd < 0) {
       
   185         return handleSocketError(env, errno);
       
   186     }
       
   187 
       
   188     /* Enable events */
       
   189     memset(&event, 0, sizeof(event));
       
   190     event.sctp_data_io_event = 1;
       
   191     event.sctp_association_event = 1;
       
   192     event.sctp_address_event = 1;
       
   193     event.sctp_send_failure_event = 1;
       
   194     //event.sctp_peer_error_event = 1;
       
   195     event.sctp_shutdown_event = 1;
       
   196     //event.sctp_partial_delivery_event = 1;
       
   197     //event.sctp_adaptation_layer_event = 1;
       
   198     if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
       
   199        handleSocketError(env, errno);
       
   200     }
       
   201     return fd;
       
   202 }
       
   203 
       
   204 /*
       
   205  * Class:     sun_nio_ch_SctpNet
       
   206  * Method:    bindx
       
   207  * Signature: (I[Ljava/net/InetAddress;IIZ)V
       
   208  */
       
   209 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_bindx
       
   210   (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port,
       
   211    jint addrsLength, jboolean add, jboolean preferIPv6) {
       
   212     SOCKADDR *sap, *tmpSap;
       
   213     int i, sa_len = sizeof(SOCKADDR);
       
   214     jobject ia;
       
   215 
       
   216     if (addrsLength < 1)
       
   217         return;
       
   218 
       
   219     if ((sap = calloc(addrsLength,  sa_len)) == NULL) {
       
   220           JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
       
   221         return;
       
   222     }
       
   223 
       
   224     tmpSap = sap;
       
   225     for (i=0; i<addrsLength; i++) {
       
   226         ia = (*env)->GetObjectArrayElement(env, addrs, i);
       
   227         if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap,
       
   228                                       &sa_len, preferIPv6) != 0) {
       
   229             free(sap);
       
   230             return;
       
   231         }
       
   232         tmpSap++;
       
   233     }
       
   234 
       
   235     if (nio_sctp_bindx(fd, (void*)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR :
       
   236                        SCTP_BINDX_REM_ADDR) != 0) {
       
   237         handleSocketError(env, errno);
       
   238     }
       
   239 
       
   240     free(sap);
       
   241 }
       
   242 
       
   243 /*
       
   244  * Class:     sun_nio_ch_SctpNet
       
   245  * Method:    listen0
       
   246  * Signature: (II)V
       
   247  */
       
   248 JNIEXPORT void JNICALL
       
   249 Java_sun_nio_ch_SctpNet_listen0
       
   250   (JNIEnv *env, jclass cl, jint fd, jint backlog) {
       
   251     if (listen(fd, backlog) < 0)
       
   252         handleSocketError(env, errno);
       
   253 }
       
   254 
       
   255 /*
       
   256  * Class:     sun_nio_ch_SctpNet
       
   257  * Method:    connect0
       
   258  * Signature: (ILjava/net/InetAddress;I)I
       
   259  */
       
   260 JNIEXPORT jint JNICALL
       
   261 Java_sun_nio_ch_SctpNet_connect0
       
   262   (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) {
       
   263     SOCKADDR sa;
       
   264     int sa_len = SOCKADDR_LEN;
       
   265     int rv;
       
   266 
       
   267     if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *) &sa,
       
   268                                   &sa_len, JNI_TRUE) != 0) {
       
   269         return IOS_THROWN;
       
   270     }
       
   271 
       
   272     rv = connect(fd, (struct sockaddr *)&sa, sa_len);
       
   273     if (rv != 0) {
       
   274         if (errno == EINPROGRESS) {
       
   275             return IOS_UNAVAILABLE;
       
   276         } else if (errno == EINTR) {
       
   277             return IOS_INTERRUPTED;
       
   278         }
       
   279         return handleSocketError(env, errno);
       
   280     }
       
   281     return 1;
       
   282 }
       
   283 
       
   284 /*
       
   285  * Class:     sun_nio_ch_SctpNet
       
   286  * Method:    close0
       
   287  * Signature: (I)V
       
   288  */
       
   289 JNIEXPORT void JNICALL
       
   290 Java_sun_nio_ch_SctpNet_close0
       
   291   (JNIEnv *env, jclass clazz, jint fd) {
       
   292     if (fd != -1) {
       
   293         int rv = close(fd);
       
   294         if (rv < 0)
       
   295             JNU_ThrowIOExceptionWithLastError(env, "Close failed");
       
   296     }
       
   297 }
       
   298 
       
   299 /*
       
   300  * Class:     sun_nio_ch_SctpNet
       
   301  * Method:    preClose0
       
   302  * Signature: (I)V
       
   303  */
       
   304 JNIEXPORT void JNICALL
       
   305 Java_sun_nio_ch_SctpNet_preClose0
       
   306   (JNIEnv *env, jclass clazz, jint fd) {
       
   307     if (preCloseFD >= 0) {
       
   308         if (dup2(preCloseFD, fd) < 0)
       
   309             JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
       
   310     }
       
   311 }
       
   312 
       
   313 void initializeISA
       
   314   (JNIEnv* env) {
       
   315     if (isaCls == 0) {
       
   316         jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
       
   317         CHECK_NULL(c);
       
   318         isaCls = (*env)->NewGlobalRef(env, c);
       
   319         CHECK_NULL(isaCls);
       
   320         (*env)->DeleteLocalRef(env, c);
       
   321         isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>",
       
   322                                      "(Ljava/net/InetAddress;I)V");
       
   323     }
       
   324 }
       
   325 
       
   326 jobject SockAddrToInetSocketAddress
       
   327   (JNIEnv *env, struct sockaddr* sap) {
       
   328     int port = 0;
       
   329 
       
   330     jobject ia = NET_SockaddrToInetAddress(env, sap, &port);
       
   331     if (ia == NULL)
       
   332         return NULL;
       
   333 
       
   334     if (isaCls == 0) {
       
   335         initializeISA(env);
       
   336         CHECK_NULL_RETURN(isaCls, NULL);
       
   337     }
       
   338 
       
   339     return (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   340 }
       
   341 
       
   342 /*
       
   343  * Class:     sun_nio_ch_SctpNet
       
   344  * Method:    getLocalAddresses0
       
   345  * Signature: (I)[Ljava/net/SocketAddress;
       
   346  */
       
   347 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getLocalAddresses0
       
   348   (JNIEnv *env, jclass klass, jint fd) {
       
   349     void *addr_buf, *laddr;
       
   350     struct sockaddr* sap;
       
   351     int i, addrCount;
       
   352     jobjectArray isaa;
       
   353 
       
   354 #ifdef __solaris__
       
   355     if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
       
   356 #else /* __linux__ */
       
   357     if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
       
   358 #endif
       
   359         handleSocketError(env, errno);
       
   360         return NULL;
       
   361     }
       
   362 
       
   363     if (addrCount < 1)
       
   364         return NULL;
       
   365 
       
   366     if (isaCls == 0) {
       
   367         initializeISA(env);
       
   368         CHECK_NULL_RETURN(isaCls, NULL);
       
   369     }
       
   370 
       
   371     isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
       
   372     if (isaa == NULL) {
       
   373         nio_sctp_freeladdrs(addr_buf);
       
   374         return NULL;
       
   375     }
       
   376 
       
   377     laddr = addr_buf;
       
   378     for (i=0; i<addrCount; i++) {
       
   379         int port = 0;
       
   380         jobject isa = NULL, ia;
       
   381         sap = (struct sockaddr*)addr_buf;
       
   382         ia = NET_SockaddrToInetAddress(env, sap, &port);
       
   383         if (ia != NULL)
       
   384             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   385         if (isa != NULL)
       
   386             (*env)->SetObjectArrayElement(env, isaa, i, isa);
       
   387 
       
   388         if (sap->sa_family == AF_INET)
       
   389             addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
       
   390         else
       
   391             addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
       
   392     }
       
   393 
       
   394     nio_sctp_freeladdrs(laddr);
       
   395     return isaa;
       
   396 }
       
   397 
       
   398 jobjectArray getRemoteAddresses
       
   399   (JNIEnv *env, jint fd, sctp_assoc_t id) {
       
   400     void *addr_buf, *paddr;
       
   401     struct sockaddr* sap;
       
   402     int i, addrCount;
       
   403     jobjectArray isaa;
       
   404 
       
   405 #if __solaris__
       
   406     if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
       
   407 #else /* __linux__ */
       
   408     if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) {
       
   409 #endif
       
   410         handleSocketError(env, errno);
       
   411         return NULL;
       
   412     }
       
   413 
       
   414     if (addrCount < 1)
       
   415         return NULL;
       
   416 
       
   417     if (isaCls == 0) {
       
   418         initializeISA(env);
       
   419         CHECK_NULL_RETURN(isaCls, NULL);
       
   420     }
       
   421 
       
   422     isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
       
   423     if (isaa == NULL) {
       
   424         nio_sctp_freepaddrs(addr_buf);
       
   425         return NULL;
       
   426     }
       
   427 
       
   428     paddr = addr_buf;
       
   429     for (i=0; i<addrCount; i++) {
       
   430         jobject ia, isa = NULL;
       
   431         int port;
       
   432         sap = (struct sockaddr*)addr_buf;
       
   433         ia = NET_SockaddrToInetAddress(env, sap, &port);
       
   434         if (ia != NULL)
       
   435             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
       
   436         if (isa != NULL)
       
   437             (*env)->SetObjectArrayElement(env, isaa, i, isa);
       
   438 
       
   439         if (sap->sa_family == AF_INET)
       
   440             addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
       
   441         else
       
   442             addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
       
   443     }
       
   444 
       
   445     nio_sctp_freepaddrs(paddr);
       
   446 
       
   447     return isaa;
       
   448 }
       
   449 
       
   450  /*
       
   451  * Class:     sun_nio_ch_SctpNet
       
   452  * Method:    getRemoteAddresses0
       
   453  * Signature: (II)[Ljava/net/SocketAddress;
       
   454  */
       
   455 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getRemoteAddresses0
       
   456   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   457     return getRemoteAddresses(env, fd, assocId);
       
   458 }
       
   459 
       
   460 /* Map the Java level option to the native level */
       
   461 int mapSocketOption
       
   462   (jint cmd, int *level, int *optname) {
       
   463     static struct {
       
   464         jint cmd;
       
   465         int level;
       
   466         int optname;
       
   467     } const opts[] = {
       
   468         { sun_nio_ch_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS,   IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
       
   469         { sun_nio_ch_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE,   IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
       
   470         { sun_nio_ch_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
       
   471         { sun_nio_ch_SctpStdSocketOption_SCTP_NODELAY,             IPPROTO_SCTP, SCTP_NODELAY },
       
   472         { sun_nio_ch_SctpStdSocketOption_SO_SNDBUF,                SOL_SOCKET,   SO_SNDBUF },
       
   473         { sun_nio_ch_SctpStdSocketOption_SO_RCVBUF,                SOL_SOCKET,   SO_RCVBUF },
       
   474         { sun_nio_ch_SctpStdSocketOption_SO_LINGER,                SOL_SOCKET,   SO_LINGER } };
       
   475 
       
   476     int i;
       
   477     for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
       
   478         if (cmd == opts[i].cmd) {
       
   479             *level = opts[i].level;
       
   480             *optname = opts[i].optname;
       
   481             return 0;
       
   482         }
       
   483     }
       
   484 
       
   485     /* not found */
       
   486     return -1;
       
   487 }
       
   488 
       
   489 /*
       
   490  * Class:     sun_nio_ch_SctpNet
       
   491  * Method:    setIntOption0
       
   492  * Signature: (III)V
       
   493  */
       
   494 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setIntOption0
       
   495   (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
       
   496     int klevel, kopt;
       
   497     int result;
       
   498     struct linger linger;
       
   499     void *parg;
       
   500     int arglen;
       
   501 
       
   502     if (mapSocketOption(opt, &klevel, &kopt) < 0) {
       
   503         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   504                                      "Unsupported socket option");
       
   505         return;
       
   506     }
       
   507 
       
   508     if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) {
       
   509         parg = (void *)&linger;
       
   510         arglen = sizeof(linger);
       
   511         if (arg >= 0) {
       
   512             linger.l_onoff = 1;
       
   513             linger.l_linger = arg;
       
   514         } else {
       
   515             linger.l_onoff = 0;
       
   516             linger.l_linger = 0;
       
   517         }
       
   518     } else {
       
   519         parg = (void *)&arg;
       
   520         arglen = sizeof(arg);
       
   521     }
       
   522 
       
   523     if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) {
       
   524         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   525                                      "sun_nio_ch_SctpNet.setIntOption0");
       
   526     }
       
   527 }
       
   528 
       
   529 /*
       
   530  * Class:     sun_nio_ch_SctpNet
       
   531  * Method:    getIntOption0
       
   532  * Signature: (II)I
       
   533  */
       
   534 JNIEXPORT int JNICALL Java_sun_nio_ch_SctpNet_getIntOption0
       
   535   (JNIEnv *env, jclass klass, jint fd, jint opt) {
       
   536     int klevel, kopt;
       
   537     int result;
       
   538     struct linger linger;
       
   539     void *arg;
       
   540     int arglen;
       
   541 
       
   542     if (mapSocketOption(opt, &klevel, &kopt) < 0) {
       
   543         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   544                                      "Unsupported socket option");
       
   545         return -1;
       
   546     }
       
   547 
       
   548     if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) {
       
   549         arg = (void *)&linger;
       
   550         arglen = sizeof(linger);
       
   551     } else {
       
   552         arg = (void *)&result;
       
   553         arglen = sizeof(result);
       
   554     }
       
   555 
       
   556     if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) {
       
   557         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   558                                      "sun.nio.ch.Net.getIntOption");
       
   559         return -1;
       
   560     }
       
   561 
       
   562     if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER)
       
   563         return linger.l_onoff ? linger.l_linger : -1;
       
   564     else
       
   565         return result;
       
   566 }
       
   567 
       
   568 /*
       
   569  * Class:     sun_nio_ch_SctpNet
       
   570  * Method:    getPrimAddrOption0
       
   571  * Signature: (II)Ljava/net/SocketAddress;
       
   572  */
       
   573 JNIEXPORT jobject JNICALL Java_sun_nio_ch_SctpNet_getPrimAddrOption0
       
   574   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   575     struct sctp_setprim prim;
       
   576     unsigned int prim_len = sizeof(prim);
       
   577     struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;
       
   578 
       
   579     prim.ssp_assoc_id = assocId;
       
   580 
       
   581     if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
       
   582         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   583                                      "sun.nio.ch.SctpNet.getPrimAddrOption0");
       
   584         return NULL;
       
   585     }
       
   586 
       
   587     return SockAddrToInetSocketAddress(env, sap);
       
   588 }
       
   589 
       
   590 /*
       
   591  * Class:     sun_nio_ch_SctpNet
       
   592  * Method:    setPrimAddrOption0
       
   593  * Signature: (IILjava/net/InetAddress;I)V
       
   594  */
       
   595 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPrimAddrOption0
       
   596   (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
       
   597     struct sctp_setprim prim;
       
   598     struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;
       
   599     int sap_len;
       
   600 
       
   601     if (NET_InetAddressToSockaddr(env, iaObj, port, sap,
       
   602                                   &sap_len, JNI_TRUE) != 0) {
       
   603         return;
       
   604     }
       
   605 
       
   606     prim.ssp_assoc_id = assocId;
       
   607 
       
   608     if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
       
   609         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   610                                      "sun.nio.ch.SctpNet.setPrimAddrOption0");
       
   611     }
       
   612 }
       
   613 
       
   614 /*
       
   615  * Class:     sun_nio_ch_SctpNet
       
   616  * Method:    setPeerPrimAddrOption0
       
   617  * Signature: (IILjava/net/InetAddress;I)V
       
   618  */
       
   619 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPeerPrimAddrOption0
       
   620   (JNIEnv *env, jclass klass, jint fd, jint assocId,
       
   621    jobject iaObj, jint port, jboolean preferIPv6) {
       
   622     struct sctp_setpeerprim prim;
       
   623     struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr;
       
   624     int sap_len;
       
   625 
       
   626     if (NET_InetAddressToSockaddr(env, iaObj, port, sap,
       
   627                                   &sap_len, preferIPv6) != 0) {
       
   628         return;
       
   629     }
       
   630 
       
   631     prim.sspp_assoc_id = assocId;
       
   632 
       
   633     if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
       
   634             sizeof(prim)) < 0) {
       
   635         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   636                                      "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
       
   637     }
       
   638 }
       
   639 
       
   640 /*
       
   641  * Class:     sun_nio_ch_SctpNet
       
   642  * Method:    getInitMsgOption0
       
   643  * Signature: (I[I)V
       
   644  */
       
   645 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_getInitMsgOption0
       
   646   (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
       
   647     struct sctp_initmsg sctp_initmsg;
       
   648     unsigned int sim_len = sizeof(sctp_initmsg);
       
   649     int vals[2];
       
   650 
       
   651     if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
       
   652             &sim_len) < 0) {
       
   653         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   654                                      "sun.nio.ch.SctpNet.getInitMsgOption0");
       
   655         return;
       
   656     }
       
   657 
       
   658     vals[0] = sctp_initmsg.sinit_max_instreams;
       
   659     vals[1] = sctp_initmsg.sinit_num_ostreams;
       
   660     (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
       
   661 }
       
   662 
       
   663 /*
       
   664  * Class:     sun_nio_ch_SctpNet
       
   665  * Method:    setInitMsgOption0
       
   666  * Signature: (III)V
       
   667  */
       
   668 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setInitMsgOption0
       
   669   (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
       
   670     struct sctp_initmsg sctp_initmsg;
       
   671 
       
   672     sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
       
   673     sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
       
   674     sctp_initmsg.sinit_max_attempts = 0;  // default
       
   675     sctp_initmsg.sinit_max_init_timeo = 0;  // default
       
   676 
       
   677     if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
       
   678           sizeof(sctp_initmsg)) < 0) {
       
   679         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
       
   680                                      "sun.nio.ch.SctpNet.setInitMsgOption0");
       
   681     }
       
   682 }
       
   683 
       
   684 /*
       
   685  * Class:     sun_nio_ch_SctpNet
       
   686  * Method:    shutdown0
       
   687  * Signature: (II)V
       
   688  */
       
   689 JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_shutdown0
       
   690   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   691     int rv;
       
   692     struct msghdr msg[1];
       
   693     struct iovec iov[1];
       
   694     int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
       
   695     char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
       
   696     struct cmsghdr* cmsg;
       
   697     struct sctp_sndrcvinfo *sri;
       
   698 
       
   699     /* SctpSocketChannel */
       
   700     if (assocId < 0) {
       
   701         shutdown(fd, SHUT_WR);
       
   702         return;
       
   703     }
       
   704 
       
   705     memset(msg, 0, sizeof (*msg));
       
   706     memset(cbuf, 0, cbuf_size);
       
   707     msg->msg_name = NULL;
       
   708     msg->msg_namelen = 0;
       
   709     iov->iov_base = NULL;
       
   710     iov->iov_len = 0;
       
   711     msg->msg_iov = iov;
       
   712     msg->msg_iovlen = 1;
       
   713     msg->msg_control = cbuf;
       
   714     msg->msg_controllen = cbuf_size;
       
   715     msg->msg_flags = 0;
       
   716 
       
   717     cmsg = CMSG_FIRSTHDR(msg);
       
   718     cmsg->cmsg_level = IPPROTO_SCTP;
       
   719     cmsg->cmsg_type = SCTP_SNDRCV;
       
   720     cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
       
   721 
       
   722     /* Initialize the payload: */
       
   723     sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
       
   724     memset(sri, 0, sizeof (*sri));
       
   725 
       
   726     if (assocId > 0) {
       
   727         sri->sinfo_assoc_id = assocId;
       
   728     }
       
   729 
       
   730     sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF;
       
   731 
       
   732     /* Sum of the length of all control messages in the buffer. */
       
   733     msg->msg_controllen = cmsg->cmsg_len;
       
   734 
       
   735     if ((rv = sendmsg(fd, msg, 0)) < 0) {
       
   736         handleSocketError(env, errno);
       
   737     }
       
   738 }
       
   739 
       
   740 /*
       
   741  * Class:     sun_nio_ch_SctpNet
       
   742  * Method:    branch
       
   743  * Signature: (II)I
       
   744  */
       
   745 JNIEXPORT int JNICALL Java_sun_nio_ch_SctpNet_branch0
       
   746   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
       
   747     int newfd = 0;
       
   748     if ((newfd = nio_sctp_peeloff(fd, assocId)) < 0) {
       
   749         handleSocketError(env, errno);
       
   750     }
       
   751 
       
   752     return newfd;
       
   753 }