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 + -
显示快捷键?