]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/autotest/v2_0/tests/autohost.inl
Initial revision
[karo-tx-redboot.git] / packages / net / autotest / v2_0 / tests / autohost.inl
1 //==========================================================================
2 //
3 //      tests/auto/autohost.inl
4 //
5 //      Automated Testing by a Host Computer
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //####BSDCOPYRIGHTBEGIN####
39 //
40 // -------------------------------------------
41 //
42 // Portions of this software may have been derived from OpenBSD or other sources,
43 // and are covered by the appropriate copyright disclaimers included herein.
44 //
45 // -------------------------------------------
46 //
47 //####BSDCOPYRIGHTEND####
48 //==========================================================================
49 //#####DESCRIPTIONBEGIN####
50 //
51 // Author(s):    hmt,gthomas
52 // Contributors: hmt,gthomas
53 // Date:         2000-10-18
54 // Purpose:      Automated testing of the eCos TCP/IP Network Stack
55 // Description:  
56
57 //      This .inl file defines routines which send /orders/ to the server
58 //      running on the host machine who served us DHCP, and receive
59 //      /results/ from the same machine or machines.
60 //
61 //      autohost_tell() sends the order to an app "awaitorder" which feeds
62 //      the order into obey.sh which obeys the order, for example, running
63 //      some tftp sessions to exercise the tftp server.
64 //
65 //      The /orders/ must come from a predefined list, to match the
66 //      selection which obey.sh is expecting, for example "TFTP_SERV_GET"
67 //      which has further parameters <target> <timeout>.  Additional
68 //      parameters are added/manipulated by obey.sh which then invokes a
69 //      relevent script (tftpget.sh) to do the test.
70 //
71 //      The test script's output is returned to us, and is collected by
72 //      autohost_getresults() which runs in a high-ist prio thread.  It
73 //      prints the output, which is expected to match the traditional eCos
74 //      PASS:<happy> FAIL:<eek!> sort of format, so that the test farm can
75 //      collect these messages from the testcase output, without any direct
76 //      connection to the server.
77 //
78 //      autohost_init() simply starts the autohost_getresults() thread.
79 //
80 //      The predefined list of orders is *not* defined here or anywhere
81 //      else besides obey.sh which does a switch statement for them, to
82 //      make it easier to extent; similarly the params each order takes are
83 //      not centrally recorded either.  It is however a convention that the
84 //      word following the /order/ is our own IP address.
85 //
86 //
87 //####DESCRIPTIONEND####
88 //
89 //==========================================================================
90
91 #include <cyg/infra/testcase.h>         // testing infrastructure
92
93 #include "memcheck.inl"                 // check on memory usage
94
95 externC int sprintf( char * /* str */, const char * /* format */, ... );
96
97 // ------------------------------------------------------------------------
98
99 #include <pkgconf/system.h>
100 #ifdef CYGPKG_IO_ETH_DRIVERS
101 #include <pkgconf/io_eth_drivers.h>
102 #endif
103
104 #if defined(XFAIL) || defined(XPASS)
105 // So that the test can override this automation
106 # if defined(XFAIL) && defined(XPASS)
107 #  error Both XFAIL and XPASS predefined
108 # endif
109 # undef XFAIL
110 # ifndef XPASS
111 #  define XFAIL "XFAIL"
112 # endif
113 #else
114 # ifdef CYGPKG_IO_ETH_DRIVERS_SIMULATED_FAILURES
115 // Then we must tell the test server to expect failures.
116 #  define XFAIL "XFAIL"
117 # endif
118 #endif // XFAIL/XPASS not predefined
119
120 // ------------------------------------------------------------------------
121
122 void
123 pexit(char *s)
124 {
125     TNR_OFF();
126     CYG_TEST_FAIL_EXIT( s );
127 }
128
129 // ------------------------------------------------------------------------
130
131 #define SOURCE_PORT 9980
132 #define RESULT_PORT 9990
133
134 static int
135 autohost_tell( struct bootp *bp, char *orders )
136 {
137     int s_host;
138     struct sockaddr_in slave, local;
139     int one = 1;
140     int len = strlen( orders );
141     char ack[32];
142     int ret;
143
144     char complete_order[256];
145
146     if ( len > 240 )
147         pexit( "Orders too long" );
148
149     memset(&slave, 0, sizeof(slave));
150     slave.sin_family = AF_INET;
151     slave.sin_len = sizeof(slave);
152     slave.sin_port = htons(SOURCE_PORT);
153     slave.sin_addr = bp->bp_siaddr; // Talk to our DHCP server
154
155     s_host = socket(AF_INET, SOCK_STREAM, 0);
156     if (s_host < 0) {
157         pexit("stream socket");
158     }
159
160     memset(&local, 0, sizeof(local));
161     local.sin_family = AF_INET;
162     local.sin_len = sizeof(local);
163     local.sin_port = INADDR_ANY;
164     local.sin_addr.s_addr = INADDR_ANY;
165     if(bind(s_host, (struct sockaddr *) &local, sizeof(local)) < 0) {
166         pexit("bind /source/ error");
167    }
168     if (setsockopt(s_host, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
169         pexit("setsockopt /source/ SO_REUSEADDR");
170     }
171
172     ret = connect(s_host, (struct sockaddr *)&slave, sizeof(slave));
173     if ( ret < 0) {
174         TNR_OFF();
175         diag_printf(
176             "Connect failed %d err %d, s_host %d, sin_port %x, sin_addr %08x\n", 
177                     ret, errno, s_host, slave.sin_port, slave.sin_addr.s_addr );
178         pexit("Can't connect to target");
179     }
180
181     sprintf( complete_order,
182 #ifdef XFAIL
183              "%s %s", XFAIL,
184 #else
185              "%s",
186 #endif
187              orders );
188     len = 1 + strlen( complete_order ); // Send the null also
189
190     if ( len != write(s_host, (unsigned char *)complete_order, len ) ) {
191         pexit("Can't send orders");
192     }
193     ret = read(s_host, (unsigned char *)&ack, sizeof(ack));
194     if ( 0 >= ret ) {
195         pexit("Can't get ACK");
196     }
197     close(s_host);
198     return 1;
199 }
200
201 // ---------------------------------------------------------------------------
202
203 #define nHALTAFTERFAIL
204 #ifdef HALTAFTERFAIL
205 static cyg_alarm ahr_fail_alarm;
206 static cyg_handle_t ahr_fail_alarm_handle = 0;
207 static cyg_alarm_t ahr_fail_alarm_function;
208
209 void ahr_fail_alarm_function(cyg_handle_t alarm, cyg_addrword_t data)
210 {
211     CYG_TEST_FAIL_EXIT( "Failure reported by autohost" );
212 }
213 #endif
214
215 static int result_passes = 0;
216 static int result_fails  = 0;
217
218 static void
219 autohost_getresults( cyg_addrword_t loop )
220 {
221     int s_source, e_source;
222     struct sockaddr_in e_source_addr, local;
223     int one = 1;
224     int len;
225     char result[256];
226
227     s_source = socket(AF_INET, SOCK_STREAM, 6 /* TCP */ );
228     if (s_source < 0) {
229         pexit("stream socket");
230     }
231
232     memset(&local, 0, sizeof(local));
233     local.sin_family = AF_INET;
234     local.sin_len = sizeof(local);
235     local.sin_port = ntohs(RESULT_PORT);
236     local.sin_addr.s_addr = INADDR_ANY;
237     if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) {
238         pexit("bind /source/ error");
239     }
240     if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
241         pexit("setsockopt /source/ SO_REUSEADDR");
242     }
243 #ifdef SO_REUSEPORT
244     if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
245         pexit("setsockopt /source/ SO_REUSEPORT");
246     }
247 #endif
248
249     listen(s_source, SOMAXCONN);
250
251     do {
252         len = sizeof(e_source_addr);
253         if ((e_source = accept(s_source,
254                  (struct sockaddr *)&e_source_addr, &len)) < 0) {
255             pexit("accept /source/");
256         }
257         
258         // Wait for "source" to tell us the result
259         if ( 0 >= (len = read(e_source, result, sizeof(result)))) {
260             pexit("Can't read result");
261         }
262
263         result[len] = 0;
264         len--;
265         while( len && ('\r' == result[len] || '\n' == result[len]) )
266             result[len--] = 0;
267
268         TNR_OFF();
269         diag_printf( "%s (from %s:%d)\n", result,
270            inet_ntoa(e_source_addr.sin_addr), ntohs(e_source_addr.sin_port));
271         TNR_ON();
272
273         // Check for a pass message right now:
274         if ( 'P' == result[0] &&
275              'A' == result[1] &&
276              'S' == result[2] &&
277              'S' == result[3] ) {
278             result_passes++;
279         }
280         else
281         // Check for a failure right now:
282         if ( 'F' == result[0] &&
283              'A' == result[1] &&
284              'I' == result[2] &&
285              'L' == result[3] ) {
286             result_fails++;
287 #ifdef HALTAFTERFAIL
288             // Wait a bit for the others, if any, to come in before halting
289             // the test, since the host is typically running multiple
290             // threads to torment us.  Set an alarm to go FAIL_EXIT in 20S.
291             if ( ! ahr_fail_alarm_handle ) {
292                 cyg_handle_t h;
293                 cyg_clock_to_counter(cyg_real_time_clock(), &h),
294                 cyg_alarm_create(
295                     h,                       /* Attached to this ctr */
296                     ahr_fail_alarm_function, /* Call-back function   */
297                     0,                       /* Call-back data       */
298                     &ahr_fail_alarm_handle,  /* Returned alarm obj   */
299                     &ahr_fail_alarm          /* put alarm here       */
300                     );
301                 cyg_alarm_initialize(
302                     ahr_fail_alarm_handle,
303                     cyg_current_time() + (20 * 100),
304                     0 );
305                 cyg_alarm_enable( ahr_fail_alarm_handle );
306             }
307 #endif
308         }
309
310         close( e_source );
311     } while ( loop );
312
313     close( s_source );
314 }
315
316 // ---------------------------------------------------------------------------
317
318 static void autohost_end( int expected_passes )
319 {
320 #ifdef HALTAFTERFAIL
321     if ( ahr_fail_alarm_handle )
322         cyg_alarm_disable( ahr_fail_alarm_handle );
323 #endif
324 #ifdef XFAIL
325     if ( ! (result_passes >= expected_passes) )
326         CYG_TEST_INFO( "XFAIL: Not enough PASS results posted" );
327     if ( ! (0 == result_fails) )
328         CYG_TEST_INFO( "XFAIL: FAIL results posted" );
329     if ( ! (result_passes >= expected_passes && 0 == result_fails) )
330         CYG_TEST_PASS( "XFAIL: Pass anyway" );
331 #else
332     CYG_TEST_CHECK( result_passes >= expected_passes,
333                     "Not enough PASS results posted" );
334     CYG_TEST_CHECK( 0 == result_fails,
335                     "FAIL results posted" );
336 #endif
337     if ( result_passes >= expected_passes && 0 == result_fails )
338         CYG_TEST_PASS( "Results from host[s] OK" );
339
340     // Record and check final state of net stack memory consumption
341     memcheck_final();
342 }
343
344 // ---------------------------------------------------------------------------
345
346 static char ahr_stack[ CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x400 ];
347 static cyg_thread ahr_thread_data;
348
349 static void autohost_init( void )
350 {
351     cyg_handle_t ahr_thread_handle;
352     cyg_thread_create(    5,            // Priority - just a number
353            autohost_getresults,         // entry
354            1,                           // entry parameter
355            "Autohost result monitor",   // Name
356            &ahr_stack[0],               // Stack
357            sizeof(ahr_stack),           // Size
358            &ahr_thread_handle,          // Handle
359            &ahr_thread_data             // Thread data structure
360         );
361     cyg_thread_resume(ahr_thread_handle);  // Start it
362
363     // Record initial state of net stack memory consumption
364     memcheck_init();
365 }
366
367 // EOF autohost.inl