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

📄 wtpsar.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
 */
void
wtp_segmented_invoke (void *trp, TRInvokeReqType *inv_req)
{
  wtp_transaction_t *tr = (wtp_transaction_t *)trp;

  if (inv_req->MoreData == SDL_False)
    tr->flags &= ~WTP_FLAG_MORE_DATA;
  
  if (tr->invoke_pdu != NULL)
    pdubuf_release (tr->invoke_pdu);
  tr->invoke_pdu = inv_req->UserData;
  tr->invoke_group = NULL;
  tr->last_segment = NULL;
}

/*
 * Create an invoke PDU from the indicated segment.
 */
static pdubuf *
wtp_create_invoke_pdu (wtp_transaction_t *tr, wtp_invoke_segment_t *iseg)
{
  pdubuf *pdu;
  BYTE   *pb;
  UINT16 length;
  UINT16 add_tpis;

  add_tpis = ((iseg->segnum == 0) && (tr->flags & WTP_FLAG_SPLIT_RESULT));
  length = (UINT16)(iseg->length + WTP_PDU_INVOKE_HEADERLEN);
  if (add_tpis) {
    /* This is the first segment in an Invoke.
     * We should add TPIs. */
    if (tr->total_send_msg_size > 0) {
      length += 4;
      if (tr->total_send_msg_size > 0xffff)
        length += 3;
    }
    length += 4;
    if (tr->max_recv_group_size > 0xffff)
      length += 3;
  }
  pdu = pdubuf_new (length);
  pdubuf_setLength (pdu, length);
  pb = pdubuf_getStart (pdu);

  if (iseg->segnum > 0) {
    pb[0] = (WTP_PDU_TYPE_SEGMENTED_INVOKE << 3);
    pb[3] = iseg->segnum;
  }
  else {
    pb[0] = (WTP_PDU_TYPE_INVOKE << 3);
    pb[3] = tr->transaction_class;
    if (tr->flags & WTP_FLAG_TID_NEW)
      pb[3] |= 0x20;
    if (tr->flags & WTP_FLAG_USER_ACK)
      pb[3] |= 0x10;
  }
  pb[1] = (tr->tid >> 8);
  pb[2] = tr->tid & 0xff;

  if (iseg->flags & WTP_FLAG_GTR)
    pb[0] |= 0x04;

  if (iseg->flags & WTP_FLAG_TTR)
    pb[0] |= 0x02;

  if (add_tpis) {
    pb[0] |= 0x80;
    pb += WTP_PDU_INVOKE_HEADERLEN;
    if (tr->total_send_msg_size > 0) {
      if (tr->total_send_msg_size > 0xffff) {
        pb[0] = (WTP_TPI_OPTION << 3) | 0x04 | 0x80;
        pb[1] = 5;
        pb[2] = WTP_TPI_OPTION_TOTAL_MESSAGE_SIZE;
        wtp_put_uintn (tr->total_send_msg_size, 4, pb + 3);
        pb += 7;
      }
      else {
        pb[0] = (WTP_TPI_OPTION << 3) | 0x03 | 0x80;
        pb[1] = WTP_TPI_OPTION_TOTAL_MESSAGE_SIZE;
        wtp_put_uintn (tr->total_send_msg_size, 2, pb + 2);
        pb += 4;
      }
    }

    if (tr->max_recv_group_size > 0xffff) {
      pb[0] = (WTP_TPI_OPTION << 3) | 0x04;
      pb[1] = 5;
      pb[2] = WTP_TPI_OPTION_MAX_GROUP_SIZE;
      wtp_put_uintn (tr->max_recv_group_size, 4, pb + 3);
      pb += 7;
    }
    else {
      pb[0] = (WTP_TPI_OPTION << 3) | 0x03;
      pb[1] = WTP_TPI_OPTION_MAX_GROUP_SIZE;
      wtp_put_uintn (tr->max_recv_group_size, 2, pb + 2);
      pb += 4;
    }
  }
  else
    pb += WTP_PDU_INVOKE_HEADERLEN;

  memcpy (pb, iseg->data, iseg->length);

  return pdu;
}

/*
 * Return a copy of the last invoke segment that was sent.
 */
pdubuf *
wtp_get_last_segment (void *trp)
{
  wtp_transaction_t *tr = (wtp_transaction_t *)trp;

  if (tr->last_segment == NULL)
    return NULL;

  return wtp_create_invoke_pdu (tr, tr->last_segment);
}

/*
 * Create next group.
 */
void
wtp_create_group (void *trp)
{
  wtp_transaction_t    *tr = (wtp_transaction_t *)trp;
  wtp_invoke_segment_t *iseg, *q = NULL;
  pdubuf               *pdu = tr->invoke_pdu;
  UINT16               length = pdubuf_getLength (pdu);
  UINT32               remaining_group_size;

  if (length == 0) {
    tr->invoke_group = NULL;
    tr->last_segment = NULL;
    return;
  }

  if ((tr->flags & WTP_FLAG_MORE_DATA) ||
      (length > tr->max_send_group_size) ||
      (tr->segnum > 0)) {
    /* We must use segmented invoke */

    /* Let first group have only one segment, to make sure
     * that responder can handle it. */
    if (tr->segnum == 0) {
      length = MIN (WTP_SAR_SEGMENT_SIZE, length);
    }
    remaining_group_size = tr->max_send_group_size;
    while (length > 0) {
      iseg = (wtp_invoke_segment_t*)OSConnectorAlloc (sizeof (wtp_invoke_segment_t));
      iseg->next = NULL;
      iseg->data = pdubuf_getStart (pdu);;
      iseg->flags = 0;
      iseg->length = MIN (WTP_SAR_SEGMENT_SIZE, length);
      iseg->length = (UINT16)MIN(iseg->length, remaining_group_size);
      iseg->segnum = tr->segnum++;
      length -= iseg->length;
      pdubuf_changeLength (pdu, (INT16)-((INT16)(iseg->length)));
      if (q == NULL)
        tr->invoke_group = iseg;
      else
        q->next = iseg;
      q = iseg;
      remaining_group_size -= iseg->length;
      if (remaining_group_size  == 0) {
        break;
      }
    }
    if ((tr->flags & WTP_FLAG_MORE_DATA) ||
        (pdubuf_getLength (tr->invoke_pdu) > 0)) {
      q->flags = WTP_FLAG_GTR;
    }
    else {
      q->flags = WTP_FLAG_TTR;
    }
  }
  else {
    /* Send entire invoke in one PDU */
    iseg = (wtp_invoke_segment_t*)OSConnectorAlloc (sizeof (wtp_invoke_segment_t));
    iseg->next = NULL;
    iseg->data = pdubuf_getStart (pdu);
    iseg->flags = WTP_FLAG_TTR;
    iseg->length = length;
    pdubuf_changeLength (pdu, (INT16)(-(INT16)length));
    iseg->segnum = tr->segnum++;
    tr->invoke_group = iseg;
  }
}

/*
 * Delete this transaction's current group of invoke segments.
 */
void
wtp_delete_group (void *trp)
{
  wtp_transaction_t    *tr = (wtp_transaction_t *)trp;
  wtp_invoke_segment_t *p;

  if (tr->last_segment == NULL)
    return;
  
  while (tr->invoke_group != NULL) {
    p = tr->invoke_group;
    tr->invoke_group = p->next;
    wtp_delete_invoke_segment (p);
  }
  tr->last_segment = NULL;
}

/*
 * Return the next segment to be sent in the current group.
 * Returns NULL in case there are no more segments waiting
 * to be transmitted.
 */
pdubuf *
wtp_get_next_segment (void *trp,
                      SDL_Boolean *group_done,
                      SDL_Boolean *msg_done)
{
  wtp_transaction_t    *tr = (wtp_transaction_t *)trp;
  wtp_invoke_segment_t *iseg;

  if (tr->last_segment == NULL)
    iseg = tr->invoke_group;
  else
    iseg = tr->last_segment->next;
  if (iseg == NULL)
    return NULL;
  tr->last_segment = iseg;

  *group_done = (iseg->flags & (WTP_FLAG_GTR | WTP_FLAG_TTR))
    ? SDL_True : SDL_False;
  *msg_done = (iseg->flags & WTP_FLAG_TTR) ? SDL_True : SDL_False;

  return wtp_create_invoke_pdu (tr, iseg);
}


/*
 * Unpack an ACK PDU and possible TPIs. Delete the PDU
 * afterwards. In case this ACK has a PSN TPI, check that
 * the sequence numbers agree.
 * Returns -1 on error, and 0 otherwise.
 */
