Example #1
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getIntOption0
 * Signature: (II)I
 */
JNIEXPORT int JNICALL Java_sun_nio_ch_sctp_SctpNet_getIntOption0
  (JNIEnv *env, jclass klass, jint fd, jint opt) {
    int klevel, kopt;
    int result;
    struct linger linger;
    void *arg;
    int arglen;

    memset((char *) &linger, 0, sizeof(linger));
    if (mapSocketOption(opt, &klevel, &kopt) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "Unsupported socket option");
        return -1;
    }

    if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
        arg = (void *)&linger;
        arglen = sizeof(linger);
    } else {
        arg = (void *)&result;
        arglen = sizeof(result);
    }

    if (NET_GetSockOpt(fd, klevel, kopt, arg, &arglen) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.Net.getIntOption");
        return -1;
    }

    if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER)
        return linger.l_onoff ? linger.l_linger : -1;
    else
        return result;
}
Example #2
0
JNIEXPORT int JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
                            jboolean stream, jboolean reuse)
{
    int fd;
    int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
#ifdef AF_INET6
    int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
#else
    int domain = AF_INET;
#endif

    fd = socket(domain, type, 0);
    if (fd < 0) {
        return handleSocketError(env, errno);
    }

#ifdef AF_INET6
    /* Disable IPV6_V6ONLY to ensure dual-socket support */
    if (domain == AF_INET6) {
        int arg = 0;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg,
                       sizeof(int)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
                                         "sun.nio.ch.Net.setIntOption");
            close(fd);
            return -1;
        }
    }
#endif

    if (reuse) {
        int arg = 1;
        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
                       sizeof(arg)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
                                         "sun.nio.ch.Net.setIntOption");
            close(fd);
            return -1;
        }
    }
#if defined(__linux__) && defined(AF_INET6)
    /* By default, Linux uses the route default */
    if (domain == AF_INET6 && type == SOCK_DGRAM) {
        int arg = 1;
        if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
                       sizeof(arg)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
                                         "sun.nio.ch.Net.setIntOption");
            close(fd);
            return -1;
        }
    }
