plainsocketimpl_md.c

来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,134 行 · 第 1/3 页

C
1,134
字号
/* * @(#)PlainSocketImpl_md.c	1.17 06/10/13 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved.   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER   *    * This program is free software; you can redistribute it and/or   * modify it under the terms of the GNU General Public License version   * 2 only, as published by the Free Software Foundation.    *    * This program is distributed in the hope that it will be useful, but   * WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU   * General Public License version 2 for more details (a copy is   * included at /legal/license.txt).    *    * You should have received a copy of the GNU General Public License   * version 2 along with this work; if not, write to the Free Software   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   * 02110-1301 USA    *    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa   * Clara, CA 95054 or visit www.sun.com if you need additional   * information or have any questions.  * */#include <errno.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#if defined(__linux__) && !defined(USE_SELECT)#include <sys/poll.h>#endif#include <netinet/tcp.h>	/* Defines TCP_NODELAY, needed for 2.6 */#include <netinet/in.h>#ifdef __linux__#include <netinet/ip.h>#endif#include <netdb.h>#include <stdlib.h>#ifndef __linux__#include <sys/filio.h>          /* for FIONBIO */#endif#include "jvm.h"#include "jni_util.h"#include "net_util.h"#include "java_net_SocketOptions.h"#include "java_net_PlainSocketImpl.h"/************************************************************************ * PlainSocketImpl */#include "jni_statics.h"/* * file descriptor used for dup2 */static int marker_fd = -1;#define SET_NONBLOCKING(fd) {		\        int flags = fcntl(fd, F_GETFL);	\        flags |= O_NONBLOCK; 		\        fcntl(fd, F_SETFL, flags);	\}#define SET_BLOCKING(fd) {		\        int flags = fcntl(fd, F_GETFL); \	flags &= ~O_NONBLOCK;		\        fcntl(fd, F_SETFL, flags);      \}/* NOTE: Retained in CDC for J2SE compatibility reference */static const int max_buffer_size = 64 * 1024;/* * Create the marker file descriptor by establishing a loopback connection  * which we shutdown but do not close the fd. The result is an fd that * can be used for read/write. */static int getMarkerFD() {    int server_fd, child_fd, connect_fd;    SOCKADDR him;    int type, len, port;    type = AF_INET;#ifdef AF_INET6    if (ipv6_available()) {	type = AF_INET6;    }#endif    /*     * Create listener on any port      */    server_fd = JVM_Socket(type, SOCK_STREAM, 0);    if (server_fd < 0) {	return -1;    }    if (JVM_Listen(server_fd, 1) == -1) {        JVM_SocketClose(server_fd);	return -1;    }    len = SOCKADDR_LEN;    if (JVM_GetSockName(server_fd, (struct sockaddr *)&him, &len) == -1) {        JVM_SocketClose(server_fd);	return -1;    }    port = NET_GetPortFromSockaddr((struct sockaddr *)&him);    /*      * Establish connection from client socket.     * Server is bound to 0.0.0.0/X or ::/X      * We connect to 127.0.0.1/X or ::1/X     */#ifdef AF_INET6    if (ipv6_available()) {	struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)&him;	jbyte caddr[16];	memset((char *) caddr, 0, 16);	caddr[15] = 1;	memset((char *)him6, 0, sizeof(struct sockaddr_in6));	memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );	him6->sin6_port = htons((short) port);	him6->sin6_family = AF_INET6; 	len = sizeof(struct sockaddr_in6) ;    } else #endif /* AF_INET6 */      {	struct sockaddr_in *him4 = (struct sockaddr_in*)&him;	memset((char *) him4, 0, sizeof(struct sockaddr_in));	him4->sin_port = htons((short) port);	him4->sin_addr.s_addr = (uint32_t) htonl(0x7f000001);	him4->sin_family = AF_INET;	len = sizeof(struct sockaddr_in);    }    connect_fd = JVM_Socket(type, SOCK_STREAM, 0);    if (connect_fd < 0) {	JVM_SocketClose(server_fd);	return -1;    }        if (JVM_Connect(connect_fd, (struct sockaddr *) &him, len) == -1) {        JVM_SocketClose(server_fd);        JVM_SocketClose(connect_fd);	return -1;    }    /*     * Server accepts connection - do in in non-blocking mode to avoid     * hanging if there's an error (should never happen!!!)     */    SET_NONBLOCKING(server_fd);    len = SOCKADDR_LEN;    child_fd = JVM_Accept(server_fd, (struct sockaddr *)&him, (jint *)&len);    if (child_fd == -1) {        JVM_SocketClose(server_fd);        JVM_SocketClose(connect_fd);	return -1;    }    /*     * Finally shutdown connect_fd (any reads to this fd will get     * EOF; any writes will get an error).     */    JVM_SocketShutdown(connect_fd, 2);    JVM_SocketClose(child_fd);    JVM_SocketClose(server_fd);    return connect_fd;}/* * Return the file descriptor given a PlainSocketImpl */static int getFD(JNIEnv *env, jobject this) {    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdID));    CHECK_NULL_RETURN(fdObj, -1);    return (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainSocketImpl, IO_fd_fdID));}/* * The initroto function is called whenever PlainSocketImpl is * loaded, to cache fieldIds for efficiency. This is called everytime * the Java class is loaded. * * Class:     java_net_PlainSocketImpl * Method:    initProto * Signature: ()V */JNIEXPORT void JNICALLJava_java_net_PlainSocketImpl_initProto(JNIEnv *env, jclass cls) {    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdID) 	= (*env)->GetFieldID(env, cls , "fd", "Ljava/io/FileDescriptor;");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_addressID) 	= (*env)->GetFieldID(env, cls, "address", "Ljava/net/InetAddress;");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_addressID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_portID) 	= (*env)->GetFieldID(env, cls, "port", "I");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_portID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_localportID) 	= (*env)->GetFieldID(env, cls, "localport", "I");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_localportID) );    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_timeoutID) 	= (*env)->GetFieldID(env, cls, "timeout", "I");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_timeoutID));        JNI_STATIC_MD(java_net_PlainSocketImpl, psi_trafficClassID) =         (*env)->GetFieldID(env, cls, "trafficClass", "I");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_trafficClassID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_serverSocketID) =         (*env)->GetFieldID(env, cls, "serverSocket", "Ljava/net/ServerSocket;");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_serverSocketID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdLockID) =         (*env)->GetFieldID(env, cls, "fdLock", "Ljava/lang/Object;");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdLockID));    JNI_STATIC_MD(java_net_PlainSocketImpl, psi_closePendingID) =         (*env)->GetFieldID(env, cls, "closePending", "Z");    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, psi_closePendingID));    JNI_STATIC_MD(java_net_PlainSocketImpl, IO_fd_fdID) 	= NET_GetFileDescriptorID(env);    CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, IO_fd_fdID));    /* Create the marker fd used for dup2 */    marker_fd = getMarkerFD();    init_IPv6Available(env);}/* a global reference to the java.net.SocketException class. In * socketCreate, we ensure that this is initialized. This is to * prevent the problem where socketCreate runs out of file * descriptors, and is then unable to load the exception class. *//*  static jclass socketExceptionCls; *//* * Class:     java_net_PlainSocketImpl * Method:    socketCreate * Signature: (Z)V */JNIEXPORT void JNICALLJava_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,					   jboolean stream) {    jobject fdObj, ssObj;    int fd;    if (JNI_STATIC_MD(java_net_PlainSocketImpl, socketExceptionCls) == NULL) {	jclass c = (*env)->FindClass(env, "java/net/SocketException");	JNI_STATIC_MD(java_net_PlainSocketImpl, socketExceptionCls)	    = (jclass)(*env)->NewGlobalRef(env, c);	CHECK_NULL(JNI_STATIC_MD(java_net_PlainSocketImpl, socketExceptionCls));    }    fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdID));    if (fdObj == NULL) {	(*env)->ThrowNew(env, JNI_STATIC_MD(java_net_PlainSocketImpl, socketExceptionCls), "null fd object");	return;    }#ifdef AF_INET6    if (ipv6_available()) {	fd = JVM_Socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);    } else#endif /* AF_INET6 */	{	    fd = JVM_Socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);	}    if (fd == JVM_IO_ERR) {	/* note: if you run out of fds, you may not be able to load	 * the exception class, and get a NoClassDefFoundError	 * instead.	 */	(*env)->ThrowNew(env, JNI_STATIC_MD(java_net_PlainSocketImpl, socketExceptionCls), strerror(errno));	return;    } else {	(*env)->SetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainSocketImpl, IO_fd_fdID), fd);    }    /*     * If this is a server socket then enable SO_REUSEADDR     * automatically     */    ssObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_serverSocketID));    if (ssObj != NULL) {	int arg = 1;        JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));    }}/* * inetAddress is the address object passed to the socket connect * call. * * Class:     java_net_PlainSocketImpl * Method:    socketConnect * Signature: (Ljava/net/InetAddress;I)V */JNIEXPORT void JNICALLJava_java_net_PlainSocketImpl_socketConnect(JNIEnv *env, jobject this,					    jobject iaObj, jint port,					    jint timeout){    jint localport = (*env)->GetIntField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_localportID));    int len = 0;    /* fdObj is the FileDescriptor field on this */    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_fdID));    jobject fdLock;    jint trafficClass = (*env)->GetIntField(env, this, JNI_STATIC_MD(java_net_PlainSocketImpl, psi_trafficClassID));    /* fd is an int field on iaObj */    jint fd;    SOCKADDR him;    /* The result of the connection */    int connect_rv = -1;    if (IS_NULL(fdObj)) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");	return;    } else {	fd = (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainSocketImpl, IO_fd_fdID));    }    if (IS_NULL(iaObj)) {	JNU_ThrowNullPointerException(env, "inet address argument null.");	return;    }    /* connect */    NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&him, &len);#ifdef AF_INET6    if (trafficClass != 0 && ipv6_available()) {	NET_SetTrafficClass((struct sockaddr *)&him, trafficClass);    }#endif /* AF_INET6 */    if (timeout <= 0) {	connect_rv = NET_Connect(fd, (struct sockaddr *)&him, len);    } else {	/* 	 * A timeout was specified. We put the socket into non-blocking	 * mode, connect, and then wait for the connection to be 	 * established, fail, or timeout.	 */	SET_NONBLOCKING(fd);	/* no need to use NET_Connect as non-blocking */	connect_rv = connect(fd, (struct sockaddr *)&him, len);	/* connection not established immediately */	if (connect_rv != 0) {	    int optlen;	    jlong prevTime = JVM_CurrentTimeMillis(env, 0);            if (errno != EINPROGRESS) {	        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",                                              "connect failed");		SET_BLOCKING(fd);	        return;	    }	    /*             * Wait for the connection to be established or a             * timeout occurs. poll/select needs to handle EINTR in	     * case lwp sig handler redirects any process signals to	     * this thread.             */	    while (1) {		jlong newTime;#ifndef USE_SELECT    	        {		    struct pollfd pfd;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?