SDL_Integer
wtp_unpack_ack_pdu (void *trp,
                    pdubuf *pdu,
                    SDL_Boolean *tidve,
                    SDL_Duration *delay_time)
{
  wtp_transaction_t *tr = (wtp_transaction_t *)trp;
  BYTE              *pb;

  if ((pdu == NULL) || (pdubuf_getLength (pdu) < WTP_PDU_ACK_HEADERLEN)) {
    pdubuf_release (pdu);
    return WTP_RET_ERROR;
  }
  pb = pdubuf_getStart (pdu);
  *tidve = (pb[0] & 0x04) ? SDL_True : SDL_False;

  tr->delay_time = 0;
  tr->ack_psn = 0;
  if (wtp_read_tpis (tr, pdu) < 0) {
    pdubuf_release (pdu);
    return WTP_RET_ERROR;
  }
  pdubuf_release (pdu);

  if ((tr->ack_psn > 0) && (tr->last_segment != NULL) &&
      (tr->ack_psn != tr->last_segment->segnum)) {
    return WTP_RET_ERROR;
  }
  if (tr->delay_time > 0) {
#ifdef XSCT_CMICRO
    *delay_time = SDL_DURATION_LIT (0, tr->delay_time, 0);
#else
    *delay_time = SDL_DURATION_LIT (0, tr->delay_time / 10,
                                    (tr->delay_time % 10) * 100000000);
#endif
  }
  else
    *delay_time = SDL_DURATION_LIT (0, 0, 0);

  return WTP_RET_OK;
}

/*
 * Delete the list of missing segments.
 */
static void
wtp_delete_missing_segments (wtp_transaction_t *tr)
{
  wtp_missing_segment_t *mseg;

  while (tr->missing_segments != NULL) {
    mseg = tr->missing_segments;
    tr->missing_segments = mseg->next;
    OSConnectorFree (mseg);
  }
}

/*
 * Unpack a NACK PDU and all TPIs. Deletes the PDU
 * afterwards. Creates a list of missing segments
 * and stores with this transaction.
 */
void
wtp_unpack_nack_pdu (void *trp, pdubuf *pdu)
{
  wtp_transaction_t     *tr = (wtp_transaction_t *)trp;
  wtp_invoke_segment_t  *iseg;
  wtp_missing_segment_t *mseg, *q;
  BYTE                  *pb;
  UINT8                 n;
  UINT8                 segnum;
  int                   i;

  pb = pdubuf_getStart (pdu);
  n = pb[3];
  tr->missing_segments = NULL;
  if (n + 3 > pdubuf_getLength (pdu)) {
    return;
  }

  wtp_delete_missing_segments (tr);
  q = NULL;
  iseg = tr->invoke_group;
  for (i = 4; i < n + 4; i++) {
    segnum = pb[i];
    for (; iseg != NULL; iseg = iseg->next) {
      if (iseg->segnum == segnum) {
        mseg = (wtp_missing_segment_t*)OSConnectorAlloc (sizeof (wtp_missing_segment_t));
        mseg->iseg = iseg;
        mseg->next = NULL;
        if (q == NULL)
          tr->missing_segments = mseg;
        else
          q->next = mseg;
        q = mseg;
        iseg = iseg->next;
        break;
      }
    }
  }
  wtp_read_tpis (tr, pdu);

  pdubuf_release (pdu);
}

/*
 * Return a copy of the first segment on the list of
 * missing segments. Deletes this segment from the list.
 * Returns NULL if the list is empty.
 */
pdubuf *
wtp_next_missing_segment (void *trp)
{
  wtp_transaction_t     *tr = (wtp_transaction_t *)trp;
  wtp_invoke_segment_t  *iseg;
  wtp_missing_segment_t *mseg;

  if (tr->missing_segments == NULL)
    return NULL;

  mseg = tr->missing_segments;
  iseg = mseg->iseg;
  tr->missing_segments = mseg->next;
  OSConnectorFree (mseg);

  return wtp_create_invoke_pdu (tr, iseg);
}


/*************************************************************
 * The routines below are used when receiving a
 * segmented result.
 ************************************************************/

/*
 * Return the sequence number of the last segment
 * in a completeley received segmented result.
 * Returns 0 if the result was not segmented.
 */
SDL_Natural
wtp_get_last_recv_seqnum (void *trp)
{
  wtp_transaction_t *tr = (wtp_transaction_t *)trp;

  return tr->first_segnum_in_current_group + tr->num_recv_segments - 1;
}


/*
 * Update parameters to make transaction ready to receive the next group.
 */
static void
wtp_group_done (wtp_transaction_t *tr, UINT16 segnum)
{
  tr->recv_group_size = 0;
  tr->num_recv_segments = 0;
  tr->first_segnum_in_previous_group = tr->first_segnum_in_current_group;
  tr->first_segnum_in_current_group = segnum + 1;
  tr->flags &= ~WTP_FLAG_SENT_NACK;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -