记BFCP解析库confiance-v7bfcp-only-05中踩过的坑

1. 记BFCP解析库confiance-v7bfcp-only-05中踩过的坑

在开发sip呼叫辅流的过程中使用了一个bfcp的解析库:
confiance-v7bfcp-only-05

然而在使用过程中发现这个解析库的一些缺陷,列举如下:

1.1. SUPPORTED-PRIMITIVESSUPPORTED-ATTRIBUTES 的字节长度问题

原始库中对这两个字段的处理都是采用的unsigned short int存储到网络交互字节中,
根据
RFC4582 5.2.10. SUPPORTED-ATTRIBUTES
RFC4582 5.2.11. SUPPORTED-PRIMITIVES 的描述,这两个字段都是占用1个字节的。

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |0 0 0 1 0 1 0|M|    Length     | Supp. Attr. |R| Supp. Attr. |R|
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | Supp. Attr. |R| Supp. Attr. |R| Supp. Attr. |R| Supp. Attr. |R|
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 /                                                               /
 /                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                               |            Padding            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

              Figure 17: SUPPORTED-ATTRIBUTES format

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |0 0 0 1 0 1 1|M|    Length     |   Primitive   |   Primitive   |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   Primitive   |   Primitive   |   Primitive   |   Primitive   |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 /                                                               /
 /                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                               |            Padding            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

              Figure 18: SUPPORTED-PRIMITIVES format

1.2. Payload Length 的字节长度及单位问题

根据 RFC4582 5.1. COMMON-HEADER Format 描述

Payload Length: This 16-bit field contains the length of the message in 4-octet units, excluding the common header

由于bfcp要求网络交互字节块必须要以4字节对齐,凡是不足4字节的都需要填充。因此称为in 4-octet units

octet 是指八个比特(bit)为一组的单位,通常是指一个字节(byte)的意思。

也就是说使用抓包工具查看bfcp的package时,Payload Length字段显示的值应该为整个BFCP包的长度减去BFCP通用头长度再除以4(即 (BFCPPackageLength - 12) / 4);相反的,在解析bfcp的package时也要根据Payload Length字段的值乘以4再加上通用头长度即为整个包的长度(即 PayloadLength * 4 + 12) ,且应该对负载长度以4求余来校验字节块是否满足这一条件。

但原始库中对于这块的处理是有问题的,包括判断逻辑也有问题。

1.3. 关于va_arg的错误使用

在修改中引入了的这个问题,linux上使用解析库时引发异常

在使用 va_arg 时传入的可变参数会经历 默认参数提升 的隐式转换过程,因此在使用过程中ap的下一个参数类型不应该指定为以下类型:

char / signed char / unsigned char
short / signed short / unsigned short
short int / signed short int / unsigned short int

有关c语言 默认参数提升 的规则描述如下:

默认参数提升
在函数调用表达式中,当调用下列函数时
  1) 无原型函数
  2) 变参数函数,其中参数表达式是匹配省略号参数的尾随参数之一
每个整数类型的参数都会经历整数提升(见后述),而每个 float 类型参数都隐式转换为 double 类型

整数提升
整数提升是任何等级小于或等于 int 等级的整数类型,或是 _Bool 、 signed int 、 unsigned int 类型的位域类型的值到 intunsigned int 类型值的隐式转换。
int 能表示原类型的整个值域(或原位域的值域),则值转换成 int 类型。否则值转化成 unsigned int 类型。
整数提升保持值,包含符号:

更详细的信息可参考:可变长参数列表误区与陷阱——va_arg不可接受的类型

1.4. 修改清单

详情参考:fix confiance-v7bfcp-only-05

左侧文件: 原始文件

右侧文件: 修改后

1.4.1. bfcp_messages.h

