Hi, all.
Some time ago I wrote simple SAR handling for testing large MMS with
connection-oriented mode. It doesn't include negative ack now.
It works for me without problem (though not tested under heavy load).
I send patch against stable version 1.2.0.
If it looks normaly and can be applied (may be after some modifications),
I can do some cleanups and extend functionality with NACK.


-- 
Vjacheslav Chekushin                                mailto:[EMAIL PROTECTED]
Latvian Mobile Phone Company                        http://www.lmt.lv
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wap_events.def wap/wap_events.def
--- /home/wapgw/kannel/gateway-1.2.0/wap/wap_events.def Thu Dec 13 13:25:08 2001
+++ wap/wap_events.def  Thu Aug 29 15:53:25 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)
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp.c wap/wtp.c
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp.c  Mon Nov 20 21:55:54 2000
+++ wap/wtp.c   Thu Aug 29 15:53:25 2002
@@ -26,6 +26,7 @@
 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_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple);
 static WAPEvent *pack_error(WAPEvent *datagram);
@@ -101,6 +102,9 @@
      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;
 
@@ -156,6 +160,24 @@
     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;
@@ -247,6 +269,9 @@
         }
        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;
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp.h wap/wtp.h
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp.h  Fri Dec  8 15:31:21 2000
+++ wap/wtp.h   Thu Aug 29 18:07:47 2002
@@ -127,6 +127,11 @@
 
 typedef struct machine_pattern machine_pattern;
 
+typedef struct sar_info_t {
+  int sar_psn;
+  Octstr *sar_data;
+} sar_info_t;
+
 /*
  * Handles possible concatenated messages. Returns a list of wap events, 
  * consisting of these events. 
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp_pack.c wap/wtp_pack.c
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_pack.c     Tue Mar 27 17:35:17 2001
+++ wap/wtp_pack.c      Thu Aug 29 15:53:25 2002
@@ -154,6 +154,29 @@
     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);
+
+    return dgram;
+}
+
 /****************************************************************************
  *
  * INTERNAL FUNCTIONS:
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp_pack.h wap/wtp_pack.h
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_pack.h     Mon Nov 20 21:55:54 2000
+++ wap/wtp_pack.h      Thu Aug 29 15:53:25 2002
@@ -54,6 +54,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 /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp.c wap/wtp_resp.c
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp.c     Fri Apr 19 19:01:07 2002
+++ wap/wtp_resp.c      Wed Sep 11 12:31:29 2002
@@ -54,6 +54,8 @@
  */
 extern int wtp_forced_sar;
 
+static void sar_info_destroy(void *sar_info);
+
 /*****************************************************************************
  *
  * Prototypes of internal functions:
@@ -124,6 +126,14 @@
 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);
+
+/*
  * 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 +209,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 +243,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, 
@@ -297,6 +322,9 @@
      * If clients request WTP-SAR should we force to continue
      * or act as be should do by telling the client to call back.
      */
+  if (1 == 1)
+    return 0;
+
     if (wtp_forced_sar) 
         return 0;
 
@@ -317,11 +345,11 @@
               handle_wrong_version(event);
         }
 
-        if (!event->u.RcvInvoke.ttr || !event->u.RcvInvoke.gtr){
+       /*        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 +387,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;
@@ -433,6 +466,12 @@
         /*
          * 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 +551,7 @@
     #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 MACHINE(field) field
     #include "wtp_resp_machine.def"
 
@@ -548,6 +588,7 @@
     #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 MACHINE(field) field
     #include "wtp_resp_machine.def"
     gw_free(resp_machine);
@@ -653,3 +694,128 @@
     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);
+}
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp.h wap/wtp_resp.h
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp.h     Tue May 14 14:05:08 2002
+++ wap/wtp_resp.h      Thu Aug 29 18:20:13 2002
@@ -38,6 +38,7 @@
        #define ADDRTUPLE(name) WAPAddrTuple *name;
        #define ENUM(name) resp_states name;
        #define EVENT(name) WAPEvent *name;
+       #define LIST(name) List *name;
        #define MACHINE(field) field
        #include "wtp_resp_machine.def"
 };
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp_machine.def 
wap/wtp_resp_machine.def
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp_machine.def   Mon Nov 20 21:55:54 
2000
+++ wap/wtp_resp_machine.def    Thu Aug 29 17:44:43 2002
@@ -42,6 +42,8 @@
     #error "Macro TIMER is missing."
 #elif !defined(EVENT) 
     #error "Macro EVENT is missing."
+#elif !defined(LIST)
+    #error "Macro LIST is missing."
 #elif !defined(ADDRTUPLE)
     #error "Macro ADDRTUPLE is missing."
 #endif
@@ -63,6 +65,8 @@
                                       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)
        )
 
 #undef MACHINE
@@ -71,3 +75,4 @@
 #undef TIMER
 #undef EVENT
 #undef ADDRTUPLE
+#undef LIST
diff -ub /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp_states.def 
wap/wtp_resp_states.def
--- /home/wapgw/kannel/gateway-1.2.0/wap/wtp_resp_states.def    Tue Mar 27 17:35:39 
2001
+++ wap/wtp_resp_states.def     Wed Sep 11 13:05:33 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.

Reply via email to