[EMAIL PROTECTED] wrote:
Hello Dave,

You once "promissed" :) to send your updated SAR patch to the Kannel mailing list. I tried to find this email on the list but couldn't find it.

Could you send your latest version to the list? Possible with your findings like quality, missing features, working phones. Alternatively I can offer you some hosting space on my ADSL box if nescessary. This would allow a simple web-page with detailed info on the patch.

Best regards,

Ruud Schramp


I adapted this patch from the two SAR patches posted to the list; the changes I made to the work of Igor and Vjacheslav were only simple changes needed to apply the path to the latest Kannel CVS snapshot.

"It worked for me" -- sort of. Since I didn't have time to go after the problems, I haven't sent it out or tried to identify the concrete problems.

In particular, SAR on responses seems to work about 50% of the time with a Nokia 7650 (tested by downloading J2ME apps) and SAR on requests seems not to work at all with Nokia devices (tested with attempted MMS-Post).

Furthermore, I suspect that CVS has changed enough that this new patch won't apply.

Here it is; I suspect that members of the core team are quite a bit further along, and I'd recommend waiting for their output. I would not recommend this patch for a production system; I have seen numerous wapbox hangs (not crashes, hangs) using this.

David WHITE
CONNECT AUSTRIA

diff -ub wap/wap_events.def ../kannel-snapshot/wap/wap_events.def
--- wap/wap_events.def  Thu Dec 13 13:25:08 2001
+++ ../kannel-snapshot/wap/wap_events.def       Fri Sep 13 05:55:02 2002
@@ -438,6 +438,17 @@
        ADDRTUPLE(addr_tuple)
        )
 
+WAPEVENT(RcvSegInvoke, "RcvSegInvoke",
+        OCTSTR(user_data)
+        INTEGER(tid)
+        INTEGER(rid)
+        INTEGER(no_cache_supported)
+        INTEGER(gtr)
+        INTEGER(ttr)
+        INTEGER(psn)
+        ADDRTUPLE(addr_tuple)
+        )
+
 WAPEVENT(RcvAbort, "RcvAbort",
        INTEGER(tid)
        INTEGER(abort_type)
@@ -449,6 +460,15 @@
        INTEGER(tid)
        INTEGER(tid_ok)
        INTEGER(rid)
+       INTEGER(psn)
+       ADDRTUPLE(addr_tuple)
+       )
+
+WAPEVENT(RcvNegativeAck, "RcvNack",
+       INTEGER(tid)
+       INTEGER(rid)
+       INTEGER(nmissing)
+       OPTIONAL_OCTSTR(missing)
        ADDRTUPLE(addr_tuple)
        )
 
diff -ub wap/wtp.c ../kannel-snapshot/wap/wtp.c
--- wap/wtp.c   Mon Nov 20 21:55:54 2000
+++ ../kannel-snapshot/wap/wtp.c        Tue Sep 24 18:34:40 2002
@@ -26,7 +26,9 @@
 static int concatenated_message(Octstr *user_data);
 static int truncated_datagram(WAPEvent *event);
 static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
+static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
+static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *pack_error(WAPEvent *datagram);
 
@@ -101,9 +103,15 @@
      case RcvInvoke:
          return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT;
 
+     case RcvSegInvoke:
+       return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT;
+
      case RcvAck:
         return event->u.RcvAck.tid < INITIATOR_TID_LIMIT;
 
+       case RcvNegativeAck:
+               return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT;
+
      case RcvAbort:
         return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT;
 
@@ -156,9 +164,29 @@
     return event;
 }
 
+static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
+{
+    WAPEvent *event;
+
+    event = wap_event_create(RcvSegInvoke);
+    event->u.RcvSegInvoke.user_data = 
+        octstr_duplicate(pdu->u.Segmented_invoke.user_data);
+    event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid;
+    event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid;
+    event->u.RcvSegInvoke.no_cache_supported = 0;
+    event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr;
+    event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr;
+    event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn;
+    event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+
+    return event;
+}
+
 static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
 {
     WAPEvent *event;
+       WTP_TPI  *tpi;
+       int     i,num_tpis;
 
     event = wap_event_create(RcvAck);
     event->u.RcvAck.tid = pdu->u.Ack.tid;
@@ -166,6 +194,31 @@
     event->u.RcvAck.rid = pdu->u.Ack.rid;
     event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
 
+       /* Set default to 0 because Ask on 1 piece message has no tpi */
+    event->u.RcvAck.psn = 0;
+       num_tpis = list_len(pdu->options);
+    for (i = 0; i < num_tpis; i++) {
+        tpi = list_get(pdu->options, i);
+               if (tpi->type == TPI_PSN ) {
+                       event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8);
+                       break;
+               }
+       }
+
+    return event;
+}
+
+static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple)
+{
+       WAPEvent *event;
+
+       event = wap_event_create(RcvNegativeAck);
+       event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid;
+       event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid;
+       event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing;
+       event->u.RcvNegativeAck.missing = 
+octstr_duplicate(pdu->u.Negative_ack.missing);
+       event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+
     return event;
 }
 
@@ -247,10 +300,18 @@
         }
        break;
 
+    case Segmented_invoke:
+      event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
+      break;
+
         case Ack:
            event = unpack_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);    
         break;
 
+       case Negative_ack:
+               event = unpack_negative_ack(pdu, 
+datagram->u.T_DUnitdata_Ind.addr_tuple);    
+               break;
+
        case Abort:
            event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple);
         break;         
diff -ub wap/wtp.h ../kannel-snapshot/wap/wtp.h
--- wap/wtp.h   Fri Dec  8 15:31:21 2000
+++ ../kannel-snapshot/wap/wtp.h        Fri Sep 13 05:55:02 2002
@@ -25,7 +25,7 @@
  */
 enum {
     NUMBER_OF_ABORT_TYPES = 2,
-    NUMBER_OF_ABORT_REASONS  = 9,
+    NUMBER_OF_ABORT_REASONS  = 10,
     NUMBER_OF_TRANSACTION_CLASSES = 3
 };
 
@@ -82,7 +82,8 @@
     WTPVERSIONZERO = 0x06,
     CAPTEMPEXCEEDED = 0x07,
     NORESPONSE = 0x08,
-    MESSAGETOOLARGE = 0x09
+       MESSAGETOOLARGE = 0x09,
+       NOTIMPLEMENTEDESAR = 0x0A
 };    
 
 /*
@@ -110,6 +111,15 @@
     RESPONDER_INDICATION = 1 
 };
 
+enum {
+       TPI_ERROR                       = 0,
+       TPI_INFO                        = 1,
+       TPI_OPTION                      = 2,
+       TPI_PSN                         = 3,
+       TPI_SDU_BOUNDARY        = 4,
+       TPI_FRAME_BOUNDARY      = 5
+};
+
 /*
  * Responder set first tid, initiator not. So all tids send by initiator are 
  * greater than 2**15.
diff -ub wap/wtp_pack.c ../kannel-snapshot/wap/wtp_pack.c
--- wap/wtp_pack.c      Tue Mar 27 17:35:17 2001
+++ ../kannel-snapshot/wap/wtp_pack.c   Fri Sep 13 05:55:02 2002
@@ -27,7 +27,9 @@
     ERROR_DATA = 0x00,
     INFO_DATA = 0x01,
     OPTION = 0x02,
-    PACKET_SEQUENCE_NUMBER = 0x03
+    PACKET_SEQUENCE_NUMBER = 0x03,
+       SDU_BOUNDARY = 0x04,
+       FRAME_BOUNDARY = 0x05
 };
 
 /*****************************************************************************
@@ -106,6 +108,54 @@
     return dgram;
 }
 
+WAPEvent *wtp_pack_sar_result(WTPRespMachine *machine, int psn)
+{
+       WAPEvent *dgram = NULL;
+       WTP_PDU *pdu = NULL;
+       Octstr *data = NULL;
+       int gtr,ttr;
+       
+       gw_assert(machine->sar && machine->sar->data);
+
+       if (psn > machine->sar->nsegm)
+               return dgram;
+
+       ttr = psn == machine->sar->nsegm ? 1 : 0;
+       gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1;
+       if (gtr || ttr) 
+               machine->sar->tr = 1;
+
+       data = octstr_copy(machine->sar->data,psn*SAR_SEGM_SIZE,SAR_SEGM_SIZE);
+
+       if (!psn) {
+               pdu = wtp_pdu_create(Result);
+               pdu->u.Result.con = 0;
+               pdu->u.Result.gtr = gtr;
+               pdu->u.Result.ttr = ttr;
+               pdu->u.Result.rid = 0;
+               pdu->u.Result.tid = send_tid(machine->tid);
+               pdu->u.Result.user_data = data;
+       }
+       else {
+               pdu = wtp_pdu_create(Segmented_result);
+               pdu->u.Segmented_result.con = 0;
+               pdu->u.Segmented_result.gtr = gtr;
+               pdu->u.Segmented_result.ttr = ttr;
+               pdu->u.Segmented_result.rid = 0;
+               pdu->u.Segmented_result.tid = send_tid(machine->tid);
+               pdu->u.Segmented_result.psn = psn;
+               pdu->u.Segmented_result.user_data = data;
+       }
+
+       dgram = wap_event_create(T_DUnitdata_Req);
+       dgram->u.T_DUnitdata_Req.addr_tuple =
+               wap_addr_tuple_duplicate(machine->addr_tuple);
+       dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
+       wtp_pdu_destroy(pdu);
+
+       return dgram;
+}
+
 void wtp_pack_set_rid(WAPEvent *dgram, long rid)
 {
     gw_assert(dgram != NULL);
@@ -148,6 +198,29 @@
 
     dgram = wap_event_create(T_DUnitdata_Req);
     dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
+    dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
+    wtp_pdu_destroy(pdu);
+
+    return dgram;
+}
+
+WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn)
+{
+    WAPEvent *dgram = NULL;
+    WTP_PDU *pdu;
+    unsigned char cpsn;
+    sprintf(&cpsn,"%c",psn);
+
+    pdu = wtp_pdu_create(Ack);
+    pdu->u.Ack.con = 1;
+    pdu->u.Ack.tidverify = ack_type;
+    pdu->u.Ack.rid = 0;
+    pdu->u.Ack.tid = send_tid(tid);
+
+    wtp_pdu_append_tpi(pdu, 3, octstr_create_from_data((char *)&cpsn, 1));
+
+    dgram = wap_event_create(T_DUnitdata_Req);
+    dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address);
     dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu);
     wtp_pdu_destroy(pdu);
 
diff -ub wap/wtp_pack.h ../kannel-snapshot/wap/wtp_pack.h
--- wap/wtp_pack.h      Mon Nov 20 21:55:54 2000
+++ ../kannel-snapshot/wap/wtp_pack.h   Fri Sep 13 05:55:02 2002
@@ -34,6 +34,8 @@
 
 WAPEvent *wtp_pack_result(WTPRespMachine *resp_machine, WAPEvent *event); 
 
+WAPEvent *wtp_pack_sar_result(WTPRespMachine *resp_machine, int psn); 
+
 /*
  * Create a datagram event, having abort PDU as user data. Fetches SDU
  * from WTP event, address four-tuple from WTP machine. 
@@ -54,6 +56,8 @@
 WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid, 
                        WAPAddrTuple *address);
 
+WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn);
+
 /*
  * Set or unset the retransmission indicator on a PDU that has already
  * been packed as a datagram.  dgram must be of type T_DUnitdata_Req.
diff -ub wap/wtp_pdu.c ../kannel-snapshot/wap/wtp_pdu.c
--- wap/wtp_pdu.c       Mon Jan 15 18:18:52 2001
+++ ../kannel-snapshot/wap/wtp_pdu.c    Fri Sep 13 05:55:02 2002
@@ -38,7 +38,7 @@
 #undef UINT
 #undef PDU
        default:
-               warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type);
+               warning(0, "Cannot create unknown WTP PDU type %d", pdu->type);
                break;
        }
 
diff -ub wap/wtp_resp.c ../kannel-snapshot/wap/wtp_resp.c
--- wap/wtp_resp.c      Fri Apr 19 19:01:07 2002
+++ ../kannel-snapshot/wap/wtp_resp.c   Fri Sep 13 07:08:51 2002
@@ -54,6 +54,9 @@
  */
 extern int wtp_forced_sar;
 
+static void sar_info_destroy(void *sar_info);
+static void sardata_destroy(void *sardata);
+
 /*****************************************************************************
  *
  * Prototypes of internal functions:
@@ -124,6 +127,17 @@
 static void handle_wrong_version(WAPEvent *event);
 
 /*
+ * SAR functions
+ */
+static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn);
+static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn);
+/* static int is_wanted_sar_data (void *a, void *b); */
+static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event);
+
+static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event);
+static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event);
+
+/*
  * Create a datagram with an Abort PDU and send it to the WDP layer.
  */
 static void send_abort(WTPRespMachine *machine, long type, long reason);
@@ -199,12 +213,15 @@
 
     while (resp_run_status == running && 
            (e = list_consume(resp_queue)) != NULL) {
+
        sm = resp_machine_find_or_create(e);
-       if (sm == NULL)
+
+       if (sm == NULL) {
            wap_event_destroy(e);
-       else
+       } else {
            resp_event_handle(sm, e);
        }
+    }
 }
 
 /*
@@ -230,6 +247,18 @@
 static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event)
 {
     WAPEvent *wsp_event = NULL;
+    WAPEvent *e = NULL; /* For SAR acknowledgment */
+
+    /* We doesn't feed sar packets into state machine untill get the whole message */
+    if (process_sar_transaction(resp_machine,&event) == 0) {
+      debug("wap.wtp", 0, "SAR event recieved, wait for continue");
+      /* For removing state machine in case of incomplete sar */
+      start_timer_W(resp_machine);
+      if (event != NULL) {
+       wap_event_destroy(event);  
+      }
+      return;
+    }
 
     debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.", 
          resp_machine->mid, 
@@ -293,15 +322,7 @@
  */
 static int erroneous_field_in(WAPEvent *event)
 {
-    /*
-     * If clients request WTP-SAR should we force to continue
-     * or act as be should do by telling the client to call back.
-     */
-    if (wtp_forced_sar) 
-        return 0;
-
-    return event->type == RcvInvoke && (event->u.RcvInvoke.version != 0 || 
-               !event->u.RcvInvoke.ttr || !event->u.RcvInvoke.gtr);
+    return event->type == RcvInvoke && event->u.RcvInvoke.version != 0;
 }
 
 /*
@@ -317,11 +338,13 @@
               handle_wrong_version(event);
         }
 
+/*
         if (!event->u.RcvInvoke.ttr || !event->u.RcvInvoke.gtr){
             debug("wap.wtp_resp", 0, "WTP_RESP: no sar implemented," 
                   "aborting transaction");
             handle_no_sar(event);
         }
+*/
     }
 }
 
@@ -359,6 +382,11 @@
             }
             break;
 
+    case RcvSegInvoke:
+      tid = event->u.RcvSegInvoke.tid;
+      tuple = event->u.RcvSegInvoke.addr_tuple;
+      break;
+
        case RcvAck:
             tid = event->u.RcvAck.tid;
             tuple = event->u.RcvAck.addr_tuple;
@@ -428,11 +456,26 @@
         case RcvInvoke:
               resp_machine = resp_machine_create(tuple, tid, 
                                               event->u.RcvInvoke.tcl);
+                       /* if SAR requested */
+                       if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) {
+                               resp_machine->sar = gw_malloc(sizeof(WTPSARData));
+                               resp_machine->sar->nsegm = 0;
+                               resp_machine->sar->csegm = 0;
+                               resp_machine->sar->lsegm = 0;
+                               resp_machine->sar->data = NULL;         
+                       }
+
             break;
 
         /*
          * This and the following branch implement test nro 3 in WTP 10.2.
          */
+           
+       case RcvSegInvoke:
+         info(0, "WTP_RESP: resp_machine_find_or_create:"
+              " segmented invoke received, yet having no machine");
+         break;
+
         case RcvAck: 
             info(0, "WTP_RESP: resp_machine_find_or_create:"
                  " ack received, yet having no machine");
@@ -512,6 +555,8 @@
     #define INTEGER(name) resp_machine->name = 0; 
     #define TIMER(name) resp_machine->name = gwtimer_create(resp_queue); 
     #define ADDRTUPLE(name) resp_machine->name = NULL; 
+    #define LIST(name) resp_machine->name = NULL;
+       #define SARDATA(name) resp_machine->name = NULL;
     #define MACHINE(field) field
     #include "wtp_resp_machine.def"
 
@@ -548,6 +593,8 @@
     #define INTEGER(name) resp_machine->name = 0; 
     #define TIMER(name) gwtimer_destroy(resp_machine->name); 
     #define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name); 
+    #define LIST(name) list_destroy(resp_machine->name,sar_info_destroy);
+       #define SARDATA(name) sardata_destroy(resp_machine->name);
     #define MACHINE(field) field
     #include "wtp_resp_machine.def"
     gw_free(resp_machine);
@@ -653,3 +700,206 @@
     e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple);
     dispatch_to_wdp(e);
 }
+
+/* Process incoming event, checking for WTP SAR */
+
+static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event) {
+  WAPEvent *e,*orig_event;
+  int psn;
+  
+  orig_event = *event;
+
+  if (orig_event->type == RcvInvoke) { 
+    if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */
+      /* Ericcson set TTR flag even if we have the only part */
+      if (orig_event->u.RcvInvoke.ttr == 1) {
+       return 1; /* Not SAR although TTR flag was set */
+      } else {
+       /* save initial event */
+       machine->sar_invoke = wap_event_duplicate(orig_event);
+
+       /* save data into list with psn = 0 */
+       add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0);
+
+       if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */
+         e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid,
+                              machine->addr_tuple, 0);
+         dispatch_to_wdp(e);
+       }
+       return 0;
+      }
+    } else {
+      return 1; /* Not SAR */
+    } 
+  }
+
+  if (orig_event->type == RcvSegInvoke) {
+    add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data, 
+                       orig_event->u.RcvSegInvoke.psn);
+
+    if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */
+      e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple,
+                          orig_event->u.RcvSegInvoke.psn);
+      dispatch_to_wdp(e);
+    }
+
+    if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */
+      /* Create assembled event */
+
+      psn = orig_event->u.RcvSegInvoke.psn;
+      wap_event_destroy(orig_event);
+      
+      *event = assembly_sar_event(machine,psn);
+
+      gw_assert(event != NULL);
+
+      return 1;
+    }
+    return 0;
+  }
+
+  /* Not SAR message */
+  return 1;
+}
+
+static int is_wanted_sar_data (void *a, void *b) {
+  sar_info_t *s;
+  int *i;
+  s = a;
+  i = b;
+
+  if (*i == s->sar_psn) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+/* 
+ * Return 0 if transaction added suscessufully, 1 overwise 
+ */
+
+static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn) {
+  sar_info_t *sar_info;
+
+  if (machine->sar_info == NULL) {
+    machine->sar_info = list_create();
+  }
+
+  if (list_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) {
+    sar_info = gw_malloc(sizeof(sar_info_t));
+    sar_info->sar_psn = psn;
+    sar_info->sar_data = octstr_duplicate(data);
+    list_append(machine->sar_info, sar_info);
+    return 0;
+  } else {
+    debug("wap.wtp", 0, "Duplicated psn found, ignore packet");
+    return 1;
+  } 
+}
+
+static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn) {
+  WAPEvent *e;
+  int i;
+  sar_info_t *sar_info;
+  
+
+  e = wap_event_duplicate(machine->sar_invoke);
+
+  for (i = 1; i<=last_psn; i++) {
+    if ((sar_info = list_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) {
+      octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data);
+    } else {
+      debug("wap.wtp", 0, "Packet with psn %d not found",i);
+      return e;
+    }
+  }
+  return e;
+}
+
+static void sar_info_destroy(void *p) {
+  sar_info_t *sar_info;
+
+  sar_info = p;
+  
+  octstr_destroy(sar_info->sar_data);
+  gw_free(sar_info);
+}
+
+
+static void sardata_destroy(void *p) 
+{
+       WTPSARData * sardata;
+       if (p) {
+               sardata = p;
+               octstr_destroy(sardata->data);
+               gw_free(sardata);
+       }
+}
+
+static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
+{
+       WAPEvent *result;
+       WTPSARData *sar;
+       int psn;
+
+       gw_assert(resp_machine->sar != NULL);
+
+       sar = resp_machine->sar;
+       
+       sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data);
+       sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE;
+       sar->tr = sar->lsegm = 0;
+       sar->csegm = -1;
+
+       debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = 
+%lu",octstr_len(sar->data));
+
+       for (psn=0;!sar->tr;psn++) {
+               result = wtp_pack_sar_result(resp_machine, psn);
+               if (sar->tr) 
+                       resp_machine->result = wap_event_duplicate(result);
+
+               debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
+               
+               dispatch_to_wdp(result);
+               sar->lsegm = psn;
+       }
+
+       resp_machine->rid = 1;
+}
+
+static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) 
+{
+       WAPEvent *result;
+       WTPSARData *sar;
+       int psn;
+
+       gw_assert(resp_machine->sar != NULL && event->type == RcvAck);
+       
+       sar = resp_machine->sar;
+
+       debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, 
+csegm=%d",sar->lsegm,sar->nsegm,sar->csegm);
+
+    start_timer_R(resp_machine);
+
+       if (event->u.RcvAck.psn>sar->csegm) {
+               sar->csegm = event->u.RcvAck.psn;
+       }
+       sar->tr = 0;
+       wap_event_destroy(resp_machine->result);
+       resp_machine->result = NULL;
+
+       for (psn=sar->csegm+1;!sar->tr;psn++) {
+               result = wtp_pack_sar_result(resp_machine, psn);
+               if (sar->tr) 
+                       resp_machine->result = wap_event_duplicate(result);
+
+               debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn);
+
+               dispatch_to_wdp(result);
+               sar->lsegm = psn;
+       }
+       
+}
+
+
diff -ub wap/wtp_resp.h ../kannel-snapshot/wap/wtp_resp.h
--- wap/wtp_resp.h      Tue May 14 14:05:08 2002
+++ ../kannel-snapshot/wap/wtp_resp.h   Fri Sep 13 05:55:02 2002
@@ -13,6 +13,27 @@
 #include "wap_events.h"
 #include "timers.h"
 
+typedef struct sar_info_t {
+       int sar_psn;
+       Octstr *sar_data;
+} sar_info_t;
+
+/*
+ * Structure to keep SAR data during transmission
+ */
+typedef struct WTPSARData {
+       int nsegm;  /* number of the last segment, i.e. total number - 1 */
+       int csegm;  /* last segment confirmed by recipient */
+       int lsegm;  /* last sent segment */
+       int tr;         /* if current psn is gtr or ttr */
+       Octstr *data;
+} WTPSARData;
+
+/* Nokia wap gw uses the size of 576, but mobiles use 1,5K size, 
+ * I will think later what is better to use
+ */
+#define                SAR_SEGM_SIZE   576
+#define                SAR_GROUP_LEN   3
 /*
  * Responder machine states and responder WTP machine.
  * See file wtp_resp_state-decl.h for comments. Note that we must define macro
@@ -38,6 +59,8 @@
        #define ADDRTUPLE(name) WAPAddrTuple *name;
        #define ENUM(name) resp_states name;
        #define EVENT(name) WAPEvent *name;
+       #define LIST(name) List *name;
+       #define SARDATA(name) WTPSARData *name;
        #define MACHINE(field) field
        #include "wtp_resp_machine.def"
 };
diff -ub wap/wtp_resp_machine.def ../kannel-snapshot/wap/wtp_resp_machine.def
--- wap/wtp_resp_machine.def    Mon Nov 20 21:55:54 2000
+++ ../kannel-snapshot/wap/wtp_resp_machine.def Fri Sep 13 05:55:02 2002
@@ -42,6 +42,10 @@
     #error "Macro TIMER is missing."
 #elif !defined(EVENT) 
     #error "Macro EVENT is missing."
+#elif !defined(LIST)
+    #error "Macro LIST is missing."
+#elif !defined(SARDATA)
+       #error "Macro SARDATA is missing."
 #elif !defined(ADDRTUPLE)
     #error "Macro ADDRTUPLE is missing."
 #endif
@@ -63,6 +67,9 @@
                                       in the global timers list */
         EVENT(invoke_indication) /* packed wsp invoke indication - for tid
                                          verification */
+       EVENT(sar_invoke)     /* initial invoke for SAR, accumulate user_data */
+       LIST(sar_info)
+        SARDATA(sar)              /* ! NULL if were we asked for SAR */
        )
 
 #undef MACHINE
@@ -71,3 +78,5 @@
 #undef TIMER
 #undef EVENT
 #undef ADDRTUPLE
+#undef LIST
+#undef SARDATA
diff -ub wap/wtp_resp_states.def ../kannel-snapshot/wap/wtp_resp_states.def
--- wap/wtp_resp_states.def     Tue Mar 27 17:35:39 2001
+++ ../kannel-snapshot/wap/wtp_resp_states.def  Fri Sep 13 07:09:04 2002
@@ -165,6 +165,15 @@
     LISTEN)
 
 /*
+ * Need to control SAR incomplete packets
+ */    
+ROW(LISTEN,
+    TimerTO_W,
+    1,
+    {},
+    LISTEN)
+
+/*
  * We must cache the newly accepted tid item, otherwise every tid after a 
  * suspected one will be validated. We use wsp event stored by the responder
  * machine.
@@ -275,7 +284,7 @@
 
 ROW(INVOKE_RESP_WAIT,
     TR_Result_Req,
-    1,
+    resp_machine->sar == NULL,
     {
      WAPEvent *result;
 
@@ -291,6 +300,21 @@
     },
     RESULT_RESP_WAIT)
 
+ROW(INVOKE_RESP_WAIT,
+    TR_Result_Req,
+    resp_machine->sar != NULL,
+    {
+     WAPEvent *result;
+
+     resp_machine->rcr = 0;
+
+     start_timer_R(resp_machine);
+     wap_event_destroy(resp_machine->result);
+     resp_machine->rid = 0;
+        begin_sar_result(resp_machine, event); 
+    },
+    RESULT_RESP_WAIT)
+
 /*
  * Conditions below do not correspond wholly ones found from the spec. (If 
  * they does, user acknowledgement flag would never be used by the protocol, 
@@ -368,7 +392,7 @@
 
 ROW(RESULT_WAIT,
     TR_Result_Req,
-    1,
+    resp_machine->sar == NULL,
     {
      WAPEvent *result;
      resp_machine->rcr = 0;
@@ -384,6 +408,23 @@
     },
     RESULT_RESP_WAIT)
 
+
+ROW(RESULT_WAIT,
+    TR_Result_Req,
+    resp_machine->sar != NULL,
+    {
+     WAPEvent *result;
+     resp_machine->rcr = 0;
+
+     start_timer_R(resp_machine);
+
+     wap_event_destroy(resp_machine->result);
+     resp_machine->rid = 0;
+        begin_sar_result(resp_machine, event); 
+    },
+    RESULT_RESP_WAIT)
+
+
 ROW(RESULT_WAIT,
     RcvAbort,
     1,
@@ -473,13 +514,21 @@
 
 ROW(RESULT_RESP_WAIT,
     RcvAck,
-    1,
+    resp_machine->sar == NULL || event->u.RcvAck.psn == resp_machine->sar->nsegm,
     {
      wsp_event = create_tr_result_cnf(resp_machine);
      wsp_session_dispatch_event(wsp_event);
     },
     LISTEN)
 
+ROW(RESULT_RESP_WAIT,
+    RcvAck,
+    resp_machine->sar != NULL && event->u.RcvAck.psn != resp_machine->sar->nsegm,
+    {
+        continue_sar_result(resp_machine, event);       
+    },
+    RESULT_RESP_WAIT)
+
 /*
  * Specs does not tell what to do, when wtp responder receives invoke pdu and
  * its state is RESULT_RESP_WAIT. This can happen, however: event causing the 


Reply via email to