111 typedef struct bfcp_floor_id_list { /* FLOOR-ID list, to manage the multiple FLOOR-ID attributes */ = 111 typedef struct bfcp_floor_id_list { /* FLOOR-ID list, to manage the multiple FLOOR-ID attributes */
112     unsigned short int ID;          /* FLOOR-ID */   112     unsigned short int ID;          /* FLOOR-ID */
113     struct bfcp_floor_id_list *next;    /* Pointer to next FLOOR-ID instance */   113     struct bfcp_floor_id_list *next;    /* Pointer to next FLOOR-ID instance */
114 } bfcp_floor_id_list;   114 } bfcp_floor_id_list;
115     115  
116 typedef struct bfcp_supported_list {    /* list to manage all the supported attributes and primitives */   116 typedef struct bfcp_supported_list {    /* list to manage all the supported attributes and primitives */
117     unsigned short int element;     /* Element (Attribute/Primitive) */ <> 117     unsigned char element;      /* Element (Attribute/Primitive) */
118     struct bfcp_supported_list *next;   /* Pointer to next supported element instance */ = 118     struct bfcp_supported_list *next;   /* Pointer to next supported element instance */
119 } bfcp_supported_list;   119 } bfcp_supported_list;
120     120  
121 typedef struct bfcp_request_status {   121 typedef struct bfcp_request_status {
122     unsigned short int rs;  /* Request Status */   122     unsigned short int rs;  /* Request Status */
123     unsigned short int qp;  /* Queue Position */   123     unsigned short int qp;  /* Queue Position */
 
243 /* Add IDs to an existing Floor ID list (last argument MUST be 0) */ = 243 /* Add IDs to an existing Floor ID list (last argument MUST be 0) */
244 int bfcp_add_floor_id_list(bfcp_floor_id_list *list, unsigned short int fID, ...);   244 int bfcp_add_floor_id_list(bfcp_floor_id_list *list, unsigned short int fID, ...);
245 /* Free a Floor ID list */   245 /* Free a Floor ID list */
246 int bfcp_free_floor_id_list(bfcp_floor_id_list *list);   246 int bfcp_free_floor_id_list(bfcp_floor_id_list *list);
247     247  
248 /* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */   248 /* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */
249 bfcp_supported_list *bfcp_new_supported_list(unsigned short int element, ...); <> 249 bfcp_supported_list *bfcp_new_supported_list(unsigned char element, ...);
250 /* Free a Supported (Primitives/Attributes) list */ = 250 /* Free a Supported (Primitives/Attributes) list */
251 int bfcp_free_supported_list(bfcp_supported_list *list);   251 int bfcp_free_supported_list(bfcp_supported_list *list);
252     252  
253 /* Create a New Request Status (RequestStatus/QueuePosition) */   253 /* Create a New Request Status (RequestStatus/QueuePosition) */
254 bfcp_request_status *bfcp_new_request_status(unsigned short int rs, unsigned short int qp);   254 bfcp_request_status *bfcp_new_request_status(unsigned short int rs, unsigned short int qp);
255 /* Free a Request Status (RequestStatus/QueuePosition) */   255 /* Free a Request Status (RequestStatus/QueuePosition) */

1.4.2. bfcp_messages.c

195         temp = next; = 195         temp = next;
196     }   196     }
197     return 0;   197     return 0;
198 }   198 }
199     199  
200 /* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */   200 /* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */
201 bfcp_supported_list *bfcp_new_supported_list(unsigned short int element, ...) <> 201 bfcp_supported_list *bfcp_new_supported_list(unsigned char element, ...)
202 { = 202 {
203     bfcp_supported_list *first, *previous, *next;   203     bfcp_supported_list *first, *previous, *next;
204     va_list ap;   204     va_list ap;
205     va_start(ap, element);   205     va_start(ap, element);
206     first = calloc(1, sizeof(bfcp_supported_list));   206     first = calloc(1, sizeof(bfcp_supported_list));
207     if(!first)  /* We could not allocate the memory, return a with failure */   207     if(!first)  /* We could not allocate the memory, return a with failure */
208         return NULL;   208         return NULL;
209     first->element = element;   209     first->element = element;
210     previous = first;   210     previous = first;
211     element = va_arg(ap, int); <> 211     element = (unsigned char)va_arg(ap, int);
212     while(element) { = 212     while(element) {
213         next = calloc(1, sizeof(bfcp_supported_list));   213         next = calloc(1, sizeof(bfcp_supported_list));
214         if(!next)   /* We could not allocate the memory, return a with failure */   214         if(!next)   /* We could not allocate the memory, return a with failure */
215             return NULL;   215             return NULL;
216         next->element = element;   216         next->element = element;
217         previous->next = next;   217         previous->next = next;
218         previous = next;   218         previous = next;
219         element = va_arg(ap, int); <> 219         element = (unsigned char)va_arg(ap, int);
220     } = 220     }
221     va_end(ap);   221     va_end(ap);
222     return first;   222     return first;
223 }   223 }
224     224  
225 /* Free a Supported (Primitives/Attributes) list */   225 /* Free a Supported (Primitives/Attributes) list */

