URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [doc/] [sample_program.html] - Rev 1765
Compare with Previous | Blame | View Log
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta name="GENERATOR" content="Mozilla/4.7 [en] (X11; I; Linux 2.2.14 ppc) [Netscape]"> </head> <body> <center> <h1> Sample Networking Program</h1></center> <p><br>This example is derived from the test program <tt>".../net/tcpip/v1_3_1/tests/ping_test.c"</tt>. <br> <blockquote><tt><font size=-1>//==========================================================================</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// tests/ping_test.c</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// Simple test of PING (ICMP) and networking support</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>//==========================================================================</font></tt> <br><tt><font size=-1>//####BSDCOPYRIGHTBEGIN####</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// -------------------------------------------</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// Portions of this software may have been derived from OpenBSD or other sources,</font></tt> <br><tt><font size=-1>// and are covered by the appropriate copyright disclaimers included herein.</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// -------------------------------------------</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>//####BSDCOPYRIGHTEND####</font></tt> <br><tt><font size=-1>//==========================================================================</font></tt> <br><tt><font size=-1>//#####DESCRIPTIONBEGIN####</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>// Author(s): gthomas</font></tt> <br><tt><font size=-1>// Contributors: gthomas</font></tt> <br><tt><font size=-1>// Date: 2000-01-10</font></tt> <br><tt><font size=-1>// Purpose:</font></tt> <br><tt><font size=-1>// Description:</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>//####DESCRIPTIONEND####</font></tt> <br><tt><font size=-1>//</font></tt> <br><tt><font size=-1>//==========================================================================</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>// PING test code</font></tt><b><tt><font size=-1></font></tt></b> <p><b><tt><font size=-1>#include <network.h></font></tt></b></blockquote> This single include directive is all that is required to pick up the networking support, including complete configuration information. <blockquote><tt><font size=-1>#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL</font></tt> <br><tt><font size=-1>static char stack[STACK_SIZE];</font></tt> <br><tt><font size=-1>static cyg_thread thread_data;</font></tt> <br><tt><font size=-1>static cyg_handle_t thread_handle;</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>#define NUM_PINGS 16</font></tt> <br><tt><font size=-1>#define MAX_PACKET 4096</font></tt> <br><tt><font size=-1>static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>#define UNIQUEID 0x1234</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>void</font></tt> <br><tt><font size=-1>cyg_test_exit(void)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> diag_printf("... Done\n");</font></tt> <br><tt><font size=-1> while (1) ;</font></tt> <br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>void</font></tt> <br><tt><font size=-1>pexit(char *s)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> perror(s);</font></tt> <br><tt><font size=-1> cyg_test_exit();</font></tt> <br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>// Compute INET checksum</font></tt> <br><tt><font size=-1>int</font></tt> <br><tt><font size=-1>inet_cksum(u_short *addr, int len)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> register int nleft = len;</font></tt> <br><tt><font size=-1> register u_short *w = addr;</font></tt> <br><tt><font size=-1> register u_short answer;</font></tt> <br><tt><font size=-1> register u_int sum = 0;</font></tt> <br><tt><font size=-1> u_short odd_byte = 0;</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1> /*</font></tt> <br><tt><font size=-1> * Our algorithm is simple, using a 32 bit accumulator (sum),</font></tt> <br><tt><font size=-1> * we add sequential 16 bit words to it, and at the end, fold</font></tt> <br><tt><font size=-1> * back all the carry bits from the top 16 bits into the lower</font></tt> <br><tt><font size=-1> * 16 bits.</font></tt> <br><tt><font size=-1> */</font></tt> <br><tt><font size=-1> while( nleft > 1 ) {</font></tt> <br><tt><font size=-1> sum += *w++;</font></tt> <br><tt><font size=-1> nleft -= 2;</font></tt> <br><tt><font size=-1> }</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1> /* mop up an odd byte, if necessary */</font></tt> <br><tt><font size=-1> if( nleft == 1 ) {</font></tt> <br><tt><font size=-1> *(u_char *)(&odd_byte) = *(u_char *)w;</font></tt> <br><tt><font size=-1> sum += odd_byte;</font></tt> <br><tt><font size=-1> }</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1> /*</font></tt> <br><tt><font size=-1> * add back carry outs from top 16 bits to low 16 bits</font></tt> <br><tt><font size=-1> */</font></tt> <br><tt><font size=-1> sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */</font></tt> <br><tt><font size=-1> sum += (sum >> 16); /* add carry */</font></tt> <br><tt><font size=-1> answer = ~sum; /* truncate to 16 bits */</font></tt> <br><tt><font size=-1> return (answer);</font></tt> <br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>static int</font></tt> <br><tt><font size=-1>show_icmp(unsigned char *pkt, int len,</font></tt> <br><tt><font size=-1> struct sockaddr_in *from, struct sockaddr_in *to)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> cyg_tick_count_t *tp, tv;</font></tt> <br><tt><font size=-1> struct ip *ip;</font></tt> <br><tt><font size=-1> struct icmp *icmp;</font></tt> <br><tt><font size=-1> tv = cyg_current_time();</font></tt> <br><tt><font size=-1> ip = (struct ip *)pkt;</font></tt> <br><tt><font size=-1> if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {</font></tt> <br><tt><font size=-1> diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n",</font></tt> <br><tt><font size=-1> inet_ntoa(from->sin_addr), len, ip->ip_v);</font></tt> <br><tt><font size=-1> return 0;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> icmp = (struct icmp *)(pkt + sizeof(*ip));</font></tt> <br><tt><font size=-1> len -= (sizeof(*ip) + 8);</font></tt> <br><tt><font size=-1> tp = (cyg_tick_count_t *)&icmp->icmp_data;</font></tt> <br><tt><font size=-1> if (icmp->icmp_type != ICMP_ECHOREPLY) {</font></tt> <br><tt><font size=-1> diag_printf("%s: Invalid ICMP - type: %d\n",</font></tt> <br><tt><font size=-1> inet_ntoa(from->sin_addr), icmp->icmp_type);</font></tt> <br><tt><font size=-1> return 0;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> if (icmp->icmp_id != UNIQUEID) {</font></tt> <br><tt><font size=-1> diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n",</font></tt> <br><tt><font size=-1> inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));</font></tt> <br><tt><font size=-1> diag_printf("icmp_seq=%d", icmp->icmp_seq);</font></tt> <br><tt><font size=-1> diag_printf(", time=%dms\n", (int)(tv - *tp)*10);</font></tt> <br><tt><font size=-1> return (from->sin_addr.s_addr == to->sin_addr.s_addr);</font></tt> <br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>static void</font></tt> <br><tt><font size=-1>ping_host(int s, struct sockaddr_in *host)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> struct icmp *icmp = (struct icmp *)pkt1;</font></tt> <br><tt><font size=-1> int icmp_len = 64;</font></tt> <br><tt><font size=-1> int seq, ok_recv, bogus_recv;</font></tt> <br><tt><font size=-1> cyg_tick_count_t *tp;</font></tt> <br><tt><font size=-1> long *dp;</font></tt> <br><tt><font size=-1> struct sockaddr_in from;</font></tt> <br><tt><font size=-1> int i, len, fromlen;</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1> ok_recv = 0;</font></tt> <br><tt><font size=-1> bogus_recv = 0;</font></tt> <br><tt><font size=-1> diag_printf("PING server %s\n", <b>inet_ntoa(host->sin_addr)</b>);</font></tt></blockquote> This function takes an IP address and returns a string representation. Useful for printing the address. <blockquote><tt><font size=-1> for (seq = 0; seq < NUM_PINGS; seq++) {</font></tt> <br><tt><font size=-1> // Build ICMP packet</font></tt> <br><tt><font size=-1> icmp->icmp_type = ICMP_ECHO;</font></tt> <br><tt><font size=-1> icmp->icmp_code = 0;</font></tt> <br><tt><font size=-1> icmp->icmp_cksum = 0;</font></tt> <br><tt><font size=-1> icmp->icmp_seq = seq;</font></tt> <br><tt><font size=-1> icmp->icmp_id = 0x1234;</font></tt> <br><tt><font size=-1> // Set up ping data</font></tt> <br><tt><font size=-1> tp = (cyg_tick_count_t *)&icmp->icmp_data;</font></tt> <br><tt><font size=-1> *tp++ = cyg_current_time();</font></tt> <br><tt><font size=-1> dp = (long *)tp;</font></tt> <br><tt><font size=-1> for (i = sizeof(*tp); i < icmp_len; i += sizeof(*dp)) {</font></tt> <br><tt><font size=-1> *dp++ = i;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> // Add checksum</font></tt> <br><tt><font size=-1> icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);</font></tt> <br><tt><font size=-1> // Send it off</font></tt> <br><tt><font size=-1> <b>if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {</b></font></tt></blockquote> This function sends a single packet, in this case via the ICMP protocol. The destination address is specified by the <tt>host</tt> argument. <blockquote><tt><font size=-1> perror("sendto");</font></tt> <br><tt><font size=-1> continue;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> // Wait for a response</font></tt> <br><tt><font size=-1> fromlen = sizeof(from);</font></tt> <br><tt><font size=-1> <b>len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);</b></font></tt></blockquote> This function waits for a packet to be sent to this interface. Note: this operation can fail if no packet is received with a given amount of time (this timeout value is setup in the <tt>ping_test()</tt> routine below). <blockquote><tt><font size=-1> if (len < 0) {</font></tt> <br><tt><font size=-1> perror("recvfrom");</font></tt> <br><tt><font size=-1> } else {</font></tt> <br><tt><font size=-1> if (show_icmp(pkt2, len, &from, host)) {</font></tt> <br><tt><font size=-1> ok_recv++;</font></tt> <br><tt><font size=-1> } else {</font></tt> <br><tt><font size=-1> bogus_recv++;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);</font></tt> <br><tt><font size=-1>}</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1>static void</font></tt> <br><tt><font size=-1>ping_test(struct bootp *bp)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> struct protoent *p;</font></tt> <br><tt><font size=-1> struct timeval tv;</font></tt> <br><tt><font size=-1> struct sockaddr_in host;</font></tt> <br><tt><font size=-1> int s;</font></tt><tt><font size=-1></font></tt> <p><tt><font size=-1> <b>if ((p = getprotobyname("icmp")) == (struct protoent *)0) {</b></font></tt></blockquote> This function gets information about the ICMP protocol. This will be used below to set up the "socket" (the handle to a network connection). <blockquote><tt><font size=-1> perror("getprotobyname");</font></tt> <br><tt><font size=-1> return;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> <b>s = socket(AF_INET, SOCK_RAW, p->p_proto);</b></font></tt></blockquote> Create the socket "s". A socket is an abstract object (sometimes called a handle or endpoint). Sockets come in many flavors, RAW sockets are used for communicating with non-structured protocols. DATAGRAM sockets are used for packet oriented protocols, such as UDP. STREAM sockets are used for reliable, sequenced byte streams, such as those provided by TCP. <blockquote><tt><font size=-1> if (s < 0) {</font></tt> <br><tt><font size=-1> perror("socket");</font></tt> <br><tt><font size=-1> return;</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1> tv.tv_sec = 1;</font></tt> <br><tt><font size=-1> tv.tv_usec = 0;</font></tt> <br><tt><font size=-1> <b>setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));</b></font></tt></blockquote> This function instructs the system that receive operations (see <tt>ping_host()</tt> above) must complete within 1 second or issue a timed out error condition. <blockquote><tt><font size=-1> // Set up host address</font></tt> <br><tt><font size=-1> host.sin_family = AF_INET;</font></tt> <br><tt><font size=-1> host.sin_addr = bp->bp_siaddr;</font></tt> <br><tt><font size=-1> host.sin_port = 0;</font></tt> <br><tt><font size=-1> ping_host(s, &host);</font></tt> <br><tt><font size=-1> // Now try a bogus host</font></tt> <br><tt><font size=-1> host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);</font></tt> <br><tt><font size=-1> ping_host(s, &host);</font></tt> <br><tt><font size=-1>}</font></tt> <br><tt><font size=-1></font></tt> </blockquote> This function drives the test. <blockquote><tt><font size=-1>void</font></tt> <br><tt><font size=-1>net_test(cyg_addrword_t p)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> diag_printf("Start PING test\n");</font></tt> <br><tt><font size=-1> <b>init_all_network_interfaces();</b></font></tt></blockquote> This is a call to the network initialization code. Note that it must be executed from a thread context, thus we can't put it in the <tt>cyg_start() </tt>function which follows. The <tt>init_all_network_interfaces()</tt> routine will cause the networking system to be initialized and any hardware interfaces will be set up. Using the system configuration information, an interface can be started using either <b>BOOTP</b>, or a predefined configuration with static IP information. It is also possible to indicate that an interface will be configured by the user code, outside of "<tt>init_all_network_interfaces()</tt>". <br><tt><font size=-1> </font></tt> <br><tt><font size=-1> #ifdef CYGHWR_NET_DRIVER_ETH0</font></tt> <br><tt><font size=-1> if (eth0_up) {</font></tt> <blockquote><tt><font size=-1> ping_test(&eth0_bootp_data);</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1>#endif</font></tt></blockquote> Notice that there is a BOOTP information structure kept about all hardware interfaces. This is created and initialized by the call to <tt>init_all_network_interfaces()</tt>, unless manual configuration is selected. This information can be used by the application to learn things such as the local IP address, server name, etc. <blockquote><tt><font size=-1>#ifdef CYGHWR_NET_DRIVER_ETH1</font></tt> <br><tt><font size=-1> if (eth1_up) {</font></tt> <br><tt><font size=-1> ping_test(&eth1_bootp_data);</font></tt> <br><tt><font size=-1> }</font></tt> <br><tt><font size=-1>#endif</font></tt></blockquote> Multiple hardware interfaces can be supported, depending on the hardware platform. If the platform provides a single ethernet device then <b><tt>CYGHWR_NET_DRIVER_ETH0 </tt></b>will be defined. If there is a second interface, then will <b><tt>CYGHWR_NET_DRIVER_ETH1 </tt></b>be defined. <blockquote><tt><font size=-1> cyg_test_exit();</font></tt> <br><tt><font size=-1>}</font></tt> <br><tt><font size=-1></font></tt> </blockquote> The following function creates an initial thread which runs the program. This could just as easily be done by naming the <tt>net_test()</tt> function <tt>main()</tt>. <blockquote><tt><font size=-1>void</font></tt> <br><tt><font size=-1>cyg_start(void)</font></tt> <br><tt><font size=-1>{</font></tt> <br><tt><font size=-1> // Create a main thread, so we can run the scheduler and have time 'pass'</font></tt> <br><tt><font size=-1> cyg_thread_create(10, // Priority - just a number</font></tt> <br><tt><font size=-1> net_test, // entry</font></tt> <br><tt><font size=-1> 0, // entry parameter</font></tt> <br><tt><font size=-1> "Network test", // Name</font></tt> <br><tt><font size=-1> &stack[0], // Stack</font></tt> <br><tt><font size=-1> STACK_SIZE, // Size</font></tt> <br><tt><font size=-1> &thread_handle, // Handle</font></tt> <br><tt><font size=-1> &thread_data // Thread data structure</font></tt> <br><tt><font size=-1> );</font></tt> <br><tt><font size=-1> cyg_thread_resume(thread_handle); // Start it</font></tt> <br><tt><font size=-1> cyg_scheduler_start();</font></tt> <br><tt><font size=-1>}</font></tt></blockquote> </body> </html>