FreeCalypso > hg > fc-magnetite
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 */ |