1.4.3. bfcp_messages_build.c

45     unsigned int ch32;      /* 32 bits */ = 45     unsigned int ch32;      /* 32 bits */
46     unsigned short int ch16;    /* 16 bits */   46     unsigned short int ch16;    /* 16 bits */
47     unsigned char *buffer = message->buffer;   47     unsigned char *buffer = message->buffer;
48     ch32 = (((ch32 & !(0xE0000000)) | (1)) << 29) +         /* First the Version (3 bits, set to 001) */   48     ch32 = (((ch32 & !(0xE0000000)) | (1)) << 29) +         /* First the Version (3 bits, set to 001) */
49         (((ch32 & !(0x1F000000)) | (0)) << 24) +        /* then the Reserved (5 bits, ignored) */   49         (((ch32 & !(0x1F000000)) | (0)) << 24) +        /* then the Reserved (5 bits, ignored) */
50         (((ch32 & !(0x00FF0000)) | (primitive)) << 16) +    /* the Primitive (8 bits) */   50         (((ch32 & !(0x00FF0000)) | (primitive)) << 16) +    /* the Primitive (8 bits) */
51         ((ch32 & !(0x0000FFFF)) | (message->length - 12));  /* and the payload length (16 bits) */ <> 51         ((ch32 & !(0x0000FFFF)) | ((message->length - 12) / 4));    /* and the payload length (16 bits), contains the length of the message in 4-octet units */
52     ch32 = htonl(ch32);     /* We want all protocol values in network-byte-order */ = 52     ch32 = htonl(ch32);     /* We want all protocol values in network-byte-order */
53     memcpy(buffer, &ch32, 4);   53     memcpy(buffer, &ch32, 4);
54     buffer = buffer+4;   54     buffer = buffer+4;
55     ch32 = htonl(entity->conferenceID);   55     ch32 = htonl(entity->conferenceID);
56     memcpy(buffer, &ch32, 4);   56     memcpy(buffer, &ch32, 4);
57     buffer = buffer+4;   57     buffer = buffer+4;
 
497     if(!attributes) /* The supported attributes list is empty, return with a failure */ = 497     if(!attributes) /* The supported attributes list is empty, return with a failure */
498         return -1;   498         return -1;
499     int attrlen = 2;    /* The Lenght of the attribute (starting from the TLV) */   499     int attrlen = 2;    /* The Lenght of the attribute (starting from the TLV) */
500     int padding = 0;    /* Number of bytes of padding */   500     int padding = 0;    /* Number of bytes of padding */
501     int position = message->position;       /* We keep track of where the TLV will have to be */   501     int position = message->position;       /* We keep track of where the TLV will have to be */
502     unsigned char *buffer = message->buffer+(message->position)+2;  /* We skip the TLV bytes */   502     unsigned char *buffer = message->buffer+(message->position)+2;  /* We skip the TLV bytes */
503     unsigned short int ch16;    /* 16 bits */ +-    
504     bfcp_supported_list *temp = attributes; = 503     bfcp_supported_list *temp = attributes;
505     while(temp) {   /* Fill all supported attributes */   504     while(temp) {   /* Fill all supported attributes */
506         ch16 = htons(temp->element); <> 505         unsigned char ch = temp->element;
507         memcpy(buffer, &ch16, 2);   506         buffer[0] = ch << 1;
508         buffer = buffer+2;   507         buffer = buffer+1;
509         attrlen = attrlen+2;   508         attrlen = attrlen+1;
510         temp = temp->next; = 509         temp = temp->next;
511     }   510     }
512     if((attrlen%4) != 0) {      /* We need padding */   511     if((attrlen%4) != 0) {      /* We need padding */
513         padding = 4-(attrlen%4);   512         padding = 4-(attrlen%4);
514         memset(buffer, 0, padding);   513         memset(buffer, 0, padding);
515     }   514     }
 
