⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtpsar.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -