📄 wtpsar.c
字号:
/*
* Copyright (C) Ericsson Mobile Communications AB, 2000.
* Licensed to AU-System AB.
* All rights reserved.
*
* This software is covered by the license agreement between
* the end user and AU-System AB, and may be used and copied
* only in accordance with the terms of the said agreement.
*
* Neither Ericsson Mobile Communications AB nor AU-System AB
* assumes any responsibility or liability for any errors or inaccuracies in
* this software, or any consequential, incidental or indirect damage arising
* out of the use of the Generic WAP Client software.
*/
/*
* wtpsar.c
*
* Created by Anders Edenbrandt, Tue Oct 17 08:45:52 2000.
*
* Revision history:
*
* 010517, MALU, Compiler-warnings removed.
*
*/
#include <string.h>
#include "wtpsuppt.h"
#include "wtpsar.h"
#ifdef WTP_TEST_SAR
#define WTP_SAR_GROUP_SIZE 300
#define WTP_SAR_SEGMENT_SIZE 12
#endif
#define WTP_FLAG_RID 0x01
#define WTP_FLAG_TTR 0x02
#define WTP_FLAG_GTR 0x04
#define WTP_FLAG_MORE_DATA 0x08
#define WTP_FLAG_TID_NEW 0x10
#define WTP_FLAG_USER_ACK 0x20
#define WTP_FLAG_SPLIT_RESULT 0x40
#define WTP_FLAG_SENT_NACK 0x80
/*
* Each invoke segment has a node of this type:
*/
typedef struct iseg_st {
struct iseg_st *next;
BYTE *data;
UINT16 length;
UINT8 segnum;
UINT8 flags;
} wtp_invoke_segment_t;
/*
* A missing segment is simply a pointer to an invoke segment.
*/
typedef struct mseg_st {
struct mseg_st *next;
wtp_invoke_segment_t *iseg;
} wtp_missing_segment_t;
/*
* Each result segment has a node of this type:
*/
typedef struct rseg_st {
struct rseg_st *next;
pdubuf *pdu;
UINT8 segnum;
UINT8 flags;
} wtp_result_segment_t;
/*
* Each transaction has information stored in this structure:
*/
typedef struct {
/* General info */
UINT16 tid;
UINT8 transaction_class;
UINT8 flags;
SDL_Integer handle;
/* Relevant to segmented invoke */
pdubuf *invoke_pdu;
wtp_invoke_segment_t *invoke_group;
wtp_invoke_segment_t *last_segment;
wtp_missing_segment_t *missing_segments;
UINT32 total_send_msg_size;
UINT32 max_send_group_size;
UINT32 delay_time;
UINT8 segnum;
UINT8 ack_psn;
/* Relevant to segmented result */
wtp_result_segment_t *result_list;
UINT32 total_recv_msg_size;
UINT32 max_recv_group_size;
UINT32 recv_msg_size;
UINT32 recv_group_size;
UINT8 num_recv_segments;
UINT8 first_segnum_in_current_group;
UINT8 first_segnum_in_previous_group;
} wtp_transaction_t;
/*
* Read an unsigned integer stored in "len" bytes
* in big-endian order. Return the value read.
*/
static UINT32
wtp_get_uintn (UINT8 *p, UINT8 len)
{
UINT32 n = 0;
while (len-- > 0) {
n <<= 8;
n |= *p++;
}
return n;
}
/*
* Store an unsigned integer, "n", in big-endian order
* in "len" bytes, at the location indicated by "p".
*/
static void
wtp_put_uintn (UINT32 n, UINT8 len, UINT8 *p)
{
p += len - 1;
while (len-- > 0) {
*p-- = (UINT8)(n & 0xff);
n >>= 8;
}
}
/*
* Lengths of PDU headers. Used by TPI-reader below.
*/
static UINT8 wtp_pdu_header_lengths[8] = {
0,
WTP_PDU_INVOKE_HEADERLEN,
WTP_PDU_RESULT_HEADERLEN,
WTP_PDU_ACK_HEADERLEN,
WTP_PDU_ABORT_HEADERLEN,
WTP_PDU_SEGMENTED_INVOKE_HEADERLEN,
WTP_PDU_SEGMENTED_RESULT_HEADERLEN,
WTP_PDU_NACK_HEADERLEN};
/*
* Read eventual TPIs in a PDU, update the transaction state
* accordingly, and delete PDU header and TPIs from the PDU.
* Returns -1 in case of error, and 0 otherwise.
*/
static int
wtp_read_tpis (wtp_transaction_t *tr, pdubuf *pdu)
{
UINT8 more_tpis = 0, long_tpi;
BYTE *pb = pdubuf_getStart (pdu), *ip;
UINT16 remaining_length = pdubuf_getLength (pdu);
UINT8 pdu_type, tpi_id, tpi_length, option_id;
UINT16 len;
more_tpis = (pb[0] >> 7) & 0x1;
pdu_type = (UINT8)((pb[0] >> 3) & 0x7);
len = wtp_pdu_header_lengths[pdu_type];
if (pdu_type == WTP_PDU_TYPE_NACK)
len += pb[3];
pb += len;
remaining_length -= len;
while (more_tpis) {
if (remaining_length < 1)
return -1;
tpi_id = (pb[0] >> 3) & 0xf;
long_tpi = (pb[0] >> 2) & 0x1;
if (long_tpi) {
if (remaining_length < 2)
return -1;
tpi_length = pb[1];
if (remaining_length < tpi_length + 2)
return -1;
}
else {
tpi_length = pb[0] & 0x3;
if (remaining_length < tpi_length + 1)
return -1;
}
more_tpis = (pb[0] >> 7) & 0x1;
switch (tpi_id) {
case WTP_TPI_OPTION:
if (long_tpi) {
option_id = pb[2];
ip = pb + 3;
}
else {
option_id = pb[1];
ip = pb + 2;
}
switch (option_id) {
case WTP_TPI_OPTION_TOTAL_MESSAGE_SIZE:
if (tpi_length > 4)
return -1;
tr->total_recv_msg_size = wtp_get_uintn (ip, (UINT8)tpi_length);
break;
case WTP_TPI_OPTION_DELAY_TRANS_TIMER:
if (tpi_length > 4)
return -1;
tr->delay_time = wtp_get_uintn (ip, (UINT8)tpi_length);
break;
case WTP_TPI_OPTION_MAX_GROUP_SIZE:
if (tpi_length > 4)
return -1;
tr->max_send_group_size = wtp_get_uintn (ip, (UINT8)tpi_length);
break;
default:
/* Ignore other Option TPIs */
break;
}
break;
case WTP_TPI_ERROR:
/* Ignore */
break;
case WTP_TPI_INFO:
/* Ignore */
break;
case WTP_TPI_PSN:
if (long_tpi) {
tr->ack_psn = (UINT8)wtp_get_uintn (pb + 2, (UINT8)(tpi_length - 1));
}
else if (tpi_length == 1) {
tr->ack_psn = pb[1];
}
else {
tr->ack_psn = (UINT8)wtp_get_uintn (pb + 1, (UINT8)(tpi_length - 1));
}
break;
default:
return -1;
}
if (long_tpi) {
pb += tpi_length + 2;
remaining_length -= tpi_length + 2;
}
else {
pb += tpi_length + 1;
remaining_length -= tpi_length + 1;
}
}
pdubuf_setLength (pdu, (UINT16)remaining_length);
return 0;
}
/*
* Initialize a transaction structure.
* Returns a pointer that is used in subsequent calls to
* refer to this transaction.
*/
void *
wtp_transaction_init (SDL_Natural tid,
SDL_Boolean tid_new,
TRInvokeReqType *req)
{
wtp_transaction_t *tr;
tr = (wtp_transaction_t*)OSConnectorAlloc (sizeof (wtp_transaction_t));
tr->tid = (UINT16)tid;
tr->transaction_class = (UINT8)req->ClassType;
tr->handle = req->Handle;
tr->flags = (tid_new == SDL_True) ? WTP_FLAG_TID_NEW : 0;
tr->flags |= (req->AckType == 1) ? WTP_FLAG_USER_ACK : 0;
tr->flags |= (req->AllowSegmentedResult == SDL_True)
? WTP_FLAG_SPLIT_RESULT : 0;
tr->flags |= (req->MoreData == SDL_True) ? WTP_FLAG_MORE_DATA : 0;
tr->invoke_pdu = req->UserData;
tr->invoke_group = NULL;
tr->last_segment = NULL;
tr->missing_segments = NULL;
tr->total_send_msg_size = req->TotalSize;
tr->max_send_group_size = WTP_SAR_GROUP_SIZE;
tr->delay_time = 0;
tr->segnum = 0;
tr->result_list = NULL;
tr->total_recv_msg_size = 0;
tr->max_recv_group_size = WTP_SAR_GROUP_SIZE;
tr->recv_msg_size = 0;
tr->recv_group_size = 0;
tr->num_recv_segments = 0;
tr->first_segnum_in_current_group = 0;
tr->first_segnum_in_previous_group = 0;
return (void *)tr;
}
/*
* Delete an invoke segment.
*/
static void
wtp_delete_invoke_segment (wtp_invoke_segment_t *seg)
{
if (seg) {
OSConnectorFree (seg);
}
}
/*
* Delete a result segment.
*/
static void
wtp_delete_result_segment (wtp_result_segment_t *seg)
{
if (seg) {
if (seg->pdu)
pdubuf_release (seg->pdu);
OSConnectorFree (seg);
}
}
/*
* Delete a transaction structure.
*/
void
wtp_delete_transaction (void *trp)
{
wtp_transaction_t *tr = (wtp_transaction_t *)trp;
wtp_invoke_segment_t *iseg;
wtp_result_segment_t *rseg;
while (tr->invoke_group != NULL) {
iseg = tr->invoke_group;
tr->invoke_group = iseg->next;
wtp_delete_invoke_segment (iseg);
}
while (tr->result_list != NULL) {
rseg = tr->result_list;
tr->result_list = rseg->next;
wtp_delete_result_segment (rseg);
}
if (tr->invoke_pdu)
pdubuf_release (tr->invoke_pdu);
OSConnectorFree (tr);
}
/*
* Create an Invoke PDU for a class 0 transaction.
*/
pdubuf *
wtp_create_invoke_pdu0 (void *trp)
{
wtp_transaction_t *tr = (wtp_transaction_t *)trp;
pdubuf *pdu = tr->invoke_pdu;
BYTE *pb;
/* We re-use the original PDU buffer in case it can be extended
* the required amount. */
tr->invoke_pdu = NULL;
if (pdubuf_changeLength (pdu, WTP_PDU_INVOKE_HEADERLEN) == NULL) {
UINT16 length = pdubuf_getLength (pdu);
pdubuf *tmp_pdu = pdubuf_new ((UINT16)(length + WTP_PDU_INVOKE_HEADERLEN));
if (tmp_pdu == NULL) {
pdubuf_release (pdu);
return NULL;
}
pdubuf_setLength (tmp_pdu, (UINT16)(length + WTP_PDU_INVOKE_HEADERLEN));
pb = pdubuf_getStart (tmp_pdu);
memcpy (pb + WTP_PDU_INVOKE_HEADERLEN, pdubuf_getStart (pdu), length);
pdubuf_release (pdu);
pdu = tmp_pdu;
}
pb = pdubuf_getStart (pdu);
pb[0] = (WTP_PDU_TYPE_INVOKE << 3) | 0x02;
pb[1] = (tr->tid >> 8);
pb[2] = tr->tid & 0xff;
pb[3] = 0;
if (tr->flags & WTP_FLAG_TID_NEW)
pb[3] |= 0x20;
if (tr->flags & WTP_FLAG_USER_ACK)
pb[3] |= 0x10;
return pdu;
}
/************************************************************
* First come the routines used for segmented invoke.
************************************************************/
/*
* Routine called when a segmented invoke request arrives.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -