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