📄 asn1_erl_driver.c
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ */#include <stdlib.h>#include <stdio.h>#include <string.h>#include "erl_driver.h"#include "ei.h"/* #define ASN1_DEBUG 1 */#define ASN1_OK 0#define ASN1_ERROR -1#define ASN1_COMPL_ERROR 1#define ASN1_MEMORY_ERROR 0#define ASN1_DECODE_ERROR 2#define ASN1_TAG_ERROR -3#define ASN1_LEN_ERROR -4#define ASN1_INDEF_LEN_ERROR -5#define ASN1_VALUE_ERROR -6#define ASN1_CLASS 0xc0#define ASN1_FORM 0x20#define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)#define ASN1_TAG 0x1f#define ASN1_LONG_TAG 0x7f#define ASN1_INDEFINITE_LENGTH 0x80#define ASN1_SHORT_DEFINITE_LENGTH 0#define ASN1_PRIMITIVE 0#define ASN1_CONSTRUCTED 0x20#define ASN1_COMPLETE 1#define ASN1_BER_TLV_DECODE 2#define ASN1_BER_TLV_PARTIAL_DECODE 3#define ASN1_NOVALUE 0#define ASN1_SKIPPED 0#define ASN1_OPTIONAL 1#define ASN1_CHOOSEN 2#define CEIL(X,Y) ((X-1) / Y + 1)#define INVMASK(X,M) (X & (M ^ 0xff))#define MASK(X,M) (X & M)typedef struct { ErlDrvPort port;} asn1_data;int min_alloc_bytes;static ErlDrvData asn1_drv_start(ErlDrvPort, char *);static void asn1_drv_stop(ErlDrvData);int asn1_drv_control(ErlDrvData, unsigned int, char *, int, char **, int);int complete(ErlDrvBinary **,unsigned char *,unsigned char *, int);int insert_octets(int, unsigned char **, unsigned char **, int *);int insert_octets_except_unused(int, unsigned char **, unsigned char **, int *, int);int insert_octets_as_bits_exact_len(int, int, unsigned char **, unsigned char **, int *);int insert_octets_as_bits(int, unsigned char **, unsigned char **,int *);int pad_bits(int, unsigned char **, int *);int insert_least_sign_bits(int, unsigned char, unsigned char **, int *);int insert_most_sign_bits(int, unsigned char, unsigned char **, int *);int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);int insert_octets_unaligned(int, unsigned char **, unsigned char **, int);int realloc_memory(ErlDrvBinary **,int,unsigned char **,unsigned char **);int decode_begin(ErlDrvBinary **,unsigned char *, int, unsigned int *);int decode(ErlDrvBinary **,int *,unsigned char *,int *, int);int decode_tag(char *,int *,unsigned char *,int,int *);int decode_value(int *,unsigned char *,int *,ErlDrvBinary **,int ,int);/* declaration of functions used for partial decode of a BER encoded message */int decode_partial(ErlDrvBinary **,unsigned char *, int);int skip_tag(unsigned char *,int *,int);int skip_length_and_value(unsigned char *,int *,int);int get_tag(unsigned char *,int *,int);int get_value(char *,unsigned char *,int *,int);static ErlDrvEntry asn1_drv_entry = { NULL, /* init, always NULL for dynamic drivers */ asn1_drv_start, /* start, called when port is opened */ asn1_drv_stop, /* stop, called when port is closed */ NULL, /* output, called when erlang has sent */ NULL, /* ready_input, called when input descriptor ready */ NULL, /* ready_output, called when output descriptor ready */ "asn1_erl_drv", /* char *driver_name, the argument to open_port */ NULL, /* finish, called when unloaded */ NULL, /* void * that is not used (BC) */ asn1_drv_control, /* control, port_control callback */ NULL, /* timeout, called on timeouts */ NULL /* outputv, vector output interface */}; DRIVER_INIT(asn1_erl_drv) /* must match name in driver_entry */{ return &asn1_drv_entry;}static ErlDrvData asn1_drv_start(ErlDrvPort port, char *buff){ extern int min_alloc_bytes; char *ptr; asn1_data* d; d = (asn1_data*)driver_alloc(sizeof(asn1_data)); set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); d->port = port; if ((ptr = getenv("ASN1_MIN_BUF_SIZE")) == NULL) min_alloc_bytes = 1024; else min_alloc_bytes = atoi(ptr); return (ErlDrvData)d;}static void asn1_drv_stop(ErlDrvData handle){ driver_free((char*)handle);}int asn1_drv_control(ErlDrvData handle, unsigned int command, char *buf, int buf_len, char **res_buf, int res_buf_len) { char *complete_buf; int complete_len, decode_len; ErlDrvBinary *drv_binary; ErlDrvBinary **drv_bin_ptr; asn1_data* a_data; extern int min_alloc_bytes; unsigned int err_pos = 0; /* in case of error, return last correct position */ int ret_err; /* return value in case of error in TLV decode, i.e. length of list in res_buf */ /* In case previous call to asn1_drv_control resulted in a change of return value from binary to integer list */ a_data = (asn1_data *)handle; set_port_control_flags(a_data->port, PORT_CONTROL_FLAG_BINARY); if (command == ASN1_COMPLETE) { /* Do the PER complete encode step */ if ((drv_binary = driver_alloc_binary(buf_len))==NULL) { /* error handling */ set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; } complete_buf = drv_binary->orig_bytes; if ((complete_len = complete(&drv_binary,complete_buf,buf,buf_len)) == ASN1_ERROR) { /* error handling due to failure in complete */ /* printf("error when running complete\n\r"); */ driver_free_binary(drv_binary); set_port_control_flags(a_data->port, 0); **res_buf = '1'; return ASN1_COMPL_ERROR; } /* printf("complete_len=%dbuf_len=%d,orig_size=%d\n\r",complete_len,buf_len,drv_binary->orig_size); */ /* now the message is complete packed, return to Erlang */ /* if (complete_len < buf_len) {*/ if (complete_len < drv_binary->orig_size) { ErlDrvBinary *tmp; if ((tmp=driver_realloc_binary(drv_binary,complete_len)) == NULL){ /*error handling due to memory allocation failure */ driver_free_binary(drv_binary); set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; }else drv_binary=tmp; } *res_buf = (char *)drv_binary; return complete_len; } else if (command == ASN1_BER_TLV_DECODE) { /* control == 2 */ /* Do the tlv decode, return the resulting term encoded on the Erlang external format *//* printf("driver: buffer_len = %d, min_alloc_bytes = %d\r\n",buf_len,min_alloc_bytes); */ if ((drv_binary = driver_alloc_binary((buf_len*5)+min_alloc_bytes))==NULL) { /* error handling */ set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; } drv_bin_ptr = &drv_binary; if ((decode_len = decode_begin(drv_bin_ptr,buf,buf_len,&err_pos)) <= ASN1_ERROR) { /* error handling due to failure in decode */ char tmp_res_buf[5]; driver_free_binary(*drv_bin_ptr); set_port_control_flags(a_data->port, 0); if(decode_len==ASN1_ERROR) tmp_res_buf[0]='1'; else if(decode_len==ASN1_TAG_ERROR) tmp_res_buf[0]='2'; else if(decode_len==ASN1_LEN_ERROR) tmp_res_buf[0]='3'; else if(decode_len==ASN1_INDEF_LEN_ERROR) tmp_res_buf[0]='4'; else if(decode_len==ASN1_VALUE_ERROR) tmp_res_buf[0]='5';/* printf("err_pos=%d\r\n",err_pos); *//* printf("decode_len:%d\r\n",decode_len); */ ret_err = 1; while(err_pos>0){ tmp_res_buf[ret_err] =(char)err_pos;/* c;*/ err_pos = err_pos >> 8; ret_err++; } strncpy(*res_buf,tmp_res_buf,ret_err); return ret_err; }/* printf("decode_len=%d\r\n",decode_len); */ if (decode_len < ((buf_len * 5) + min_alloc_bytes)) { /* not all memory was used => we have to reallocate */ ErlDrvBinary *tmp; if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){ /*error handling due to memory allocation failure */ driver_free_binary(*drv_bin_ptr); set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; }else *drv_bin_ptr=tmp; } *res_buf = (char *)(*drv_bin_ptr); return decode_len; } else { /*command == ASN1_BER_TLV_PARTIAL_DECODE */ if ((drv_binary = driver_alloc_binary(buf_len))==NULL) { /* error handling */ set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; } drv_bin_ptr = &drv_binary; if ((decode_len = decode_partial(drv_bin_ptr,buf,buf_len)) <= ASN1_ERROR) { /* error handling due to failure in decode */ driver_free_binary(*drv_bin_ptr); set_port_control_flags(a_data->port, 0); /* printf("asn1_drv_control 1: decode_len=%d\r\n",decode_len); */ if(decode_len==ASN1_ERROR) **res_buf = '1'; return ASN1_DECODE_ERROR; } if (decode_len < buf_len) { /* not all memory was used => we have to reallocate */ ErlDrvBinary *tmp;/* printf("asn1_drv_control 2: decode_len=%d\r\n",decode_len); */ if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){ /*error handling due to memory allocation failure */ driver_free_binary(*drv_bin_ptr); set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; }else *drv_bin_ptr=tmp; } *res_buf = (char *)(*drv_bin_ptr); return decode_len; }}/* * * This section defines functionality for the complete encode of a * PER encoded message * */int complete(ErlDrvBinary **drv_binary,unsigned char *complete_buf, unsigned char *in_buf, int in_buf_len){ int counter = in_buf_len; /* counter keeps track of number of bytes left in the input buffer */ int buf_space = in_buf_len; /* This is the amount of allocated space left of the complete_buf. It is possible when padding is applied that more space is needed than was originally allocated. */ int buf_size = in_buf_len; /* Size of the buffer. May become reallocated and thus other than in_buf_len */ unsigned char *in_ptr, *ptr; /* in_ptr points at the next byte in in_buf to be moved to complete_buf. ptr points into the new completed buffer, complete_buf, at the position of the next byte that will be set */ int unused = 8; /* unused = [1,...,8] indicates how many of the rigthmost bits of the byte that ptr points at that are unassigned */ int no_bits,no_bytes,in_unused,desired_len,ret, saved_mem, needed, pad_bits; unsigned char val; in_ptr = in_buf; ptr = complete_buf; *ptr = 0x00; while(counter > 0) { counter--;/* printf("*in_ptr = %d\n\r",*in_ptr); */ switch (*in_ptr) { case 0: /* just one zero-bit should be added to the buffer */ if(unused == 1){ unused = 8; *++ptr = 0x00; buf_space--; } else unused--; break; case 1: /* one one-bit should be added to the buffer */ if(unused == 1){ *ptr = *ptr | 1; unused = 8; *++ptr = 0x00; buf_space--; } else { *ptr = *ptr | (1 << (unused - 1)); unused--; } break; case 2: /* align buffer to end of byte */ if (unused != 8) { *++ptr = 0x00; buf_space--; unused = 8; } break; case 10: /* next byte in in_buf tells how many bits in the second next byte that will be used */ /* The leftmost unused bits in the value byte are supposed to be zero bits */ no_bits = (int)*(++in_ptr); val = *(++in_ptr); counter -= 2; if ((ret=insert_least_sign_bits(no_bits,val,&ptr,&unused)) == ASN1_ERROR) return ASN1_ERROR; buf_space -= ret; break; case 20: /* in this case the next value in_ptr points at holds the number of following bytes that holds the value that will be inserted in the completed buffer */ no_bytes = (int)*(++in_ptr); counter -= (no_bytes + 1); if ((counter<0) || (ret=insert_octets(no_bytes,&in_ptr,&ptr,&unused)) == ASN1_ERROR) return ASN1_ERROR; buf_space -= ret; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -