📄 wtpsar.c
字号:
*/
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 + -