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