tcp_echo.c

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

C
1,125
字号
   SOCKTYPE tmp;
   TCPCLIENT tcpclient;

   /* If client socket isn't open or host has changed, open it */
   tcpclient = tcp_client_from_pio(pio);
   if ( tcpclient == NULL )   /* not found */
   {
      if ( (e=tcp_client_add(pio)) != SUCCESS )
      {
         if ( e == TCPE_ALL_SOCKS_USED )
         {
            ns_printf(pio,"All TCP Echo Client connections are in use.\n");
            ns_printf(pio,"Please try at a later time.\n");
         }
         return e;
      }
      tcpclient = tcp_client_from_pio(pio);
   }

   if ( tcpclient->sock == INVALID_SOCKET || fhost != tcpclient->rhost )
   {
      if (tcpclient->sock != INVALID_SOCKET) /* host changed */
      {
         socketclose(tcpclient->sock);
         tcpclient->sock=INVALID_SOCKET;
      }

      /* (re)open new socket to client for echo */
      tmp = socket(AF_INET, SOCK_STREAM, 0);
      if (tmp == INVALID_SOCKET)
      {
         ns_printf(pio,"tcp echo: can't open socket\n");
         tcp_client_del(tcpclient);
         return TCPE_CANT_OPEN_SOCKET ;
      }

      sa.sin_family = AF_INET;
      /* host is already in network endian */
      sa.sin_addr.s_addr = tcpclient->rhost = fhost;
      sa.sin_port = htons(ECHO_PORT);

      e = connect(tmp, (struct sockaddr*)&sa, sizeof(sa));
      if (e != 0)
      {
         e = t_errno(tmp);
         ns_printf(pio,"tcp_echo: bad socket connect: %d %s\n", e, so_perror(e));
         tcp_client_del(tcpclient);
         return TCPE_CONNECT_FAILED ;
      }
      /* Put in non-block mode */
      sock_noblock(tmp, TRUE);      
      tcpclient->sock = tmp;
   }


   tcpclient->replies   = 0;
   tcpclient->times     = times;
   tcpclient->delay     = pingdelay;
   tcpclient->ticks     = cticks;
   tcpclient->state     = TCP_BUSY ;
   tcpclient->len       = len ;
   tcpclient->send_cnt  = 0 ;

   return tcp_send_an_echo(tcpclient);
}

 

/* FUNCTION: tcp_send_an_echo()
 * 
 * Send a TCP Echo packet from our client to remote server
 *
 * PARAM1: TCPCLIENT tcpclient - Pointer to client's connection (IN)
 *
 * RETURNS: 0 on SUCCESS or error number 
 */

