tcp_echo.c

来自「在ARM7和UC/OSII的平台上实现了GPS自动报站的功能,涉及GPS模块LE」· C语言 代码 · 共 1,125 行 · 第 1/2 页

C
1,125
字号
/*
 * FILENAME: tcp_echo.c
 *
 * Copyright  2000 By InterNiche Technologies Inc. All rights reserved
 *
 * Test program for TCP sockets API. Implements an echo 
 * server and client
 *
 * MODULE: MISCLIB
 *
 * ROUTINES: tcp_client_add(), tcp_client_del(), 
 * ROUTINES: tcp_client_from_pio(), tcp_client_from_sock(), tcp_secho_init(), 
 * ROUTINES: tcp_secho_close(), tcp_cecho_close(), tcp_echo_cleanup(), 
 * ROUTINES: tcp_echo_init(), tcp_sendecho(), tcp_send_an_echo(), 
 * ROUTINES: echo_svr_upcall(), tcp_echo_recv(), tcp_echo_poll(), 
 * ROUTINES: tcp_echo_stats(),
 *
 * PORTABLE: yes
 */

 
#include "ipport.h"     /* NetPort embedded system includes */

#ifdef TCP_ECHOTEST     /* whole file can be ifdeffed out */

#ifndef WINSOCK
#include "tcpport.h"    /* NetPort embedded system includes */
#include "in_utils.h"

/* define NP sockets to standard calls */
#define  SOCKTYPE                long
#define  socket(x,y,z)           t_socket(x,y,z)
#define  bind(s,a,l)             t_bind(s,a)
#define  connect(s,a,l)          t_connect(s,a)
#define  listen(s,i)             t_listen(s,i)
#define  accept(s,a,l)           t_accept(s,a)
#define  send(s,b,l,f)           t_send(s,b,l,f)
#define  recv(s,b,l,f)           t_recv(s,b,l,f)
#define  socketclose(s)          t_socketclose(s)
#define  setsockopt(s,  l, o, d) t_setsockopt(s,   o, d)
#ifndef sock_noblock
#define  sock_noblock(sock,   flag) setsockopt(sock,  SOL_SOCKET, SO_NBIO, NULL)
#endif
#endif   /* WINSUCK */


#define  ECHO_PORT               7  /* standard UDP/TCP echo port */

/* The states of a TCP_ECHO Client. Either it is IDLE or BUSY exchaning
   TCP Echo packets */
#define  TCP_IDLE                1
#define  TCP_BUSY                2

/* TCP_IDLE_TIMEOUT is used to cleanup idle TCP Echo Client connections 
   If a TCP Echo Client has not been used for this long, delete it */
#define  TCP_IDLE_TIMEOUT        600   /* value in seconds */

/* TCP_MAX_ECHO_CONN defines the maximum simultaneous TCP Echo 
 * Clients connections allowed. This is required because for polling 
 * TCP Echo Clients we are using t_select() call. t_select() uses 
 * fd_set array, which can hold a maximum of FD_SETSIZE sockets. As 
 * one socket is needed to poll TCP Echo Server, the maximum 
 * available for TCP Echo Clients is 
 */
#define  TCP_MAX_ECHO_CONN       FD_SETSIZE-1   /* max TCP Echo Client conns*/


SOCKTYPE elisten_sock =         INVALID_SOCKET; /* echo server socket */
SOCKTYPE esvr_sock    =         INVALID_SOCKET; /* echo server active socket */

extern   int                    kbhit(void); /* from Microsquash|Borland lib*/
extern   char *                  prompt;

/* This global switch can be set prior to calling tcp_echos_init() */
int      tcpecho_server =  TRUE;

/* Do we need to close the server's active socket? */
int      esvr_sock_close = FALSE;

#ifndef  ECHOBUFSIZE
#define  ECHOBUFSIZE    (8*1024) 
#endif

/* List of error codes used by this file */

#define  TCPE_BASE                  400
#define  TCPE_ALLOC_ERROR           (TCPE_BASE+1)
#define  TCPE_NODE_NOT_FOUND        (TCPE_BASE+2)
#define  TCPE_CANT_OPEN_SOCKET      (TCPE_BASE+3)
#define  TCPE_CONNECT_FAILED        (TCPE_BASE+4)
#define  TCPE_SEND_FAILED           (TCPE_BASE+5)
#define  TCPE_BAD_SOCKET            (TCPE_BASE+6)
#define  TCPE_BIND_FAILED           (TCPE_BASE+7)
#define  TCPE_LISTEN_FAILED         (TCPE_BASE+8)
#define  TCPE_CLIENT_NOT_FOUND      (TCPE_BASE+9)
#define  TCPE_TIME_NOT_RIPE         (TCPE_BASE+10)
#define  TCPE_ALL_SOCKS_USED        (TCPE_BASE+11)
#define  TCPE_BLOCKED               (TCPE_BASE+12)

#define  SUCCESS                    0


/* Structure for holding information regarding a TCP Client connection */

struct TcpClient
{
   SOCKTYPE sock;                /* client socket */
   void *   pio;                 /* Output messages go to this device */
   ip_addr  rhost;               /* TCP Echos to be sent to this host */
   u_long   replies;             /* Number of burst replies received */
   u_long   times;               /* Number of bursts is to be sent */
   u_long   send_cnt ;           /* Number of the reply to be sent(counter) */
   int      state;               /* state of the TCP connection */
   u_long   ticks;               /* ClockTick when next burst is to be sent */
   u_long   delay;               /* Delay between two Echo bursts */
   u_long   len;                 /* Length of TCP each burst to be sent */
   u_long   tot_sent;            /* Total echo bytes sent */
   u_long   tot_rcvd;            /* Total echo bytes received */
   struct   TcpClient * next;
   char     inbuf[ECHOBUFSIZE];  /* per-client data buffer */
   int      sending;             /* non-zero while client is in send loop */
};

char *   srv_inbuf   =  NULL;

typedef struct TcpClient * TCPCLIENT ;
TCPCLIENT tcpq;                  /* Start node for queue of TCP clients */


int         tcp_client_add(void *  pio);
int         tcp_client_del(TCPCLIENT tcpclient);
TCPCLIENT tcp_client_from_pio (void *  pio);
TCPCLIENT tcp_client_from_sock(SOCKTYPE  sock);
int         tcp_secho_init (void * pio);
int         tcp_secho_close(void * pio);   
int         tcp_cecho_close(void * pio);
int         tcp_send_an_echo(TCPCLIENT tcpclient);
void        tcp_echo_poll(void);
int         tcp_echo_init(void);
void        tcp_echo_cleanup(void);
int         tcp_echo_stats(void * pio);
int         tcp_sendecho(void * pio, ip_addr fhost, long len, long times);


/* FUNCTION: tcp_client_add()
 *
 * Add a new client to the Queue
 * 1. Allocates memory for a new node
 * 2. Adds to queue
 * 3. Initialized data members
 *
 * 
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number 
 */

int
tcp_client_add(void * pio)
{
   TCPCLIENT tmpclient;
   int   num_of_conn=0;

   tmpclient=tcpq;
   while ( tmpclient )
   {
      num_of_conn++;
      tmpclient=tmpclient->next;
   }

   if ( num_of_conn >= TCP_MAX_ECHO_CONN )
   {
      return TCPE_ALL_SOCKS_USED ;
   }

   /* Allocate memory */
   tmpclient = (TCPCLIENT) npalloc( sizeof(struct TcpClient) ) ;
   if ( tmpclient == NULL )
   {
      ns_printf(pio,"Allocation error.\n");
      return TCPE_ALLOC_ERROR;
   }

   /* Add the new node to the queue */
   if ( tcpq == NULL )
   {
      tcpq = tmpclient ;
      tmpclient->next=NULL;
   }
   else
   {
      /* Insert it at the beginning */
      tmpclient->next = tcpq;
      tcpq=tmpclient ;
   }

   /* Initialize data members */
   tmpclient->sock      = INVALID_SOCKET;
   tmpclient->pio       = pio;
   tmpclient->rhost     = 0;
   tmpclient->times     = 1;           /* Count of total EchoPkts to be sent */
   tmpclient->send_cnt  = 0;        /* Num of Echo Pkts sent till now */
   tmpclient->ticks     = cticks;   /* Timetick to track sending of echos */
   tmpclient->state     = TCP_IDLE ;   /* Are we sending TCP Echos? No. */
   tmpclient->replies   = 0 ;       /* Num of replies received so far */
   tmpclient->len       = 64 ;      /* Default value of Echo Pkt */
   tmpclient->tot_sent  = 0;
   tmpclient->tot_rcvd  = 0;

   return SUCCESS ;
}


/* FUNCTION: tcp_client_del()
 * 
 * Cleanup stuff for a TCP Echo Client Three things to be done here
 * 1. Close the underlying socket 
 * 2. Remove node from the Q
 * 3. Free the memory used by the node
 *
 * PARAM1: TCPCLIENT tcpclient - Pointer to TCP Echo Client connection
 *
 * RETURNS: 0 on SUCCESS or error number 
 */

int 
tcp_client_del(TCPCLIENT tcpclient)
{
   int   e;
   TCPCLIENT tmpclient,prevclient;

   /* Close the underlying socket */
   if ( tcpclient->sock != INVALID_SOCKET )
   {  
      e = socketclose(tcpclient->sock);
      if (e)
      {
         e = t_errno(tcpclient->sock);
         ns_printf(tcpclient->pio,"tcp echo: close error %d\n", e);
      }
   }

   /* Remove from the q */
   if ( tcpq == tcpclient )
   {
      /* It is the first node */
      tcpq = tcpq->next;
   }
   else
   {
      prevclient=tcpq;
      tmpclient=tcpq->next;
      while ( tmpclient )
      {
         if ( tmpclient == tcpclient )
         {
            /* Found the node in the list */
            prevclient->next=tmpclient->next ;
            break;
         }
         else
         {
            prevclient=tmpclient;
            tmpclient=tmpclient->next ;
         }
      }

      /* Was the node found in Q ? */
      if (tmpclient == NULL )
      {
         /* Node not found in Q !! */
         dtrap("tcp_echo 0\n");
         return TCPE_NODE_NOT_FOUND ;
      }
   }

   npfree(tcpclient);

   return SUCCESS;
}


/* FUNCTION: tcp_client_from_pio()
 * 
 * Return the TCP Echo Client connect for a particular session.
 *
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: Pointer to TCPCLIENT. NULL if connection not found.  
 */

TCPCLIENT
tcp_client_from_pio(void * pio)
{
   TCPCLIENT tmpclient=tcpq;

   while ( tmpclient )
   {
      if ( tmpclient->pio == pio )
         break ;
      else
         tmpclient=tmpclient->next;
   }

   return tmpclient;
}



/* FUNCTION: tcp_client_from_sock()
 * 
 * Return the TCP Echo Client connection for a particular session.
 *
 * PARAM1: SOCKTYPE sock
 *
 * RETURNS: Pointer to TCPCLIENT. NULL if connection not found. 
 */

TCPCLIENT
tcp_client_from_sock(SOCKTYPE sock)
{
   TCPCLIENT tmpclient=tcpq;

   while ( tmpclient )
   {
      if ( tmpclient->sock == sock )
         break ;
      else
         tmpclient=tmpclient->next;
   }

   return tmpclient;
}



/* FUNCTION: tcp_secho_init()
 * 
 * Initialize the TCP Echo Server. If the flag tcpecho_server is false,
 * then Server Init is not done.
 * 
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int 
tcp_secho_init(void * pio)
{
   int   e;    /* error holder */
   struct sockaddr_in   me;   /* my IP info, for bind() */
   int   opt;

   if (tcpecho_server)
   {
      ns_printf(pio,"tcp echo srv - starting.\n");

      /* open TCP socket */
      elisten_sock = socket(AF_INET, SOCK_STREAM, 0);
      if (elisten_sock == INVALID_SOCKET)
      {
         ns_printf(pio,"TCP echo: bad socket: %d\n", elisten_sock);
         return TCPE_BAD_SOCKET ;
      }

      opt = 1;
      e = t_setsockopt(elisten_sock, SO_REUSEADDR, &opt);
      if (e != 0)
      {
         e = t_errno(elisten_sock);
         dtrap("tcp_echo 1\n");
         dprintf("error %d setting SO_REUSEADDR on port %d\n", e, ECHO_PORT);
         return SYS_SOCKETNULL;
      }

      me.sin_family = AF_INET;
      me.sin_addr.s_addr = INADDR_ANY;
      me.sin_port = htons(ECHO_PORT);

      e = bind(elisten_sock, (struct sockaddr*)&me, sizeof(me));
      if (e != 0)
      {
         e = t_errno(elisten_sock);
         ns_printf(pio,"tcp_echo: bad socket bind: %d, %s\n", e, so_perror(e) );
         socketclose(elisten_sock);
         elisten_sock = INVALID_SOCKET;
         return TCPE_BIND_FAILED ;
      }
      e = listen(elisten_sock, 3);
      if (e != 0)
      {
         e = t_errno(elisten_sock);
         ns_printf(pio,"tcp_echo: bad socket listen: %d %s\n", e, so_perror(e));
         socketclose(elisten_sock);
         elisten_sock = INVALID_SOCKET;
         return TCPE_LISTEN_FAILED;
      }
      /* for listen socket into Non-blocking mode so we can poll accept */
      sock_noblock(elisten_sock, TRUE);
   }
   else
      ns_printf(pio,"tcp echo server not enabled\n");

   srv_inbuf = (char *)npalloc(ECHOBUFSIZE);
   if (srv_inbuf == NULL)
   {
      ns_printf(pio, "tcp server: alloc failed\n");
      socketclose(elisten_sock);
      elisten_sock = INVALID_SOCKET;
      return TCPE_LISTEN_FAILED;
   }

   return SUCCESS;
}


/* FUNCTION: tcp_secho_close()
 * 
 * Close the TCP Echo Server.
 *
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int
tcp_secho_close(void * pio)
{
   int   e  =  0;       /* scratch error holder */
   int   retval   =  0; /* return last non-zero error */

   if (esvr_sock != INVALID_SOCKET)
   {
      e = socketclose(esvr_sock);
      if (e)
      {
         retval = e = t_errno(esvr_sock);
         ns_printf(pio,"tcp echo server: close error %d %s\n", e, so_perror(e));
      }
      else
      {
         ns_printf(pio,"tcp echo srv - closing.\n");
         esvr_sock = INVALID_SOCKET;
      }
   }

   if (srv_inbuf)
   {
      npfree(srv_inbuf);
      srv_inbuf=NULL;
   }
   if (elisten_sock == INVALID_SOCKET)
      return e;

   e = socketclose(elisten_sock);
   if (e)
   {
      retval = e = t_errno(elisten_sock);
      ns_printf(pio,"tcp echo: server close error %d %s\n", e, so_perror(e) );
   }
   elisten_sock = INVALID_SOCKET;

   return retval;
}


/* FUNCTION: tcp_cecho_close()
 *
 * Close the TCP Echo Client.
 *
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int
tcp_cecho_close(void * pio)
{
   TCPCLIENT  tcpclient;

   tcpclient=tcp_client_from_pio(pio);
   if ( tcpclient == NULL )
   {
      ns_printf(pio,"No TCP Echo Client found for this session.\n");   
      return TCPE_CLIENT_NOT_FOUND ;
   }
   else
   {
      ns_printf(pio,"Closing TCP Echo Client.\n");   
      return tcp_client_del(tcpclient);
   }

}


/* FUNCTION: tcp_echo_cleanup()
 *
 * Cleanup all TCP Echo related data structures.
 *
 * PARAM1: void
 *
 * RETURNS: 
 */

void
tcp_echo_cleanup(void)
{
   TCPCLIENT  tcpclient=tcpq;
   TCPCLIENT  nextclient;

   /* Close all the open clients */
   while ( tcpclient )
   {
      nextclient=tcpclient->next; 
      tcp_client_del(tcpclient);
      tcpclient=nextclient;
   }

   tcp_secho_close(NULL);
}


/* FUNCTION: tcp_echo_init()
 * 
 * Initialize TCP Echo Server
 * Remarks : This function has been defined so that a clean interface 
 * is provided for TCP Echo.
 *
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int
tcp_echo_init(void)
{
   return tcp_secho_init(NULL);
}
 

/* FUNCTION: tcp_sendecho()
 * 
 * Send TCP Echo packets to a TCP Echo Server. If a TCP Echo Client
 * has not be created, then it is done (one per GenericIO device).
 * Also, if the TCP Echo Server IP address is different from the
 * one being used earlier, then socket reinitialization is done.
 *
 * PARAM1: void * pio      - device for console output
 * PARAM2: ip_addr fhost   - IP Address of TCP Echo Server (IN)
 * PARAM3: long len        - Length of TCP Echo pkt to be sent (IN)
 * PARAM4: long times)     - Number of TCP Echo pkts to be sent (IN)
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int
tcp_sendecho(void * pio,
   ip_addr  fhost,      /* already in net endian */
   long     len,
   long     times)
{
   struct sockaddr_in   sa;
   int   e;

⌨️ 快捷键说明

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