#endif
    return fd;
}
Example #3
0
void
NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                   const char *defaultDetail) {
    char errmsg[255];
    sprintf(errmsg, "errno: %d, error: %s\n", WSAGetLastError(), defaultDetail); 
    JNU_ThrowByNameWithLastError(env, name, errmsg); 
}
Example #4
0
jint
handleSocketError(JNIEnv *env, jint errorValue)
{
    char *xn;
    switch (errorValue) {
        case EINPROGRESS:     /* Non-blocking connect */
            return 0;
        case EPROTO:
            xn= JNU_JAVANETPKG "ProtocolException";
            break;
        case ECONNREFUSED:
            xn = JNU_JAVANETPKG "ConnectException";
            break;
        case ETIMEDOUT:
            xn = JNU_JAVANETPKG "ConnectException";
            break;
        case EHOSTUNREACH:
            xn = JNU_JAVANETPKG "NoRouteToHostException";
            break;
        case EADDRINUSE:  /* Fall through */
        case EADDRNOTAVAIL:
            xn = JNU_JAVANETPKG "BindException";
            break;
        default:
            xn = JNU_JAVANETPKG "SocketException";
            break;
    }
    errno = errorValue;
    JNU_ThrowByNameWithLastError(env, xn, "NioSocketError");
    return IOS_THROWN;
}
Example #5
0
void throwByNameWithLastError
  (JNIEnv *env, const char *name, const char *defaultDetail)
{
  char defaultMsg[255];
  sprintf(defaultMsg, "errno: %d, %s", errno, defaultDetail);
  JNU_ThrowByNameWithLastError(env, name, defaultMsg);
}
/*
 * Class:     java_net_DualStackPlainSocketImpl
 * Method:    getIntOption
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
  (JNIEnv *env, jclass clazz, jint fd, jint cmd) {

    int level, opt;
    int result=0;
    struct linger linger;
    char *arg;
    int arglen;

    if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "Unsupported socket option");
        return -1;
    }

    if (opt == java_net_SocketOptions_SO_LINGER) {
        arg = (char *)&linger;
        arglen = sizeof(linger);
    } else {
        arg = (char *)&result;
        arglen = sizeof(result);
    }

    if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
        NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
        return -1;
    }

    if (opt == java_net_SocketOptions_SO_LINGER)
        return linger.l_onoff ? linger.l_linger : -1;
    else
        return result;
}
Example #7
0
JNIEXPORT int JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean stream,
                            jboolean reuse)
{
    int fd;

#ifdef AF_INET6
    if (ipv6_available())
	fd = socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
    else
#endif /* AF_INET6 */
	fd = socket(AF_INET, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);

    if (fd < 0) {
	return handleSocketError(env, errno);
    }
    if (reuse) {
	int arg = 1;
        if (NET_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg,
                           sizeof(arg)) < 0) {
            JNU_ThrowByNameWithLastError(env,
                                         JNU_JAVANETPKG "SocketException",
                                         "sun.nio.ch.Net.setIntOption");
        }
    }
    return fd;
}
/*
 * Class:     java_net_DualStackPlainSocketImpl
 * Method:    setIntOption
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_setIntOption
  (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) {

    int level, opt;
    struct linger linger;
    char *parg;
    int arglen;

    if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "Invalid option");
        return;
    }

    if (opt == java_net_SocketOptions_SO_LINGER) {
        parg = (char *)&linger;
        arglen = sizeof(linger);
        if (value >= 0) {
            linger.l_onoff = 1;
            linger.l_linger = (unsigned short)value;
        } else {
            linger.l_onoff = 0;
            linger.l_linger = 0;
        }
    } else {
        parg = (char *)&value;
        arglen = sizeof(value);
    }

    if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
        NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
    }
}
Example #9
0
jint
handleSocketError(JNIEnv *env, jint errorValue)
{
    char *xn;
    errno = 0;
    switch (errorValue) {
	case EINPROGRESS:	/* Non-blocking connect */
	    return 0;
	case EPROTO:
	    xn = JNU_JAVANETPKG "ProtocolException";
	    break;
	case ECONNREFUSED:
	    xn = JNU_JAVANETPKG "ConnectException";
	    break;
	case ETIMEDOUT:
	    xn = JNU_JAVANETPKG "ConnectException";
	    break;
	case EHOSTUNREACH:
	    xn = JNU_JAVANETPKG "NoRouteToHostException";
	    break;
	default:
	    xn = JNU_JAVANETPKG "SocketException";
	    break;
    }
    JNU_ThrowByNameWithLastError(env, xn, strerror(errorValue));
    return IOS_THROWN;
}
Example #10
0
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
                                  jboolean mayNeedConversion, jint level,
                                  jint opt, jint arg, jboolean isIPv6)
{
    int result;
    struct linger linger;
    u_char carg;
    void *parg;
    socklen_t arglen;
    int n;

    /* Option value is an int except for a few specific cases */

    parg = (void*)&arg;
    arglen = sizeof(arg);

    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
        parg = (void*)&carg;
        arglen = sizeof(carg);
        carg = (u_char)arg;
    }

    if (level == SOL_SOCKET && opt == SO_LINGER) {
        parg = (void *)&linger;
        arglen = sizeof(linger);
        if (arg >= 0) {
            linger.l_onoff = 1;
            linger.l_linger = arg;
        } else {
            linger.l_onoff = 0;
            linger.l_linger = 0;
        }
    }

    if (mayNeedConversion) {
        n = NET_SetSockOpt(fdval(env, fdo), level, opt, parg, arglen);
    } else {
        n = setsockopt(fdval(env, fdo), level, opt, parg, arglen);
    }
    if (n < 0) {
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.Net.setIntOption");
    }
#ifdef __linux__
    if (level == IPPROTO_IPV6 && opt == IPV6_TCLASS && isIPv6) {
        // set the V4 option also
        setsockopt(fdval(env, fdo), IPPROTO_IP, IP_TOS, parg, arglen);
    }
#endif
}
Example #11
0
JNIEXPORT void JNICALL
Java_sun_nio_ch_Net_setIntOption0(JNIEnv *env, jclass clazz,
				  jobject fdo, jint opt, jint arg)
{
    int klevel, kopt;
    int result;
    struct linger linger;
    void *parg;
    int arglen;

    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
	JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
				     "Unsupported socket option");
	return;
    }

    if (opt == java_net_SocketOptions_SO_LINGER) {
	parg = (void *)&linger;
	arglen = sizeof(linger);
	if (arg >= 0) {
	    linger.l_onoff = 1;
	    linger.l_linger = arg;
	} else {
	    linger.l_onoff = 0;
	    linger.l_linger = 0;
	}
    } else {
	parg = (void *)&arg;
	arglen = sizeof(arg);
    }

    if (NET_SetSockOpt(fdval(env, fdo), klevel, kopt, parg, arglen) < 0) {
	JNU_ThrowByNameWithLastError(env,
				     JNU_JAVANETPKG "SocketException",
				     "sun.nio.ch.Net.setIntOption");
    }
}
Example #12
0
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz, jobject fdo,
                                  jboolean mayNeedConversion, jint level, jint opt)
{
    int result;
    struct linger linger;
    u_char carg;
    void *arg;
    socklen_t arglen;
    int n;

    /* Option value is an int except for a few specific cases */

    arg = (void *)&result;
    arglen = sizeof(result);

    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP)) {
        arg = (void*)&carg;
        arglen = sizeof(carg);
    }

    if (level == SOL_SOCKET && opt == SO_LINGER) {
        arg = (void *)&linger;
        arglen = sizeof(linger);
    }

    if (mayNeedConversion) {
        n = NET_GetSockOpt(fdval(env, fdo), level, opt, arg, (int*)&arglen);
    } else {
        n = getsockopt(fdval(env, fdo), level, opt, arg, &arglen);
    }
    if (n < 0) {
        JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.Net.getIntOption");
        return -1;
    }

    if (level == IPPROTO_IP &&
        (opt == IP_MULTICAST_TTL || opt == IP_MULTICAST_LOOP))
    {
        return (jint)carg;
    }

    if (level == SOL_SOCKET && opt == SO_LINGER)
        return linger.l_onoff ? (jint)linger.l_linger : (jint)-1;

    return (jint)result;
}
/*
 * Class:     java_net_DualStackPlainDatagramSocketImpl
 * Method:    socketSetIntOption
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
  (JNIEnv *env, jclass clazz, jint fd , jint cmd, jint value) {
    int level = 0, opt = 0;

    if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "Invalid option");
        return;
    }

    if (NET_SetSockOpt(fd, level, opt, (char *)&value, sizeof(value)) < 0) {
        NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
    }
}
Example #14
0
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_getIntOption0(JNIEnv *env, jclass clazz,
				  jobject fdo, jint opt)
{
    int klevel, kopt;
    int result;
    struct linger linger;
    void *arg;
    int arglen;

    if (NET_MapSocketOption(opt, &klevel, &kopt) < 0) {
	JNU_ThrowByNameWithLastError(env,
                                     JNU_JAVANETPKG "SocketException",
                                     "Unsupported socket option");
	return -1;
    }

    if (opt == java_net_SocketOptions_SO_LINGER) {
	arg = (void *)&linger;
	arglen = sizeof(linger);
    } else {
	arg = (void *)&result;
	arglen = sizeof(result);
    }

    if (NET_GetSockOpt(fdval(env, fdo), klevel, kopt, arg, &arglen) < 0) {
	JNU_ThrowByNameWithLastError(env,
				     JNU_JAVANETPKG "SocketException",
				     "sun.nio.ch.Net.getIntOption");
	return -1;
    }

    if (opt == java_net_SocketOptions_SO_LINGER)
	return linger.l_onoff ? linger.l_linger : -1;
    else
	return result;
}
Example #15
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    setInitMsgOption0
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setInitMsgOption0
  (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
    struct sctp_initmsg sctp_initmsg;

    sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
    sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
    sctp_initmsg.sinit_max_attempts = 0;  // default
    sctp_initmsg.sinit_max_init_timeo = 0;  // default

    if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
          sizeof(sctp_initmsg)) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.SctpNet.setInitMsgOption0");
    }
}
Example #16
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getPrimAddrOption0
 * Signature: (II)Ljava/net/SocketAddress;
 */