524     if(!primitives) /* The supported attributes list is empty, return with a failure */ = 523     if(!primitives) /* The supported attributes list is empty, return with a failure */
525         return -1;   524         return -1;
526     int attrlen = 2;    /* The Lenght of the attribute (starting from the TLV) */   525     int attrlen = 2;    /* The Lenght of the attribute (starting from the TLV) */
527     int padding = 0;    /* Number of bytes of padding */   526     int padding = 0;    /* Number of bytes of padding */
528     int position = message->position;       /* We keep track of where the TLV will have to be */   527     int position = message->position;       /* We keep track of where the TLV will have to be */
529     unsigned char *buffer = message->buffer+(message->position)+2;  /* We skip the TLV bytes */   528     unsigned char *buffer = message->buffer+(message->position)+2;  /* We skip the TLV bytes */
530     unsigned short int ch16;    /* 16 bits */ +-    
531     bfcp_supported_list *temp = primitives; = 529     bfcp_supported_list *temp = primitives;
532     while(temp) {   /* Fill all supported primitives */   530     while(temp) {   /* Fill all supported primitives */
533         ch16 = htons(temp->element); <> 531         unsigned char ch = temp->element;
534         memcpy(buffer, &ch16, 2);   532         memcpy(buffer, &ch, 1);
535         buffer = buffer+2;   533         buffer = buffer+1;
536         attrlen = attrlen+2;   534         attrlen = attrlen+1;
537         temp = temp->next; = 535         temp = temp->next;
538     }   536     }
539     if((attrlen%4) != 0) {      /* We need padding */   537     if((attrlen%4) != 0) {      /* We need padding */
540         padding = 4-(attrlen%4);   538         padding = 4-(attrlen%4);
541         memset(buffer, 0, padding);   539         memset(buffer, 0, padding);
542     }   540     }

1.4.4. bfcp_messages_parse.c

190     if((recvM->reserved) != 0) {    /* Reserved bits are not 0, return with an error */ = 190     if((recvM->reserved) != 0) {    /* Reserved bits are not 0, return with an error */
191         recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_RESERVED_NOT_ZERO);   191         recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_RESERVED_NOT_ZERO);
192         if(!(recvM->errors))   192         if(!(recvM->errors))
193             return NULL;    /* An error occurred while recording the error, return with failure */   193             return NULL;    /* An error occurred while recording the error, return with failure */
194     }   194     }
195     recvM->primitive = ((ch32 & 0x00FF0000) >> 16); /* Primitive identifier */   195     recvM->primitive = ((ch32 & 0x00FF0000) >> 16); /* Primitive identifier */
    <> 196     /* cause the Payload Lenght contains the length of the message in 4-octet units, here we need to multiple with 4 */
196     recvM->length = (ch32 & 0x0000FFFF) + 12;   /* Payload Lenght of the message + 12 (Common Header) */   197     recvM->length = (ch32 & 0x0000FFFF) * 4 + 12;   /* Payload Lenght of the message + 12 (Common Header) */
197     if(((recvM->length) != message->length) || !(recvM->length)%4) {    /* The message length is wrong */   198     if((recvM->length != message->length) || (recvM->length % 4)) { /* The message length is wrong */
198             /* Either the length in the header is different from the length of the buffer... */ = 199             /* Either the length in the header is different from the length of the buffer... */
199             /*   ...or the length is not a multiple of 4, meaning it's surely not aligned */   200             /*   ...or the length is not a multiple of 4, meaning it's surely not aligned */
200         recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_WRONG_LENGTH);   201         recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_WRONG_LENGTH);
201         if(!(recvM->errors))   202         if(!(recvM->errors))
202             return NULL;    /* An error occurred while recording the error, return with failure */   203             return NULL;    /* An error occurred while recording the error, return with failure */
203     }   204     }
 
