/* * 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; }
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; }
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); }
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; }
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; }
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"); } }
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; }
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 }
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"); } }
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"); } }
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; }
/* * 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"); } }
/* * 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); }
/* * 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); }
/* * 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; }
/* * 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; }