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.