icmpsocket.c

来自「opennms得相关源码 请大家看看」· C语言 代码 · 共 1,026 行 · 第 1/2 页

C
1,026
字号
	 */	addrArrayMethodID = (*env)->GetMethodID(env,						addrClass,						"getAddress",						"()[B");	if(addrArrayMethodID == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_inet;	addrData = (*env)->CallObjectMethod(env,instance,addrArrayMethodID);	if(addrData == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_inet;	(*env)->GetByteArrayRegion(env,				   addrData,				   0,				   4,				   (jbyte *)&retAddr);	(*env)->DeleteLocalRef(env, addrClass);	(*env)->DeleteLocalRef(env, addrData);end_inet:	return retAddr;}/* * Class:     org_opennms_protocols_icmp_IcmpSocket * Method:    initSocket * Signature: ()V */JNIEXPORT void JNICALLJava_org_opennms_protocols_icmp_IcmpSocket_initSocket (JNIEnv *env, jobject instance){	int icmp_fd = openIcmpSocket();	if(icmp_fd < 0)	{		char	errBuf[128];	/* for exceptions */		int	savedErrno  = errno;		jclass  ioException = (*env)->FindClass(env, "java/net/SocketException");		if(ioException != NULL)		{			sprintf(errBuf, "System error creating ICMP socket (%d, %s)", savedErrno, strerror(savedErrno));			(*env)->ThrowNew(env, ioException, (char *)errBuf);		}	}	else	{		setIcmpFd(env, instance, icmp_fd);	}	return;}	/* * Class:     org_opennms_protocols_icmp_IcmpSocket * Method:    receive * Signature: ()Ljava/net/DatagramPacket; */JNIEXPORT jobject JNICALLJava_org_opennms_protocols_icmp_IcmpSocket_receive (JNIEnv *env, jobject instance){	struct sockaddr_in	inAddr;	socklen_t		inAddrLen;	int			iRC;	void *			inBuf = NULL;	iphdr_t *		ipHdr = NULL;	icmphdr_t *		icmpHdr = NULL;	jbyteArray		byteArray 	= NULL;	jobject			addrInstance 	= NULL;	jobject			datagramInstance = NULL;	jclass			datagramClass 	= NULL;	jmethodID		datagramCtorID 	= NULL;	/**	 * Get the current descriptor's value	 */	jint fd_value = getIcmpFd(env, instance);	if((*env)->ExceptionOccurred(env) != NULL)	{		goto end_recv; /* jump to end if necessary */	}	else if(fd_value < 0)	{		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");		(*env)->ThrowNew(env, ioEx, "Invalid Socket Descriptor");		goto end_recv;	}		/**	 * Allocate a buffer to receive data if necessary.	 * This is probably more than necessary, but we don't	 * want to lose messages if we don't need to. This also	 * must be dynamic for MT-Safe reasons and avoids blowing	 * up the stack.	 */	inBuf = malloc(512);	if(inBuf == NULL)	{		jclass noMem = (*env)->FindClass(env, "java/lang/OutOfMemoryError");		(*env)->ThrowNew(env, noMem, "Failed to allocate memory to receive icmp datagram");		goto end_recv;	}	/**	 * Clear out the address structures where the	 * operating system will store the to/from address	 * information.	 */	memset((void *)&inAddr, 0, sizeof(inAddr));	inAddrLen = sizeof(inAddr);	/**	 * Receive the data from the operating system. This	 * will also include the IP header that preceeds	 * the ICMP data, we'll strip that off later.	 */	iRC = recvfrom((int)fd_value,		       inBuf,		       512,		       0,		       (struct sockaddr *)&inAddr,		       &inAddrLen);	if(iRC < 0)	{		/*		 * Error reading the information from the socket		 */		char errBuf[256];		int savedErrno = errno;		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");		sprintf(errBuf, "Error reading data from the socket descriptor (%d, %s)", savedErrno, strerror(savedErrno));		(*env)->ThrowNew(env, ioEx, (char *)errBuf);		goto end_recv;	}	else if(iRC == 0)	{		/*		 * Error reading the information from the socket		 */		jclass ioEx = (*env)->FindClass(env, "java/io/EOFException");		(*env)->ThrowNew(env, ioEx, "End-Of-File returned from socket descriptor");		goto end_recv;	}	/**	 * update the length by removing the IP	 * header from the message. Don't forget to decrement	 * the bytes received by the size of the IP header.	 *	 * NOTE: The ihl field of the IP header is the number	 * of 4 byte values in the header. Thus the ihl must	 * be multiplied by 4 (or shifted 2 bits).	 */	ipHdr = (iphdr_t *)inBuf;	iRC -= ipHdr->ihl << 2;	if(iRC <= 0)	{		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");		(*env)->ThrowNew(env, ioEx, "Malformed ICMP datagram received");		goto end_recv;	}	icmpHdr = (icmphdr_t *)((char *)inBuf + (ipHdr->ihl << 2));	/**	 * Check the ICMP header for type equal 0, which is ECHO_REPLY, and	 * then check the payload for the 'OpenNMS!' marker. If it's one	 * we sent out then fix the recv time!	 *	 * Don't forget to check for a buffer overflow!	 */#if defined(__SOLARIS__) || defined(__DARWIN__) || defined(__FreeBSD__)	if(iRC >= (OPENNMS_TAG_OFFSET + OPENNMS_TAG_LEN)	   && icmpHdr->icmp_type == 0	   && memcmp((char *)icmpHdr + OPENNMS_TAG_OFFSET, OPENNMS_TAG, OPENNMS_TAG_LEN) == 0)#else	if(iRC >= (OPENNMS_TAG_OFFSET + OPENNMS_TAG_LEN)	   && icmpHdr->type == 0	   && memcmp((char *)icmpHdr + OPENNMS_TAG_OFFSET, OPENNMS_TAG, OPENNMS_TAG_LEN) == 0)#endif	{		uint64_t now;		uint64_t sent;		uint64_t diff;		/**		 * get the current time in microseconds and then		 * compute the difference		 */		CURRENTTIMEMICROS(now);		memcpy((char *)&sent, (char *)icmpHdr + SENTTIME_OFFSET, TIME_LENGTH);		sent = ntohll(sent);		diff = now - sent;		/*		 * Now fill in the sent, received, and diff		 */		sent = MICROS_TO_MILLIS(sent);		sent = htonll(sent);		memcpy((char *)icmpHdr + SENTTIME_OFFSET, (char *)&sent, TIME_LENGTH);		now  = MICROS_TO_MILLIS(now);		now  = htonll(now);		memcpy((char *)icmpHdr + RECVTIME_OFFSET, (char *)&now, TIME_LENGTH);		diff = htonll(diff);		memcpy((char *)icmpHdr + RTT_OFFSET, (char *)&diff, TIME_LENGTH);		/* no need to recompute checksum on this on		 * since we don't actually check it upon receipt		 */	}	/**	 * Now construct a new java.net.InetAddress object from	 * the recipt information. The network address must	 * be passed in network byte order!	 */	addrInstance = newInetAddress(env, (unsigned long)ntohl(inAddr.sin_addr.s_addr));	if(addrInstance == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_recv;	/**	 * Get the byte array needed to setup	 * the datagram constructor.	 */	byteArray = (*env)->NewByteArray(env, (jsize)iRC);	if(byteArray != NULL && (*env)->ExceptionOccurred(env) == NULL)	{		(*env)->SetByteArrayRegion(env,					   byteArray,					   0,					   (jsize)iRC,					   (jbyte *)icmpHdr);	}	if((*env)->ExceptionOccurred(env) != NULL)		goto end_recv;	/**	 * get the datagram class	 */	datagramClass = (*env)->FindClass(env, "java/net/DatagramPacket");	if(datagramClass == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_recv;	/**	 * datagram constructor identifier	 */	datagramCtorID = (*env)->GetMethodID(env,					     datagramClass,					     "<init>",					     "([BILjava/net/InetAddress;I)V");	if(datagramCtorID == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_recv;	/*	 * new one!	 */	datagramInstance = (*env)->NewObject(env,					     datagramClass,					     datagramCtorID,					     byteArray,					     (jint)iRC,					     addrInstance,					     (jint)0);	/**	 * they will be deleted anyway, 	 * but we're just speeding up the process.	 */	(*env)->DeleteLocalRef(env, addrInstance);	(*env)->DeleteLocalRef(env, byteArray);	(*env)->DeleteLocalRef(env, datagramClass);end_recv:	if(inBuf != NULL)		free(inBuf);	return datagramInstance;}/* * Class:     org_opennms_protocols_icmp_IcmpSocket * Method:    send * Signature: (Ljava/net/DatagramPacket;)V */JNIEXPORT void JNICALLJava_org_opennms_protocols_icmp_IcmpSocket_send (JNIEnv *env, jobject instance, jobject packet){	jclass		dgramClass;	jmethodID	dgramGetDataID;	jmethodID	dgramGetAddrID;	jobject		addrInstance;	jbyteArray	icmpDataArray;	unsigned long	netAddr   = 0UL;	char *		outBuffer = NULL;	jsize		bufferLen = 0;	int		iRC;	struct sockaddr_in Addr;	/**	 * Recover the operating system file descriptor	 * so that we can use it in the sendto function.	 */	jint icmpfd = getIcmpFd(env, instance);	/**	 * Check for exception	 */	if((*env)->ExceptionOccurred(env) != NULL)		goto end_send;	/**	 * check the descriptor	 */	if(icmpfd < 0)	{		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");		(*env)->ThrowNew(env, ioEx, "Invalid File Descriptor");		goto end_send;	}	/**	 * get the DatagramPacket class information	 */	dgramClass = (*env)->GetObjectClass(env, packet);	if(dgramClass == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_send;	/**	 * Get the identifiers for the getData() and getAddress()	 * methods that are part of the DatagramPacket class.	 */	dgramGetDataID = (*env)->GetMethodID(env, dgramClass, "getData", "()[B");	if(dgramGetDataID == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_send;	dgramGetAddrID = (*env)->GetMethodID(env, dgramClass, "getAddress", "()Ljava/net/InetAddress;");	if(dgramGetAddrID == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_send;	(*env)->DeleteLocalRef(env, dgramClass);	dgramClass = NULL;	/**	 * Get the address information from the DatagramPacket	 * so that a useable Operating System address can	 * be constructed.	 */	addrInstance = (*env)->CallObjectMethod(env, packet, dgramGetAddrID);	if(addrInstance == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_send;	netAddr = getInetAddress(env, addrInstance);	if((*env)->ExceptionOccurred(env) != NULL)		goto end_send;	/**	 * Remove local references that are no longer needed	 */	(*env)->DeleteLocalRef(env, addrInstance);	addrInstance = NULL;	/**	 * Get the byte[] data from the DatagramPacket	 * and then free up the local reference to the	 * method id of the getData() method.	 */	icmpDataArray = (*env)->CallObjectMethod(env, packet, dgramGetDataID);	if(icmpDataArray == NULL || (*env)->ExceptionOccurred(env) != NULL)		goto end_send;	/**	 * Get the length of the buffer so that	 * a suitable 'char *' buffer can be allocated	 * and used with the sendto() function.	 */	bufferLen = (*env)->GetArrayLength(env, icmpDataArray);	if(bufferLen <= 0)	{		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");		(*env)->ThrowNew(env, ioEx, "Insufficent data");		goto end_send;	}	/**	 * Allocate the buffer where the java byte[] information	 * is to be transfered to.	 */	outBuffer = malloc((size_t)bufferLen);	if(outBuffer == NULL)	{		char buf[128]; /* error condition: java.lang.OutOfMemoryError! */		int serror = errno;		jclass memEx = (*env)->FindClass(env, "java/lang/OutOfMemoryError");				sprintf(buf, "Insufficent Memory (%d, %s)", serror, strerror(serror));		(*env)->ThrowNew(env, memEx, (const char *)buf);		goto end_send;	}	/**	 * Copy the contents of the packet's byte[] array	 * into the newly allocated buffer.	 */	(*env)->GetByteArrayRegion(env,				   icmpDataArray,				   0,				   bufferLen,				   (jbyte *)outBuffer);	if((*env)->ExceptionOccurred(env) != NULL)		goto end_send;	(*env)->DeleteLocalRef(env, icmpDataArray);	/**	 * Check for 'OpenNMS!' at byte offset 32. If	 * it's found then we need to modify the time	 * and checksum for transmission. ICMP type	 * must equal 8 for ECHO_REQUEST	 *	 * Don't forget to check for a potential buffer	 * overflow!	 */#if defined(__SOLARIS__) || defined(__DARWIN__) || defined(__FreeBSD__)	if(bufferLen >= (OPENNMS_TAG_OFFSET + OPENNMS_TAG_LEN)	   && ((icmphdr_t *)outBuffer)->icmp_type == 0x08	   && memcmp((char *)outBuffer + OPENNMS_TAG_OFFSET, OPENNMS_TAG, OPENNMS_TAG_LEN) == 0)#else	if(bufferLen >= (OPENNMS_TAG_OFFSET + OPENNMS_TAG_LEN)	   && ((icmphdr_t *)outBuffer)->type == 0x08	   && memcmp((char *)outBuffer + OPENNMS_TAG_OFFSET, OPENNMS_TAG, OPENNMS_TAG_LEN) == 0)#endif	{		uint64_t now = 0;		memcpy((char *)outBuffer + RECVTIME_OFFSET, (char *)&now, TIME_LENGTH);		memcpy((char *)outBuffer + RTT_OFFSET, (char *)&now, TIME_LENGTH);		CURRENTTIMEMICROS(now);		now = htonll(now);		memcpy((char *)outBuffer + SENTTIME_OFFSET, (char *)&now, TIME_LENGTH);		/* recompute the checksum */#if defined(__SOLARIS__) || defined(__DARWIN__) || defined(__FreeBSD__)		((icmphdr_t *)outBuffer)->icmp_cksum = 0;		((icmphdr_t *)outBuffer)->icmp_cksum = checksum((unsigned short *)outBuffer, bufferLen);#else		((icmphdr_t *)outBuffer)->checksum = 0;		((icmphdr_t *)outBuffer)->checksum = checksum((unsigned short *)outBuffer, bufferLen);#endif	}	/**	 * Now send the damn data before Jeff drives me nuts!	 */	memset(&Addr, 0, sizeof(Addr));	Addr.sin_family = AF_INET;	Addr.sin_port   = 0;	Addr.sin_addr.s_addr = netAddr;	iRC = sendto((int)icmpfd,		     (void *)outBuffer,		     (int)bufferLen,		     0,		     (struct sockaddr *)&Addr,		     sizeof(Addr));	if(iRC == -1 && errno == EACCES)	{		jclass ioEx = (*env)->FindClass(env, "java/net/NoRouteToHostException");		(*env)->ThrowNew(env, ioEx, "cannot send to broadcast address");	}	else if(iRC != bufferLen)	{		char buf[128];		int serror = errno;		jclass ioEx = (*env)->FindClass(env, "java/io/IOException");				sprintf(buf, "sendto error (%d, %s)", serror, strerror(serror));		(*env)->ThrowNew(env, ioEx, (const char *)buf);	}	end_send:	if(outBuffer != NULL)		free(outBuffer);	return;}/* * Class:     org_opennms_protocols_icmp_IcmpSocket * Method:    close * Signature: ()V */JNIEXPORT voidJNICALL Java_org_opennms_protocols_icmp_IcmpSocket_close (JNIEnv *env, jobject instance){	jint fd_value = getIcmpFd(env, instance);	if(fd_value >= (jint)0 && (*env)->ExceptionOccurred(env) == NULL)	{		close((int)fd_value);		setIcmpFd(env, instance, (jint)-1);	}	return;}

⌨️ 快捷键说明

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