📄 osptnprobe.c
字号:
/**########################################################################*########################################################################*########################################################################* * COPYRIGHT (c) 1998, 1999 by TransNexus, LLC * * This software contains proprietary and confidential information * of TransNexus, LLC. Except as may be set forth in the license * agreement under which this software is supplied, use, disclosure, * or reproduction is prohibited without the prior, express, written* consent of TransNexus, LLC. * *******#########################################################################*#########################################################################*#########################################################################*//*osptnprobe.c Summary: Functions that probe a list of IP addresses and return the response time value for each system. Modifications: MM/DD/YYYY Who Description ---------- --- ----------------------------------------- Release #: 0.9.0 Description OSPPTNProbe() provides a means of testing the response time of each server in a list provided by the caller. The response time for each server is captured and returned to the caller. To call OSPPTNProbe, fill in the ospmipaddr field of an array of OSPT_TN_PROBE structures and indicating the size of the array. The function will return by filling in the ospmTime field for each element with the number of milliseconds the system took to respond to a message sent to its echo/udp service. The uMaxWait parameter indicates the maximum number of milliseconds to wait before giving up. The function works by sending a small UDP datagram to each remote host and measuring the time that elapses until the reply. There are advantages and disadvantages to this approach: Good: - cleaner, easier to port code (compared to ICMP echo) - closer simulation of voice traffic (which uses RTP/UDP) especially since many routers will treat ICMP special Bad: - not all hosts (e.g. WinNT 4.0) automatically install deamons on the echo port (for WinNT 4.0, it's part of the optionally installed Simple TCP/IP Services) Enhancements: - currently, the function only sends a single datagram to each host. With next hop caching in routers, as well as problems sending back-to-back packets in some OSs (e.g. Win95), it might be better to send several datagrams to each host, ignore the first reply (which establishes the routers' caches), and average the remainder. Notes*//******************************************************************************* INCLUDE FILES*******************************************************************************/#ifndef _WIN32#include <sys/timeb.h>#else#include <sys\timeb.h>#endif#include "osptnprobe.h"#include "ospdest.h"#include "osputils.h"#include "ospcomm.h"#include "ospconfig.h"#include "ospsocket.h"#ifdef TESTMODE#include <stdio.h>#endif/*-----------------------------------------------------------------------*//* private header file stuff *//* different status values */enum socket_stats{ OSPE_PRINIT, /* 0 initialized */ OSPE_PRCONN, /* 1 connected */ OSPE_PRSENT, /* 2 request sent */ OSPE_PRREAD, /* 3 reply received */ OSPE_PRDONE /* 4 probe complete */};/* miscellaneous constants */#define OSPC_TN_UDP_ECHOPORT 7 /* UDP echo port is 7 *//* private globals - for multithreading, these MUST be read-only */static char tnBuffer[] = "test message";/*-----------------------------------------------------------------------*//* OSPPTNProbe - probe systems and return response times */intOSPPTNProbe( /*0 - normal; < 0 - error code */ OSPT_TN_PROBE *pProbeList, /* list to probe */ unsigned uNumHosts, /* number of hosts to check */ unsigned uMaxWait /* maximum wait in milliseconds */){ fd_set fdSocketSet; /* set of sockets for testing */ int nMaxFd = 0, nMinFd = 0; int uErr = OSPC_ERR_TNPROBE_ERROR; do { /* Break out of loop on error */ /* * Nothing real fancy here, we initialize a socket for each host * (and set up the socket set), do the actual probes on the sockets, * and then clean up. Note that we do the cleanup step even if * there is an error in the intermediate processing. That way we * can be sure to release resources. It means, though, that the * intermediate functions can't just "bail out" when they encounter * an error. They must leave things in a reasonably consistent * state so that the cleanup process can function okay. */ /* Step 1: Prepare the sockets for testing */ if ((nMaxFd = OSPPTNProbeInit(pProbeList, &uNumHosts, &fdSocketSet, &nMinFd))== -1) { break; } /* Step 2: Do the probes */ OSPPTNProbeEcho(&fdSocketSet, pProbeList, uNumHosts, uMaxWait, nMaxFd, nMinFd); uErr = OSPC_ERR_NO_ERROR; } while (0); /* Step 3: Clean up the Sockets */ OSPPTNProbeCleanup(pProbeList, uNumHosts); return(uErr);}/*-----------------------------------------------------------------------*//* OSPPTNProbeInit - set up the sockets for probing */int /* returns maxFD (< 0 on error) */OSPPTNProbeInit( OSPT_TN_PROBE *pProbeList, /* list to initialize */ unsigned *lpNumHosts, /* number of hosts */ fd_set *pSocketSet, /* socket set */ int *nMinFd /* Min fdSocket val */){ int fdSocket; /* single socket */ register unsigned uCnt; /* simple counter */ int nMaxFd; /* max fdSocket value */ int errorcode = 0; int one = 1; /* * This function tries to set up things as much as possible prior * to the actual probes. Nothing in here is timed, but it assumes * that everything after it returns will be. We start out by * setting the maximum fd value to -1. If no socket it successfully * opened, then it will stay there and we'll return an error. */ nMaxFd = -1; /* so far, no error */ *nMinFd = 0x0fffffff; /* ZERO OUT THE SOCKET SET */ FD_ZERO(pSocketSet); /* * The maxFd stuff is a little tricky, but we need to set it up * to make the select processing reasonably efficient later on. * Each socket is identified by a standard UNIX file descriptor, * which is a simple integer. The select call takes an array, * indexed by file descriptor value, and returns when any of the * referenced sockets has activity. On return, we need to find * out which specific socket needs service, so we're going to * have to scan the array. Without maxFd, we'd have to scan the * whole array each time. That could be inefficient, since the * array is likely to be a whole bunch bigger than the number * of hosts we're probing. Therefore, we keep track of the * maximum file descriptor value ever assigned to us. In scanning * the array, we can stop once we've reached this value. */ /* iterate through the list of hosts to try */ for ( uCnt = 0; uCnt < *lpNumHosts; uCnt++) { /* * initialize the status value - note that we must go through the entire * list here to make sure that each entry is set to the OSPE_PRINIT state; * otherwise cleanup will be confusing. That means no breaking out of * the for loop. */ pProbeList[uCnt].ospmPrStatus = OSPE_PRINIT; /* open a socket to each remote host */ fdSocket = OSPPTNProbeConnect(pProbeList[uCnt].ospmipaddr); pProbeList[uCnt].ospmSocket = fdSocket; if (fdSocket >= 0) /* negative socket is an error */ { /* if no errors, update the status to connected */ pProbeList[uCnt].ospmPrStatus = OSPE_PRCONN; /* remember the socket */ OSPM_BLOCKIO(fdSocket, one, errorcode); if(errorcode == 0) { /* add it to select list */ FD_SET((unsigned)fdSocket, pSocketSet); /* and update the maxFd variable if needed */ if (fdSocket > nMaxFd) { nMaxFd = fdSocket; } if (fdSocket < *nMinFd) { *nMinFd = fdSocket; } } } } return(nMaxFd);}/* OSPPTNProbeConnect - connect socket to specific address for probes */int /* returns socket descriptor, < 0 == error */OSPPTNProbeConnect( OSPTIPADDR ipAddr /* remote address to connect */){ int fdSocket; /* socket file descriptor */ int uErr = OSPC_ERR_NO_ERROR; struct timeval timeout; OSPTSSLSESSION *sslsess = OSPC_OSNULL; /* allocate a socket */ OSPM_UDP_SOCKET(fdSocket, uErr); timeout.tv_sec = OSPC_DEFAULT_PROBE_CONNECT / 1000; timeout.tv_usec = OSPC_DEFAULT_PROBE_CONNECT % 1000 * 1000; if ((fdSocket >= 0) && uErr == 0) { /* connect the socket */ uErr = OSPPSockConnect(&fdSocket, OSPC_DEFAULT_BLOCKING_FLAG, ipAddr, htons(OSPC_TN_UDP_ECHOPORT), &timeout, &sslsess); if (uErr) { fdSocket = -1; } } return(fdSocket);}/*-----------------------------------------------------------------------*//* OSPPTNProbeCleanup - free resources, etc. after probing */voidOSPPTNProbeCleanup( OSPT_TN_PROBE *pProbeList, /* list to cleanup */ unsigned uNumHosts /* number of hosts */){ register unsigned uCnt; /* simple counter */ int errorcode = OSPC_ERR_NO_ERROR; /* * Two things happening here: First, we close all the sockets * that we opened. Second, if we weren't able to get a * response from a host, we set the response time for that * host to infinity. */ for ( uCnt=0; uCnt < uNumHosts; uCnt++ ) { /* if we were able to open a socket, close it */ if (pProbeList[uCnt].ospmPrStatus > OSPE_PRINIT) { OSPM_CLOSE(pProbeList[uCnt].ospmSocket, errorcode); } /* if an error, set the response time to infinite */ if (pProbeList[uCnt].ospmPrStatus < OSPE_PRDONE) { pProbeList[uCnt].ospmTime = (unsigned long)(-1); } }}/*-----------------------------------------------------------------------*//* OSPPTNProbeEcho - actually do the echo and wait for replies */voidOSPPTNProbeEcho( fd_set *pSockets, /* sockets to probe */ OSPT_TN_PROBE *pProbeList, /* place to store results */ unsigned uNumHosts, /* number of hosts to probe */ unsigned uMaxWait, /* max ms to wait */ int nMaxFd, /* max fd number for sockets */ int nMinFd /* min fd number for sockets */){ fd_set fdReadSet; /* current working set */ int fdSocket = 0; /* current socket */ unsigned uHostsLeft = 0; /* hosts still pending */ unsigned uTimeLeft = 0; /* time remaining */ register unsigned uHost = 0; /* element number in pProbeList */ unsigned uSent = 0; /* bytes sent */ int nRecv = 0; /* bytes received */ register int nCnt = 0; /* simple counter */ int nRetVal = 0; /* return value from select */ unsigned long uTime1 = 0; /* temp value for time calculations */ unsigned long uTime2 = 0; /* temp value for time calculations */ struct timeval timeout; /* timeout value for select */ int uErr = OSPC_ERR_NO_ERROR; /* Error value */ char recvbuf[100]; OSPM_MEMSET(recvbuf, 0, sizeof(recvbuf)); OSPM_MEMSET(&timeout, 0, sizeof(struct timeval)); do { /* Break out of loop on error */ /* * This function actually sends the test datagram and waits * for a response. The general steps are * - iterate through the list and send a datagram * - note the time that the datagram was sent
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -