plaindatagramsocketimpl_md.c

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

C
2,016
字号
    }#endif}/* * Returns relevant info as a jint. * * Class:     java_net_PlainDatagramSocketImpl * Method:    socketGetOption * Signature: (I)Ljava/lang/Object; */JNIEXPORT jobject JNICALLJava_java_net_PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,						      jint opt) {    int fd;    int level, optname, optlen;    union {        int i;	char c;    } optval;    fd = getFD(env, this);    if (fd < 0) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",			"socket closed");	return NULL;    }    /*     * Handle IP_MULTICAST_IF seperately     */    if (opt == java_net_SocketOptions_IP_MULTICAST_IF ||	opt == java_net_SocketOptions_IP_MULTICAST_IF2) {	return getMulticastInterface(env, this, fd, opt);    }    /*     * SO_BINDADDR implemented using getsockname     */    if (opt == java_net_SocketOptions_SO_BINDADDR) {	/* find out local IP address */	SOCKADDR him;	socklen_t len = 0;	int port;	jobject iaObj;	len = SOCKADDR_LEN;	if (getsockname(fd, (struct sockaddr *)&him, &len) == -1) {	    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                                         "Error getting socket name");	    return NULL;	}	iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&him, &port);	return iaObj;    }    /*     * Map the Java level socket option to the platform specific     * level and option name.     */    if (NET_MapSocketOption(opt, &level, &optname)) {        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");        return NULL;    }    /*     * IP_MULTICAST_LOOP socket option isn't available on Linux 2.2      * kernel with IPv6 so return value stored in impl.     */#if defined(AF_INET6) && defined(__linux__)     if (isOldKernel && opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&	level == IPPROTO_IPV6) {	int mode = (int)(*env)->GetBooleanField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_loopbackID));	return createBoolean(env, mode);    }#endif    if (opt == java_net_SocketOptions_IP_MULTICAST_LOOP &&	level == IPPROTO_IP) {	optlen = sizeof(optval.c);    } else {	optlen = sizeof(optval.i);    }    if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                          "Error getting socket option");        return NULL;    }    switch (opt) {	case java_net_SocketOptions_IP_MULTICAST_LOOP:	    /* getLoopbackMode() returns true if IP_MULTICAST_LOOP disabled */	    if (level == IPPROTO_IP) {		return createBoolean(env, (int)!optval.c);	    } else {		return createBoolean(env, !optval.i);	    }	case java_net_SocketOptions_SO_BROADCAST:	case java_net_SocketOptions_SO_REUSEADDR:	    return createBoolean(env, optval.i);	case java_net_SocketOptions_SO_SNDBUF: 	case java_net_SocketOptions_SO_RCVBUF:	case java_net_SocketOptions_IP_TOS:	    return createInteger(env, optval.i);    }    /* should never rearch here */    return NULL;}/* * Multicast-related calls */JNIEXPORT void JNICALLJava_java_net_PlainDatagramSocketImpl_setTTL(JNIEnv *env, jobject this,					     jbyte ttl) {    jint ittl = ttl;    if (ittl < 0) {        ittl += 0x100;    }    Java_java_net_PlainDatagramSocketImpl_setTimeToLive(env, this, (jint)ittl);}/* * Class:     java_net_PlainDatagramSocketImpl * Method:    setTTL * Signature: (B)V */JNIEXPORT void JNICALLJava_java_net_PlainDatagramSocketImpl_setTimeToLive(JNIEnv *env, jobject this,						    jint ttl) {    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_fdID));    int fd;    /* it is important to cast this to a char, otherwise setsockopt gets confused */    if (IS_NULL(fdObj)) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",			"Socket closed");	return;    } else {	fd = (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID));    }    /* setsockopt to be correct ttl */#ifdef AF_INET6    if (ipv6_available()) {	if (JVM_SetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,			   (char*)&ttl, sizeof(ttl)) < 0) {	    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                           "Error setting socket option");	    return;	}	if (isOldKernel) {	    (*env)->SetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_ttlID), ttl);	}    } else #endif /* AF_INET6 */	{	    if (JVM_SetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl,			       sizeof(ttl)) < 0) {		NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                               "Error setting socket option");	    }	}}/* * Class:     java_net_PlainDatagramSocketImpl * Method:    getTTL * Signature: ()B */JNIEXPORT jbyte JNICALLJava_java_net_PlainDatagramSocketImpl_getTTL(JNIEnv *env, jobject this) {    return (jbyte)Java_java_net_PlainDatagramSocketImpl_getTimeToLive(env, this);}/* * Class:     java_net_PlainDatagramSocketImpl * Method:    getTTL * Signature: ()B */JNIEXPORT jint JNICALLJava_java_net_PlainDatagramSocketImpl_getTimeToLive(JNIEnv *env, jobject this) {    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_fdID));    jint fd = -1;    if (IS_NULL(fdObj)) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",			"Socket closed");	return -1;    } else {	fd = (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID));    }    /* getsockopt of ttl */#ifdef AF_INET6    if (ipv6_available()) {	int ttl = 0;	int len = sizeof(ttl);	/*	 * Linux 2.2 kernel doesn't support IPV6_MULTICAST_HOPS socket option	 */	if (isOldKernel) {	    return (*env)->GetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_ttlID));	}	if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,			       (char*)&ttl, &len) < 0) {		NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                               "Error getting socket option");		return -1;	    }	return (jint)ttl;    } else #endif /* AF_INET6 */	{	    jint ttl = 0;	    int len = sizeof(ttl);	    if (JVM_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_TTL,			       (char*)&ttl, &len) < 0) {		NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",                               "Error getting socket option");		return -1;	    }	    return ttl;	}}/* * mcast_join_leave: Join or leave a multicast group. * * For IPv4 sockets use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option * to join/leave multicast group. * * For IPv6 sockets use IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP socket option * to join/leave multicast group. If multicast group is an IPv4 address then * an IPv4-mapped address is used. * * On Linux with IPv6 if we wish to join/leave an IPv4 multicast group then * we must use the IPv4 socket options. This is because the IPv6 socket options * don't support IPv4-mapped addresses. This is true as per 2.2.19 and 2.4.7 * kernel releases. In the future it's possible that IP_ADD_MEMBERSHIP  * will be updated to return ENOPROTOOPT if uses with an IPv6 socket (Solaris * already does this). Thus to cater for this we first try with the IPv4 * socket options and if they fail we use the IPv6 socket options. This * seems a reasonable failsafe solution. */static void mcast_join_leave(JNIEnv *env, jobject this,			     jobject iaObj, jobject niObj,			     jboolean join) {    jobject fdObj = (*env)->GetObjectField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_fdID));    jint fd;        jint ipv6_join_leave;    if (IS_NULL(fdObj)) {	JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",		        "Socket closed");        return;    } else {        fd = (*env)->GetIntField(env, fdObj, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, IO_fd_fdID));    }    if (IS_NULL(iaObj)) {        JNU_ThrowNullPointerException(env, "iaObj");        return;    }    /*     * Determine if this is an IPv4 or IPv6 join/leave.     */#ifdef AF_INET6     ipv6_join_leave = ipv6_available();#ifdef __linux__    if ((*env)->GetIntField(env, iaObj, JNI_STATIC(java_net_InetAddress, ia_familyID)) == IPv4) {	ipv6_join_leave = JNI_FALSE;    }#endif#else    /*     * IPv6 not compiled in     */    ipv6_join_leave = JNI_FALSE;#endif    /*     * For IPv4 join use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP socket option     *     * On Linux if IPv4 or IPv6 use IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP     */    if (!ipv6_join_leave) {#ifdef __linux__	struct ip_mreqn mname;#else	struct ip_mreq mname;#endif	int mname_len = 0;	/*   	 * joinGroup(InetAddress, NetworkInterface) implementation :-	 *	 * Linux/IPv6:	use ip_mreqn structure populated with multicast 	 *		address and interface index.	 *	 * IPv4:	use ip_mreq structure populated with multicast	 *		address and first address obtained from	 *		NetworkInterface	 */	if (niObj != NULL) {#if defined(__linux__) && defined(AF_INET6) 	    if (ipv6_available()) {		static jfieldID ni_indexID;                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);                }		mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, JNI_STATIC(java_net_InetAddress, ia_addressID)));		mname.imr_address.s_addr = 0;		mname.imr_ifindex =  (*env)->GetIntField(env, niObj, ni_indexID);		mname_len = sizeof(struct ip_mreqn);	    } else #endif	    {	        static jfieldID ni_addrsID;		jobjectArray addrArray;		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);	        }	    	        addrArray = (*env)->GetObjectField(env, niObj, ni_addrsID);		if ((*env)->GetArrayLength(env, addrArray) < 1) {		    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",                    	"bad argument for IP_ADD_MEMBERSHIP: "			"No IP addresses bound to interface");		    return;		}		addr = (*env)->GetObjectArrayElement(env, addrArray, 0);		mname.imr_multiaddr.s_addr = htonl((*env)->GetIntField(env, iaObj, JNI_STATIC(java_net_InetAddress, ia_addressID)));#ifdef __linux__                mname.imr_address.s_addr = htonl((*env)->GetIntField(env, addr, JNI_STATIC(java_net_InetAddress, ia_addressID)));#else		mname.imr_interface.s_addr = htonl((*env)->GetIntField(env, addr, JNI_STATIC(java_net_InetAddress, ia_addressID)));#endif		mname_len = sizeof(struct ip_mreq);	    }	}	/*         * joinGroup(InetAddress) implementation :-         *         * Linux/IPv6:  use ip_mreqn structure populated with multicast         *              address and interface index. index obtained	 *		from cached value or IPV6_MULTICAST_IF.         *         * IPv4:        use ip_mreq structure populated with multicast         *              address and local address obtained from         *              IP_MULTICAST_IF. On Linux IP_MULTICAST_IF	 *		returns different structure depending on 	 *		kernel.         */	if (niObj == NULL) {#if defined(__linux__) && defined(AF_INET6)	    if (ipv6_available()) {            	int index;            	int len = sizeof(index);            	if (isOldKernel) {                    index = (*env)->GetIntField(env, this, JNI_STATIC_MD(java_net_PlainDatagramSocketImpl, pdsi_multicastInterfaceID));                } else {                    if (JVM_GetSockOpt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,                                       (char*)&index, &len) < 0) {

⌨️ 快捷键说明

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