diff src/g23m-fad/app/app_core.c @ 1:fa8dc04885d8

src/g23m-*: import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:25:50 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-fad/app/app_core.c	Fri Oct 16 06:25:50 2020 +0000
@@ -0,0 +1,1841 @@
+/*-*- 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 */