int
tcp_send_an_echo(TCPCLIENT tcpclient)
{
   int   e;
   u_long   total;
   u_long   sendsize;
   u_long   starttime;
   int      block;
   u_long   words;      /* send data word index */
   u_long   dataval;
   u_long   sent  =  0; /* sent in this loop */

   if ( tcpclient->ticks > cticks )  
      return TCPE_TIME_NOT_RIPE ;
   if (tcpclient->sending)    /* guard against re-entry */
      return TCPE_BLOCKED;
   tcpclient->sending++;

   ns_printf(tcpclient->pio,"sending TCP echo %ld to %s\n", 
    tcpclient->send_cnt, print_ipad(tcpclient->rhost) );

   total = tcpclient->len;
   block = 0;
   starttime = cticks;
   while (total > sent)
   {
      tcpclient->ticks = cticks + tcpclient->delay;   /* back off time for next send */
      sendsize = total - sent;
      if (sendsize > ECHOBUFSIZE)
         sendsize = ECHOBUFSIZE;

      /* write pattern into full-size data for integrity test */
      dataval = (tcpclient->tot_sent + sent)/4;    /* data for first word of buffer */
      for (words = 0; words < (ECHOBUFSIZE/4); words++)
         *((u_long*)tcpclient->inbuf + words) = dataval++;

      e = send(tcpclient->sock, tcpclient->inbuf, (int)sendsize, 0);
      if (e < 0)
      {
         e = t_errno(tcpclient->sock);
         if (e == EWOULDBLOCK)
         {
            tk_yield();
            continue;
         }
         ns_printf(tcpclient->pio,"error %d sending TCP echo number %ld\n", 
            e, tcpclient->send_cnt);
         ns_printf(tcpclient->pio,"   on byte %ld\n", e);

         tcp_client_del(tcpclient);
         tcpclient->sending--;
         return TCPE_SEND_FAILED;
      }
      sent += e;
      if ((block += e) >= ECHOBUFSIZE)
      {
         ns_printf(tcpclient->pio, ".");
         block -= ECHOBUFSIZE;
      }
      tk_yield();    /* let other tasks run */
   }

   tcpclient->send_cnt++;  /* keep counters current */
   tcpclient->tot_sent += sent;
   ns_printf(tcpclient->pio, "\ntcpecho: echoed %ld bytes", sent);

   if (total > ECHOBUFSIZE)   /* see if we should print performance numbers */
   {
      u_long   endticks;
      u_long   bps;
      int   fraction;

      /* wait for all data to come back */
      endticks = cticks + (5*TPS);        /* use endticks for timeout */
      while ((tcpclient->tot_rcvd < tcpclient->tot_sent) &&
          (cticks > endticks))
      {
         tk_yield();
      }

      endticks = cticks - starttime;
      if (endticks > 0) /* avoid divide by 0 */
      {
         bps = sent/endticks;    /* bytes per tick */
         bps *= TPS;             /* convert to bytes/Sec */
         bps /= 1024;            /* KBytes/Sec */
         fraction = (int)endticks % TPS;
         endticks /= TPS;
         ns_printf(tcpclient->pio, " in %d and %d/%d seconds.\n%ld KBytes/sec", 
          (int)endticks, fraction, TPS, bps);
      }
   }
   ns_printf(tcpclient->pio, "\n");

   tcpclient->sending--;   /* clear reentry flag */
   return SUCCESS;
}


#ifdef TCP_ZEROCOPY


/* FUNCTION: echo_svr_upcall()
 *
 * echo_svr_upcall() - TCP ZEROCOPY callback for echo server socket.
 *
 * 
 * PARAM1: SOCKTYPE esrv_sock
 * PARAM2: PACKET inpkt
 * PARAM3: int err
 *
 * RETURNS: 
 */

int 
echo_svr_upcall(SOCKTYPE sock, PACKET inpkt, int err)
{
   int   e;

   if(sock != esvr_sock)
   {
      dtrap("tcp_echo 2\n");
   }

   if (err)
   {
      if (inpkt)
         tcp_pktfree(inpkt);
      /* If this is a graceful close from the client then start our 
       * close too, else just print a message to console.
       */
      if(err == ESHUTDOWN)
      {
         /* tell tcp_echo_recv() to close the socket */
         esvr_sock_close = TRUE;
      }
      else
         dprintf("echo server callback error %d\n", err);
      e = 0;   /* should this be an error??? later */
   }
   else     /* return echo */
   {
      e = tcp_xout(sock, inpkt);
      if (e > 0)  /* ignore codes like ENP_SEND_PENDING */
         e = 0;
   }
   return e;
}
#endif   /* TCP_ZEROCOPY */




/* FUNCTION: tcp_echo_recv()
 *
 * tcp_echo_recv() - check for and process received echo data
 * 
 * PARAM1: none
 *
 * RETURNS: void
 */

void
tcp_echo_recv(void)
{
   int   len;        /* length of recv data */
   int   e;          /* error holder */
   unsigned i;       /* generic index */
   int   count;      /* select return */
   fd_set fd_recv;   /* fd for recv */
   fd_set fd_accept; /* fd for accept */
   TCPCLIENT tmpclient = tcpq;
   struct sockaddr_in client;
   SOCKTYPE tmpsock; /* scratch socket */

   if (elisten_sock == INVALID_SOCKET && tcpq == NULL)
      return;  /* Echo not set up, don't bother */

   /* select on all open data sockets */
   i = 0;
   count = 0;
   while ( tmpclient )
   {
      if ( tmpclient->sock != INVALID_SOCKET )
         fd_recv.fd_array[i++] = tmpclient->sock ;
      tmpclient=tmpclient->next;
   }

#ifndef TCP_ZEROCOPY
   /* if we need to listen for server receives too */
   if (tcpecho_server)
   {
      if (esvr_sock != INVALID_SOCKET)
         fd_recv.fd_array[i++] = esvr_sock;
   }
#else
   /* if we need to close the server's active socket */
   if (esvr_sock_close != FALSE)
   {
      if (esvr_sock != INVALID_SOCKET)
      {
         socketclose(esvr_sock);
         esvr_sock = INVALID_SOCKET;
      }
      esvr_sock_close = FALSE;
   }
#endif   /* TCP_ZEROCOPY */

   fd_recv.fd_count = i;

   /* make this a short timeout since elisten may create soon */
   if (elisten_sock != INVALID_SOCKET)
   {
      fd_accept.fd_array[0] = elisten_sock;
      fd_accept.fd_count = 1;
      count = t_select(&fd_recv, NULL, &fd_accept, 1);
   }
   else 
   {
      if (i)   /* if no fd_set sockets filled in, don't bother */
         count = t_select(&fd_recv, NULL, NULL, 1);
   }

   /* While the t_select() was executing, commands can be 
    * executed from cmd-prompt and sockets can be cleaned up. 
    * Check for that. 
    */
   if (elisten_sock == INVALID_SOCKET && tcpq == NULL)
      return;  /* Echo not set up, don't bother */

   for (i = 0; i < fd_recv.fd_count; i++)
   {
      tmpsock = fd_recv.fd_array[i];

      /* Find out the client connection corresponding to this socket */
      tmpclient = tcp_client_from_sock(tmpsock);

      /* try a receive. Pick buffer according to client or server */
      if (tmpclient)    /* found a client for this one */
         len = recv(tmpsock, tmpclient->inbuf, ECHOBUFSIZE, 0);
#ifndef TCP_ZEROCOPY
      else if(tmpsock == esvr_sock)
         len = recv(tmpsock, srv_inbuf, ECHOBUFSIZE, 0);
#endif   /* TCP_ZEROCOPY */
      else
      {
         continue;
      }

      if (len < 0)
      {
         e = t_errno(tmpsock);
         if (e != EWOULDBLOCK)
         {
            if (tmpsock != esvr_sock)
               ns_printf(tmpclient->pio,"TCP echo recv error %d\n", e);
            else
               ns_printf(NULL,"TCP echo recv error %d\n", e);
         }
      }
      else if(len == 0)
      {
         ns_printf(NULL,"TCPECHO:socket closed by other side\n");
         if ( tmpsock == esvr_sock )
         {
            esvr_sock = INVALID_SOCKET;
         }
         else
         {
            if ( tmpclient == NULL )
            {
               dtrap("tcp_echo 3\n");
            }          
            else
            {
               tmpclient->sock = INVALID_SOCKET ;
               tcp_client_del(tmpclient);
            }
         }
      }
      else  /* if(len > 0) - got some echo data */
      {
#ifndef TCP_ZEROCOPY
         if (tmpsock == esvr_sock )
         {
            /* we must be server, send echo reply */
            if (tcpecho_server)
            {
               e = send(esvr_sock, srv_inbuf, len, 0);
               if (e < 0)
               {
                  /* Print the error to console */
                  e = t_errno(esvr_sock);
                  ns_printf(NULL,
                   "TCP echo server, error %d sending reply\n", e);
               }
            }
         }
         else     /* not the server socket, must be client */
#endif   /* TCP_ZEROCOPY */
         {
            /* If not a bulk test, print info */
            if (tmpclient->len <= ECHOBUFSIZE)
            {
               ns_printf(tmpclient->pio,"TCP echo reply from:%s, len:%d, reply:%lu", 
                print_ipad(tmpclient->rhost), len, tmpclient->replies);
               ns_printf(tmpclient->pio,"\n%s",prompt);
            }
            else
            {
               u_long   dataval;
               u_long * rxbuf =  (u_long*)(tmpclient->inbuf);
               u_long * rxend =  (u_long*)(tmpclient->inbuf +  (len  &  ~3));

               dataval = tmpclient->tot_rcvd/4;

               /* adjust for odd sized previous receives */
               if (tmpclient->tot_rcvd & 3)
               {
                  MEMMOVE(rxbuf, tmpclient->inbuf + (len & 3), len);
                  rxend--;
                  dataval++;     /* ignore sliced word */
               }

               while (rxbuf < rxend)
               {
                  if (*rxbuf != dataval)
                  {
                     ns_printf(tmpclient->pio,
                      "tcp_echo data error; got %lu, expected %lu\n",
                      *rxbuf, dataval);
                  }
                  rxbuf++;
                  dataval++;
               }
            }
            tmpclient->replies++;
            tmpclient->tot_rcvd += len;
         }
      }
   }

   /* if no server listen to poll, return now */
   if (elisten_sock == INVALID_SOCKET)
      return;

#ifdef NOTDEF
   MEMSET(&client, 0, sizeof(client));
   client.sin_family = AF_INET;
   client.sin_addr.s_addr = INADDR_ANY;
   client.sin_port = htons(ECHO_PORT);
#endif

   /* check for received echo connection on server */
   tmpsock = accept(elisten_sock, (struct sockaddr*)&client, &e );
   if (tmpsock != INVALID_SOCKET)
   {
      if (esvr_sock == INVALID_SOCKET)
      {
         esvr_sock = tmpsock;
#ifdef TCP_ZEROCOPY
         t_setsockopt(esvr_sock, SO_CALLBACK, (void*)echo_svr_upcall);
#endif   /* TCP_ZEROCOPY */
      }
      else  /* we already have a connection */
      {
         dprintf("tcpecho: rejected extra connection\n");
         socketclose(tmpsock);   /* refuse to serve another */
      }
   }
}



