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 */ |
