目录

asn1c库编码函数返回的encoded,存在一个小问题

ASN.1编码我用的asn1c库,在使用UPER编码的时候,返回值有个需要注意的地方

uper编码可以使用

  • asn_encode_to_buffer
  • uper_encode_to_buffer

uper编码源代码

asn_encode_to_buffer函数

函数定义如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
asn_enc_rval_t
asn_encode_to_buffer(const asn_codec_ctx_t *opt_codec_ctx,
                     enum asn_transfer_syntax syntax,
                     const asn_TYPE_descriptor_t *td, const void *sptr,
                     void *buffer, size_t buffer_size) {
    struct overrun_encoder_key buf_key;
    asn_enc_rval_t er;

    if(buffer_size > 0 && !buffer) {
        errno = EINVAL;
        ASN__ENCODE_FAILED;
    }

    buf_key.buffer = buffer;
    buf_key.buffer_size = buffer_size;
    buf_key.computed_size = 0;

    er = asn_encode_internal(opt_codec_ctx, syntax, td, sptr,
                             overrun_encoder_cb, &buf_key);

    if(er.encoded >= 0 && (size_t)er.encoded != buf_key.computed_size) {
        ASN_DEBUG("asn_encode() returned %" ASN_PRI_SSIZE
                  " yet produced %" ASN_PRI_SIZE " bytes",
                  er.encoded, buf_key.computed_size);
        assert(er.encoded < 0 || (size_t)er.encoded == buf_key.computed_size);
    }

    return er;
}

uper_encode_to_buffer函数

函数定义如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
asn_enc_rval_t
uper_encode_to_buffer(const asn_TYPE_descriptor_t *td,
                      const asn_per_constraints_t *constraints,
                      const void *sptr, void *buffer, size_t buffer_size) {
    enc_to_buf_arg key;

    key.buffer = buffer;
    key.left = buffer_size;

    if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name);

    return uper_encode(td, constraints, sptr, encode_to_buffer_cb, &key);
}

两个函数的返回值类型

两个函数编码返回的都是asn_enc_rval_t类型的结构体。

类型定义如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * Type of the return value of the encoding functions (der_encode, xer_encode).
 */
typedef struct asn_enc_rval_s {
	/*
	 * Number of bytes encoded.
	 * -1 indicates failure to encode the structure.
	 * In this case, the members below this one are meaningful.
	 */
	ssize_t encoded;

	/*
	 * Members meaningful when (encoded == -1), for post mortem analysis.
	 */

	/* Type which cannot be encoded */
	const struct asn_TYPE_descriptor_s *failed_type;

	/* Pointer to the structure of that type */
	const void *structure_ptr;
} asn_enc_rval_t;

该结构体包含3个成员【编码的字节数、无法编码的类型描述指针、指向该类型结构的指针】。

uper编码返回值问题

按理说选择了同样的编码方式,返回的编码字节数应该一致(即encoded值相同),但我发现对于同一个测试消息帧

  1. ec = asn_encode_to_buffer(0, ATS_UNALIGNED_CANONICAL_PER, &asn_DEF_MessageFrame, msgFrame, buf, sizeof(buf));

  2. ec = uper_encode_to_buffer(&asn_DEF_MessageFrame, 0, msgFrame, buf, sizeof(buf));

第一个函数返回ec.encoded=37,第二个返回ec.encoded=296。

源代码分析

uper_encode_to_buffer中调用了函数uper_encode,其中encoded计算的是bits(第6行)

1
2
3
4
5
6
size_t bits_to_flush;

bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff;

/* Set number of bits encoded to a firm value */
er.encoded = (po.flushed_bytes << 3) + bits_to_flush;

asn_encode_to_buffer中调用了函数asn_encode_internal,其中encodedbits转换成了bytes(第24行)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
case ATS_UNALIGNED_BASIC_PER:
    /* CANONICAL-UPER is a superset of BASIC-UPER. */
    /* Fall through. */
case ATS_UNALIGNED_CANONICAL_PER:
    if(td->op->uper_encoder) {
        er = uper_encode(td, 0, sptr, callback, callback_key);
        if(er.encoded == -1) {
            if(er.failed_type && er.failed_type->op->uper_encoder) {
                errno = EBADF;  /* Structure has incorrect form. */
            } else {
                errno = ENOENT; /* UPER is not defined for this type. */
            }
        } else {
            ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded);
            if(er.encoded == 0) {
                /* Enforce "Complete Encoding" of X.691 #11.1 */
                if(callback("\0", 1, callback_key) < 0) {
                    errno = EBADF;
                    ASN__ENCODE_FAILED;
                }
                er.encoded = 8; /* Exactly 8 zero bits is added. */
            }
            /* Convert bits into bytes */
            er.encoded = (er.encoded + 7) >> 3;
        }

分析源代码发现uper_encode_to_buffer返回的其实是编码的比特数,而不是字节数。在asn_encode_to_buffer中则进行了字节数转换。

也就是(296+7)»3=37