FreeCalypso > hg > fc-magnetite
view src/g23m-fad/app/app_core.c @ 293:5b2ebc94cae4
aci3: integrated all Openmoko AT commands except AT@BAND
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 02 Sep 2017 17:37:06 +0000 |
parents | 90eb61ecd093 |
children |
line wrap: on
line source
/*-*- c-basic-offset: 2 -*- +------------------------------------------------------------------------------ | File: app_core.c +------------------------------------------------------------------------------ | Copyright 2003 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : Example application for TCP/IP and Socket API -- core functions. +----------------------------------------------------------------------------- */ /* This should only be compiled into the entity if TCP/IP is enabled */ #ifdef FF_GPF_TCPIP #define APP_CORE_C #define ENTITY_APP /*==== INCLUDES =============================================================*/ #include <string.h> /* String functions, e. g. strncpy(). */ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #ifndef _SIMULATION_ #include "typedefs.h" /* Condat data types. */ #endif /* _SIMULATION_ */ #include "vsi.h" /* A lot of macros. */ #ifndef _SIMULATION_ #include "custom.h" #include "gsm.h" /* A lot of macros. */ #include "prim.h" /* Definitions of used SAP and directions. */ #include "pei.h" /* PEI interface. */ #include "tools.h" /* Common tools. */ #endif /* _SIMULATION_ */ #include "socket_api.h" /* Socket API. */ #include "app.h" /* Global entity definitions. */ /*==== Local data ============================================================*/ #define NPROCS 1 /* Maximum number of application processes. */ #define PORT_CHARGEN 19 /* Chargen service for download. */ #define PORT_ECHO 7 /* Echo port for tcpecho and udpecho. */ #define PORT_DISCARD 9 /* Discard port for upload. */ #define FQDN_LENGTH 255 /* Maximum length of a fully-qualified domain * name. */ #undef HTONS #define HTONS(a) ((((a) & 0xff) << 8) | (((a) & 0xff00) >> 8)) #undef NTOHS #define NTOHS(a) HTONS(a) #define MIN(a, b) ((a) < (b) ? (a) : (b)) /* We can run different types of application processes, according to the * commend sent by the user. */ typedef enum { AP_NONE, /* For uninitialized process types. */ AP_TCPDL, /* Download some data over TCP. */ AP_TCPUL, /* Upload some data over TCP. */ AP_UDPDL, /* Download some data over UDP. */ AP_UDPUL, /* Upload some data over UDP. */ AP_TCPECHO, /* Send/receive data to/from TCP echo port. */ AP_UDPECHO, /* Send/receive data to/from UDP echo port. */ AP_TCPSRV, /* TCP server application. */ AP_DNSQRY, /* Issue DNS queries and collect result. */ AP_TCPFORK, /* Forked TCP server process. */ AP_INVALID } APP_PROCTYPE_T ; /* Strings for process types; used for debugging and MUST correspond strictly * to the process type enum labels defined above. */ static char *proc_type_name[] = { "AP_NONE", /* 00 */ "AP_TCPDL", /* dl */ "AP_TCPUL", /* ul */ "AP_UDPDL", "AP_UDPUL", "AP_TCPECHO", /* te */ "AP_UDPECHO", /* ue */ "AP_TCPSRV", "AP_DNSQRY", /* dq */ "AP_TCPFORK", "AP_INVALID" } ; /* Process states; the state transitions are mostly linear in this order. */ typedef enum { PS_IDLE, /* Initial state, process not running. */ PS_W_DCM_OPEN, /* Waiting for DCM to open connection. */ PS_W_DCM_OPEN_ONLY, /* Waiting for DCM to open connection - no further action. */ PS_W_CREAT, /* Waiting for socket create confirmation. */ PS_W_SCONN, /* Waiting for socket connect confirmation. */ PS_W_BIND, /* Waiting for socket bind confirmation. */ PS_W_LISTN, /* Waiting for confirmation of listen call. */ PS_LISTENS, /* Listens for client connections. */ PS_W_DNS, /* Waiting for a DNS query. */ PS_COMM, /* Happily exchanging data. */ PS_W_SCLOS, /* Waiting for socket close confirmation. */ PS_W_DCLOS, /* Waiting for DCM to close connection. */ PS_W_CONN_INFO, /* Waiting for connection information */ PS_DCM_OPEN, /* DCM (bearer) connecion opened*/ PS_SOCK_OPEN, /* Socket and bearer open */ PS_INVALID } PROC_STAT_T ; /* Strings for the process states; used for debugging and MUST correspond * strictly to the process state enum labels defined above, as the array is * indexed by those. */ static char *proc_state_name[] = { "PS_IDLE", "PS_W_DCM_OPEN", "PS_W_DCM_OPEN_ONLY", "PS_W_CREAT", "PS_W_SCONN", "PS_W_BIND", "PS_W_LISTN", "PS_W_LISTENS", "PS_W_DNS", "PS_COMM", "PS_W_SCLOS", "PS_W_DCLOS", "PS_W_CONN_INFO", "PS_DCM_OPEN", "PS_SOCK_OPEN", "PS_INVALID" } ; /* The data a process holds. May be dynamically allocated in the future. */ typedef struct PROCESS_CONTEXT_S { APP_PROCTYPE_T ptype ; /* Type of application process */ PROC_STAT_T pstate ; /* Process status as defined above. */ int in_shutdown ; /* Non-zero iff process is being shut down. */ T_SOCK_EVENTSTRUCT *last_evt; /* Last event passed from the Socket API. */ T_SOCK_IPPROTO ipproto ; /* IP protocol number for this process (TCP or * UDP); unused with dq. */ char *server_name ; /* May be a domain name or an IP address in * dotted decimal notation. */ T_SOCK_IPADDR server_ipaddr ; /* Server IP address. (Will be IPADDR_ANY in * case of AP_TCPSRV.) */ T_SOCK_PORT server_port ; /* Server port number. (Also in case of * AP_TCPSRV.) */ /* The following variables are in use only where appropriate, of course -- * as indicated in the comment. */ int f_id ; /* Identity of TCP server fork. */ int spec_items ; /* Specified number of items to transfer. (The * items are single bytes for dl and ul.) */ int spec_reps ; /* Specified number of repetitions. */ int data_sent ; /* Total amount of data sent (ul, te, ue). */ int data_rcvd ; /* Total amount of data recvd (dl, te, ue). */ int items_sent ; /* Number of blocks/packets/queries sent (ul, * te, ue, dq). */ int items_rcvd ; /* Number of blocks/packets/responses received * (dl, te, ue, dq). */ int n_reps ; /* Number of repetitions done. */ int errors ; /* Number of errors at all. */ T_SOCK_SOCKET psocket ; /* The socket in use by the process. */ int network_is_open ; /* Non-zero iff we have an open network * connection. */ int psocket_is_open ; /* Non-zero iff we have an open psocket. */ BOOL bearer_only; /* if set, only a Bearer will be opened */ } PROC_CONTEXT_T ; static PROC_CONTEXT_T proc_context ; static PROC_CONTEXT_T cl_context[APP_N_CLIENTS] ; static char server_name[FQDN_LENGTH+1] = APP_DEF_SERVER ; /* Global server name. */ static char query_name[FQDN_LENGTH+1] = APP_DEF_DNSQUERY_ADDR ; static int buffer_size = APP_DEF_BUFFER_SIZE ; static U16 port_number = 0 ; /* Port number override if non-zero. */ static int udp_interval = APP_DEF_UDP_INTERVAL ; static T_SOCK_BEARER_TYPE bearer_select = SOCK_BEARER_AS_SPECIFIED; static T_SOCK_BEARER_TYPE sock_bearer_type = SOCK_BEARER_GPRS; EXTERN BOOL custom_apn_valid; /* The cache for DNS queries is RNET_RT_RESOLV_CACHE_MAX queries big, i. e. 8 * in the current configuration. We need to overflow this cache in order to * test lookup robustness. */ static char *domain_name[] = { #ifdef _SIMULATION_ /* Not in the simulation, though. */ "chuck.berlin.tide.ti.com", #else /* _SIMULATION_ */ "gsmtest.com", "w21.org", "gw.w21.org", "troll.cs.tu-berlin.de", "gatekeeper.dec.com", "www.mcvax.org", "www.mcvaymedia.com", "www.vodafone.de", "www.ti.com", "mailbox.tu-berlin.de", "ge-2-3-0.r02.asbnva01.us.bb.verio.net", "www.condat.de", "www.tellique.de", "prz.tu-berlin.de", #endif /* _SIMULATION_ */ 0 } ; /*==== Local functions =======================================================*/ /* * Utility functions. */ static char *sock_bearer_type_string(T_SOCK_BEARER_TYPE btype) { switch (btype) { case SOCK_BEARER_ANY: return "SOCK_BEARER_ANY" ; case SOCK_BEARER_GPRS: return "SOCK_BEARER_GPRS" ; case SOCK_BEARER_GSM: return "SOCK_BEARER_GSM" ; case SOCK_BEARER_USE_PROFILE: return "SOCK_BEARER_USE_PROFILE" ; case SOCK_BEARER_AS_SPECIFIED: return "SOCK_BEARER_AS_SPECIFIED" ; default: return "<unknown bearer type>" ; } } /** Give a print representation for the specified character. This is the * character itself for printable characters and a substitution character for * others. * * @param c the character * @return the print representation */ static char p_char(char c) { return isprint(c) ? c : '~' ; } #define DUMP_LLENGTH 16 /* Data dump line length. */ #define DBUF_LENGTH (4 * DUMP_LLENGTH + 10) /* See example below. */ #define XDIGIT(n) ("0123456789abcdef"[n]) /** Dump the specified portion of the data as event traces like this: * 0000: 27 28 29 2a 2b 2c 2d 2e-2f 30 31 32 33 34 35 36 ['()*+,-./0123456] * * @param data Pointer to data area * @param size Size of data to dump */ void trace_dump_data(U8 *data, int size) { char dump_buf[DBUF_LENGTH] ; /* Buffer to dump a line into. */ int lcount = 0 ; /* Line count. */ int i ; /* Index into data. */ char *cp ; /* Pointer to current char in dump_buf[]. */ while (size > 0) { cp = dump_buf ; /* Hex values. */ for (i = 0; i < DUMP_LLENGTH && i < size; i++) { *cp++ = XDIGIT(data[i] >> 4) ; *cp++ = XDIGIT(data[i] & 0xf) ; *cp++ = (i == DUMP_LLENGTH/2 - 1) ? '-' : ' ' ; } /* Fill up with blanks. */ for ( ; i < DUMP_LLENGTH; i++) { *cp++ = ' ' ; *cp++ = ' ' ; *cp++ = ' ' ; } /* Literal characters with some decoration. */ *cp++ = '[' ; for (i = 0; i < DUMP_LLENGTH && i < size; i++, cp++) { *cp = p_char(data[i]) ; } *cp++ = ']' ; *cp++ = 0 ; TRACE_EVENT_P2("%04x: %s", DUMP_LLENGTH * lcount++, dump_buf) ; size -= DUMP_LLENGTH ; data += DUMP_LLENGTH ; } } /** Build a string, characterizing a process, suitable for tracing. The string * is statically allocated and will be overwritten with the next call. * * @param pcont Pointer to process context. * @return The string. */ char *proc_string(PROC_CONTEXT_T *pcont) { /* This string must fit the longest possible process string. */ static char procstring[sizeof("AP_TCPFORK99(PS_W_DCM_OPEN_ONLY)")] ; /*lint -e685 (Warning -- Relational operator always evaluates to true) */ sprintf(procstring, "%s%d(%s)", pcont->ptype <= AP_INVALID ? proc_type_name[pcont->ptype] : "AP_UNKNOWN", pcont->ptype == AP_TCPFORK ? pcont->f_id : 0, pcont->pstate <= PS_INVALID ? proc_state_name[pcont->pstate] : "PS_UNKNOWN") ; /*lint +e685 (Warning -- Relational operator always evaluates to true) */ return procstring ; } /** Converts a numeric IP address in network order into an IP address in * dotted decimal string notation. The string returned is statically allocated * and will be overwritten on the next call. * * @param ipaddr The IP address in network order * @return String with the IP address in dotted decimal.. */ static char *inet_ntoa(T_SOCK_IPADDR ipaddr) { U8 *addrbyte ; static char addr_string[sizeof("000.000.000.000")] ; addrbyte = (U8 *) &ipaddr ; sprintf(addr_string, "%u.%u.%u.%u", addrbyte[0], addrbyte[1], addrbyte[2], addrbyte[3]) ; return addr_string ; } /** Converts an IP address in dotted decimal string notation into a numeric IP * address in network order. * * @param addr_string String with the IP address in dotted decimal. * @return The IP address in network order, or SOCK_IPADDR_ANY if the address * string cannot be parsed. */ static T_SOCK_IPADDR inet_aton(char *addr_string) { T_SOCK_IPADDR ipaddr ; U8 *addrbyte ; int o1, o2, o3, o4 ; if (sscanf(addr_string, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) != 4) { TRACE_EVENT_P1("cannot parse '%s' as an IP address", addr_string) ; return SOCK_IPADDR_ANY ; } addrbyte = (U8 *) &ipaddr ; addrbyte[0] = (U8) o1 ; addrbyte[1] = (U8) o2 ; addrbyte[2] = (U8) o3 ; addrbyte[3] = (U8) o4 ; return ipaddr ; } LOCAL char *sock_result_string(T_SOCK_RESULT result) { switch(result) { case SOCK_RESULT_OK : return "SOCK_RESULT_OK"; case SOCK_RESULT_INVALID_PARAMETER : return "SOCK_RESULT_INVALID_PARAMETER"; case SOCK_RESULT_INTERNAL_ERROR : return "SOCK_RESULT_INTERNAL_ERROR"; case SOCK_RESULT_ADDR_IN_USE : return "SOCK_RESULT_ADDR_IN_USE"; case SOCK_RESULT_OUT_OF_MEMORY : return "SOCK_RESULT_OUT_OF_MEMORY"; case SOCK_RESULT_NOT_SUPPORTED : return "SOCK_RESULT_NOT_SUPPORTED"; case SOCK_RESULT_UNREACHABLE : return "SOCK_RESULT_UNREACHABLE"; case SOCK_RESULT_CONN_REFUSED : return "SOCK_RESULT_CONN_REFUSED"; case SOCK_RESULT_TIMEOUT : return "SOCK_RESULT_TIMEOUT"; case SOCK_RESULT_IS_CONNECTED : return "SOCK_RESULT_IS_CONNECTED"; case SOCK_RESULT_HOST_NOT_FOUND : return "SOCK_RESULT_HOST_NOT_FOUND"; case SOCK_RESULT_DNS_TEMP_ERROR : return "SOCK_RESULT_DNS_TEMP_ERROR"; case SOCK_RESULT_DNS_PERM_ERROR : return "SOCK_RESULT_DNS_PERM_ERROR"; case SOCK_RESULT_NO_IPADDR : return "SOCK_RESULT_NO_IPADDR"; case SOCK_RESULT_NOT_CONNECTED : return "SOCK_RESULT_NOT_CONNECTED"; case SOCK_RESULT_MSG_TOO_BIG : return "SOCK_RESULT_MSG_TOO_BIG"; case SOCK_RESULT_CONN_RESET : return "SOCK_RESULT_CONN_RESET"; case SOCK_RESULT_CONN_ABORTED : return "SOCK_RESULT_CONN_ABORTED"; case SOCK_RESULT_NO_BUFSPACE : return "SOCK_RESULT_NO_BUFSPACE"; case SOCK_RESULT_NETWORK_LOST : return "SOCK_RESULT_NETWORK_LOST"; case SOCK_RESULT_NOT_READY : return "SOCK_RESULT_NOT_READY"; case SOCK_RESULT_BEARER_NOT_READY : return "SOCK_RESULT_BEARER_NOT_READY"; case SOCK_RESULT_IN_PROGRESS : return "SOCK_RESULT_IN_PROGRESS"; case SOCK_RESULT_BEARER_ACTIVE : return "SOCK_RESULT_BEARER_ACTIVE"; default : return "<INVALID SOCKET RESULT!>"; } } /** Trace a specific socket API result code with some context. * * @param pcont Pointer to process context. * @param function The function or event that reported the error. * @param result Socket API result code. * @return */ static void sock_trace_result(PROC_CONTEXT_T *pcont, char *function, T_SOCK_RESULT result) { if(result NEQ SOCK_RESULT_OK) { TRACE_ERROR("Sock Result Error"); } TRACE_EVENT_P3("%s: %s for %s", function, sock_result_string(result), proc_string(pcont)); } /** Return the string for a Socket API event type. We don't have the values * under our (i. e. APP's) own control, so we rather do a switch than indexing * an array. * * @param event_type Type of the event. * @return String for the event type. */ char *sock_event_string(T_SOCK_EVENTTYPE event_type) { switch (event_type) { case SOCK_CREATE_CNF: return "SOCK_CREATE_CNF" ; case SOCK_CLOSE_CNF: return "SOCK_CLOSE_CNF" ; case SOCK_BIND_CNF: return "SOCK_BIND_CNF" ; case SOCK_LISTEN_CNF: return "SOCK_LISTEN_CNF" ; case SOCK_CONNECT_CNF: return "SOCK_CONNECT_CNF" ; case SOCK_SOCKNAME_CNF: return "SOCK_SOCKNAME_CNF" ; case SOCK_PEERNAME_CNF: return "SOCK_PEERNAME_CNF" ; case SOCK_HOSTINFO_CNF: return "SOCK_HOSTINFO_CNF" ; case SOCK_MTU_SIZE_CNF: return "SOCK_MTU_SIZE_CNF" ; case SOCK_RECV_IND: return "SOCK_RECV_IND" ; case SOCK_CONNECT_IND: return "SOCK_CONNECT_IND" ; case SOCK_CONN_CLOSED_IND: return "SOCK_CONN_CLOSED_IND" ; case SOCK_ERROR_IND: return "SOCK_ERROR_IND" ; case SOCK_FLOW_READY_IND: return "SOCK_FLOW_READY_IND" ; case SOCK_OPEN_BEARER_CNF: return "SOCK_OPEN_BEARER_CNF"; case SOCK_CLOSE_BEARER_CNF: return "SOCK_CLOSE_BEARER_CNF"; case SOCK_BEARER_INFO_CNF: return "SOCK_BEARER_INFO_CNF"; case SOCK_BAERER_CLOSED_IND: return "SOCK_BAERER_CLOSED_IND"; default: return "<INVALID EVENT>" ; } } /* * Process functions. */ static void proc_shutdown(PROC_CONTEXT_T *pcont) ; static void proc_close_socket(PROC_CONTEXT_T *pcont) ; static void proc_begin_comm(PROC_CONTEXT_T *pcont) ; static void proc_close_conn(PROC_CONTEXT_T *pcont) ; /** Switch process to a new state. Done mostly to have a single place to trace * process state transitions. * * @param pcont Pointer to process context. * @param newstate New state of process. */ static void proc_new_state(PROC_CONTEXT_T *pcont, PROC_STAT_T newstate) { if (newstate < PS_INVALID) { TRACE_EVENT_P2("%s -> %s", proc_string(pcont), proc_state_name[newstate]) ; pcont->pstate = newstate ; } else { TRACE_EVENT_P2("%s invalid new state %d", proc_string(pcont), newstate) ; proc_shutdown(pcont) ; } } /** Fork a new TCP server process context to handle a TCP client. Return a * pointer to the process context or NULL, if no process context is free any * more. * */ static PROC_CONTEXT_T *proc_new_tcpfork(PROC_CONTEXT_T *oldp) { int i ; PROC_CONTEXT_T *pcont ; TRACE_FUNCTION("proc_new_tcpfork()") ; for (i = 0; i < APP_N_CLIENTS; i++) { if (cl_context[i].ptype EQ AP_NONE) { break ; } } if (i == APP_N_CLIENTS) { return NULL ; } pcont = &cl_context[i] ; memset(pcont, 0, sizeof(*pcont)) ; pcont->f_id = i ; pcont->ptype = AP_TCPFORK ; pcont->pstate = PS_IDLE ; pcont->ipproto = oldp->ipproto ; pcont->server_name = oldp->server_name ; pcont->server_ipaddr = oldp->server_ipaddr ; pcont->server_port = oldp->server_port ; pcont->network_is_open = TRUE ; pcont->psocket_is_open = TRUE ; return pcont ; } /** Free a TCP server process context. * */ static void proc_free_tcpfork(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("proc_free_tcpfork()") ; proc_new_state(pcont, PS_IDLE) ; memset(pcont, 0, sizeof(*pcont)) ; } static void proc_init(int prov, int size, int reps, APP_PROCTYPE_T ptype, T_SOCK_IPPROTO ipproto, U16 port) { T_SOCK_BEARER_INFO bearer_info; PROC_CONTEXT_T *pcont ; BOOL bear_only = proc_context.bearer_only; TRACE_FUNCTION("proc_init()") ; pcont = &proc_context ; if (pcont->pstate != PS_IDLE) { TRACE_ERROR("proc_init: process still active") ; return ; } memset(pcont, 0, sizeof(*pcont)) ; pcont->bearer_only = bear_only; pcont->ptype = ptype ; pcont->ipproto = ipproto ; pcont->server_name = (ptype EQ AP_TCPSRV) ? "<myself>" : server_name ; pcont->server_ipaddr = (ptype EQ AP_TCPSRV) ? SOCK_IPADDR_ANY : inet_aton(pcont->server_name) ; pcont->server_port = HTONS(port) ; pcont->spec_items = size ; pcont->spec_reps = reps ; pcont->in_shutdown = FALSE; pcont->psocket = 0; pcont->network_is_open = FALSE; pcont->psocket_is_open = FALSE; TRACE_EVENT_P7("%s for %d bytes %d reps, server %s:%d/%s on %s", proc_string(pcont), pcont->spec_items, pcont->spec_reps, inet_ntoa(pcont->server_ipaddr), NTOHS(pcont->server_port), (ipproto EQ SOCK_IPPROTO_UDP) ? "udp" : "tcp", sock_bearer_type_string(sock_bearer_type)) ; app_pstat(); // fill connection params bearer_info.bearer_handle = sock_bearer_handle; bearer_info.app_handle = APP_handle; bearer_info.bearer_type = sock_bearer_type; if(sock_bearer_type == SOCK_BEARER_GPRS) { bearer_info.apn_valid = TRUE; bearer_info.phone_nr_valid = FALSE; bearer_info.cid = 1; switch(prov) { case APP_PROV_T_MOBILE: strcpy(bearer_info.apn, "internet.t-d1.de"); strcpy(bearer_info.user_id, "t-d1"); strcpy(bearer_info.password, "gprs"); break; case APP_PROV_HUTCH: strcpy(bearer_info.apn, "www"); strcpy(bearer_info.user_id, ""); strcpy(bearer_info.password, ""); break; case APP_PROV_AIRTEL: strcpy(bearer_info.apn, "airtelgprs.com"); strcpy(bearer_info.user_id, ""); strcpy(bearer_info.password, ""); break; case APP_PROV_CUSTOM: /* Copy valid APN */ if(custom_apn_valid) { strcpy(bearer_info.apn, custom_apn); strcpy(bearer_info.user_id, custom_user_id); strcpy(bearer_info.password, custom_password); break; } /* Copy default settings for invalid APN settings */ default: strcpy(bearer_info.apn,"web.vodafone.de"); strcpy(bearer_info.user_id, ""); strcpy(bearer_info.password, ""); break; } } else { bearer_info.phone_nr_valid = TRUE; bearer_info.apn_valid = FALSE; bearer_info.cid = 0; if(prov == APP_PROV_T_MOBILE) { strcpy(bearer_info.phone_nr, "+491712524120"); strcpy(bearer_info.user_id, "t-d1"); strcpy(bearer_info.password, "wap"); } else { strcpy(bearer_info.phone_nr, "+491722290000"); strcpy(bearer_info.user_id, ""); strcpy(bearer_info.password, ""); } } bearer_info.user_id_valid = TRUE; bearer_info.password_valid = TRUE; bearer_info.ip_address = SOCK_IPADDR_ANY; bearer_info.dns1 = SOCK_IPADDR_ANY; bearer_info.dns2 = SOCK_IPADDR_ANY; bearer_info.gateway = SOCK_IPADDR_ANY; bearer_info.authtype = SOCK_AUTH_NO; bearer_info.data_compr = FALSE; bearer_info.header_comp = FALSE; bearer_info.precedence = 0; bearer_info.delay = 0; bearer_info.reliability = 0; bearer_info.peak_throughput = 0; bearer_info.mean_througput = 0; bearer_info.shareable = FALSE; sock_open_bearer(sock_api_inst,bearer_select,0,&bearer_info,app_sock_callback,pcont); if(pcont->bearer_only) { proc_new_state(pcont, PS_W_DCM_OPEN_ONLY) ; } else { proc_new_state(pcont, PS_W_DCM_OPEN) ; } } static void proc_client_closed(PROC_CONTEXT_T *pcont) { T_SOCK_RESULT result ; TRACE_FUNCTION("proc_client_closed()") ; result = sock_close(pcont->psocket); if (result != SOCK_RESULT_OK) { TRACE_EVENT_P1("%s: error closing client socket", proc_string(pcont)) ; proc_shutdown(pcont) ; return; } proc_free_tcpfork(pcont) ; } /*********************************************************************** * Communication functions. */ /** Fill and send data buffer. * * @param pcont Pointer to process context. * @param size Size of data buffer. * @return */ static BOOL comm_send_buffer(PROC_CONTEXT_T *pcont, int size) { char *payload ; /* Pointer to payload buffer. */ char *cp ; /* Pointer into paylaod buffer. */ char *pp ; /* Pointer into test pattern. */ T_SOCK_RESULT result ; /* Result of send call. */ TRACE_FUNCTION("comm_send_buffer()") ; MALLOC(payload, size) ; TRACE_EVENT_P1("PALLOC payload %x", payload) ; /* Fill buffer with pattern. */ for (cp = payload, pp = APP_SEND_PATTERN; cp < payload + size; cp++, pp++) { if (pp >= APP_SEND_PATTERN + sizeof(APP_SEND_PATTERN) - 1) { pp = APP_SEND_PATTERN ; } *cp = *pp ; } if(pcont->ipproto == SOCK_IPPROTO_UDP) { // use UDP socket and specify destination IP address and destination port result = sock_sendto(pcont->psocket, payload, (U16)size, pcont->server_ipaddr,pcont->server_port) ; } else { result = sock_send(pcont->psocket, payload, (U16)size) ; } sock_trace_result(pcont, "sock_send()", result) ; MFREE(payload) ; switch (result) { case SOCK_RESULT_OK: TRACE_EVENT_P6("%s sent %d (%d/%d) bytes in rep %d/%d", proc_string(pcont), size, pcont->data_sent, pcont->spec_items, //* ((pcont->ipproto EQ SOCK_IPPROTO_TCP) ? 1 : size), pcont->n_reps, pcont->spec_reps) ; return TRUE ; case SOCK_RESULT_NO_BUFSPACE: return FALSE ; /* Pause until SOCK_FLOW_READY_IND. */ default: proc_shutdown(pcont) ; return FALSE ; } } /** Server: send some data to the client. * * @param pcont Pointer to process context. * @return */ static BOOL comm_send_srvprompt(PROC_CONTEXT_T *pcont) { char *payload ; /* Pointer to payload buffer. */ int size ; /* Actual size of payload. */ T_SOCK_RESULT result ; /* Result of send call. */ TRACE_FUNCTION("comm_send_srv()") ; MALLOC(payload, 600) ; sprintf(payload, "%s: %sin_shutdown, last_evt %s, will %srepeat\n", proc_string(pcont), pcont->in_shutdown ? "" : "not ", pcont->last_evt ? sock_event_string(pcont->last_evt->event_type) : "NULL", pcont->spec_reps ? "" : "not ") ; sprintf(payload + strlen(payload), " rx %d B %d pkts, tx %d B %d pkts, errs %d conn %d\n", pcont->data_rcvd, pcont->items_rcvd, pcont->data_sent, pcont->items_sent, pcont->errors, pcont->n_reps) ; size = strlen(payload) ; result = sock_send(pcont->psocket, payload, (U16)size) ; sock_trace_result(pcont, "sock_send()", result) ; MFREE(payload) ; switch (result) { case SOCK_RESULT_OK: pcont->data_sent += size ; pcont->items_sent++ ; TRACE_EVENT_P5("%s sent %d (%d/%d) bytes in conn %d", proc_string(pcont), size, pcont->data_sent, pcont->spec_items * size, pcont->n_reps) ; return TRUE ; case SOCK_RESULT_NO_BUFSPACE: return FALSE ; /* Pause until SOCK_FLOW_READY_IND. */ default: proc_shutdown(pcont) ; return FALSE ; } } /** Issue a DNS query. Called for AP_DNSQRY in state PS_COMM. * * @param pcont Pointer to process context. */ static void comm_query(PROC_CONTEXT_T *pcont) { static int next_query = 0 ; /* Next query index. */ char *name ; /* Domain name to query for. */ T_SOCK_RESULT result ; /* Result of query call. */ TRACE_FUNCTION("comm_query()") ; if (query_name[0]) { name = query_name ; } else { name = domain_name[next_query] ; } TRACE_EVENT_P4("%s: query (%d/%d) for %s", proc_string(pcont), pcont->items_sent + 1, pcont->spec_items, name) ; result = sock_gethostbyname(sock_api_inst, name, app_sock_callback, pcont) ; sock_trace_result(pcont, "sock_gethostbyname()", result) ; if (result != SOCK_RESULT_OK) { pcont->errors++ ; TRACE_ERROR("sock_gethostbyname() failed, sleep...") ; vsi_t_sleep(VSI_CALLER 2000) ; } if (!domain_name[++next_query]) { next_query = 0 ; } pcont->items_sent++ ; } /** Send data. Called for all but AP_DNSQRY in state PS_COMM. * * @param pcont Pointer to process context. */ static void comm_send(PROC_CONTEXT_T *pcont) { TRACE_EVENT_P1("comm_send() %s", proc_string(pcont)) ; switch (pcont->ptype) { case AP_TCPDL: /* Do nothing -- the server will send again anyway. */ return ; case AP_UDPDL: if (pcont->data_sent >= pcont->spec_items) { return; } break; case AP_TCPUL: case AP_UDPUL: if (pcont->data_sent >= pcont->spec_items) { TRACE_EVENT_P2("%s done after %d bytes", proc_string(pcont), pcont->data_sent) ; proc_close_socket(pcont) ; pcont->n_reps++ ; return ; } break ; case AP_TCPECHO: case AP_UDPECHO: if (pcont->items_sent >= pcont->spec_items) { TRACE_EVENT_P2("%s done after %d writes", proc_string(pcont), pcont->items_sent) ; proc_close_socket(pcont) ; pcont->n_reps++ ; return ; } break ; case AP_DNSQRY: comm_query(pcont) ; return ; case AP_TCPFORK: /* Send some data, perhaps. */ switch (pcont->server_port) { case PORT_CHARGEN: /* Send something (below). */ break ; case PORT_ECHO: /* Send somewhere else. */ case PORT_DISCARD: /* Don't send anything. */ return ; default: /* Send a server prompt. */ comm_send_srvprompt(pcont) ; break ; } return ; case AP_NONE: case AP_INVALID: default: TRACE_EVENT_P1("Invalid process type %s", proc_string(pcont)) ; return ; } if (comm_send_buffer(pcont, buffer_size)) { pcont->items_sent++ ; TRACE_EVENT_P1("Sent Items: %u",pcont->items_sent); pcont->data_sent += buffer_size ; vsi_t_sleep(VSI_CALLER udp_interval); } else { if (pcont->ptype EQ AP_UDPUL) { TRACE_EVENT_P2("%s sleeps %d ms", proc_string(pcont), udp_interval) ; vsi_t_sleep(VSI_CALLER udp_interval); } } } /** Handle an incoming DNS result. Called for AP_DNSQRY in state PS_COMM. * * @param pcont Pointer to process context. */ static void comm_dns_result(PROC_CONTEXT_T *pcont) { T_SOCK_HOSTINFO_CNF *hinfo ; TRACE_FUNCTION("comm_dns_result()") ; pcont->items_rcvd++ ; hinfo = (T_SOCK_HOSTINFO_CNF *) pcont->last_evt ; if (hinfo->result != SOCK_RESULT_OK) { TRACE_EVENT_P3("lookup error %d in %d/%d queries", pcont->errors, pcont->items_rcvd, pcont->spec_items) ; } else { TRACE_EVENT_P1("Answer for host %s", hinfo->hostname) ; TRACE_EVENT_P3("has address %s (%d/%d)", inet_ntoa(hinfo->ipaddr), pcont->items_rcvd, pcont->spec_items) ; } if (pcont->items_rcvd < pcont->spec_items) { comm_send(pcont) ; } else { proc_close_conn(pcont) ; } } /** Receive incoming data. Called for all but AP_TCPUL in state PS_COMM. * * @param pcont Pointer to process context. */ static void comm_recv(PROC_CONTEXT_T *pcont) { T_SOCK_RECV_IND *recv_ind = (T_SOCK_RECV_IND *) pcont->last_evt ; TRACE_FUNCTION("comm_recv()") ; if (pcont->ptype EQ AP_DNSQRY OR pcont->ptype EQ AP_TCPUL) { TRACE_EVENT_P2("%s: %s unexpected for ptype", proc_string(pcont), sock_event_string(pcont->last_evt->event_type)) ; proc_shutdown(pcont) ; return ; } pcont->data_rcvd += recv_ind->data_length ; pcont->items_rcvd++ ; TRACE_EVENT_P5("%s: recv #%d:%u bytes, total %u, total items sent:%u", proc_string(pcont), pcont->items_rcvd, recv_ind->data_length, pcont->data_rcvd,pcont->items_sent); trace_dump_data((U8 *) recv_ind->data_buffer, MIN(APP_DATA_DUMP_LENGTH, recv_ind->data_length)) ; MFREE(recv_ind->data_buffer) ; recv_ind->data_buffer = 0 ; switch (pcont->ptype) { case AP_UDPDL: /* After every sent UDP packet, a "answer" comes from the Chargen server. * If all packets are sent we are waiting for the last packet to * receive, else an unexpected event would be the result in the * "app_sock_callback()"; TCPIP_DATA_IND is received instead of SOCK_CLOSE_CNF * TODO: why (pcont->items_sent-1), I assume that the server "confirms" * every packet */ if ((pcont->data_sent >= pcont->spec_items) && (pcont->items_rcvd == pcont->items_sent)) { TRACE_EVENT("last UDP-DL packet received"); pcont->n_reps++ ; proc_close_socket(pcont) ; } else { comm_send(pcont); } break; case AP_TCPDL: if (pcont->data_rcvd >= pcont->spec_items) { TRACE_EVENT_P3("%s done after %d/%d bytes", proc_string(pcont), pcont->data_rcvd, pcont->spec_items) ; pcont->n_reps++ ; proc_close_socket(pcont) ; } break ; case AP_UDPECHO: case AP_TCPECHO: case AP_TCPFORK: comm_send(pcont) ; break ; default: TRACE_ERROR("Unexpected ptype in comm_recv()") ; break ; } } /** Handle a communication event according to the process type. Called for all * process types in state PS_COMM. * * @param pcont Pointer to process context. */ static void comm_event(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("comm_event()") ; switch (pcont->last_evt->event_type) { case SOCK_CONN_CLOSED_IND: if (pcont->ptype EQ AP_TCPFORK) { proc_client_closed(pcont) ; break ; } /*lint -fallthrough */ case SOCK_ERROR_IND: TRACE_EVENT_P2("%s: %s, shutdown", proc_string(pcont), sock_event_string(pcont->last_evt->event_type)) ; // server should not reset , even if connection is reset by client. // but client should shutdown , if connection is reset by server. if((pcont->ptype EQ AP_TCPFORK) AND (pcont->last_evt->result == SOCK_RESULT_CONN_RESET OR pcont->last_evt->result == SOCK_RESULT_TIMEOUT)) { proc_client_closed(pcont) ; return; } else proc_shutdown(pcont) ; return ; case SOCK_RECV_IND: comm_recv(pcont) ; break ; case SOCK_FLOW_READY_IND: if(pcont->ptype NEQ AP_UDPDL) { comm_send(pcont) ; } break ; case SOCK_HOSTINFO_CNF: if (pcont->ptype EQ AP_DNSQRY) { comm_dns_result(pcont) ; break ; } /*lint -fallthrough */ case SOCK_CREATE_CNF: case SOCK_CLOSE_CNF: case SOCK_BIND_CNF: case SOCK_LISTEN_CNF: case SOCK_CONNECT_CNF: case SOCK_SOCKNAME_CNF: case SOCK_PEERNAME_CNF: case SOCK_MTU_SIZE_CNF: case SOCK_CONNECT_IND: TRACE_EVENT_P2("%s: %s unexpected at all", proc_string(pcont), sock_event_string(pcont->last_evt->event_type)) ; proc_shutdown(pcont) ; return ; case SOCK_BAERER_CLOSED_IND: proc_shutdown(pcont); break; default: TRACE_EVENT_P2("comm_event(): %s unknown event %d", proc_string(pcont), pcont->last_evt->event_type) ; proc_shutdown(pcont) ; break ; } } /*********************************************************************** * State machine functions (i. e. state-changing functions) */ /** Finish the process after the network connection has been closed. * * @param pcont Pointer to process context. */ static void proc_finish(PROC_CONTEXT_T *pcont) { TRACE_EVENT_P1("%s finished", proc_string(pcont)) ; pcont->network_is_open = FALSE ; pcont->in_shutdown = FALSE; proc_new_state(pcont, PS_IDLE) ; } /** Shutdown process hard, usually after an error or user request. This * includes closing the process's socket and network connection. * * @param pcont Pointer to process context. */ static void proc_shutdown(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("proc_shutdown()") ; if(pcont->in_shutdown) { TRACE_EVENT("Allready in shutdown"); return; } pcont->in_shutdown = TRUE ; app_pstat() ; if (pcont->psocket_is_open) { proc_close_socket(pcont); return; } if (pcont->network_is_open OR pcont->pstate == PS_W_DCM_OPEN OR pcont->pstate == PS_W_DCM_OPEN_ONLY) { proc_close_conn(pcont); return; } else { proc_finish(pcont); } } /** Create a socket after the network connection has been established. * * @param pcont Pointer to process context. */ static void proc_open_socket(PROC_CONTEXT_T *pcont) { T_SOCK_RESULT result ; TRACE_FUNCTION("proc_open_socket()") ; /* We don't need to do this for the DNS query process. */ if (pcont->ptype EQ AP_DNSQRY) { proc_begin_comm(pcont) ; } else { result = sock_create(sock_api_inst, pcont->ipproto, app_sock_callback, pcont); if (result NEQ SOCK_RESULT_OK) { sock_trace_result(pcont, "sock_create()", result) ; proc_shutdown(pcont) ; return; } proc_new_state(pcont, PS_W_CREAT) ; } } /** Close the network connection after the task has been done. * * @param pcont Pointer to process context. */ static void proc_close_conn(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("proc_close_conn()"); if(pcont->network_is_open) { pcont->in_shutdown = TRUE; sock_close_bearer(sock_api_inst, sock_bearer_handle, app_sock_callback, pcont); proc_new_state(pcont, PS_W_DCLOS) ; } else { proc_finish(pcont); } } /** Connect the socket after it has been created. * * @param pcont Pointer to process context. */ static void proc_connect_socket(PROC_CONTEXT_T *pcont) { T_SOCK_RESULT result ; TRACE_FUNCTION("proc_connect_socket()") ; /* If we do not yet have an IP address to connect to, look it up first. */ if (pcont->server_ipaddr EQ SOCK_IPADDR_ANY) { result = sock_gethostbyname(sock_api_inst, pcont->server_name,app_sock_callback, pcont); if (result NEQ SOCK_RESULT_OK) { sock_trace_result(pcont, "sock_gethostbyname()", result) ; proc_shutdown(pcont) ; return; } proc_new_state(pcont, PS_W_DNS) ; return ; } result = sock_connect(pcont->psocket, pcont->server_ipaddr, pcont->server_port); if (result NEQ SOCK_RESULT_OK) { sock_trace_result(pcont, "sock_connect()", result) ; proc_shutdown(pcont) ; return; } proc_new_state(pcont, PS_W_SCONN) ; } /** Begin communicating after the socket has been created. * * @param pcont Pointer to process context. */ static void proc_begin_comm(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("proc_begin_comm()") ; proc_new_state(pcont, PS_COMM) ; switch (pcont->ptype) { case AP_TCPDL: /* We wait for data from the server to arrive. */ break ; case AP_UDPDL: /* Trigger the chargen server to send fisrt UDP packet */ comm_send(pcont); break ; case AP_TCPUL: case AP_UDPUL: case AP_TCPECHO: case AP_UDPECHO: case AP_DNSQRY: case AP_TCPFORK: comm_send(pcont) ; break ; default: TRACE_EVENT_P2("%s unknown state (%d)", proc_string (pcont), pcont->ptype) ; break ; } } /** Close the socket after the requested communication has been done. * * @param pcont Pointer to process context. */ static void proc_close_socket(PROC_CONTEXT_T *pcont) { TRACE_FUNCTION("proc_close_socket()") ; sock_close(pcont->psocket) ; proc_new_state(pcont, PS_W_SCLOS) ; } static void proc_bind_socket(PROC_CONTEXT_T *pcont) { T_SOCK_RESULT result ; TRACE_FUNCTION("proc_bind_socket()") ; if ((result = sock_bind(pcont->psocket, pcont->server_port)) != SOCK_RESULT_OK) { sock_trace_result(pcont, "sock_bind()", result) ; proc_shutdown(pcont) ; return; } proc_new_state(pcont, PS_W_BIND) ; } static void proc_listen(PROC_CONTEXT_T *pcont) { T_SOCK_RESULT result ; TRACE_FUNCTION("proc_listen()") ; if ((result = sock_listen(pcont->psocket)) != SOCK_RESULT_OK) { sock_trace_result(pcont, "sock_listen()", result) ; proc_shutdown(pcont) ; return; } proc_new_state(pcont, PS_W_LISTN) ; } static void proc_incoming(PROC_CONTEXT_T *pcont) { T_SOCK_CONNECT_IND *conn_ind ; PROC_CONTEXT_T *newp ; T_SOCK_RESULT result ; TRACE_FUNCTION("proc_incoming()") ; conn_ind = (T_SOCK_CONNECT_IND *) pcont->last_evt ; if ((newp = proc_new_tcpfork(pcont)) EQ NULL) { TRACE_EVENT_P1("%s: failed to fork server, close new socket", proc_string(pcont)) ; sock_close(conn_ind->new_socket) ; return ; } /* We cannot make two calls to proc_string() without one overwriting the * other, so we print the process strings in two successive traces. */ TRACE_EVENT_P1("%s: forking to handle client connection...", proc_string(pcont)) ; TRACE_EVENT_P1("...forked process is %s", proc_string(newp)) ; newp->psocket = conn_ind->new_socket ; sock_set_callback(newp->psocket, app_sock_callback, newp) ; TRACE_EVENT_P3("%s connection from %s:%d, looking up...", proc_string(pcont), inet_ntoa(conn_ind->peer_ipaddr), NTOHS(conn_ind->peer_port)) ; if ((result = sock_gethostbyaddr(sock_api_inst, conn_ind->peer_ipaddr, app_sock_callback, newp)) != SOCK_RESULT_OK) { sock_trace_result(newp, "sock_gethostbyaddr()", result) ; proc_shutdown(newp) ; proc_shutdown(pcont) ; return; } proc_new_state(newp, PS_W_DNS) ; } static void proc_hostinfo_recvd(PROC_CONTEXT_T *pcont) { T_SOCK_HOSTINFO_CNF *hinfo ; TRACE_FUNCTION("proc_hostinfo_recvd()") ; hinfo = (T_SOCK_HOSTINFO_CNF *) pcont->last_evt ; if (hinfo->result != SOCK_RESULT_OK) { sock_trace_result(pcont, "SOCK_HOSTINFO_CNF", hinfo->result) ; } else { TRACE_EVENT_P3("%s: connected peer is %s (%s)", proc_string(pcont), hinfo->hostname, inet_ntoa(hinfo->ipaddr)) ; } proc_begin_comm(pcont) ; } /*==== Exported functions ====================================================*/ /** Initialize the application core. * * @param handle own communication handle * @return PEI_OK/PEI_ERROR depending on the success of the initialization. */ BOOL app_initialize_tcpip(T_HANDLE app_handle) { TRACE_FUNCTION("app_initialize_tcpip()") ; memset(&proc_context, 0, sizeof(proc_context)) ; return PEI_OK ; } /* Macro for checking the Socket API events in app_sock_callback(). */ #define CHECK_SOCK_EVT(evttype) \ { \ if (event->event_type != evttype) \ { \ TRACE_ERROR("unexpected event type waiting for " #evttype) ; \ proc_shutdown(pcont) ; \ break ; \ } \ if (event->result != SOCK_RESULT_OK) \ { \ if(pcont->pstate == PS_W_DCM_OPEN OR \ pcont->pstate == PS_W_DCM_OPEN_ONLY) \ { proc_new_state(pcont, PS_IDLE); } \ proc_shutdown(pcont) ; \ break ; \ } \ } /** Socket callback function as specified in the Socket API. * * @param event Pointer to event struct passed by API. * @param context Pointer to application context (here: process context) * @return */ void app_sock_callback(T_SOCK_EVENTSTRUCT *event, void *context) { PROC_CONTEXT_T *pcont ; T_SOCK_BEARER_INFO_CNF *info; TRACE_FUNCTION("app_sock_callback()") ; pcont = (PROC_CONTEXT_T *)context ; pcont->last_evt = event ; /* Save event in process context. */ sock_trace_result(pcont, sock_event_string(event->event_type), event->result) ; if (event->result != SOCK_RESULT_OK) { pcont->errors++ ; if(event->result == SOCK_RESULT_NETWORK_LOST) { pcont->network_is_open = FALSE; } } switch (pcont->pstate) /* Do a preliminary check of the event. */ { case PS_W_DCM_OPEN: /* Waiting for DCM to open connection. */ CHECK_SOCK_EVT(SOCK_OPEN_BEARER_CNF); // FST: can't be evaluated-> see makro CHECK_SOCK_EVT if (event->result != SOCK_RESULT_OK AND event->result != SOCK_RESULT_BEARER_ACTIVE) { proc_shutdown(pcont) ; return ; } if (pcont->network_is_open) { TRACE_ERROR("SOCK_OPEN_BEARER_CNF received but pcont->network_is_open") ; proc_shutdown(pcont); return ; } pcont->network_is_open = TRUE ; proc_open_socket(pcont) ; break; case PS_W_DCM_OPEN_ONLY: CHECK_SOCK_EVT(SOCK_OPEN_BEARER_CNF); pcont->network_is_open = TRUE ; proc_new_state(pcont, PS_DCM_OPEN); break; case PS_W_DCLOS: /* Waiting for DCM to close connection. */ CHECK_SOCK_EVT(SOCK_CLOSE_BEARER_CNF); if (!pcont->network_is_open AND pcont->pstate != PS_IDLE) { TRACE_ERROR("DCM_CONN_CLOSED received but !pcont->network_is_open") ; proc_shutdown(pcont) ; return ; } proc_finish(pcont) ; break; case PS_W_CONN_INFO: CHECK_SOCK_EVT(SOCK_BEARER_INFO_CNF); info = (T_SOCK_BEARER_INFO_CNF *)event; app_print_conn_info(info); TRACE_EVENT("SOCK_BEARER_INFO_CNF received"); break; case PS_W_CREAT: /* Waiting for socket create confirmation. */ CHECK_SOCK_EVT(SOCK_CREATE_CNF) ; pcont->psocket = event->socket ; pcont->psocket_is_open = TRUE ; if (pcont->ptype EQ AP_TCPSRV) { proc_bind_socket(pcont) ; } else if(pcont->ipproto == SOCK_IPPROTO_TCP) { proc_connect_socket(pcont) ; } else { // This is not possible in the moment because the RNET_API does not // provide a sendto() function. Therefore it is is only possible to sent // via "connected" UDP sockets. // TODO: if the next statement will be enabled the "proc_connect_socket()" has to be removed!! // proc_begin_comm(pcont); proc_connect_socket(pcont) ; } break ; case PS_W_BIND: CHECK_SOCK_EVT(SOCK_BIND_CNF) ; proc_listen(pcont) ; break ; case PS_W_LISTN: CHECK_SOCK_EVT(SOCK_LISTEN_CNF) ; app_pstat() ; proc_new_state(pcont, PS_LISTENS) ; /* Nothing more to do here. */ break ; case PS_LISTENS: /* SOCK_CONNECT_IND or SOCK_CLOSE_CNF */ if (event->event_type EQ SOCK_CONNECT_IND) { proc_incoming(pcont) ; } break ; case PS_W_DNS: /* After sending connect confirm to client, client will send data to server and server is dnsquerying now , server will be shutdown ,here Unfortunately.. but we want to exchange data happily, so this code is added.... */ if((event->event_type == SOCK_RECV_IND) AND (pcont->ptype == AP_TCPFORK)) break; CHECK_SOCK_EVT(SOCK_HOSTINFO_CNF) ; proc_hostinfo_recvd(pcont) ; break ; case PS_W_SCONN: /* Waiting for socket connect confirmation. */ CHECK_SOCK_EVT(SOCK_CONNECT_CNF) ; proc_begin_comm(pcont) ; break ; case PS_COMM: /* Happily exchanging data. */ comm_event(pcont) ; break ; case PS_W_SCLOS: /* Waiting for socket close confirmation. */ CHECK_SOCK_EVT(SOCK_CLOSE_CNF) ; pcont->psocket_is_open = FALSE ; pcont->psocket = 0; app_pstat() ; if (pcont->n_reps >= pcont->spec_reps OR pcont->in_shutdown) { proc_close_conn(pcont) ; } else { pcont->data_sent = 0 ; pcont->data_rcvd = 0 ; pcont->items_sent = 0 ; pcont->items_rcvd = 0 ; proc_open_socket(pcont) ; } break ; case PS_IDLE: /* Initial state, process not running. */ TRACE_EVENT_P2("app_sock_callback(): %s receives %s (ignored)", proc_string(pcont), sock_event_string(event->event_type)) ; break ; case PS_DCM_OPEN: if(event->event_type == SOCK_BAERER_CLOSED_IND) { TRACE_ERROR("SOCK_BAERER_CLOSED_IND -> Shutdown"); if(event->result == SOCK_RESULT_NETWORK_LOST) { pcont->network_is_open = FALSE; } proc_shutdown(pcont) ; } break; case PS_INVALID: /* Invalid state. */ TRACE_EVENT_P1("app_sock_callback(): %s invalid state", proc_string(pcont)) ; break; default: TRACE_ERROR("app_sock_callback(): Default Statement"); break; /* if(event->event_type == SOCK_DCM_ERR_IND) { TRACE_ERROR("SOCK_DCM_ERR_IND -> Shutdown"); } proc_shutdown(pcont) ; return ; */ } /* Free data buffer if it has not been freed yet. */ if ( (event->event_type EQ SOCK_RECV_IND) AND ((T_SOCK_RECV_IND *) event)->data_buffer ) { MFREE(((T_SOCK_RECV_IND *) event)->data_buffer) ; } pcont->last_evt = NULL ; TRACE_EVENT_P1("leave app_sock_callback() for %s", proc_string(pcont)) ; } /* * Application command functions. */ /** Start a data communication process of the appropriate type.. * * @param size Amount of data to download or number of items to transfer. */ void app_start_tcpdl(int prov, int size, int reps) { proc_init(prov, size, reps, AP_TCPDL, SOCK_IPPROTO_TCP, port_number ? port_number : PORT_CHARGEN) ; } void app_start_tcpul(int prov, int size, int reps) { proc_init(prov, size, reps, AP_TCPUL, SOCK_IPPROTO_TCP, port_number ? port_number : PORT_DISCARD) ; } void app_start_udpdl(int prov, int size, int reps) { proc_init(prov, size, reps, AP_UDPDL, SOCK_IPPROTO_UDP, port_number ? port_number : PORT_CHARGEN) ; } void app_start_udpul(int prov, int size, int reps) { proc_init(prov, size, reps, AP_UDPUL, SOCK_IPPROTO_UDP, port_number ? port_number : PORT_DISCARD) ; } void app_start_tcpecho(int prov, int items, int reps) { proc_init(prov, items, reps, AP_TCPECHO, SOCK_IPPROTO_TCP, port_number ? port_number : PORT_ECHO) ; } void app_start_udpecho(int prov, int items, int reps) { proc_init(prov, items, reps, AP_UDPECHO, SOCK_IPPROTO_UDP, port_number ? port_number : PORT_ECHO) ; } void app_start_dnsquery(int prov, int times, char *address) { if (address) { strncpy(query_name, address, FQDN_LENGTH) ; } else { query_name[0] =0 ; } proc_init(prov, times,1, AP_DNSQRY,(T_SOCK_IPPROTO)0, 0) ; } void app_start_tcpsrv(int prov, int port, int repeat) { proc_init(prov, 0, repeat, AP_TCPSRV, SOCK_IPPROTO_TCP, port) ; } /** Shutdown the specified process. * * @param pid Process ID. */ void app_shutdown(void) { TRACE_FUNCTION("app_shutdown()") ; proc_shutdown(&proc_context) ; } /** Set the current server name or IP address. * * @param server Name or IP address (in dotted decimal notation) of server. */ void app_server(char *server) { if (server) { strncpy(server_name, server, FQDN_LENGTH) ; } TRACE_EVENT_P1("server_name is %s", server_name) ; } /** Set or show the current buffer size. * * @param bufsize size of buffer as a string or NULL */ void app_buffer(char *bufsize) { if (bufsize) { buffer_size = atoi(bufsize) ; } TRACE_EVENT_P1("buffer_size is %d", buffer_size) ; } /** Set or show the current buffer size. * * @param port port number override */ void app_port(char *port) { if (port) { port_number = (U16) atoi(port) ; } if (port_number) { TRACE_EVENT_P1("port number override is %d", port_number) ; } else { TRACE_EVENT("standard port numbers used") ; } } /** Set or show the current bearer type. * * @param bearer bearer type */ void app_bearer(char *bearer) { if (bearer) { if (!strcmp(string_to_lower(bearer), "any")) { sock_bearer_type = SOCK_BEARER_ANY; } else if (!strcmp(string_to_lower(bearer), "gprs")) { sock_bearer_type = SOCK_BEARER_GPRS ; } else if (!strcmp(string_to_lower(bearer), "gsm")) { sock_bearer_type = SOCK_BEARER_GSM; } else if (!strcmp(string_to_lower(bearer), "prof")) { sock_bearer_type = SOCK_BEARER_USE_PROFILE; } else if (!strcmp(string_to_lower(bearer), "spec")) { sock_bearer_type = SOCK_BEARER_AS_SPECIFIED; } else { TRACE_EVENT_P1("bearer type %s unknown", bearer) ; } } TRACE_EVENT_P1("bearer type is %s", sock_bearer_type_string(sock_bearer_type)) ; } /** Trace information about the process. */ void app_pstat(void) { PROC_CONTEXT_T *pcont ; TRACE_FUNCTION("app_pstat()") ; pcont = &proc_context ; TRACE_EVENT_P3("%s in_shutdown %d last_evt %08x", proc_string(pcont), pcont->in_shutdown, pcont->last_evt) ; TRACE_EVENT_P6("prot %d srv %s %s:%d sp_it %d sp_rep %d", pcont->ipproto, pcont->server_name ? pcont->server_name : "", inet_ntoa(pcont->server_ipaddr), NTOHS(pcont->server_port), pcont->spec_items, pcont->spec_reps) ; TRACE_EVENT_P6("dta tx %d dta rx %d it tx %d it rx %d rep %d errs %d", pcont->data_sent, pcont->data_rcvd, pcont->items_sent, pcont->items_rcvd, pcont->n_reps, pcont->errors) ; TRACE_EVENT_P5("Socket descr: %x, %sNetwork%s, %spSocket%s", pcont->psocket, pcont->network_is_open ? "" : "no ", pcont->network_is_open ? " open" : "", pcont->psocket_is_open ? "" : "no ", pcont->psocket_is_open ? " open" : "") ; TRACE_EVENT_P4("global: server %s query %s buffer %d port %d", server_name, query_name, buffer_size, port_number) ; } /** Make the application stop or continue receiving data from the network by * calling the xoff or xon function, respectively. * * @param flow_on if non-zero, switch flow on; off otherwise. */ void app_switch_flow(int flow_on) { PROC_CONTEXT_T *pcont = &proc_context ; TRACE_FUNCTION("app_switch_flow()") ; if (flow_on) { TRACE_EVENT("switching socket to xon") ; sock_flow_xon(pcont->psocket) ; } else { TRACE_EVENT("switching socket to xoff") ; sock_flow_xoff(pcont->psocket) ; } } LOCAL void app_print_conn_info(T_SOCK_BEARER_INFO_CNF *info) { TRACE_EVENT_P1("BearerType: %s", sock_bearer_type_string(info->bearer_params.bearer_type)); TRACE_EVENT_P1("APN: %s", info->bearer_params.apn); TRACE_EVENT_P1("PhoneNumber: %s", info->bearer_params.phone_nr); TRACE_EVENT_P1("UserId: %s", info->bearer_params.user_id); TRACE_EVENT_P1("Password: %s", info->bearer_params.password); TRACE_EVENT_P1("IP-Address: %s", inet_ntoa(info->bearer_params.ip_address)); TRACE_EVENT_P1("DNS1-Address: %s", inet_ntoa(info->bearer_params.dns1)); TRACE_EVENT_P1("DNS2-Address: %s", inet_ntoa(info->bearer_params.dns2)); TRACE_EVENT_P1("Gateway-Address: %s", inet_ntoa(info->bearer_params.gateway)); TRACE_EVENT_P1("CID: %d",info->bearer_params.cid); } void app_open_bearer(int prov, int size, int reps) { proc_context.bearer_only = TRUE; proc_init(prov, size, reps, AP_NONE, SOCK_IPPROTO_TCP, port_number ); proc_context.bearer_only = FALSE; } void app_close_bearer() { app_shutdown(); } #endif /* FF_GPF_TCPIP */ /* EOF */