plaindatagramsocketimpl_md.c

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

C
2,016
字号
	fullPacket = &(BUF[0]);    }    /*     * On Linux with the 2.2 kernel we simulate connected datagrams by     * discarding packets     */    if (isOldKernel) {        connected = (*env)->GetBooleanField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_connected));        if (connected) {            connectedAddress = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_connectedAddress));            connectedPort = (*env)->GetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_connectedPort));	    if (timeout) {		prevTime = JVM_CurrentTimeMillis(env, 0);	    }        }    }    do {	retry = JNI_FALSE;	if (timeout) {            int ret = NET_Timeout(fd, timeout);            if (ret <= 0) {                if (ret == 0) {                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",                                    "Receive timed out");                } else if (ret == JVM_IO_ERR) {                    if (errno == EBADF) {                         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");                     } else {                         NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");                     }                } else if (ret == JVM_IO_INTR) {                    JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",                                    "operation interrupted");                }                if (mallocedPacket) {                    free(fullPacket);                }                return;            }        }	/*	 * Security Note: For Linux 2.2 with connected datagrams ensure that 	 * you receive into the stack/heap allocated buffer - do not attempt	 * to receive directly into DatagramPacket's byte array.	 * (ie: if the virtual machine support pinning don't use 	 * GetByteArrayElements or a JNI critical section and receive	 * directly into the byte array)	 */        len = SOCKADDR_LEN;        n = NET_RecvFrom(fd, fullPacket, packetBufferLen, 0,                         (struct sockaddr *)&remote_addr, &len);        /* truncate the data if the packet's length is too small */        if (n > packetBufferLen) {            n = packetBufferLen;        }        if (n == JVM_IO_ERR) {            if (errno == ECONNREFUSED) {                JNU_ThrowByName(env, JNU_JAVANETPKG "PortUnreachableException",                                "ICMP Port Unreachable");            } else {                if (errno == EBADF) {                      JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");                 } else {                     NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Receive failed");                 }            }            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_offsetID), 0);            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_lengthID), 0);        } else if (n == JVM_IO_INTR) {            JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",                            "operation interrupted");            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_offsetID), 0);            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_lengthID), 0);        } else {            int port;            jobject packetAddress;            /*             * If we are connected then we know that the datagram that we have             * received is from the address that we are connected too. However             * on Linux with 2.2 kernel we have to simulate this behaviour by             * discarding any datagrams that aren't from the connected address.             */            if (isOldKernel && connected) {                if (NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr) != connectedPort ||                    !NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, connectedAddress)) {                    /*                     * Discard the datagram as it's not from the connected                     * address                     */                    retry = JNI_TRUE;                    /*                     * Adjust timeout if necessary to ensure that we adhere to                     * timeout semantics.                     */                    if (timeout) {                        jlong newTime = JVM_CurrentTimeMillis(env, 0);                        timeout -= (newTime - prevTime);                        if (timeout <= 0) {                            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",                                    "Receive timed out");                            if (mallocedPacket) {                                free(fullPacket);                            }                            return;			}			prevTime = newTime;                    }                    continue;                }            }            /*             * success - fill in received address...             *             * REMIND: Fill in an int on the packet, and create inetadd             * object in Java, as a performance improvement. Also             * construct the inetadd object lazily.             */            /*             * Check if there is an InetAddress already associated with this             * packet. If so we check if it is the same source address. We             * can't update any existing InetAddress because it is immutable             */            packetAddress = (*env)->GetObjectField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_addressID));            if (packetAddress != NULL) {                if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&remote_addr, packetAddress)) {                    /* force a new InetAddress to be created */                    packetAddress = NULL;                }            }            if (packetAddress == NULL) {                packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&remote_addr, &port);                /* stuff the new Inetaddress in the packet */                (*env)->SetObjectField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_addressID), packetAddress);            } else {                /* only get the new port number */                port = NET_GetPortFromSockaddr((struct sockaddr *)&remote_addr);            }            /* and fill in the data, remote address/port and such */            (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,                                       (jbyte *)fullPacket);            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_portID), port);            (*env)->SetIntField(env, packet, JNI_STATIC(java_net_DatagramPacket, dp_lengthID), n);        }    } while (retry);    if (mallocedPacket) {	free(fullPacket);    }}/* * Class:     java_net_PlainDatagramSocketImpl * Method:    datagramSocketCreate * Signature: ()V */JNIEXPORT void JNICALLJava_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,							   jobject this) {    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_fdID));    int fd;    int t = 1;    if (IS_NULL(fdObj)) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",			"Socket closed");	return;    } else {#ifdef AF_INET6	if (ipv6_available()) {		    fd =  JVM_Socket(AF_INET6, SOCK_DGRAM, 0);	} else #endif /* AF_INET6 */	    {		fd =  JVM_Socket(AF_INET, SOCK_DGRAM, 0);	    }    }    if (fd == JVM_IO_ERR) {	NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                                     "Error creating socket");	return;    }    setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));    if (isOldKernel) {        setsockopt(fd, SOL_SOCKET, SO_BSDCOMPAT, (char*) &t, sizeof(int));     }#ifdef AF_INET6    /*     * On Linux for IPv6 sockets we must set the hop limit     * to 1 to be compatible with default ttl of 1 for IPv4 sockets.     */    if (ipv6_available()) {        int ttl = 1;	setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, 		   sizeof(ttl));	if (isOldKernel) {            (*env)->SetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_ttlID), ttl);        }    }#endif      (*env)->SetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID), fd);}/* * Class:     java_net_PlainDatagramSocketImpl * Method:    datagramSocketClose * Signature: ()V */JNIEXPORT void JNICALLJava_java_net_PlainDatagramSocketImpl_datagramSocketClose(JNIEnv *env,							  jobject this) {    /*     * REMIND: PUT A LOCK AROUND THIS CODE     */    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_fdID));    int fd;    if (IS_NULL(fdObj)) {	return;    }    fd = (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID));    if (fd == -1) {	return;    }    (*env)->SetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID), -1);    NET_SocketClose(fd);}/* * Sets the multicast interface.  * * SocketOptions.IP_MULTICAST_IF :- *	value is a InetAddress *	IPv4:	set outgoing multicast interface using  * 		IPPROTO_IP/IP_MULTICAST_IF *	IPv6:	Get the index of the interface to which the *		InetAddress is bound *		Set outgoing multicast interface using *		IPPROTO_IPV6/IPV6_MULTICAST_IF *		On Linux 2.2 record interface index as can't *		query the multicast interface. * * SockOptions.IF_MULTICAST_IF2 :- *	value is a NetworkInterface  *	IPv4:	Obtain IP address bound to network interface *		(NetworkInterface.addres[0]) *		set outgoing multicast interface using  *              IPPROTO_IP/IP_MULTICAST_IF *	IPv6:	Obtain NetworkInterface.index *		Set outgoing multicast interface using *              IPPROTO_IPV6/IPV6_MULTICAST_IF *              On Linux 2.2 record interface index as can't *              query the multicast interface.  * */static void setMulticastInterface(JNIEnv *env, jobject this, int fd,				  jint opt, jobject value){    if (opt == java_net_SocketOptions_IP_MULTICAST_IF) {	/*  	 * value is an InetAddress.	 * On IPv4 system use IP_MULTICAST_IF socket option	 * On IPv6 system get the NetworkInterface that this IP	 * address is bound too and use the IPV6_MULTICAST_IF 	 * option instead of IP_MULTICAST_IF	 */#ifdef AF_INET6	if (ipv6_available()) {	    static jclass ni_class;	    if (ni_class == NULL) { 		jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");		CHECK_NULL(c);		ni_class = (*env)->NewGlobalRef(env, c);		CHECK_NULL(ni_class);	    }	    value = Java_java_net_NetworkInterface_getByInetAddress0(env, ni_class, value);	    if (value == NULL) {		if (!(*env)->ExceptionOccurred(env)) {		    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",	                 "bad argument for IP_MULTICAST_IF"			 ": address not bound to any interface");		}		return;	    }	    opt = java_net_SocketOptions_IP_MULTICAST_IF2;	} else#endif /* AF_INET6 */	{	    static jfieldID ia_addressID;	    struct in_addr in;	    if (ia_addressID == NULL) {		jclass c = (*env)->FindClass(env,"java/net/InetAddress");		CHECK_NULL(c);		ia_addressID = (*env)->GetFieldID(env, c, "address", "I");		CHECK_NULL(ia_addressID);	    }	                in.s_addr = htonl( (*env)->GetIntField(env, value, ia_addressID) );            if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,                               (const char*)&in, sizeof(in)) < 0) {                NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                                 "Error setting socket option");	    }	    return;	}    }    if (opt == java_net_SocketOptions_IP_MULTICAST_IF2) {	/*	 * value is a NetworkInterface.	 * On IPv6 system get the index of the interface and use the         * IPV6_MULTICAST_IF socket option	 * On IPv4 system extract addr[0] and use the IP_MULTICAST_IF         * option.	 */#ifdef AF_INET6        if (ipv6_available()) {	    static jfieldID ni_indexID;	    int index;	    if (ni_indexID == NULL) {		jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");		CHECK_NULL(c);		ni_indexID = (*env)->GetFieldID(env, c, "index", "I");		CHECK_NULL(ni_indexID);	    }            index = (*env)->GetIntField(env, value, ni_indexID);            if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,			       (const char*)&index, sizeof(index)) < 0) {		if (errno == EINVAL && index > 0) {		    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",			"IPV6_MULTICAST_IF failed (interface has IPv4 "			"address only?)");		} else {	            NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                                   "Error setting socket option");	  	}		return;	    }	    /*	     * Linux 2.2 kernel doesn't support IPV6_MULTICAST_IF socket	     * option so record index for later retrival.	     */	    if (isOldKernel) {	        (*env)->SetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_multicastInterfaceID), (jint)index);	    }	    return;        } else#endif /* AF_INET6 */        {	    static jfieldID ni_addrsID;	    static jfieldID ia_addressID;	    struct in_addr in;	    jobjectArray addrArray;	    jsize len;	    jobject addr;	    if (ni_addrsID == NULL) {		jclass c = (*env)->FindClass(env, "java/net/NetworkInterface");		CHECK_NULL(c);		ni_addrsID = (*env)->GetFieldID(env, c, "addrs", 						"[Ljava/net/InetAddress;");		CHECK_NULL(ni_addrsID);	 	c = (*env)->FindClass(env,"java/net/InetAddress");	        CHECK_NULL(c);                ia_addressID = (*env)->GetFieldID(env, c, "address", "I");		CHECK_NULL(ia_addressID);	    }	    addrArray = (*env)->GetObjectField(env, value, ni_addrsID);	    len = (*env)->GetArrayLength(env, addrArray);	    /* 	     * Check that there is at least one address bound to this	     * interface.	     */	    if (len < 1) {		JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",		    "bad argument for IP_MULTICAST_IF2: No IP addresses bound to interface");

⌨️ 快捷键说明

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