comparison src/g23m-fad/app/app_core.c @ 174:90eb61ecd093

src/g23m-fad: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 12 Oct 2016 05:40:46 +0000
parents
children
comparison
equal deleted inserted replaced
173:bf64d785238a 174:90eb61ecd093
1 /*-*- c-basic-offset: 2 -*-
2 +------------------------------------------------------------------------------
3 | File: app_core.c
4 +------------------------------------------------------------------------------
5 | Copyright 2003 Texas Instruments Berlin, AG
6 | All rights reserved.
7 |
8 | This file is confidential and a trade secret of Texas
9 | Instruments Berlin, AG
10 | The receipt of or possession of this file does not convey
11 | any rights to reproduce or disclose its contents or to
12 | manufacture, use, or sell anything it may describe, in
13 | whole, or in part, without the specific written consent of
14 | Texas Instruments Berlin, AG.
15 +-----------------------------------------------------------------------------
16 | Purpose : Example application for TCP/IP and Socket API -- core functions.
17 +-----------------------------------------------------------------------------
18 */
19
20
21 /* This should only be compiled into the entity if TCP/IP is enabled */
22 #ifdef FF_GPF_TCPIP
23
24 #define APP_CORE_C
25
26 #define ENTITY_APP
27
28 /*==== INCLUDES =============================================================*/
29
30 #include <string.h> /* String functions, e. g. strncpy(). */
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifndef _SIMULATION_
35 #include "typedefs.h" /* Condat data types. */
36 #endif /* _SIMULATION_ */
37 #include "vsi.h" /* A lot of macros. */
38 #ifndef _SIMULATION_
39 #include "custom.h"
40 #include "gsm.h" /* A lot of macros. */
41 #include "prim.h" /* Definitions of used SAP and directions. */
42 #include "pei.h" /* PEI interface. */
43 #include "tools.h" /* Common tools. */
44 #endif /* _SIMULATION_ */
45 #include "socket_api.h" /* Socket API. */
46 #include "app.h" /* Global entity definitions. */
47
48
49 /*==== Local data ============================================================*/
50
51 #define NPROCS 1 /* Maximum number of application processes. */
52
53 #define PORT_CHARGEN 19 /* Chargen service for download. */
54 #define PORT_ECHO 7 /* Echo port for tcpecho and udpecho. */
55 #define PORT_DISCARD 9 /* Discard port for upload. */
56
57 #define FQDN_LENGTH 255 /* Maximum length of a fully-qualified domain
58 * name. */
59
60 #undef HTONS
61 #define HTONS(a) ((((a) & 0xff) << 8) | (((a) & 0xff00) >> 8))
62 #undef NTOHS
63 #define NTOHS(a) HTONS(a)
64 #define MIN(a, b) ((a) < (b) ? (a) : (b))
65
66 /* We can run different types of application processes, according to the
67 * commend sent by the user. */
68 typedef enum {
69 AP_NONE, /* For uninitialized process types. */
70 AP_TCPDL, /* Download some data over TCP. */
71 AP_TCPUL, /* Upload some data over TCP. */
72 AP_UDPDL, /* Download some data over UDP. */
73 AP_UDPUL, /* Upload some data over UDP. */
74 AP_TCPECHO, /* Send/receive data to/from TCP echo port. */
75 AP_UDPECHO, /* Send/receive data to/from UDP echo port. */
76 AP_TCPSRV, /* TCP server application. */
77 AP_DNSQRY, /* Issue DNS queries and collect result. */
78 AP_TCPFORK, /* Forked TCP server process. */
79 AP_INVALID
80 } APP_PROCTYPE_T ;
81
82 /* Strings for process types; used for debugging and MUST correspond strictly
83 * to the process type enum labels defined above. */
84 static char *proc_type_name[] = {
85 "AP_NONE", /* 00 */
86 "AP_TCPDL", /* dl */
87 "AP_TCPUL", /* ul */
88 "AP_UDPDL",
89 "AP_UDPUL",
90 "AP_TCPECHO", /* te */
91 "AP_UDPECHO", /* ue */
92 "AP_TCPSRV",
93 "AP_DNSQRY", /* dq */
94 "AP_TCPFORK",
95 "AP_INVALID"
96 } ;
97
98 /* Process states; the state transitions are mostly linear in this order. */
99 typedef enum {
100 PS_IDLE, /* Initial state, process not running. */
101 PS_W_DCM_OPEN, /* Waiting for DCM to open connection. */
102 PS_W_DCM_OPEN_ONLY, /* Waiting for DCM to open connection - no further action. */
103 PS_W_CREAT, /* Waiting for socket create confirmation. */
104 PS_W_SCONN, /* Waiting for socket connect confirmation. */
105 PS_W_BIND, /* Waiting for socket bind confirmation. */
106 PS_W_LISTN, /* Waiting for confirmation of listen call. */
107 PS_LISTENS, /* Listens for client connections. */
108 PS_W_DNS, /* Waiting for a DNS query. */
109 PS_COMM, /* Happily exchanging data. */
110 PS_W_SCLOS, /* Waiting for socket close confirmation. */
111 PS_W_DCLOS, /* Waiting for DCM to close connection. */
112 PS_W_CONN_INFO, /* Waiting for connection information */
113 PS_DCM_OPEN, /* DCM (bearer) connecion opened*/
114 PS_SOCK_OPEN, /* Socket and bearer open */
115 PS_INVALID
116 } PROC_STAT_T ;
117
118 /* Strings for the process states; used for debugging and MUST correspond
119 * strictly to the process state enum labels defined above, as the array is
120 * indexed by those. */
121 static char *proc_state_name[] = {
122 "PS_IDLE",
123 "PS_W_DCM_OPEN",
124 "PS_W_DCM_OPEN_ONLY",
125 "PS_W_CREAT",
126 "PS_W_SCONN",
127 "PS_W_BIND",
128 "PS_W_LISTN",
129 "PS_W_LISTENS",
130 "PS_W_DNS",
131 "PS_COMM",
132 "PS_W_SCLOS",
133 "PS_W_DCLOS",
134 "PS_W_CONN_INFO",
135 "PS_DCM_OPEN",
136 "PS_SOCK_OPEN",
137 "PS_INVALID"
138 } ;
139
140 /* The data a process holds. May be dynamically allocated in the future. */
141 typedef struct PROCESS_CONTEXT_S {
142 APP_PROCTYPE_T ptype ; /* Type of application process */
143 PROC_STAT_T pstate ; /* Process status as defined above. */
144 int in_shutdown ; /* Non-zero iff process is being shut down. */
145 T_SOCK_EVENTSTRUCT *last_evt; /* Last event passed from the Socket API. */
146 T_SOCK_IPPROTO ipproto ; /* IP protocol number for this process (TCP or
147 * UDP); unused with dq. */
148 char *server_name ; /* May be a domain name or an IP address in
149 * dotted decimal notation. */
150 T_SOCK_IPADDR server_ipaddr ; /* Server IP address. (Will be IPADDR_ANY in
151 * case of AP_TCPSRV.) */
152 T_SOCK_PORT server_port ; /* Server port number. (Also in case of
153 * AP_TCPSRV.) */
154
155 /* The following variables are in use only where appropriate, of course --
156 * as indicated in the comment. */
157
158 int f_id ; /* Identity of TCP server fork. */
159 int spec_items ; /* Specified number of items to transfer. (The
160 * items are single bytes for dl and ul.) */
161 int spec_reps ; /* Specified number of repetitions. */
162
163 int data_sent ; /* Total amount of data sent (ul, te, ue). */
164 int data_rcvd ; /* Total amount of data recvd (dl, te, ue). */
165 int items_sent ; /* Number of blocks/packets/queries sent (ul,
166 * te, ue, dq). */
167 int items_rcvd ; /* Number of blocks/packets/responses received
168 * (dl, te, ue, dq). */
169 int n_reps ; /* Number of repetitions done. */
170 int errors ; /* Number of errors at all. */
171 T_SOCK_SOCKET psocket ; /* The socket in use by the process. */
172 int network_is_open ; /* Non-zero iff we have an open network
173 * connection. */
174 int psocket_is_open ; /* Non-zero iff we have an open psocket. */
175 BOOL bearer_only; /* if set, only a Bearer will be opened */
176 } PROC_CONTEXT_T ;
177
178 static PROC_CONTEXT_T proc_context ;
179 static PROC_CONTEXT_T cl_context[APP_N_CLIENTS] ;
180 static char server_name[FQDN_LENGTH+1] = APP_DEF_SERVER ;
181 /* Global server name. */
182 static char query_name[FQDN_LENGTH+1] = APP_DEF_DNSQUERY_ADDR ;
183 static int buffer_size = APP_DEF_BUFFER_SIZE ;
184 static U16 port_number = 0 ; /* Port number override if non-zero. */
185 static int udp_interval = APP_DEF_UDP_INTERVAL ;
186 static T_SOCK_BEARER_TYPE bearer_select = SOCK_BEARER_AS_SPECIFIED;
187 static T_SOCK_BEARER_TYPE sock_bearer_type = SOCK_BEARER_GPRS;
188 EXTERN BOOL custom_apn_valid;
189
190
191 /* The cache for DNS queries is RNET_RT_RESOLV_CACHE_MAX queries big, i. e. 8
192 * in the current configuration. We need to overflow this cache in order to
193 * test lookup robustness. */
194 static char *domain_name[] = {
195 #ifdef _SIMULATION_ /* Not in the simulation, though. */
196 "chuck.berlin.tide.ti.com",
197 #else /* _SIMULATION_ */
198 "gsmtest.com",
199 "w21.org",
200 "gw.w21.org",
201 "troll.cs.tu-berlin.de",
202 "gatekeeper.dec.com",
203 "www.mcvax.org",
204 "www.mcvaymedia.com",
205 "www.vodafone.de",
206 "www.ti.com",
207 "mailbox.tu-berlin.de",
208 "ge-2-3-0.r02.asbnva01.us.bb.verio.net",
209 "www.condat.de",
210 "www.tellique.de",
211 "prz.tu-berlin.de",
212 #endif /* _SIMULATION_ */
213 0
214 } ;
215
216
217
218 /*==== Local functions =======================================================*/
219
220 /*
221 * Utility functions.
222 */
223
224
225 static char *sock_bearer_type_string(T_SOCK_BEARER_TYPE btype)
226 {
227 switch (btype)
228 {
229 case SOCK_BEARER_ANY: return "SOCK_BEARER_ANY" ;
230 case SOCK_BEARER_GPRS: return "SOCK_BEARER_GPRS" ;
231 case SOCK_BEARER_GSM: return "SOCK_BEARER_GSM" ;
232 case SOCK_BEARER_USE_PROFILE: return "SOCK_BEARER_USE_PROFILE" ;
233 case SOCK_BEARER_AS_SPECIFIED: return "SOCK_BEARER_AS_SPECIFIED" ;
234 default: return "<unknown bearer type>" ;
235 }
236 }
237
238 /** Give a print representation for the specified character. This is the
239 * character itself for printable characters and a substitution character for
240 * others.
241 *
242 * @param c the character
243 * @return the print representation
244 */
245 static char p_char(char c)
246 {
247 return isprint(c) ? c : '~' ;
248 }
249
250
251 #define DUMP_LLENGTH 16 /* Data dump line length. */
252 #define DBUF_LENGTH (4 * DUMP_LLENGTH + 10) /* See example below. */
253 #define XDIGIT(n) ("0123456789abcdef"[n])
254
255 /** Dump the specified portion of the data as event traces like this:
256 * 0000: 27 28 29 2a 2b 2c 2d 2e-2f 30 31 32 33 34 35 36 ['()*+,-./0123456]
257 *
258 * @param data Pointer to data area
259 * @param size Size of data to dump
260 */
261 void trace_dump_data(U8 *data, int size)
262 {
263 char dump_buf[DBUF_LENGTH] ; /* Buffer to dump a line into. */
264 int lcount = 0 ; /* Line count. */
265 int i ; /* Index into data. */
266 char *cp ; /* Pointer to current char in dump_buf[]. */
267
268 while (size > 0)
269 {
270 cp = dump_buf ;
271 /* Hex values. */
272 for (i = 0; i < DUMP_LLENGTH && i < size; i++)
273 {
274 *cp++ = XDIGIT(data[i] >> 4) ;
275 *cp++ = XDIGIT(data[i] & 0xf) ;
276 *cp++ = (i == DUMP_LLENGTH/2 - 1) ? '-' : ' ' ;
277 }
278
279 /* Fill up with blanks. */
280 for ( ; i < DUMP_LLENGTH; i++)
281 {
282 *cp++ = ' ' ; *cp++ = ' ' ; *cp++ = ' ' ;
283 }
284
285 /* Literal characters with some decoration. */
286 *cp++ = '[' ;
287 for (i = 0; i < DUMP_LLENGTH && i < size; i++, cp++)
288 {
289 *cp = p_char(data[i]) ;
290 }
291 *cp++ = ']' ;
292 *cp++ = 0 ;
293 TRACE_EVENT_P2("%04x: %s", DUMP_LLENGTH * lcount++, dump_buf) ;
294 size -= DUMP_LLENGTH ;
295 data += DUMP_LLENGTH ;
296 }
297 }
298
299
300 /** Build a string, characterizing a process, suitable for tracing. The string
301 * is statically allocated and will be overwritten with the next call.
302 *
303 * @param pcont Pointer to process context.
304 * @return The string.
305 */
306 char *proc_string(PROC_CONTEXT_T *pcont)
307 {
308 /* This string must fit the longest possible process string. */
309 static char procstring[sizeof("AP_TCPFORK99(PS_W_DCM_OPEN_ONLY)")] ;
310
311 /*lint -e685 (Warning -- Relational operator always evaluates to true) */
312 sprintf(procstring, "%s%d(%s)",
313 pcont->ptype <= AP_INVALID ? proc_type_name[pcont->ptype] : "AP_UNKNOWN",
314 pcont->ptype == AP_TCPFORK ? pcont->f_id : 0,
315 pcont->pstate <= PS_INVALID ? proc_state_name[pcont->pstate] : "PS_UNKNOWN") ;
316 /*lint +e685 (Warning -- Relational operator always evaluates to true) */
317 return procstring ;
318 }
319
320
321 /** Converts a numeric IP address in network order into an IP address in
322 * dotted decimal string notation. The string returned is statically allocated
323 * and will be overwritten on the next call.
324 *
325 * @param ipaddr The IP address in network order
326 * @return String with the IP address in dotted decimal..
327 */
328 static char *inet_ntoa(T_SOCK_IPADDR ipaddr)
329 {
330 U8 *addrbyte ;
331 static char addr_string[sizeof("000.000.000.000")] ;
332
333 addrbyte = (U8 *) &ipaddr ;
334 sprintf(addr_string, "%u.%u.%u.%u",
335 addrbyte[0], addrbyte[1], addrbyte[2], addrbyte[3]) ;
336 return addr_string ;
337 }
338
339
340 /** Converts an IP address in dotted decimal string notation into a numeric IP
341 * address in network order.
342 *
343 * @param addr_string String with the IP address in dotted decimal.
344 * @return The IP address in network order, or SOCK_IPADDR_ANY if the address
345 * string cannot be parsed.
346 */
347 static T_SOCK_IPADDR inet_aton(char *addr_string)
348 {
349 T_SOCK_IPADDR ipaddr ;
350 U8 *addrbyte ;
351 int o1, o2, o3, o4 ;
352
353 if (sscanf(addr_string, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) != 4)
354 {
355 TRACE_EVENT_P1("cannot parse '%s' as an IP address", addr_string) ;
356 return SOCK_IPADDR_ANY ;
357 }
358 addrbyte = (U8 *) &ipaddr ;
359 addrbyte[0] = (U8) o1 ;
360 addrbyte[1] = (U8) o2 ;
361 addrbyte[2] = (U8) o3 ;
362 addrbyte[3] = (U8) o4 ;
363
364 return ipaddr ;
365 }
366
367
368 LOCAL char *sock_result_string(T_SOCK_RESULT result)
369 {
370 switch(result)
371 {
372 case SOCK_RESULT_OK : return "SOCK_RESULT_OK";
373 case SOCK_RESULT_INVALID_PARAMETER : return "SOCK_RESULT_INVALID_PARAMETER";
374 case SOCK_RESULT_INTERNAL_ERROR : return "SOCK_RESULT_INTERNAL_ERROR";
375 case SOCK_RESULT_ADDR_IN_USE : return "SOCK_RESULT_ADDR_IN_USE";
376 case SOCK_RESULT_OUT_OF_MEMORY : return "SOCK_RESULT_OUT_OF_MEMORY";
377 case SOCK_RESULT_NOT_SUPPORTED : return "SOCK_RESULT_NOT_SUPPORTED";
378 case SOCK_RESULT_UNREACHABLE : return "SOCK_RESULT_UNREACHABLE";
379 case SOCK_RESULT_CONN_REFUSED : return "SOCK_RESULT_CONN_REFUSED";
380 case SOCK_RESULT_TIMEOUT : return "SOCK_RESULT_TIMEOUT";
381 case SOCK_RESULT_IS_CONNECTED : return "SOCK_RESULT_IS_CONNECTED";
382 case SOCK_RESULT_HOST_NOT_FOUND : return "SOCK_RESULT_HOST_NOT_FOUND";
383 case SOCK_RESULT_DNS_TEMP_ERROR : return "SOCK_RESULT_DNS_TEMP_ERROR";
384 case SOCK_RESULT_DNS_PERM_ERROR : return "SOCK_RESULT_DNS_PERM_ERROR";
385 case SOCK_RESULT_NO_IPADDR : return "SOCK_RESULT_NO_IPADDR";
386 case SOCK_RESULT_NOT_CONNECTED : return "SOCK_RESULT_NOT_CONNECTED";
387 case SOCK_RESULT_MSG_TOO_BIG : return "SOCK_RESULT_MSG_TOO_BIG";
388 case SOCK_RESULT_CONN_RESET : return "SOCK_RESULT_CONN_RESET";
389 case SOCK_RESULT_CONN_ABORTED : return "SOCK_RESULT_CONN_ABORTED";
390 case SOCK_RESULT_NO_BUFSPACE : return "SOCK_RESULT_NO_BUFSPACE";
391 case SOCK_RESULT_NETWORK_LOST : return "SOCK_RESULT_NETWORK_LOST";
392 case SOCK_RESULT_NOT_READY : return "SOCK_RESULT_NOT_READY";
393 case SOCK_RESULT_BEARER_NOT_READY : return "SOCK_RESULT_BEARER_NOT_READY";
394 case SOCK_RESULT_IN_PROGRESS : return "SOCK_RESULT_IN_PROGRESS";
395 case SOCK_RESULT_BEARER_ACTIVE : return "SOCK_RESULT_BEARER_ACTIVE";
396 default : return "<INVALID SOCKET RESULT!>";
397 }
398 }
399
400
401
402 /** Trace a specific socket API result code with some context.
403 *
404 * @param pcont Pointer to process context.
405 * @param function The function or event that reported the error.
406 * @param result Socket API result code.
407 * @return
408 */
409 static void sock_trace_result(PROC_CONTEXT_T *pcont, char *function,
410 T_SOCK_RESULT result)
411 {
412 if(result NEQ SOCK_RESULT_OK)
413 {
414 TRACE_ERROR("Sock Result Error");
415 }
416 TRACE_EVENT_P3("%s: %s for %s", function,
417 sock_result_string(result), proc_string(pcont));
418 }
419
420
421 /** Return the string for a Socket API event type. We don't have the values
422 * under our (i. e. APP's) own control, so we rather do a switch than indexing
423 * an array.
424 *
425 * @param event_type Type of the event.
426 * @return String for the event type.
427 */
428 char *sock_event_string(T_SOCK_EVENTTYPE event_type)
429 {
430 switch (event_type)
431 {
432 case SOCK_CREATE_CNF: return "SOCK_CREATE_CNF" ;
433 case SOCK_CLOSE_CNF: return "SOCK_CLOSE_CNF" ;
434 case SOCK_BIND_CNF: return "SOCK_BIND_CNF" ;
435 case SOCK_LISTEN_CNF: return "SOCK_LISTEN_CNF" ;
436 case SOCK_CONNECT_CNF: return "SOCK_CONNECT_CNF" ;
437 case SOCK_SOCKNAME_CNF: return "SOCK_SOCKNAME_CNF" ;
438 case SOCK_PEERNAME_CNF: return "SOCK_PEERNAME_CNF" ;
439 case SOCK_HOSTINFO_CNF: return "SOCK_HOSTINFO_CNF" ;
440 case SOCK_MTU_SIZE_CNF: return "SOCK_MTU_SIZE_CNF" ;
441 case SOCK_RECV_IND: return "SOCK_RECV_IND" ;
442 case SOCK_CONNECT_IND: return "SOCK_CONNECT_IND" ;
443 case SOCK_CONN_CLOSED_IND: return "SOCK_CONN_CLOSED_IND" ;
444 case SOCK_ERROR_IND: return "SOCK_ERROR_IND" ;
445 case SOCK_FLOW_READY_IND: return "SOCK_FLOW_READY_IND" ;
446 case SOCK_OPEN_BEARER_CNF: return "SOCK_OPEN_BEARER_CNF";
447 case SOCK_CLOSE_BEARER_CNF: return "SOCK_CLOSE_BEARER_CNF";
448 case SOCK_BEARER_INFO_CNF: return "SOCK_BEARER_INFO_CNF";
449 case SOCK_BAERER_CLOSED_IND: return "SOCK_BAERER_CLOSED_IND";
450 default: return "<INVALID EVENT>" ;
451 }
452 }
453
454
455
456 /*
457 * Process functions.
458 */
459
460 static void proc_shutdown(PROC_CONTEXT_T *pcont) ;
461 static void proc_close_socket(PROC_CONTEXT_T *pcont) ;
462 static void proc_begin_comm(PROC_CONTEXT_T *pcont) ;
463 static void proc_close_conn(PROC_CONTEXT_T *pcont) ;
464
465
466 /** Switch process to a new state. Done mostly to have a single place to trace
467 * process state transitions.
468 *
469 * @param pcont Pointer to process context.
470 * @param newstate New state of process.
471 */
472 static void proc_new_state(PROC_CONTEXT_T *pcont, PROC_STAT_T newstate)
473 {
474 if (newstate < PS_INVALID)
475 {
476 TRACE_EVENT_P2("%s -> %s", proc_string(pcont), proc_state_name[newstate]) ;
477 pcont->pstate = newstate ;
478 }
479 else
480 {
481 TRACE_EVENT_P2("%s invalid new state %d", proc_string(pcont), newstate) ;
482 proc_shutdown(pcont) ;
483 }
484 }
485
486
487 /** Fork a new TCP server process context to handle a TCP client. Return a
488 * pointer to the process context or NULL, if no process context is free any
489 * more.
490 *
491 */
492 static PROC_CONTEXT_T *proc_new_tcpfork(PROC_CONTEXT_T *oldp)
493 {
494 int i ;
495 PROC_CONTEXT_T *pcont ;
496
497 TRACE_FUNCTION("proc_new_tcpfork()") ;
498 for (i = 0; i < APP_N_CLIENTS; i++)
499 {
500 if (cl_context[i].ptype EQ AP_NONE)
501 {
502 break ;
503 }
504 }
505 if (i == APP_N_CLIENTS)
506 {
507 return NULL ;
508 }
509
510 pcont = &cl_context[i] ;
511 memset(pcont, 0, sizeof(*pcont)) ;
512 pcont->f_id = i ;
513 pcont->ptype = AP_TCPFORK ;
514 pcont->pstate = PS_IDLE ;
515 pcont->ipproto = oldp->ipproto ;
516 pcont->server_name = oldp->server_name ;
517 pcont->server_ipaddr = oldp->server_ipaddr ;
518 pcont->server_port = oldp->server_port ;
519 pcont->network_is_open = TRUE ;
520 pcont->psocket_is_open = TRUE ;
521
522 return pcont ;
523 }
524
525 /** Free a TCP server process context.
526 *
527 */
528 static void proc_free_tcpfork(PROC_CONTEXT_T *pcont)
529 {
530 TRACE_FUNCTION("proc_free_tcpfork()") ;
531 proc_new_state(pcont, PS_IDLE) ;
532 memset(pcont, 0, sizeof(*pcont)) ;
533 }
534
535
536 static void proc_init(int prov, int size, int reps, APP_PROCTYPE_T ptype,
537 T_SOCK_IPPROTO ipproto, U16 port)
538 {
539 T_SOCK_BEARER_INFO bearer_info;
540 PROC_CONTEXT_T *pcont ;
541 BOOL bear_only = proc_context.bearer_only;
542
543 TRACE_FUNCTION("proc_init()") ;
544
545 pcont = &proc_context ;
546 if (pcont->pstate != PS_IDLE)
547 {
548 TRACE_ERROR("proc_init: process still active") ;
549 return ;
550 }
551 memset(pcont, 0, sizeof(*pcont)) ;
552 pcont->bearer_only = bear_only;
553 pcont->ptype = ptype ;
554 pcont->ipproto = ipproto ;
555 pcont->server_name = (ptype EQ AP_TCPSRV) ? "<myself>" : server_name ;
556 pcont->server_ipaddr = (ptype EQ AP_TCPSRV) ?
557 SOCK_IPADDR_ANY : inet_aton(pcont->server_name) ;
558 pcont->server_port = HTONS(port) ;
559 pcont->spec_items = size ;
560 pcont->spec_reps = reps ;
561 pcont->in_shutdown = FALSE;
562
563 pcont->psocket = 0;
564 pcont->network_is_open = FALSE;
565 pcont->psocket_is_open = FALSE;
566
567 TRACE_EVENT_P7("%s for %d bytes %d reps, server %s:%d/%s on %s",
568 proc_string(pcont), pcont->spec_items, pcont->spec_reps,
569 inet_ntoa(pcont->server_ipaddr), NTOHS(pcont->server_port),
570 (ipproto EQ SOCK_IPPROTO_UDP) ? "udp" : "tcp",
571 sock_bearer_type_string(sock_bearer_type)) ;
572 app_pstat();
573
574 // fill connection params
575 bearer_info.bearer_handle = sock_bearer_handle;
576 bearer_info.app_handle = APP_handle;
577 bearer_info.bearer_type = sock_bearer_type;
578
579 if(sock_bearer_type == SOCK_BEARER_GPRS)
580 {
581 bearer_info.apn_valid = TRUE;
582 bearer_info.phone_nr_valid = FALSE;
583 bearer_info.cid = 1;
584
585 switch(prov)
586 {
587 case APP_PROV_T_MOBILE:
588 strcpy(bearer_info.apn, "internet.t-d1.de");
589 strcpy(bearer_info.user_id, "t-d1");
590 strcpy(bearer_info.password, "gprs");
591 break;
592
593 case APP_PROV_HUTCH:
594 strcpy(bearer_info.apn, "www");
595 strcpy(bearer_info.user_id, "");
596 strcpy(bearer_info.password, "");
597 break;
598
599 case APP_PROV_AIRTEL:
600 strcpy(bearer_info.apn, "airtelgprs.com");
601 strcpy(bearer_info.user_id, "");
602 strcpy(bearer_info.password, "");
603 break;
604
605 case APP_PROV_CUSTOM:
606 /* Copy valid APN */
607 if(custom_apn_valid)
608 {
609 strcpy(bearer_info.apn, custom_apn);
610 strcpy(bearer_info.user_id, custom_user_id);
611 strcpy(bearer_info.password, custom_password);
612 break;
613 }
614 /* Copy default settings for invalid APN settings */
615
616 default:
617 strcpy(bearer_info.apn,"web.vodafone.de");
618 strcpy(bearer_info.user_id, "");
619 strcpy(bearer_info.password, "");
620 break;
621 }
622 }
623 else
624 {
625 bearer_info.phone_nr_valid = TRUE;
626 bearer_info.apn_valid = FALSE;
627 bearer_info.cid = 0;
628 if(prov == APP_PROV_T_MOBILE)
629 {
630 strcpy(bearer_info.phone_nr, "+491712524120");
631 strcpy(bearer_info.user_id, "t-d1");
632 strcpy(bearer_info.password, "wap");
633 }
634 else
635 {
636 strcpy(bearer_info.phone_nr, "+491722290000");
637 strcpy(bearer_info.user_id, "");
638 strcpy(bearer_info.password, "");
639 }
640 }
641 bearer_info.user_id_valid = TRUE;
642 bearer_info.password_valid = TRUE;
643
644 bearer_info.ip_address = SOCK_IPADDR_ANY;
645 bearer_info.dns1 = SOCK_IPADDR_ANY;
646 bearer_info.dns2 = SOCK_IPADDR_ANY;
647 bearer_info.gateway = SOCK_IPADDR_ANY;
648 bearer_info.authtype = SOCK_AUTH_NO;
649 bearer_info.data_compr = FALSE;
650 bearer_info.header_comp = FALSE;
651 bearer_info.precedence = 0;
652 bearer_info.delay = 0;
653 bearer_info.reliability = 0;
654 bearer_info.peak_throughput = 0;
655 bearer_info.mean_througput = 0;
656 bearer_info.shareable = FALSE;
657
658 sock_open_bearer(sock_api_inst,bearer_select,0,&bearer_info,app_sock_callback,pcont);
659 if(pcont->bearer_only)
660 {
661 proc_new_state(pcont, PS_W_DCM_OPEN_ONLY) ;
662 }
663 else
664 {
665 proc_new_state(pcont, PS_W_DCM_OPEN) ;
666 }
667 }
668
669
670 static void proc_client_closed(PROC_CONTEXT_T *pcont)
671 {
672 T_SOCK_RESULT result ;
673 TRACE_FUNCTION("proc_client_closed()") ;
674
675 result = sock_close(pcont->psocket);
676 if (result != SOCK_RESULT_OK)
677 {
678 TRACE_EVENT_P1("%s: error closing client socket", proc_string(pcont)) ;
679 proc_shutdown(pcont) ;
680 return;
681 }
682 proc_free_tcpfork(pcont) ;
683 }
684
685
686
687 /***********************************************************************
688 * Communication functions.
689 */
690
691
692 /** Fill and send data buffer.
693 *
694 * @param pcont Pointer to process context.
695 * @param size Size of data buffer.
696 * @return
697 */
698 static BOOL comm_send_buffer(PROC_CONTEXT_T *pcont, int size)
699 {
700 char *payload ; /* Pointer to payload buffer. */
701 char *cp ; /* Pointer into paylaod buffer. */
702 char *pp ; /* Pointer into test pattern. */
703 T_SOCK_RESULT result ; /* Result of send call. */
704
705 TRACE_FUNCTION("comm_send_buffer()") ;
706 MALLOC(payload, size) ;
707 TRACE_EVENT_P1("PALLOC payload %x", payload) ;
708 /* Fill buffer with pattern. */
709 for (cp = payload, pp = APP_SEND_PATTERN; cp < payload + size; cp++, pp++)
710 {
711 if (pp >= APP_SEND_PATTERN + sizeof(APP_SEND_PATTERN) - 1)
712 {
713 pp = APP_SEND_PATTERN ;
714 }
715 *cp = *pp ;
716 }
717 if(pcont->ipproto == SOCK_IPPROTO_UDP)
718 {
719 // use UDP socket and specify destination IP address and destination port
720 result = sock_sendto(pcont->psocket, payload, (U16)size,
721 pcont->server_ipaddr,pcont->server_port) ;
722 }
723 else
724 {
725 result = sock_send(pcont->psocket, payload, (U16)size) ;
726 }
727 sock_trace_result(pcont, "sock_send()", result) ;
728 MFREE(payload) ;
729 switch (result)
730 {
731 case SOCK_RESULT_OK:
732 TRACE_EVENT_P6("%s sent %d (%d/%d) bytes in rep %d/%d",
733 proc_string(pcont), size, pcont->data_sent,
734 pcont->spec_items,
735 //* ((pcont->ipproto EQ SOCK_IPPROTO_TCP) ? 1 : size),
736 pcont->n_reps, pcont->spec_reps) ;
737 return TRUE ;
738 case SOCK_RESULT_NO_BUFSPACE:
739 return FALSE ; /* Pause until SOCK_FLOW_READY_IND. */
740 default:
741 proc_shutdown(pcont) ;
742 return FALSE ;
743 }
744 }
745
746
747 /** Server: send some data to the client.
748 *
749 * @param pcont Pointer to process context.
750 * @return
751 */
752 static BOOL comm_send_srvprompt(PROC_CONTEXT_T *pcont)
753 {
754 char *payload ; /* Pointer to payload buffer. */
755 int size ; /* Actual size of payload. */
756 T_SOCK_RESULT result ; /* Result of send call. */
757 TRACE_FUNCTION("comm_send_srv()") ;
758
759 MALLOC(payload, 600) ;
760 sprintf(payload, "%s: %sin_shutdown, last_evt %s, will %srepeat\n",
761 proc_string(pcont), pcont->in_shutdown ? "" : "not ",
762 pcont->last_evt
763 ? sock_event_string(pcont->last_evt->event_type) : "NULL",
764 pcont->spec_reps ? "" : "not ") ;
765 sprintf(payload + strlen(payload),
766 " rx %d B %d pkts, tx %d B %d pkts, errs %d conn %d\n",
767 pcont->data_rcvd, pcont->items_rcvd,
768 pcont->data_sent, pcont->items_sent,
769 pcont->errors, pcont->n_reps) ;
770
771 size = strlen(payload) ;
772 result = sock_send(pcont->psocket, payload, (U16)size) ;
773 sock_trace_result(pcont, "sock_send()", result) ;
774 MFREE(payload) ;
775 switch (result)
776 {
777 case SOCK_RESULT_OK:
778 pcont->data_sent += size ;
779 pcont->items_sent++ ;
780 TRACE_EVENT_P5("%s sent %d (%d/%d) bytes in conn %d",
781 proc_string(pcont), size, pcont->data_sent,
782 pcont->spec_items * size,
783 pcont->n_reps) ;
784 return TRUE ;
785 case SOCK_RESULT_NO_BUFSPACE:
786 return FALSE ; /* Pause until SOCK_FLOW_READY_IND. */
787 default:
788 proc_shutdown(pcont) ;
789 return FALSE ;
790 }
791 }
792
793
794 /** Issue a DNS query. Called for AP_DNSQRY in state PS_COMM.
795 *
796 * @param pcont Pointer to process context.
797 */
798 static void comm_query(PROC_CONTEXT_T *pcont)
799 {
800 static int next_query = 0 ; /* Next query index. */
801 char *name ; /* Domain name to query for. */
802 T_SOCK_RESULT result ; /* Result of query call. */
803
804 TRACE_FUNCTION("comm_query()") ;
805 if (query_name[0])
806 {
807 name = query_name ;
808 }
809 else
810 {
811 name = domain_name[next_query] ;
812 }
813 TRACE_EVENT_P4("%s: query (%d/%d) for %s", proc_string(pcont),
814 pcont->items_sent + 1, pcont->spec_items, name) ;
815 result = sock_gethostbyname(sock_api_inst, name, app_sock_callback, pcont) ;
816 sock_trace_result(pcont, "sock_gethostbyname()", result) ;
817 if (result != SOCK_RESULT_OK)
818 {
819 pcont->errors++ ;
820 TRACE_ERROR("sock_gethostbyname() failed, sleep...") ;
821 vsi_t_sleep(VSI_CALLER 2000) ;
822 }
823
824 if (!domain_name[++next_query])
825 {
826 next_query = 0 ;
827 }
828 pcont->items_sent++ ;
829 }
830
831
832
833 /** Send data. Called for all but AP_DNSQRY in state PS_COMM.
834 *
835 * @param pcont Pointer to process context.
836 */
837 static void comm_send(PROC_CONTEXT_T *pcont)
838 {
839 TRACE_EVENT_P1("comm_send() %s", proc_string(pcont)) ;
840
841 switch (pcont->ptype)
842 {
843 case AP_TCPDL:
844 /* Do nothing -- the server will send again anyway. */
845 return ;
846 case AP_UDPDL:
847 if (pcont->data_sent >= pcont->spec_items)
848 {
849 return;
850 }
851 break;
852 case AP_TCPUL:
853 case AP_UDPUL:
854 if (pcont->data_sent >= pcont->spec_items)
855 {
856 TRACE_EVENT_P2("%s done after %d bytes",
857 proc_string(pcont), pcont->data_sent) ;
858 proc_close_socket(pcont) ;
859 pcont->n_reps++ ;
860 return ;
861 }
862 break ;
863 case AP_TCPECHO:
864 case AP_UDPECHO:
865 if (pcont->items_sent >= pcont->spec_items)
866 {
867 TRACE_EVENT_P2("%s done after %d writes",
868 proc_string(pcont), pcont->items_sent) ;
869 proc_close_socket(pcont) ;
870 pcont->n_reps++ ;
871 return ;
872 }
873 break ;
874 case AP_DNSQRY:
875 comm_query(pcont) ;
876 return ;
877 case AP_TCPFORK: /* Send some data, perhaps. */
878 switch (pcont->server_port)
879 {
880 case PORT_CHARGEN: /* Send something (below). */
881 break ;
882 case PORT_ECHO: /* Send somewhere else. */
883 case PORT_DISCARD: /* Don't send anything. */
884 return ;
885 default: /* Send a server prompt. */
886 comm_send_srvprompt(pcont) ;
887 break ;
888 }
889 return ;
890 case AP_NONE:
891 case AP_INVALID:
892 default:
893 TRACE_EVENT_P1("Invalid process type %s", proc_string(pcont)) ;
894 return ;
895 }
896
897 if (comm_send_buffer(pcont, buffer_size))
898 {
899 pcont->items_sent++ ;
900 TRACE_EVENT_P1("Sent Items: %u",pcont->items_sent);
901 pcont->data_sent += buffer_size ;
902 vsi_t_sleep(VSI_CALLER udp_interval);
903 }
904 else
905 {
906 if (pcont->ptype EQ AP_UDPUL)
907 {
908 TRACE_EVENT_P2("%s sleeps %d ms", proc_string(pcont), udp_interval) ;
909 vsi_t_sleep(VSI_CALLER udp_interval);
910 }
911 }
912 }
913
914
915 /** Handle an incoming DNS result. Called for AP_DNSQRY in state PS_COMM.
916 *
917 * @param pcont Pointer to process context.
918 */
919 static void comm_dns_result(PROC_CONTEXT_T *pcont)
920 {
921 T_SOCK_HOSTINFO_CNF *hinfo ;
922
923 TRACE_FUNCTION("comm_dns_result()") ;
924 pcont->items_rcvd++ ;
925
926 hinfo = (T_SOCK_HOSTINFO_CNF *) pcont->last_evt ;
927 if (hinfo->result != SOCK_RESULT_OK)
928 {
929 TRACE_EVENT_P3("lookup error %d in %d/%d queries",
930 pcont->errors, pcont->items_rcvd, pcont->spec_items) ;
931 }
932 else
933 {
934 TRACE_EVENT_P1("Answer for host %s", hinfo->hostname) ;
935 TRACE_EVENT_P3("has address %s (%d/%d)",
936 inet_ntoa(hinfo->ipaddr),
937 pcont->items_rcvd, pcont->spec_items) ;
938 }
939 if (pcont->items_rcvd < pcont->spec_items)
940 {
941 comm_send(pcont) ;
942 }
943 else
944 {
945 proc_close_conn(pcont) ;
946 }
947 }
948
949
950 /** Receive incoming data. Called for all but AP_TCPUL in state PS_COMM.
951 *
952 * @param pcont Pointer to process context.
953 */
954 static void comm_recv(PROC_CONTEXT_T *pcont)
955 {
956 T_SOCK_RECV_IND *recv_ind = (T_SOCK_RECV_IND *) pcont->last_evt ;
957
958 TRACE_FUNCTION("comm_recv()") ;
959 if (pcont->ptype EQ AP_DNSQRY OR pcont->ptype EQ AP_TCPUL)
960 {
961 TRACE_EVENT_P2("%s: %s unexpected for ptype", proc_string(pcont),
962 sock_event_string(pcont->last_evt->event_type)) ;
963 proc_shutdown(pcont) ;
964 return ;
965 }
966 pcont->data_rcvd += recv_ind->data_length ;
967 pcont->items_rcvd++ ;
968 TRACE_EVENT_P5("%s: recv #%d:%u bytes, total %u, total items sent:%u", proc_string(pcont),
969 pcont->items_rcvd, recv_ind->data_length, pcont->data_rcvd,pcont->items_sent);
970 trace_dump_data((U8 *) recv_ind->data_buffer,
971 MIN(APP_DATA_DUMP_LENGTH, recv_ind->data_length)) ;
972 MFREE(recv_ind->data_buffer) ;
973 recv_ind->data_buffer = 0 ;
974 switch (pcont->ptype)
975 {
976 case AP_UDPDL:
977 /* After every sent UDP packet, a "answer" comes from the Chargen server.
978 * If all packets are sent we are waiting for the last packet to
979 * receive, else an unexpected event would be the result in the
980 * "app_sock_callback()"; TCPIP_DATA_IND is received instead of SOCK_CLOSE_CNF
981 * TODO: why (pcont->items_sent-1), I assume that the server "confirms"
982 * every packet
983 */
984 if ((pcont->data_sent >= pcont->spec_items) &&
985 (pcont->items_rcvd == pcont->items_sent))
986 {
987 TRACE_EVENT("last UDP-DL packet received");
988 pcont->n_reps++ ;
989 proc_close_socket(pcont) ;
990 }
991 else {
992 comm_send(pcont);
993 }
994 break;
995 case AP_TCPDL:
996 if (pcont->data_rcvd >= pcont->spec_items)
997 {
998 TRACE_EVENT_P3("%s done after %d/%d bytes",
999 proc_string(pcont), pcont->data_rcvd,
1000 pcont->spec_items) ;
1001 pcont->n_reps++ ;
1002 proc_close_socket(pcont) ;
1003 }
1004 break ;
1005 case AP_UDPECHO:
1006 case AP_TCPECHO:
1007 case AP_TCPFORK:
1008 comm_send(pcont) ;
1009 break ;
1010 default:
1011 TRACE_ERROR("Unexpected ptype in comm_recv()") ;
1012 break ;
1013 }
1014 }
1015
1016
1017 /** Handle a communication event according to the process type. Called for all
1018 * process types in state PS_COMM.
1019 *
1020 * @param pcont Pointer to process context.
1021 */
1022 static void comm_event(PROC_CONTEXT_T *pcont)
1023 {
1024 TRACE_FUNCTION("comm_event()") ;
1025
1026 switch (pcont->last_evt->event_type)
1027 {
1028 case SOCK_CONN_CLOSED_IND:
1029 if (pcont->ptype EQ AP_TCPFORK)
1030 {
1031 proc_client_closed(pcont) ;
1032 break ;
1033 }
1034 /*lint -fallthrough */
1035 case SOCK_ERROR_IND:
1036 TRACE_EVENT_P2("%s: %s, shutdown", proc_string(pcont),
1037 sock_event_string(pcont->last_evt->event_type)) ;
1038 // server should not reset , even if connection is reset by client.
1039 // but client should shutdown , if connection is reset by server.
1040 if((pcont->ptype EQ AP_TCPFORK) AND
1041 (pcont->last_evt->result == SOCK_RESULT_CONN_RESET OR
1042 pcont->last_evt->result == SOCK_RESULT_TIMEOUT))
1043 {
1044 proc_client_closed(pcont) ;
1045 return;
1046 }
1047 else
1048 proc_shutdown(pcont) ;
1049 return ;
1050 case SOCK_RECV_IND:
1051 comm_recv(pcont) ;
1052 break ;
1053 case SOCK_FLOW_READY_IND:
1054 if(pcont->ptype NEQ AP_UDPDL) {
1055 comm_send(pcont) ;
1056 }
1057 break ;
1058 case SOCK_HOSTINFO_CNF:
1059 if (pcont->ptype EQ AP_DNSQRY) {
1060 comm_dns_result(pcont) ;
1061 break ;
1062 }
1063 /*lint -fallthrough */
1064 case SOCK_CREATE_CNF:
1065 case SOCK_CLOSE_CNF:
1066 case SOCK_BIND_CNF:
1067 case SOCK_LISTEN_CNF:
1068 case SOCK_CONNECT_CNF:
1069 case SOCK_SOCKNAME_CNF:
1070 case SOCK_PEERNAME_CNF:
1071 case SOCK_MTU_SIZE_CNF:
1072 case SOCK_CONNECT_IND:
1073 TRACE_EVENT_P2("%s: %s unexpected at all", proc_string(pcont),
1074 sock_event_string(pcont->last_evt->event_type)) ;
1075 proc_shutdown(pcont) ;
1076 return ;
1077 case SOCK_BAERER_CLOSED_IND:
1078 proc_shutdown(pcont);
1079 break;
1080 default:
1081 TRACE_EVENT_P2("comm_event(): %s unknown event %d",
1082 proc_string(pcont), pcont->last_evt->event_type) ;
1083 proc_shutdown(pcont) ;
1084 break ;
1085 }
1086 }
1087
1088
1089
1090 /***********************************************************************
1091 * State machine functions (i. e. state-changing functions)
1092 */
1093
1094 /** Finish the process after the network connection has been closed.
1095 *
1096 * @param pcont Pointer to process context.
1097 */
1098 static void proc_finish(PROC_CONTEXT_T *pcont)
1099 {
1100 TRACE_EVENT_P1("%s finished", proc_string(pcont)) ;
1101 pcont->network_is_open = FALSE ;
1102 pcont->in_shutdown = FALSE;
1103 proc_new_state(pcont, PS_IDLE) ;
1104 }
1105
1106
1107 /** Shutdown process hard, usually after an error or user request. This
1108 * includes closing the process's socket and network connection.
1109 *
1110 * @param pcont Pointer to process context.
1111 */
1112 static void proc_shutdown(PROC_CONTEXT_T *pcont)
1113 {
1114 TRACE_FUNCTION("proc_shutdown()") ;
1115
1116 if(pcont->in_shutdown)
1117 {
1118 TRACE_EVENT("Allready in shutdown");
1119 return;
1120 }
1121 pcont->in_shutdown = TRUE ;
1122 app_pstat() ;
1123 if (pcont->psocket_is_open)
1124 {
1125 proc_close_socket(pcont);
1126 return;
1127 }
1128 if (pcont->network_is_open OR
1129 pcont->pstate == PS_W_DCM_OPEN OR pcont->pstate == PS_W_DCM_OPEN_ONLY)
1130 {
1131 proc_close_conn(pcont);
1132 return;
1133 }
1134 else
1135 {
1136 proc_finish(pcont);
1137 }
1138 }
1139
1140
1141 /** Create a socket after the network connection has been established.
1142 *
1143 * @param pcont Pointer to process context.
1144 */
1145 static void proc_open_socket(PROC_CONTEXT_T *pcont)
1146 {
1147 T_SOCK_RESULT result ;
1148
1149 TRACE_FUNCTION("proc_open_socket()") ;
1150 /* We don't need to do this for the DNS query process. */
1151 if (pcont->ptype EQ AP_DNSQRY)
1152 {
1153 proc_begin_comm(pcont) ;
1154 }
1155 else
1156 {
1157 result = sock_create(sock_api_inst, pcont->ipproto, app_sock_callback, pcont);
1158 if (result NEQ SOCK_RESULT_OK)
1159 {
1160 sock_trace_result(pcont, "sock_create()", result) ;
1161 proc_shutdown(pcont) ;
1162 return;
1163 }
1164 proc_new_state(pcont, PS_W_CREAT) ;
1165 }
1166 }
1167
1168
1169 /** Close the network connection after the task has been done.
1170 *
1171 * @param pcont Pointer to process context.
1172 */
1173 static void proc_close_conn(PROC_CONTEXT_T *pcont)
1174 {
1175
1176
1177 TRACE_FUNCTION("proc_close_conn()");
1178 if(pcont->network_is_open)
1179 {
1180 pcont->in_shutdown = TRUE;
1181 sock_close_bearer(sock_api_inst, sock_bearer_handle, app_sock_callback, pcont);
1182 proc_new_state(pcont, PS_W_DCLOS) ;
1183 }
1184 else
1185 {
1186 proc_finish(pcont);
1187 }
1188 }
1189
1190
1191 /** Connect the socket after it has been created.
1192 *
1193 * @param pcont Pointer to process context.
1194 */
1195 static void proc_connect_socket(PROC_CONTEXT_T *pcont)
1196 {
1197 T_SOCK_RESULT result ;
1198
1199 TRACE_FUNCTION("proc_connect_socket()") ;
1200 /* If we do not yet have an IP address to connect to, look it up first. */
1201 if (pcont->server_ipaddr EQ SOCK_IPADDR_ANY)
1202 {
1203 result = sock_gethostbyname(sock_api_inst, pcont->server_name,app_sock_callback, pcont);
1204 if (result NEQ SOCK_RESULT_OK)
1205 {
1206 sock_trace_result(pcont, "sock_gethostbyname()", result) ;
1207 proc_shutdown(pcont) ;
1208 return;
1209 }
1210 proc_new_state(pcont, PS_W_DNS) ;
1211 return ;
1212 }
1213
1214 result = sock_connect(pcont->psocket, pcont->server_ipaddr, pcont->server_port);
1215 if (result NEQ SOCK_RESULT_OK)
1216 {
1217 sock_trace_result(pcont, "sock_connect()", result) ;
1218 proc_shutdown(pcont) ;
1219 return;
1220 }
1221 proc_new_state(pcont, PS_W_SCONN) ;
1222 }
1223
1224
1225 /** Begin communicating after the socket has been created.
1226 *
1227 * @param pcont Pointer to process context.
1228 */
1229 static void proc_begin_comm(PROC_CONTEXT_T *pcont)
1230 {
1231 TRACE_FUNCTION("proc_begin_comm()") ;
1232
1233 proc_new_state(pcont, PS_COMM) ;
1234 switch (pcont->ptype)
1235 {
1236 case AP_TCPDL:
1237 /* We wait for data from the server to arrive. */
1238 break ;
1239 case AP_UDPDL:
1240 /* Trigger the chargen server to send fisrt UDP packet */
1241 comm_send(pcont);
1242 break ;
1243 case AP_TCPUL:
1244 case AP_UDPUL:
1245 case AP_TCPECHO:
1246 case AP_UDPECHO:
1247 case AP_DNSQRY:
1248 case AP_TCPFORK:
1249 comm_send(pcont) ;
1250 break ;
1251 default:
1252 TRACE_EVENT_P2("%s unknown state (%d)",
1253 proc_string (pcont), pcont->ptype) ;
1254 break ;
1255 }
1256 }
1257
1258
1259 /** Close the socket after the requested communication has been done.
1260 *
1261 * @param pcont Pointer to process context.
1262 */
1263 static void proc_close_socket(PROC_CONTEXT_T *pcont)
1264 {
1265 TRACE_FUNCTION("proc_close_socket()") ;
1266
1267 sock_close(pcont->psocket) ;
1268 proc_new_state(pcont, PS_W_SCLOS) ;
1269 }
1270
1271
1272 static void proc_bind_socket(PROC_CONTEXT_T *pcont)
1273 {
1274 T_SOCK_RESULT result ;
1275 TRACE_FUNCTION("proc_bind_socket()") ;
1276
1277 if ((result = sock_bind(pcont->psocket, pcont->server_port))
1278 != SOCK_RESULT_OK)
1279 {
1280 sock_trace_result(pcont, "sock_bind()", result) ;
1281 proc_shutdown(pcont) ;
1282 return;
1283 }
1284 proc_new_state(pcont, PS_W_BIND) ;
1285 }
1286
1287
1288 static void proc_listen(PROC_CONTEXT_T *pcont)
1289 {
1290 T_SOCK_RESULT result ;
1291 TRACE_FUNCTION("proc_listen()") ;
1292
1293 if ((result = sock_listen(pcont->psocket)) != SOCK_RESULT_OK)
1294 {
1295 sock_trace_result(pcont, "sock_listen()", result) ;
1296 proc_shutdown(pcont) ;
1297 return;
1298 }
1299 proc_new_state(pcont, PS_W_LISTN) ;
1300 }
1301
1302
1303 static void proc_incoming(PROC_CONTEXT_T *pcont)
1304 {
1305 T_SOCK_CONNECT_IND *conn_ind ;
1306 PROC_CONTEXT_T *newp ;
1307 T_SOCK_RESULT result ;
1308 TRACE_FUNCTION("proc_incoming()") ;
1309
1310 conn_ind = (T_SOCK_CONNECT_IND *) pcont->last_evt ;
1311
1312 if ((newp = proc_new_tcpfork(pcont)) EQ NULL)
1313 {
1314 TRACE_EVENT_P1("%s: failed to fork server, close new socket",
1315 proc_string(pcont)) ;
1316 sock_close(conn_ind->new_socket) ;
1317 return ;
1318 }
1319
1320 /* We cannot make two calls to proc_string() without one overwriting the
1321 * other, so we print the process strings in two successive traces. */
1322 TRACE_EVENT_P1("%s: forking to handle client connection...",
1323 proc_string(pcont)) ;
1324 TRACE_EVENT_P1("...forked process is %s", proc_string(newp)) ;
1325 newp->psocket = conn_ind->new_socket ;
1326 sock_set_callback(newp->psocket, app_sock_callback, newp) ;
1327 TRACE_EVENT_P3("%s connection from %s:%d, looking up...", proc_string(pcont),
1328 inet_ntoa(conn_ind->peer_ipaddr), NTOHS(conn_ind->peer_port)) ;
1329 if ((result = sock_gethostbyaddr(sock_api_inst, conn_ind->peer_ipaddr,
1330 app_sock_callback, newp))
1331 != SOCK_RESULT_OK)
1332 {
1333 sock_trace_result(newp, "sock_gethostbyaddr()", result) ;
1334 proc_shutdown(newp) ;
1335 proc_shutdown(pcont) ;
1336 return;
1337 }
1338 proc_new_state(newp, PS_W_DNS) ;
1339 }
1340
1341
1342 static void proc_hostinfo_recvd(PROC_CONTEXT_T *pcont)
1343 {
1344 T_SOCK_HOSTINFO_CNF *hinfo ;
1345 TRACE_FUNCTION("proc_hostinfo_recvd()") ;
1346
1347 hinfo = (T_SOCK_HOSTINFO_CNF *) pcont->last_evt ;
1348 if (hinfo->result != SOCK_RESULT_OK)
1349 {
1350 sock_trace_result(pcont, "SOCK_HOSTINFO_CNF", hinfo->result) ;
1351 }
1352 else
1353 {
1354 TRACE_EVENT_P3("%s: connected peer is %s (%s)", proc_string(pcont),
1355 hinfo->hostname, inet_ntoa(hinfo->ipaddr)) ;
1356 }
1357 proc_begin_comm(pcont) ;
1358 }
1359
1360
1361
1362 /*==== Exported functions ====================================================*/
1363
1364
1365 /** Initialize the application core.
1366 *
1367 * @param handle own communication handle
1368 * @return PEI_OK/PEI_ERROR depending on the success of the initialization.
1369 */
1370 BOOL app_initialize_tcpip(T_HANDLE app_handle)
1371 {
1372 TRACE_FUNCTION("app_initialize_tcpip()") ;
1373 memset(&proc_context, 0, sizeof(proc_context)) ;
1374 return PEI_OK ;
1375 }
1376
1377
1378 /* Macro for checking the Socket API events in app_sock_callback(). */
1379 #define CHECK_SOCK_EVT(evttype) \
1380 { \
1381 if (event->event_type != evttype) \
1382 { \
1383 TRACE_ERROR("unexpected event type waiting for " #evttype) ; \
1384 proc_shutdown(pcont) ; \
1385 break ; \
1386 } \
1387 if (event->result != SOCK_RESULT_OK) \
1388 { \
1389 if(pcont->pstate == PS_W_DCM_OPEN OR \
1390 pcont->pstate == PS_W_DCM_OPEN_ONLY) \
1391 { proc_new_state(pcont, PS_IDLE); } \
1392 proc_shutdown(pcont) ; \
1393 break ; \
1394 } \
1395 }
1396
1397
1398 /** Socket callback function as specified in the Socket API.
1399 *
1400 * @param event Pointer to event struct passed by API.
1401 * @param context Pointer to application context (here: process context)
1402 * @return
1403 */
1404 void app_sock_callback(T_SOCK_EVENTSTRUCT *event, void *context)
1405 {
1406 PROC_CONTEXT_T *pcont ;
1407 T_SOCK_BEARER_INFO_CNF *info;
1408
1409 TRACE_FUNCTION("app_sock_callback()") ;
1410
1411 pcont = (PROC_CONTEXT_T *)context ;
1412 pcont->last_evt = event ; /* Save event in process context. */
1413
1414 sock_trace_result(pcont, sock_event_string(event->event_type),
1415 event->result) ;
1416 if (event->result != SOCK_RESULT_OK)
1417 {
1418 pcont->errors++ ;
1419 if(event->result == SOCK_RESULT_NETWORK_LOST)
1420 {
1421 pcont->network_is_open = FALSE;
1422 }
1423 }
1424 switch (pcont->pstate) /* Do a preliminary check of the event. */
1425 {
1426 case PS_W_DCM_OPEN: /* Waiting for DCM to open connection. */
1427 CHECK_SOCK_EVT(SOCK_OPEN_BEARER_CNF);
1428
1429 // FST: can't be evaluated-> see makro CHECK_SOCK_EVT
1430 if (event->result != SOCK_RESULT_OK AND
1431 event->result != SOCK_RESULT_BEARER_ACTIVE)
1432 {
1433 proc_shutdown(pcont) ;
1434 return ;
1435 }
1436 if (pcont->network_is_open)
1437 {
1438 TRACE_ERROR("SOCK_OPEN_BEARER_CNF received but pcont->network_is_open") ;
1439 proc_shutdown(pcont);
1440 return ;
1441 }
1442 pcont->network_is_open = TRUE ;
1443 proc_open_socket(pcont) ;
1444 break;
1445
1446 case PS_W_DCM_OPEN_ONLY:
1447 CHECK_SOCK_EVT(SOCK_OPEN_BEARER_CNF);
1448 pcont->network_is_open = TRUE ;
1449 proc_new_state(pcont, PS_DCM_OPEN);
1450 break;
1451
1452 case PS_W_DCLOS: /* Waiting for DCM to close connection. */
1453 CHECK_SOCK_EVT(SOCK_CLOSE_BEARER_CNF);
1454
1455 if (!pcont->network_is_open AND pcont->pstate != PS_IDLE)
1456 {
1457 TRACE_ERROR("DCM_CONN_CLOSED received but !pcont->network_is_open") ;
1458 proc_shutdown(pcont) ;
1459 return ;
1460 }
1461 proc_finish(pcont) ;
1462 break;
1463
1464 case PS_W_CONN_INFO:
1465 CHECK_SOCK_EVT(SOCK_BEARER_INFO_CNF);
1466
1467 info = (T_SOCK_BEARER_INFO_CNF *)event;
1468 app_print_conn_info(info);
1469
1470 TRACE_EVENT("SOCK_BEARER_INFO_CNF received");
1471 break;
1472
1473 case PS_W_CREAT: /* Waiting for socket create confirmation. */
1474 CHECK_SOCK_EVT(SOCK_CREATE_CNF) ;
1475 pcont->psocket = event->socket ;
1476 pcont->psocket_is_open = TRUE ;
1477 if (pcont->ptype EQ AP_TCPSRV)
1478 {
1479 proc_bind_socket(pcont) ;
1480 }
1481 else if(pcont->ipproto == SOCK_IPPROTO_TCP)
1482 {
1483 proc_connect_socket(pcont) ;
1484 }
1485 else
1486 {
1487 // This is not possible in the moment because the RNET_API does not
1488 // provide a sendto() function. Therefore it is is only possible to sent
1489 // via "connected" UDP sockets.
1490 // TODO: if the next statement will be enabled the "proc_connect_socket()" has to be removed!!
1491 // proc_begin_comm(pcont);
1492 proc_connect_socket(pcont) ;
1493 }
1494 break ;
1495
1496 case PS_W_BIND:
1497 CHECK_SOCK_EVT(SOCK_BIND_CNF) ;
1498 proc_listen(pcont) ;
1499 break ;
1500
1501 case PS_W_LISTN:
1502 CHECK_SOCK_EVT(SOCK_LISTEN_CNF) ;
1503 app_pstat() ;
1504 proc_new_state(pcont, PS_LISTENS) ; /* Nothing more to do here. */
1505 break ;
1506
1507 case PS_LISTENS: /* SOCK_CONNECT_IND or SOCK_CLOSE_CNF */
1508 if (event->event_type EQ SOCK_CONNECT_IND)
1509 {
1510 proc_incoming(pcont) ;
1511 }
1512 break ;
1513
1514 case PS_W_DNS:
1515 /* After sending connect confirm to client, client will send data to server
1516 and server is dnsquerying now , server will be shutdown ,here Unfortunately..
1517 but we want to exchange data happily, so this code is added.... */
1518 if((event->event_type == SOCK_RECV_IND) AND (pcont->ptype == AP_TCPFORK))
1519 break;
1520
1521 CHECK_SOCK_EVT(SOCK_HOSTINFO_CNF) ;
1522 proc_hostinfo_recvd(pcont) ;
1523 break ;
1524
1525 case PS_W_SCONN: /* Waiting for socket connect confirmation. */
1526 CHECK_SOCK_EVT(SOCK_CONNECT_CNF) ;
1527 proc_begin_comm(pcont) ;
1528 break ;
1529
1530 case PS_COMM: /* Happily exchanging data. */
1531 comm_event(pcont) ;
1532 break ;
1533
1534 case PS_W_SCLOS: /* Waiting for socket close confirmation. */
1535 CHECK_SOCK_EVT(SOCK_CLOSE_CNF) ;
1536
1537 pcont->psocket_is_open = FALSE ;
1538 pcont->psocket = 0;
1539 app_pstat() ;
1540 if (pcont->n_reps >= pcont->spec_reps OR
1541 pcont->in_shutdown)
1542 {
1543 proc_close_conn(pcont) ;
1544 }
1545 else
1546 {
1547 pcont->data_sent = 0 ;
1548 pcont->data_rcvd = 0 ;
1549 pcont->items_sent = 0 ;
1550 pcont->items_rcvd = 0 ;
1551 proc_open_socket(pcont) ;
1552 }
1553 break ;
1554
1555 case PS_IDLE: /* Initial state, process not running. */
1556 TRACE_EVENT_P2("app_sock_callback(): %s receives %s (ignored)",
1557 proc_string(pcont), sock_event_string(event->event_type)) ;
1558 break ;
1559
1560 case PS_DCM_OPEN:
1561 if(event->event_type == SOCK_BAERER_CLOSED_IND)
1562 {
1563 TRACE_ERROR("SOCK_BAERER_CLOSED_IND -> Shutdown");
1564 if(event->result == SOCK_RESULT_NETWORK_LOST)
1565 {
1566 pcont->network_is_open = FALSE;
1567 }
1568 proc_shutdown(pcont) ;
1569 }
1570 break;
1571
1572 case PS_INVALID: /* Invalid state. */
1573 TRACE_EVENT_P1("app_sock_callback(): %s invalid state", proc_string(pcont)) ;
1574 break;
1575
1576 default:
1577 TRACE_ERROR("app_sock_callback(): Default Statement");
1578 break;
1579 /*
1580 if(event->event_type == SOCK_DCM_ERR_IND)
1581 {
1582 TRACE_ERROR("SOCK_DCM_ERR_IND -> Shutdown");
1583 }
1584 proc_shutdown(pcont) ;
1585 return ;
1586 */
1587 }
1588 /* Free data buffer if it has not been freed yet. */
1589 if ( (event->event_type EQ SOCK_RECV_IND) AND
1590 ((T_SOCK_RECV_IND *) event)->data_buffer )
1591 {
1592 MFREE(((T_SOCK_RECV_IND *) event)->data_buffer) ;
1593 }
1594 pcont->last_evt = NULL ;
1595 TRACE_EVENT_P1("leave app_sock_callback() for %s", proc_string(pcont)) ;
1596 }
1597
1598
1599
1600 /*
1601 * Application command functions.
1602 */
1603
1604
1605 /** Start a data communication process of the appropriate type..
1606 *
1607 * @param size Amount of data to download or number of items to transfer.
1608 */
1609 void app_start_tcpdl(int prov, int size, int reps)
1610 { proc_init(prov, size, reps, AP_TCPDL, SOCK_IPPROTO_TCP,
1611 port_number ? port_number : PORT_CHARGEN) ; }
1612
1613 void app_start_tcpul(int prov, int size, int reps)
1614 { proc_init(prov, size, reps, AP_TCPUL, SOCK_IPPROTO_TCP,
1615 port_number ? port_number : PORT_DISCARD) ; }
1616
1617 void app_start_udpdl(int prov, int size, int reps)
1618 { proc_init(prov, size, reps, AP_UDPDL, SOCK_IPPROTO_UDP,
1619 port_number ? port_number : PORT_CHARGEN) ; }
1620
1621 void app_start_udpul(int prov, int size, int reps)
1622 { proc_init(prov, size, reps, AP_UDPUL, SOCK_IPPROTO_UDP,
1623 port_number ? port_number : PORT_DISCARD) ; }
1624
1625 void app_start_tcpecho(int prov, int items, int reps)
1626 { proc_init(prov, items, reps, AP_TCPECHO, SOCK_IPPROTO_TCP,
1627 port_number ? port_number : PORT_ECHO) ; }
1628
1629 void app_start_udpecho(int prov, int items, int reps)
1630 { proc_init(prov, items, reps, AP_UDPECHO, SOCK_IPPROTO_UDP,
1631 port_number ? port_number : PORT_ECHO) ; }
1632
1633 void app_start_dnsquery(int prov, int times, char *address)
1634 {
1635 if (address)
1636 {
1637 strncpy(query_name, address, FQDN_LENGTH) ;
1638 }
1639 else
1640 {
1641 query_name[0] =0 ;
1642 }
1643 proc_init(prov, times,1, AP_DNSQRY,(T_SOCK_IPPROTO)0, 0) ;
1644 }
1645
1646 void app_start_tcpsrv(int prov, int port, int repeat)
1647 { proc_init(prov, 0, repeat, AP_TCPSRV, SOCK_IPPROTO_TCP, port) ; }
1648
1649
1650
1651 /** Shutdown the specified process.
1652 *
1653 * @param pid Process ID.
1654 */
1655 void app_shutdown(void)
1656 {
1657 TRACE_FUNCTION("app_shutdown()") ;
1658 proc_shutdown(&proc_context) ;
1659 }
1660
1661
1662 /** Set the current server name or IP address.
1663 *
1664 * @param server Name or IP address (in dotted decimal notation) of server.
1665 */
1666 void app_server(char *server)
1667 {
1668 if (server)
1669 {
1670 strncpy(server_name, server, FQDN_LENGTH) ;
1671 }
1672 TRACE_EVENT_P1("server_name is %s", server_name) ;
1673 }
1674
1675
1676 /** Set or show the current buffer size.
1677 *
1678 * @param bufsize size of buffer as a string or NULL
1679 */
1680 void app_buffer(char *bufsize)
1681 {
1682 if (bufsize)
1683 {
1684 buffer_size = atoi(bufsize) ;
1685 }
1686 TRACE_EVENT_P1("buffer_size is %d", buffer_size) ;
1687 }
1688
1689
1690 /** Set or show the current buffer size.
1691 *
1692 * @param port port number override
1693 */
1694 void app_port(char *port)
1695 {
1696 if (port)
1697 {
1698 port_number = (U16) atoi(port) ;
1699 }
1700 if (port_number)
1701 {
1702 TRACE_EVENT_P1("port number override is %d", port_number) ;
1703 }
1704 else
1705 {
1706 TRACE_EVENT("standard port numbers used") ;
1707 }
1708 }
1709
1710
1711 /** Set or show the current bearer type.
1712 *
1713 * @param bearer bearer type
1714 */
1715 void app_bearer(char *bearer)
1716 {
1717 if (bearer)
1718 {
1719 if (!strcmp(string_to_lower(bearer), "any"))
1720 {
1721 sock_bearer_type = SOCK_BEARER_ANY;
1722 }
1723 else if (!strcmp(string_to_lower(bearer), "gprs"))
1724 {
1725 sock_bearer_type = SOCK_BEARER_GPRS ;
1726 }
1727 else if (!strcmp(string_to_lower(bearer), "gsm"))
1728 {
1729 sock_bearer_type = SOCK_BEARER_GSM;
1730 }
1731 else if (!strcmp(string_to_lower(bearer), "prof"))
1732 {
1733 sock_bearer_type = SOCK_BEARER_USE_PROFILE;
1734 }
1735 else if (!strcmp(string_to_lower(bearer), "spec"))
1736 {
1737 sock_bearer_type = SOCK_BEARER_AS_SPECIFIED;
1738 }
1739
1740 else
1741 {
1742 TRACE_EVENT_P1("bearer type %s unknown", bearer) ;
1743 }
1744 }
1745 TRACE_EVENT_P1("bearer type is %s", sock_bearer_type_string(sock_bearer_type)) ;
1746 }
1747
1748
1749 /** Trace information about the process.
1750 */
1751 void app_pstat(void)
1752 {
1753 PROC_CONTEXT_T *pcont ;
1754
1755 TRACE_FUNCTION("app_pstat()") ;
1756
1757 pcont = &proc_context ;
1758 TRACE_EVENT_P3("%s in_shutdown %d last_evt %08x",
1759 proc_string(pcont), pcont->in_shutdown, pcont->last_evt) ;
1760 TRACE_EVENT_P6("prot %d srv %s %s:%d sp_it %d sp_rep %d",
1761 pcont->ipproto,
1762 pcont->server_name ? pcont->server_name : "",
1763 inet_ntoa(pcont->server_ipaddr),
1764 NTOHS(pcont->server_port),
1765 pcont->spec_items,
1766 pcont->spec_reps) ;
1767 TRACE_EVENT_P6("dta tx %d dta rx %d it tx %d it rx %d rep %d errs %d",
1768 pcont->data_sent,
1769 pcont->data_rcvd,
1770 pcont->items_sent,
1771 pcont->items_rcvd,
1772 pcont->n_reps,
1773 pcont->errors) ;
1774 TRACE_EVENT_P5("Socket descr: %x, %sNetwork%s, %spSocket%s",
1775 pcont->psocket,
1776 pcont->network_is_open ? "" : "no ",
1777 pcont->network_is_open ? " open" : "",
1778 pcont->psocket_is_open ? "" : "no ",
1779 pcont->psocket_is_open ? " open" : "") ;
1780 TRACE_EVENT_P4("global: server %s query %s buffer %d port %d",
1781 server_name, query_name, buffer_size, port_number) ;
1782 }
1783
1784
1785 /** Make the application stop or continue receiving data from the network by
1786 * calling the xoff or xon function, respectively.
1787 *
1788 * @param flow_on if non-zero, switch flow on; off otherwise.
1789 */
1790 void app_switch_flow(int flow_on)
1791 {
1792 PROC_CONTEXT_T *pcont = &proc_context ;
1793 TRACE_FUNCTION("app_switch_flow()") ;
1794
1795 if (flow_on)
1796 {
1797 TRACE_EVENT("switching socket to xon") ;
1798 sock_flow_xon(pcont->psocket) ;
1799 }
1800 else
1801 {
1802 TRACE_EVENT("switching socket to xoff") ;
1803 sock_flow_xoff(pcont->psocket) ;
1804 }
1805 }
1806
1807
1808 LOCAL void app_print_conn_info(T_SOCK_BEARER_INFO_CNF *info)
1809 {
1810 TRACE_EVENT_P1("BearerType: %s",
1811 sock_bearer_type_string(info->bearer_params.bearer_type));
1812 TRACE_EVENT_P1("APN: %s", info->bearer_params.apn);
1813 TRACE_EVENT_P1("PhoneNumber: %s", info->bearer_params.phone_nr);
1814 TRACE_EVENT_P1("UserId: %s", info->bearer_params.user_id);
1815 TRACE_EVENT_P1("Password: %s", info->bearer_params.password);
1816 TRACE_EVENT_P1("IP-Address: %s", inet_ntoa(info->bearer_params.ip_address));
1817 TRACE_EVENT_P1("DNS1-Address: %s", inet_ntoa(info->bearer_params.dns1));
1818 TRACE_EVENT_P1("DNS2-Address: %s", inet_ntoa(info->bearer_params.dns2));
1819 TRACE_EVENT_P1("Gateway-Address: %s", inet_ntoa(info->bearer_params.gateway));
1820 TRACE_EVENT_P1("CID: %d",info->bearer_params.cid);
1821 }
1822
1823
1824
1825 void app_open_bearer(int prov, int size, int reps)
1826 {
1827 proc_context.bearer_only = TRUE;
1828 proc_init(prov, size, reps, AP_NONE, SOCK_IPPROTO_TCP, port_number );
1829 proc_context.bearer_only = FALSE;
1830
1831 }
1832
1833 void app_close_bearer()
1834 {
1835 app_shutdown();
1836 }
1837
1838
1839 #endif /* FF_GPF_TCPIP */
1840
1841 /* EOF */