RE: SAR
Igor Ivoilov <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all, here is a patch to put above the one provided by Vjacheslav Chekushin to implement SAR result. So with this 2 patches gw is working ok for mms proxy relay Really I have not implemented yet error handling, it's going to be the next step Regards, Igor (www.thunderworx.com) > -----Original Message----- > From: Vjacheslav Chekushin [mailto:[email protected]] > Sent: Wednesday, September 11, 2002 1:46 PM > To: [email protected] > Subject: SAR > > > 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 >
sar2.patch
(application/octet-stream, 15.5 KB)
diff -ub wap-slava/wap_events.def ../kannel-snapshot/wap/wap_events.def
--- wap-slava/wap_events.def Fri Sep 13 03:43:32 2002
+++ ../kannel-snapshot/wap/wap_events.def Fri Sep 13 05:55:02 2002
@@ -460,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-slava/wtp.c ../kannel-snapshot/wap/wtp.c
--- wap-slava/wtp.c Fri Sep 13 03:43:32 2002
+++ ../kannel-snapshot/wap/wtp.c Fri Sep 13 05:55:02 2002
@@ -28,6 +28,7 @@
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);
@@ -108,6 +109,9 @@
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;
@@ -181,6 +185,8 @@
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;
@@ -188,6 +194,30 @@
event->u.RcvAck.rid = pdu->u.Ack.rid;
event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple);
+ event->u.RcvAck.psn = -1;
+ 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;
}
@@ -272,10 +302,15 @@
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-slava/wtp.h ../kannel-snapshot/wap/wtp.h
--- wap-slava/wtp.h Fri Sep 13 03:43:32 2002
+++ ../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.
@@ -127,11 +137,6 @@
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 wap-slava/wtp_pack.c ../kannel-snapshot/wap/wtp_pack.c
--- wap-slava/wtp_pack.c Fri Sep 13 03:43:32 2002
+++ ../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);
diff -ub wap-slava/wtp_pack.h ../kannel-snapshot/wap/wtp_pack.h
--- wap-slava/wtp_pack.h Fri Sep 13 03:43:32 2002
+++ ../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.
diff -ub wap-slava/wtp_pdu.c ../kannel-snapshot/wap/wtp_pdu.c
--- wap-slava/wtp_pdu.c Fri Sep 13 03:42:44 2002
+++ ../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-slava/wtp_resp.c ../kannel-snapshot/wap/wtp_resp.c
--- wap-slava/wtp_resp.c Fri Sep 13 03:43:32 2002
+++ ../kannel-snapshot/wap/wtp_resp.c Fri Sep 13 07:08:51 2002
@@ -55,6 +55,7 @@
extern int wtp_forced_sar;
static void sar_info_destroy(void *sar_info);
+static void sardata_destroy(void *sardata);
/*****************************************************************************
*
@@ -133,6 +134,9 @@
/* 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.
*/
@@ -318,18 +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 (1 == 1)
- return 0;
-
- 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;
}
/*
@@ -345,11 +338,13 @@
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);
- } */
+ }
+*/
}
}
@@ -461,6 +456,15 @@
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;
/*
@@ -552,6 +556,7 @@
#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"
@@ -589,6 +594,7 @@
#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);
@@ -819,3 +825,81 @@
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-slava/wtp_resp.h ../kannel-snapshot/wap/wtp_resp.h
--- wap-slava/wtp_resp.h Fri Sep 13 03:43:32 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
@@ -39,6 +60,7 @@
#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-slava/wtp_resp_machine.def ../kannel-snapshot/wap/wtp_resp_machine.def
--- wap-slava/wtp_resp_machine.def Fri Sep 13 03:43:32 2002
+++ ../kannel-snapshot/wap/wtp_resp_machine.def Fri Sep 13 05:55:02 2002
@@ -44,6 +44,8 @@
#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
@@ -67,6 +69,7 @@
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
@@ -76,3 +79,4 @@
#undef EVENT
#undef ADDRTUPLE
#undef LIST
+#undef SARDATA
diff -ub wap-slava/wtp_resp_states.def ../kannel-snapshot/wap/wtp_resp_states.def
--- wap-slava/wtp_resp_states.def Fri Sep 13 03:43:32 2002
+++ ../kannel-snapshot/wap/wtp_resp_states.def Fri Sep 13 07:09:04 2002
@@ -284,7 +284,7 @@
ROW(INVOKE_RESP_WAIT,
TR_Result_Req,
- 1,
+ resp_machine->sar == NULL,
{
WAPEvent *result;
@@ -300,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,
@@ -377,7 +392,7 @@
ROW(RESULT_WAIT,
TR_Result_Req,
- 1,
+ resp_machine->sar == NULL,
{
WAPEvent *result;
resp_machine->rcr = 0;
@@ -393,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,
@@ -482,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