JNIEXPORT jobject JNICALL Java_sun_nio_ch_sctp_SctpNet_getPrimAddrOption0
  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
    struct sctp_setprim prim;
    unsigned int prim_len = sizeof(prim);
    struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;

    prim.ssp_assoc_id = assocId;

    if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.SctpNet.getPrimAddrOption0");
        return NULL;
    }

    return SockAddrToInetSocketAddress(env, sap);
}
Example #17
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getInitMsgOption0
 * Signature: (I[I)V
 */
JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_getInitMsgOption0
  (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
    struct sctp_initmsg sctp_initmsg;
    unsigned int sim_len = sizeof(sctp_initmsg);
    int vals[2];

    if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
            &sim_len) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.SctpNet.getInitMsgOption0");
        return;
    }

    vals[0] = sctp_initmsg.sinit_max_instreams;
    vals[1] = sctp_initmsg.sinit_num_ostreams;
    (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
}
Example #18
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    setPrimAddrOption0
 * Signature: (IILjava/net/InetAddress;I)V
 */
JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0
  (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
    struct sctp_setprim prim;
    struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;
    int sap_len = sizeof(sap);

    if (NET_InetAddressToSockaddr(env, iaObj, port, sap,
                                  &sap_len, JNI_TRUE) != 0) {
        return;
    }

    prim.ssp_assoc_id = assocId;

    if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun.nio.ch.SctpNet.setPrimAddrOption0");
    }
}
/*
 * Class:     java_net_DualStackPlainDatagramSocketImpl
 * Method:    socketGetIntOption
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
  (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
    int level = 0, opt = 0, result=0;
    int result_len = sizeof(result);

    if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "Invalid option");
        return -1;
    }

    if (NET_GetSockOpt(fd, level, opt, (void *)&result, &result_len) < 0) {
        NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
        return -1;
    }

    return result;
}
Example #20
0
/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getLocalAddresses0
 * Signature: (I)[Ljava/net/SocketAddress;
 */
JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0
  (JNIEnv *env, jclass klass, jint fd) {
    void *addr_buf, *laddr;
    struct sockaddr* sap;
    int i, addrCount;
    jobjectArray isaa;

#ifdef __solaris__
    if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
#else /* __linux__ */
    if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
#endif
        handleSocketError(env, errno);
        return NULL;
    }

    if (addrCount < 1)
        return NULL;

    if (isaCls == 0) {
        initializeISA(env);
        CHECK_NULL_RETURN(isaCls, NULL);
    }

    isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
    if (isaa == NULL) {
        nio_sctp_freeladdrs(addr_buf);
        return NULL;
    }

    laddr = addr_buf;
    for (i=0; i<addrCount; i++) {
        int port = 0;
        jobject isa = NULL, ia;
        sap = (struct sockaddr*)addr_buf;
        ia = NET_SockaddrToInetAddress(env, sap, &port);
        if (ia != NULL)
            isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
        if (isa == NULL)
            break;
        (*env)->SetObjectArrayElement(env, isaa, i, isa);

        if (sap->sa_family == AF_INET)
            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
        else
            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
    }

    nio_sctp_freeladdrs(laddr);
    return isaa;
}

jobjectArray getRemoteAddresses
  (JNIEnv *env, jint fd, sctp_assoc_t id) {
    void *addr_buf, *paddr;
    struct sockaddr* sap;
    int i, addrCount;
    jobjectArray isaa;

#if __solaris__
    if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
#else /* __linux__ */
    if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) {
#endif
        handleSocketError(env, errno);
        return NULL;
    }

    if (addrCount < 1)
        return NULL;

    if (isaCls == 0) {
        initializeISA(env);
        CHECK_NULL_RETURN(isaCls, NULL);
    }

    isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
    if (isaa == NULL) {
        nio_sctp_freepaddrs(addr_buf);
        return NULL;
    }

    paddr = addr_buf;
    for (i=0; i<addrCount; i++) {
        jobject ia, isa = NULL;
        int port = 0;
        sap = (struct sockaddr*)addr_buf;
        ia = NET_SockaddrToInetAddress(env, sap, &port);
        if (ia != NULL)
            isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
        if (isa == NULL)
            break;
        (*env)->SetObjectArrayElement(env, isaa, i, isa);

        if (sap->sa_family == AF_INET)
            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
        else
            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
    }

    nio_sctp_freepaddrs(paddr);

    return isaa;
}

 /*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    getRemoteAddresses0
 * Signature: (II)[Ljava/net/SocketAddress;
 */
JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getRemoteAddresses0
  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
    return getRemoteAddresses(env, fd, assocId);
}

/* Map the Java level option to the native level */
int mapSocketOption
  (jint cmd, int *level, int *optname) {
    static struct {
        jint cmd;
        int level;
        int optname;
    } const opts[] = {
        { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS,   IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
        { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE,   IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
        { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
        { sun_nio_ch_sctp_SctpStdSocketOption_SCTP_NODELAY,             IPPROTO_SCTP, SCTP_NODELAY },
        { sun_nio_ch_sctp_SctpStdSocketOption_SO_SNDBUF,                SOL_SOCKET,   SO_SNDBUF },
        { sun_nio_ch_sctp_SctpStdSocketOption_SO_RCVBUF,                SOL_SOCKET,   SO_RCVBUF },
        { sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER,                SOL_SOCKET,   SO_LINGER } };

    int i;
    for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
        if (cmd == opts[i].cmd) {
            *level = opts[i].level;
            *optname = opts[i].optname;
            return 0;
        }
    }

    /* not found */
    return -1;
}

/*
 * Class:     sun_nio_ch_sctp_SctpNet
 * Method:    setIntOption0
 * Signature: (III)V
 */
JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setIntOption0
  (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
    int klevel, kopt;
    int result;
    struct linger linger;
    void *parg;
    int arglen;

    if (mapSocketOption(opt, &klevel, &kopt) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "Unsupported socket option");
        return;
    }

    if (opt == sun_nio_ch_sctp_SctpStdSocketOption_SO_LINGER) {
        parg = (void *)&linger;
        arglen = sizeof(linger);
        if (arg >= 0) {
            linger.l_onoff = 1;
            linger.l_linger = arg;
        } else {
            linger.l_onoff = 0;
            linger.l_linger = 0;
        }
    } else {
        parg = (void *)&arg;
        arglen = sizeof(arg);
    }

    if (NET_SetSockOpt(fd, klevel, kopt, parg, arglen) < 0) {
        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                     "sun_nio_ch_sctp_SctpNet.setIntOption0");
    }
}
JNIEXPORT jint JNICALL
Java_java_lang_UNIXProcess_forkAndExec(JNIEnv *env,
				       jobject process,
				       jobjectArray cmdarray,
				       jobjectArray envp,
                                       jstring path,
				       jobject stdin_fd,
				       jobject stdout_fd,
				       jobject stderr_fd)
{
    jstring str;
    int resultPid = -1;
    int fdin[2], fdout[2], fderr[2], k;
    char **cmdv, **envv;
    int cmdlen, envlen = 0;
    char fullpath[MAXPATHLEN+1];
    int i, j;
    char *cwd = NULL;
 

    if (initFieldIDs(env, process, stdin_fd) != 0)
	return -1;

    cmdlen = (*env)->GetArrayLength(env, cmdarray);
    if (cmdlen == 0) {
	JNU_ThrowIllegalArgumentException(env, NULL);
	return -1;
    }
    cmdv = (char **)malloc((cmdlen + 1) * sizeof(char *));
    if (cmdv == NULL) {
	JNU_ThrowOutOfMemoryError(env, 0);
	return -1;
    }
    cmdv[cmdlen] = NULL;
    for (i = 0; i < cmdlen; ++i) {
	str = (*env)->GetObjectArrayElement(env, cmdarray, i);
	if (str == 0) {
	    JNU_ThrowNullPointerException(env, NULL);
	    for (j = 0; j < i; ++j) free(cmdv[j]);
	    goto cleanup1;
	}
	cmdv[i] = (char *) JNU_GetStringPlatformChars(env, str, NULL);
	if (cmdv[i] == NULL) {
	    for (j = 0; j < i; ++j) free(cmdv[j]);
	    goto cleanup1;
	}
    }

    if (PATH == 0) {
	parsePath();
    }

    if (fullPath(env, cmdv[0], fullpath) == NULL) {
	/* fullPath has signalled an exception so we just return */
	free(cmdv[0]);
	goto cleanup2;
    }
    free(cmdv[0]);
    cmdv[0] = fullpath;

    if (0 != envp) {
	envlen = (*env)->GetArrayLength(env, envp);
    }
    envv = (char **)malloc((envlen+1) * sizeof(char *));
    if (envv == NULL) {
	JNU_ThrowOutOfMemoryError(env, 0);
	goto cleanup2;
    }
    envv[envlen] = NULL;
    if (envlen != 0) {
	for (i = 0; i < envlen; ++i) {
	    str = (*env)->GetObjectArrayElement(env, envp, i);
	    if (str == 0) {
		JNU_ThrowNullPointerException(env, NULL);
		for (j = 0; j < i; ++j) free(envv[j]);
		goto cleanup3;
	    }
	    envv[i] = (char *) JNU_GetStringPlatformChars(env, str, NULL);
	    if (envv[i] == NULL) {
		for (j = 0; j < i; ++j) free(envv[j]);
		goto cleanup3;
 	    }
	}
    }

    if ((k=0, pipe(fdin)<0) || (k=1, pipe(fdout)<0) || (k=2, pipe(fderr)<0)) {
	char errmsg[128];
        sprintf(errmsg, "errno: %d, error: %s\n", errno, "Bad file descriptor");
        JNU_ThrowIOExceptionWithLastError(env, errmsg);
	/* make sure we clean up */
	switch (k) {
	case 2:	close(fdout[0]);
		close(fdout[1]);
	case 1:	close(fdin[0]);
		close(fdin[1]);
	case 0: ;
	}
	goto cleanup4;
    }

    /*
     * Can't do this after the fork1 in child, because child can deadlock
     * on locks if they are held in parent
     */
    if (path != NULL) {
        cwd = (char *)JNU_GetStringPlatformChars(env, path, NULL);
    }
 
    resultPid = fork1();
    if (resultPid < 0) {
	char errmsg[128];
        sprintf(errmsg, "errno: %d, error: %s\n", errno, "Fork failed");
        JNU_ThrowIOExceptionWithLastError(env, errmsg);
	/* make sure we clean up our side of the pipes */
	close(fdin[1]);
	close(fdout[0]);
	close(fderr[0]);
	goto cleanup5;
    }

    if (resultPid == 0) {
	/* Child process */
	int i, max_fd;


	/* 0 open for reading, 1 open for writing */
	/* (Note: it is possible for fdin[0] == 0 - 4180429) */
	dup2(fdin[0], 0);
	dup2(fdout[1], 1);
	dup2(fderr[1], 2);

	/* Close pipe fds here since they don't always show up
	 * in /proc/<pid>/fd
	 */
	 if (fdin[0] > 2)
	     close(fdin[0]);
	 if (fdout[1] > 2)
	     close(fdout[1]);
	 if (fderr[1] > 2)
	     close(fderr[1]);

        /* close everything */
        if (closeDescriptors() == 0) { /* failed,  close the old way */
            max_fd = (int)sysconf(_SC_OPEN_MAX);
            for (i = 3; i < max_fd; i++) close(i);
        }

        /* change to the new cwd */
        if (cwd != NULL) {
            if (chdir(cwd) < 0) {
                /* failed to change directory, cleanup */
                char errmsg[128];
                sprintf(errmsg, "errno: %d, error: %s\n", errno, "Failed to change directory");
                JNU_ThrowByNameWithLastError(env, "java/io/IOException", errmsg);
                goto cleanup5;
            }
        }

#ifdef __solaris__
#define environ _environ
#endif
	if (0 != envp) {
	    /* So why isn't there an execvpe(), then? */
	    extern char **environ;
	    environ = envv;
	} 
	execvp(cmdv[0], cmdv);

	_exit(-1);
    }

    /* parent process */
    if (cwd != NULL)
        JNU_ReleaseStringPlatformChars(env, path, cwd);        
    (*env)->SetIntField(env, stdin_fd, field_fd, fdin[1]);
    (*env)->SetIntField(env, stdout_fd, field_fd, fdout[0]);
    (*env)->SetIntField(env, stderr_fd, field_fd, fderr[0]);

 cleanup5:
    /* clean up the child's side of the pipes */
    close(fdin[0]);
    close(fdout[1]);
    close(fderr[1]);
 cleanup4:
    for (j = 0; j < envlen; ++j) free(envv[j]);
 cleanup3:
    free(envv);
 cleanup2:
    for (j = 1; j < cmdlen; ++j) free(cmdv[j]);
 cleanup1:
    free(cmdv);

    return resultPid;
}