/* FUNCTION: tcp_echo_poll()
 * 
 * Do routine processing for TCP  Echos.
 * 1. Check is Echo packets has been received for TCP Echo 
 *    Server. If yes, send a reply.
 * 2. Check if Echo replys have been recieved for TCP Echo Clients.
 *    If yes, update data structures, display messages.
 *
 * PARAM1: void
 *
 * RETURNS: 
 */

static int in_echopoll = 0;   /* re-entry flag */

void
tcp_echo_poll(void)
{
   TCPCLIENT tmpclient = tcpq;

   if (elisten_sock == INVALID_SOCKET && tcpq == NULL)
      return;  /* Echo not set up, don't bother */

#ifdef SUPERLOOP
   in_echopoll++;    /* don't re-enter from tk_yield() */
   if (in_echopoll != 1)
   {
      in_echopoll--;
      return;
   }
   tcp_echo_recv();
#endif   /* SUPERLOOP */

   /* Check if we need to send TCP Echo packets */
   tmpclient=tcpq;
   while ( tmpclient )
   {
      if ( tmpclient->state == TCP_BUSY )
      {
         if ( tmpclient->send_cnt  >= tmpclient->times )
         {
            /* Previous "techo" command has completed */
            tmpclient->state = TCP_IDLE ;
         }
         else
         {
            if ( tcp_send_an_echo(tmpclient) == SUCCESS )
               ns_printf(tmpclient->pio,"%s",prompt);
         }
      }
      if ( tmpclient->ticks + (TCP_IDLE_TIMEOUT*TPS) < cticks )
      {
         /* This client has been lying around ldle for a long time */
         ns_printf(tmpclient->pio,"Deleting idle TCP Echo Client.\n%s",prompt);
         tcp_client_del(tmpclient);
      }


      tmpclient=tmpclient->next;
   }

   in_echopoll--;
}


/* FUNCTION: tcp_echo_stats()
 * 
 * Show statistics about all TCP Echo Clients and Servers
 *
 * PARAM1: void * pio - device for console output
 *
 * RETURNS: 0 on SUCCESS or error number. 
 */

int
tcp_echo_stats(void * pio)
{
   ns_printf(pio,"Showing TCP Echo statistics.\n");
   if ( esvr_sock == INVALID_SOCKET )
   {
      ns_printf(pio,"   There are no Server connections.\n");
   }
   else
   {
      ns_printf(pio,"   There is one Server connection.\n");
   }

   if ( tcpq == NULL )
      ns_printf(pio,"   There are no Client connections.\n");
   else
   {
      TCPCLIENT tmpclient=tcpq;
      int   cnt=0;
      while (tmpclient)
      {
         cnt++;
         ns_printf(pio,"   Total bytes for Client %d: sent=%ld,rcvd=%ld\n",
          cnt, tmpclient->tot_sent, tmpclient->tot_rcvd);
         tmpclient=tmpclient->next;
      }
      ns_printf(pio,"   Total Client connections=%d.\n",cnt);
   }
   return SUCCESS;
}


#endif   /* TCP_ECHOTEST */



⌨️ 快捷键说明

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