621 bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_received_attribute *recvA) = 622 bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_received_attribute *recvA)
622 {   623 {
623     if(recvA->length<3) /* The length of this attribute is wrong */   624     if(recvA->length<3) /* The length of this attribute is wrong */
624         return NULL;   625         return NULL;
625     int i;   626     int i;
626     bfcp_supported_list *first, *previous, *next;   627     bfcp_supported_list *first, *previous, *next;
627     unsigned short int ch16;    /* 16 bits */ +-    
628     unsigned char *buffer = message->buffer+recvA->position+2;  /* Skip the Header */ = 628     unsigned char *buffer = message->buffer+recvA->position+2;  /* Skip the Header */
629     int number = (recvA->length-2)/2;   /* Each supported attribute takes 2 bytes */ <> 629     int number = (recvA->length-2); /* Each supported attribute takes 1 bytes */
630     if(!number) = 630     if(!number)
631         return NULL;    /* No supported attributes? */   631         return NULL;    /* No supported attributes? */
632     first = calloc(1, sizeof(bfcp_supported_list));   632     first = calloc(1, sizeof(bfcp_supported_list));
633     if(!first)  /* An error occurred in creating a new Supported Attributes list */   633     if(!first)  /* An error occurred in creating a new Supported Attributes list */
634         return NULL;   634         return NULL;
635     memcpy(&ch16, buffer, 2); <>    
636     first->element = ntohs(ch16);   635     first->element = buffer[0] & 0xFE;
637     previous = first; = 636     previous = first;
638     if(number>1) {      /* Let's parse each other supported attribute we find */   637     if(number>1) {      /* Let's parse each other supported attribute we find */
639         for(i = 1;i<number;i++) {   638         for(i = 1;i<number;i++) {
640             next = calloc(1, sizeof(bfcp_supported_list));   639             next = calloc(1, sizeof(bfcp_supported_list));
641             if(!next)   /* An error occurred in creating a new Supported Attributes list */   640             if(!next)   /* An error occurred in creating a new Supported Attributes list */
642                 return NULL;   641                 return NULL;
643             buffer = buffer+2;  /* Skip to the next supported attribute */ <> 642             buffer = buffer + 1;    /* Skip to the next supported attribute */
644             memcpy(&ch16, buffer, 2);   643             next->element = buffer[0] & 0xFE;
645             next->element = ntohs(ch16);      
646             previous->next = next; = 644             previous->next = next;
647             previous = next;   645             previous = next;
648         }   646         }
649     }   647     }
650     return first;   648     return first;
651 }   649 }
 
653 bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_received_attribute *recvA) = 651 bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_received_attribute *recvA)
654 {   652 {
655     if(recvA->length<3) /* The length of this attribute is wrong */   653     if(recvA->length<3) /* The length of this attribute is wrong */
656         return NULL;   654         return NULL;
657     int i;   655     int i;
658     bfcp_supported_list *first, *previous, *next;   656     bfcp_supported_list *first, *previous, *next;
659     unsigned short int ch16;    /* 16 bits */ +-    
660     unsigned char *buffer = message->buffer+recvA->position+2;  /* Skip the Header */ = 657     unsigned char *buffer = message->buffer+recvA->position+2;  /* Skip the Header */
661     int number = (recvA->length-2)/2;   /* Each supported primitive takes 2 bytes */ <> 658     int number = (recvA->length-2); /* Each supported primitive takes 1 bytes */
662     if(!number) = 659     if(!number)
663         return NULL;    /* No supported primitives? */   660         return NULL;    /* No supported primitives? */
664     first = calloc(1, sizeof(bfcp_supported_list));   661     first = calloc(1, sizeof(bfcp_supported_list));
665     if(!first)  /* An error occurred in creating a new Supported Attributes list */   662     if(!first)  /* An error occurred in creating a new Supported Attributes list */
666         return NULL;   663         return NULL;
667     memcpy(&ch16, buffer, 2); <>    
668     first->element = ntohs(ch16);   664     first->element = buffer[0];
669     previous = first; = 665     previous = first;
670     if(number>1) {      /* Let's parse each other supported primitive we find */   666     if(number>1) {      /* Let's parse each other supported primitive we find */
671         for(i = 1;i<number;i++) {   667         for(i = 1;i<number;i++) {
672             next = calloc(1, sizeof(bfcp_supported_list));   668             next = calloc(1, sizeof(bfcp_supported_list));
673             if(!next)   /* An error occurred in creating a new Supported Attributes list */   669             if(!next)   /* An error occurred in creating a new Supported Attributes list */
674                 return NULL;   670                 return NULL;
675             buffer = buffer+2;  /* Skip to the next supported primitive */ <> 671             buffer = buffer + 1;    /* Skip to the next supported primitive */
676             memcpy(&ch16, buffer, 2);      
677             next->element = ntohs(ch16);   672             next->element = buffer[0];
678             previous->next = next; = 673             previous->next = next;
679             previous = next;   674             previous = next;
680         }   675         }
681     }   676     }
682     return first;   677     return first;
683 }   678 }
posted @ 2020-12-29 17:22  never715  阅读(721)  评论(0编辑  收藏  举报