ROHC报头压缩

1. ROHC-1.7动态库安装

1.1 确定操作系统版本

由于ROHC类库与操作系统、编译器、交叉编译环境、libc标准库存在兼容性等各种问题,因此选择目前最新版本ubuntu-gnome-15.10-desktop-i386.iso

1.2 选择类库安装类型

  • Debian Linux
  • Gentoo Linux
  • Arch Linux
  • 其他

选择其他,以源码形式创建并安装

注:本程序只支持1.6.0及其以上版本

1.3 安装步骤

1. 准备ubuntu-gnome-15.10-desktop-i386.iso系统镜像
2. 安装Ubuntu虚拟机
3. 安装VMwareTools-9.6.2-1688356.tar.gz
tar  -zxvf 解压gzip格式 
tar  -jxvf  解压bz2格式
tar  -xvf   解压上述两种格式
4. 选择安装类型:本机系统安装或者交叉编译到对应目标
On Unix-like systems
Cross-compilation for ARM/PowerPC on Unix-like systems
Cross-compilation for Android ARM on Unix-like systems

Cross-compilation for Microsoft Windows on Unix-like systems
Build for Microsoft Windows with Cygwin
选择On Unix-like systems
5. 安装library
(1)以普通用户身份登录系统

(2)检查系统准备好安装ROHC library

(3)检索来源

最佳方法:下载ROHC的最新版本源代码(一次性下载打包压缩文件)

源代码被分成了三个库:

1)压缩和解压在一起的库

2)压缩库

3)解压库:对于.xz压缩格式的包,先执行xz -d 解压成.gz格式的在执行tar解压命令

					$ wget https://rohc-lib.org/download/rohc-latest.tar.xz
					$ wget https://rohc-lib.org/download/rohc-latest.tar.xz.sha256
					$ wget https://rohc-lib.org/download/rohc-latest.tar.xz.asc
					//上三步手动下载
					$ sha256sum -c rohc-latest.tar.xz.sha256//hash校验文件完整性
					rohc-latest.tar.xz.sha256: OK//这样显示完整
					$ gpg --recv-keys 008E8DAD 	//只在第一次检索GPG秘钥
					$ gpg --verify rohc-latest.tar.xz.asc	//检验文件真实性
					$ tar xvJf rohc-latest.tar.xz 		//OpenBSD 注意:使用gtar代替tar
					$ cd rohc-X.Y.Z  	//用版本编号替换X.Y.Z
或者:查找开发版本

					$ git clone --depth 10 https://github.com/didier-barvaux/rohc.git
					$ cd rohc

(4)配置 library

	$ ./autogen.sh --prefix=/usr   //设置安装路径:/usr

出现错误(原因:未使用xz解压,解压的包异常):

			xcy@xcy:~/Desktop/rohc-1.7.0$ sudo ./autogen.sh --prefix=/usr 
			Running aclocal... failed
			Command aclocal not found, please install it

解决办法:

			Sudo apt-get install aclocal 

又出现如下问题:

			xcy@xcy:~/Desktop/rohc-1.7.0$ sudo apt-get install aclocal
			Reading package lists... Done
			Building dependency tree       
			Reading state information... Done
			E: Unable to locate package aclocal

解决办法:

			Sudo apt-get update //用apt-get install 这个命令安装软件包时,系统检查软件包目录,apt-get update 更新软件目录树

注意:如果操作系统为64位,添加--libdir=/usr/lib64参数

(5)创建库和工具

		$ make all
(6)运行non-regression tests(检测test程序)//我并未使用
		$ make check

(7)生成说明文档

$ ./configure --enable-doc

 		$ make -C doc/
打开./doc/html/index.html即可查看,说明文档包含了对应的应用函数接口、结构体等数据说明信息 (8)以root权限安装library和工具
$ su
# make install
# exit

6.查看在/usr/lib路径下是否存在关于ROHC的动态库

Librohc.so

Librohc_common.so

Librohc_comp.so

Librohc_decomp.so

7.将动态库添加到编译时的搜索路径(本程序make install的时候已经将动态库添加到/usr/lib)

动态库的搜索路径的顺序:

1)编译目标代码时指定的动态库搜索路径;

2)环境变量LD_LIBRARY_PATH指定的动态库搜索路径;

3)配置文件/etc/ld.so.conf中指定的动态库搜索路径;

4)默认的动态库搜索路径/lib /usr/lib

8.阅读例子文件

进入当前解压目录文件下example/的文件

Simple_rohc_program.c //IP报头压缩

print_rohc_version //打印rohc动态库版本

rtp_detection //带回调检测函数的例子

example_rohc_decomp //解压程序例子

2. ROHC压缩原理

报头之所以能够进行压缩处理,主要是因为报头字段之间存在着冗余,这些冗余信息表现在两方面:一是在一个特定的分组流里面,前后两个分组之间存在着字段的重复,比如IP头里面的源IP地址,目的IP地址;二是每一个分组自身也存在着冗余信息,比如IP头和UDP头中的长度字段,这些字段可以由解压方解压后推导得出。ROHC压缩器的最终目的就是要消除报头中的这些冗余信息,对其他变化的字段,采取特定的编码方式对其进行编码,把编码后的少量信息发送给解压器,以达到报头压缩的目的.

3. ROHC工作模式

ROHC协议定义了三种工作模式,分别是U模式、R模式、O模式。

3.1 U模式

当ROHC系统没有或者无法使用feedback时,选择U模式。这个时候,解压缩端无法向压缩端发送feedback。压缩端通过2种方法进行状态迁移。
(1)乐观逼近(Optimistic approach):压缩端在低状态下,只要连续发送了n个包时就认为解压缩端已经能够正确解压缩并建立Context,此时压缩端向高状态迁移。
(2)周期性:压缩端在高状态时,每经过一定的timeout,即迁移到低状态,以保证解压缩端能够收到包含完整Context的压缩包。而timeout值的大小也对系统的压缩率和鲁棒性有一定的影响。

3.2 O模式

当ROHC系统有可以使用的feedback通道时,选择O模式。压缩端根据乐观逼近或受到ACK时进行升状态,收到NACK或者STATIC-NACK时进行降状态。
(1)ACK:当解压缩端正确的解压缩时,即向压缩端发送ACK。压缩端收到ACK时,即升到最高状态,提高压缩率。
(2)NACK:当解压缩端连续错误的解压缩时,即向压缩端发送 NACK。压缩端收到NACK时,即需要降到最低状态,重新使用全Context进行压缩,保持压缩端与解压缩端Context一致。
(3)STATIC-NACK:当解压缩端对信息头STATIC域连续错误的解压缩时,即向压缩端发送STATIC-NACK。压缩端收到STATIC-NACK时,即需要降到中间状态,重新使用Context中STATIC域部分进行压缩,保持压缩端与解压缩端Context一致。

3.3 R模式

当ROHC系统工作状态比较好的时候,使用R模式进行压缩处理,完全依靠Feedback进行状态迁移。

4.配置文件(profile

为了能够对多种类型的信息头进行压缩处理,ROHC协议引入了Profile的概念。根据信息头的不同,ROHC协议制定了唯一Profile ID与之相对应,比如说IP/TCP的Profile ID为0x0006 。
通常使用到的配置文件有:
根据信息头类型 Profile编号
UNCOMPRESSOR 0x0000
IP/UDP/RTP 0X0001
IP/UDP 0X0002
IP/ESP 0X0003
IP 0X0004
IP/TCP 0X0006
IP_UDP LITE 0X0008

5.上下文(context)

ROHC协议为了能够更好的对IP数据流进行区分,在引入Profile ID的同时,提出了Context ID的概念。不同的IP数据流将会分配到唯一的Context ID,用来标识该数据流。而通过Profile ID和Context ID,解压缩端就可以对指定的数据进行解压缩处理。
压缩端在发送IR的时候,将分配给该信息头的Profile ID, Context ID和信息头中各个域的内容全部发送到解压缩端,解压缩端则将其记录下来存到Context中。解压缩端对于之后收到的压缩数据包,会先进行压缩包内的Profile ID和Context ID的解析,判断该组数据流是否已经存入到Context中,并进行解压缩处理。

6.反馈(feedback)

ROHC协议为了提高压缩率和鲁棒性,引入了feedback机制。解压缩端在工作过程中,不论解压缩成功还是失败,都需要将结果通知压缩端,以便于压缩端判断是否进行状态迁移。当压缩端收到ACK时,则要迁移到高状态,使用压缩率比较高的包类型进行压缩处理;当压缩端收到NACK或者STATIC-NACK时,则要从高状态迁移到相应的低状态,重新发送相对完整的Context,以保持压缩端和解压缩端同步。

7.ROHC压缩端

7.1 工作状态

压缩端共有三种工作状态:IR状态(Initialization and Refresh)、 FO状态(First Order)和SO状态(Second Order)
1)IR状态(Initialization and Refresh)
IR状态是三个状态中的最低状态,是在ROHC系统初始化时或者需要更新Context中动态域和静态域时所处的工作状态。在IR状态下,压缩端需要连续发送n个IR包,或收到解压缩端发送的ACK时,迁移到最高状态。
2)FO状态(First Order)
FO状态属于中间状态。当压缩端在最高状态收到解压缩端在连续发送的n次STATIC-NACK之后,压缩端从最高状态降到FO状态。此时压缩端只对信息头中的动态域进行压缩处理即可。而当压缩端收到解压缩端发送的ACK时,即将状态迁移到最高状态。
3)SO状态(Second Order)
SO状态是压缩端的最高状态。SO状态下,压缩端只需要将信息头动态域发生变化的部分进行压缩处理并发送到解压缩端。SO状态,可以根据发生变化的动态域的变化量选择不同类型的压缩包,此时,压缩之后的压缩包最小,压缩率也就最高。

7.2 状态迁移

ROHC系统初始化时,压缩端的状态为IR状态。之后则根据解压缩发送的feedback来决定是否进行状态迁移。

7.3 总结

经过ROHC库压缩过的数据包,第一位表示压缩包类型:
压缩端状态 压缩包第一位
IR 0xfd
FO 0xf8
SO 其他

8. ROHC解压端

Ø 工作状态

解压端共有三种工作模式:NC状态((No Context)SC状态(Static Context)FU状态(Full Context)

NC状态((No Context)

    NC状态是解压缩端的最低状态,在ROHC初始化或者当解压缩端连续几次进行错误解压缩数据之后由高状态降到NC状态。NC状态下,只能接收并处理由压缩端发送的IR包。

SC状态(Static Context)

    SC状态是解压缩端的中间状态,与压缩端FO状态相对应,当解压缩端连续对信息头中的动态域进行错误解压缩之后,解压缩端由最高状态降到SC状态。理论上也可以由NC状态升到SC状态,但是实际实施中,我们并没有设计此功能。

FU状态(Full Context)

Fu状态是解压缩端的最高状态。当解压缩端正确解压缩并成功建立Context之后,状态由低状态升到FC状态。FC状态下,可以进行高压缩率的解压缩处理。

状态迁移

解压缩端在ROHC初始化时处于NC状态。当正确解压缩数据并成功建立Context之后,立刻从NC状态升到FC状态。当解压缩端在连续发生几次解压缩失败之后,根据信息头解压缩错误的部分来决定迁移到SC状态或者NC状态。当低状态再次成功解压缩信息头之后,解压缩端状态迁移到最高状态。

 

1. 常用接口

Ø 结构体

数据包结构体

struct rohc_buf{

struct rohc_ts time; //接收时间,为0表示未知

uint8_t * data; //数据包

size_t max_len; //存储数据包的buffer的最大空间

size_t offset; //有效数据相对data的偏移

size_t len; //data数据的有效长度

}

 

压缩器指针

struct rohc_comp

 

解压器指针

struct rohc_decomp

Ø 压缩方式的宏

ROHC_LARGE_CID ROHC_SMALL_CID

ROHC关于压缩方式,采用large cids方式压缩,压缩结果比small方式多添加一个字节来表示CID

 

Ø  初始化rohc_buf结构体

Rohc_buf_init_empty(struct rohc_buf packet, size_t max_len)

 

Ø 判断rohc_buf是否为空或满

bool  rohc_buf_is_empty (const struct rohc_buf buf)

 

rohc_buf_init_full(__data, __len, __time)

Ø 访问结构体的具体数据data

rohc_buf_byte_at(__buf, __offset)

Ø 创建压缩器

Rohc_status_t rohc_compress4(struct rohc_comp * const comp

Const struct rohc_buf uncomp_packet

Struct rohc_buf* const  rohc_packet)

参数1:压缩器指针

参数2:未压缩的包的结构体

参数3rohc_packet结构体

返回值:ROHC_STATUS_OK,成功

ROHC_STATUS_SEGMENT,返回第一段

ROHC_STATUS_OUTPUT_TOO_SMALL,给的rohc_packetbuffer太小

ROHC_STATUS_ERROR,错误

 

Ø 压缩

Rohc_status_t rohc_compress4(struct rohc_comp * const comp

Const struct rohc_buf uncomp_packet

Struct rohc_buf* const  rohc_packet)

参数1:压缩器指针

参数2:未压缩的包的结构体

参数3rohc_packet结构体

返回值:ROHC_STATUS_OK,成功

ROHC_STATUS_SEGMENT,返回第一段

ROHC_STATUS_OUTPUT_TOO_SMALL,给的rohc_packetbuffer太小

ROHC_STATUS_ERROR,错误

 

Ø 使能压缩配置文件

Bool rohc_comp_enable_profile(struct rohc_comp * const comp,

Const  rohc_profile_t profile)

使能配置文件

参数1:压缩器指针

参数2:配置文件

返回值:

True:配置文件存在且使能

False:配置文件无效不存在或者禁用

 

Bool rohc_comp_enable_profiles(struct rohc_comp *const comp

...

)

使能多个配置文件

参数1:压缩器指针

... -1终止

返回值:

True:全都存在

False:至少有一个不存在

Ø Segment获取分段

ohc_status_t rohc_comp_get_segment2(struct rohc_comp * const comp

Struct rohc_buf *const segment)

参数1:压缩器指针

参数2:存储segment的结构体

 

返回值:ROHC_NEED_SEGMENT,还有其他分段

ROHC_OK,分段取完

ROHC_ERROR,错误

 

Ø 设置判断RTP包函数

Bool rohc_comp_set_rtp_detection_cb(struct rohc_comp *const comp

Rohc_rtp_detection_callback_t callback

Void * const rtp_private)

设置RTP回调函数,在UDP流中检测RTP

UDP包压缩的时候,callback函数就被调用一次,若返回结果为trueRTP配置文件就被用到压缩上,否则就使用IP/UDP配置文件

参数1:压缩器指针

参数2:检测RTP包的回调函数,如果为NULL则回调函数无效

参数3: 为回调提供的外部内存区域指针

 

返回值:成功返回true,失败返回false

 

Ø 销毁压缩器

void rohc_comp_free(struct rohc_buf*comp);

 

Ø 创建解压器

Struct rohc_decomp* rohc_decomp_new2(const rohc_cid_type_t cid_type

Const rohc_cid_t max_cid

Const rohc_mode_t mode)

创建解压器

参数cid_typeROHC_LARGE_CID ROHC_SMALL

参数max_cid:解压处理流数,ROHC_SMALL_CID [0ROHC_SMALL_CID]

    ROHC_LARGE_CID[0ROHC_LARGE_CID]

参数mode ROHC_U_MODE,单向模式

ROHC_O_MODE,双向优化模式

ROHC_R_MODE,双向可靠模式

返回值:

成功返回解压器指针

失败返回NULL

 

Ø 使能解压配置文件

bool rohc_decomp_enable_profile ( struct rohc_decomp *const decomp,

 const rohc_profile_t profile

)

使能配置文件

 

bool rohc_decomp_enable_profiles ( struct rohc_decomp *const decomp,

  ...

)

使能多个配置文件

 

 

Ø 解压

Rohc_status_t rohc_decompress3(struct rohc_decomp* const decomp

Const struct rohc_buf rohc_packet

Struct rohc_buf * const uncomp_packet

Struct rohc_buf * const rcvd_feedback

Struct rohc_buf * const feedback_send)

解压缩

参数decomp:解压器指针

参数rohc_packetROHC包结构体

参数uncomp_packet:输出结构体,存放解压得到的包的结构体

参数rcv_feedback:输出参数,存放通过反馈通道接收到的远端同侧压缩器的反馈

NULL:忽略反馈信息

NULL:存储反馈

参数feedback_send:输出参数,存放要通过反馈通道发送给远端压缩器的反馈信息

NULL:解压器不给压缩器传递反馈

NULL:传递

返回值:

ROHC_STATUS_OK 解压成功

ROHC_STATUS_NO_CONTEXT: 没有与ROHC包中相适合的CID(上下文)而且

ROHC不是一个IR

ROHC_STATUS_OUTPUT_TOO_SMALL: 给的buffer太小

ROHC_STATUS_MALFORMED:给的ROHC有错误

ROHC_STATUS_BAD_CRCCRC检测错误

ROHC_STATUS_ERROR:其他

 

Ø 销毁解压器

Void rohc_free_decompressor(struct rohc_decmop* decomp)

销毁ROHC压缩器

参数:要销毁的压缩器

 

2. 编写程序

Ø 发送端

功能描述:

监听网卡设备,读取经过网卡的数据包,将读取的目的端口号是设定端口号的数据包压缩,使用UDP套接字传输压缩后的数据。

流程图:

自定义函数:

int handle_read_eth0(int sockfd);//通过eth1发送数据

int gen_random_num(const struct rohc_comp* const comp,

void * const user_context); //用来产生CID(上下文编号)

 

struct rohc_comp * create_compressor(void); //创建压缩器

 

void dump_packet(const struct rohc_buf packet); //遍历数据包

 

bool compress_with_callback(struct rohc_comp *const compressor,

                                   struct rohc_buf uncomp_packet,

                                   struct rohc_buf *const packet); //压缩数据包

 

bool rtp_detect(const unsigned char *const ip, //判断UDPRTP专用传输端口号

                       const unsigned char *const udp,

                       const unsigned char *const payload,

                       const unsigned int payload_size,

                       void *const rtp_private);

                       //根据UDP端口号判断是不是RTP

 

 

int getifinfo(void); //获取本地网卡信息

 

int set_promisc(char *interface, int fd);  //将对应网卡设置为混杂模式

 

int create_listen_eth0(void); //监听网卡eth0

 

int create_write_eth0(void); //通过网卡eth0发送数据

 

int filter_packet(const struct rohc_buf packet,int f_port);//通过端口号过滤收到的包

 

int check_length(const struct rohc_buf packet);//检验是否带有CRC

具体实现步骤:

1) 创建压缩器

创建压缩器用来压缩原始包

compressor = create_compressor();

2) 获取本地网卡信息

获取本地网卡信息

getifinfo();

3) 监听eth0

create_listen_eth0();

包含:

1) 创建原始套接字

用来监听网卡设备,接收将要用来压缩的数据包

listen_eth0 = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))

2) 设置网卡为混杂模式

接收全部类型的数据包

set_promisc(localeth.name[DATA_ETH0], listen_eth0);

3) Bind网络设备

bind(listen_eth0, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll))

4) 准备发送数据

通过eth0发送数据做准备

create_write_eth0();

包含:

1) 创建UDP套接字

send_eth0 = socket( AF_INET,SOCK_DGRAM, 0))

2) 设置设备输出

setsockopt(send_eth0,SOL_SOCKET,SO_BINDTODEVICE,(char *)&ifq, sizeof(ifq))

3) 初始化UDP目的结构体

目的地址、地址协议族、目的端口号等

5) 循环处理发送

调用函数handle_read_eth1(listen_eth0),处理数据

包含:

1) 通过网卡0接收并过滤数据

调用函数fiter_packet函数过滤数据包

2) 压缩包

compress_with_callback(compressor,ip_packet,&rohc_packet);

包含:

1) 设置回调函数检测RTP

自定义回调函数检测UDP包还是RTP包(判断UDP端口号)

rohc_comp_set_rtp_detection_cb(compressor, rtp_detect, NULL);

2) 保存MAC头和CRC校验

//截取MAC

memcpy(mac,uncomp_packet.data,MAC_LEN);

判断是否带有CRC校验,如果有

将标志flag置为1,没有就置为0

 

//flag加入MAC

memset(mac,flag,sizeof(uint_8));

 

//截取MAC校验

memcpy(check,

uncomp_packet.data+uncomp_packet.len - CHECK_MAC,

CHECK_MAC);

3) 修改偏移量

rohc_buf_pull(&uncomp_packet,MAC_LEN);

4) 压缩数据包

rohc_compress4(compressor, uncomp_packet, &rohc_packet);

5) MAC头和CRC校验还原

//MAC头插入rohc_packet包的头部

rohc_buf_prepend(&rohc_packet,mac,(const size_t)MAC_LEN + 1);

 

如果有CRC校验

//MAC校验尾部追加

memcpy(rohc_packet.data+rohc_packet.len,check,CHECK_MAC);

rohc_packet.len += CHECK_MAC;

3) 使用UDP套接字发送压缩包

sendto(send_eth0,buff_to_eth0,length_to_eth0,0,(struct sockaddr*)&sin_adr,sizeof(struct sockaddr_in));

Ø 接收端

功能描述

实现对接收到UDP数据包进行解压还原。

流程图:

自定义函数:

 

int handle_read_eth1(int sockfd); //处理数据包

void dump_packet(const struct rohc_buf packet); //遍历数据包

 

bool decompress_with_callback(struct rohc_decomp *const decomp,

   struct rohc_buf rohc_packet,

   struct rohc_buf *const ip_packet); //解压ROHC数据包

int filter_packet(const struct rohc_buf packet); //过滤数据包,将UDP目的端口号

不是指定的过滤

 

struct rohc_decomp* create_decomp(void); //创建压缩器

 

int getifinfo(void); //获取网卡信息

 

int set_promisc(char *interface, int fd); //设置混杂模式

 

int create_listen_eth1(void); //设置eth1原始套接字监听

int create_write_eth0(void); //设置send_eth0套接字

int filter_packet(const struct rohc_buf packet,int f_port);//过滤数据包

int check_length(const struct rohc_buf packet);//检查校验

 

具体实现步骤:

 

1) 创建解压器

Decompressor = rohc_decomp_new2(ROHC_LARGE_CID,

ROHC_LARGE_CID_MAX,

ROHC_O_MODE);

2) 获取网卡信息

getifinfo();

 

3) 监听网卡设备eth1

create_listen_eth1();

包含:

1) 创建原始套接字

listen_eth1 = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)))

2) 设置混杂模式

set_promisc(localeth.name[DATA_ETH1], listen_eth1);

3) Bind网络设备

bind(listen_eth1, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll));

4) 准备发送的目的结构体(暂时不用)

4) 循环接收处理

handle_read_eth1(listen_eth0);

包含:

1) 接收数据包

recvfrom(sockfd, buff, 1520 , 0, (struct sockaddr*)&remote_ll, (socklen_t*) &socksize);

2) 过滤数据包

根据UDP包的目的端口号过滤收到的数据包

filter_packet(rohc_packet);

端口号符合就进行下一步的处理,不符合就丢弃

 

 

 

3) 解压

decompress_with_callback(decompressor,rohc_packet,&ip_packet)

包含:

1) 保存MAC头和CRC校验

//保存MAC

memcpy(mac,rohc_packet.data+42,MAC_LEN);

 

//保存校验位

flag = (uint8_t)rohc_packet.data[42] ;

 

判断收到的UDP包是否带有CRC校验,若有

//去除CRC

memset(rohc_packet.data+

 rohc_packet.len - CHECK_MAC,

0,

CHECK_MAC);

rohc_packet.len -= CHECK_MAC;

2) 设置偏移量

//拉开ROHC包的报头

rohc_buf_pull(&rohc_packet,42 + MAC_LEN + 1);

3) 判断压缩数据是否带有CRC

如果flag = 1

//去除压缩数据的CRC

memset(rohc_packet.data+rohc_packet.len-CHECK_MAC,

0,CHECK_MAC);

rohc_packet.len -= CHECK_MAC;

4) 解压

rohc_decompress3(decomp,rohc_packet,&packet,NULL,NULL);

5) 还原数据

//添加MAC

rohc_buf_prepend(&packet,mac,MAC_LEN);

packet.len += CHECK_MAC;

 

3. ROHC库移植到DM8148

   使用的虚拟机系统是ruiva-ubuntu11-dm8148newflowOK

11.1下载rohc-1.7.1.tar.gz

11.2解压

以下均在Linux下完成

Xz   -d  *.xz //解压成.tar格式

Tar -xvf *.tar //解压文件

Tar  -zcvf  rohc-1.7.0.tar.gz  rohc-1.7.0/ //因为在开发板上解压出现

tar: warning: skipping header 'x'

tar: warning: skipping header 'x' 错误

11.3配置 library

1. Cd  rohc-1.7.0

2. ./configure  --prefix=/usr  --host=arm-none-linux-gnueabi

执行./configure  --prefix=/usr,出现

configure: error: cannot run C compiled programs.

If you meant to cross compile, use `--host'.

See `config.log' for more details

3. 进入src源码目录下

Common //压缩解压公共库源码文件

Comp //创建压缩库所需的源码库文件

Decomp //创建解压库所需的文件

11.4创建rohc_common公共库

1. common目录中创建include目录和src目录,将原来的common下的.h头文件移动到include目录下,将所有的 .c源文件移动到src目录

 

缺少的config.h文件在解压的源目录下

 

2. 修改.h.c文件代码中头文件包含的路径

3. Make编译环境

执行(Linux软件开发工具包)

a. source ~/.bashrc

b. Export EZSDK="/home/ruiva/project/ruiva-dm8148-dvsdk5/ti-ezsdk_dm814x-evm_5_05_01_04"

c.  source ${EZSDK}/linux-devkit/environment-setup

 

执行以上几步,目的是为了构建交叉编译环境

 

4. 交叉编译

分别交叉编译librohc_common.solibrohc_comp.solibrohc_decomp.so

例:arm-none-linux-gnueabi-gcc --shared  *.c  -o librohc_common.so

 

注意:编译解压缩库librohc_decomp.so时会遇到缺少__rohc_comp_piggyback_feedback__rohc_comp_deliver_feedback的定义,需要在源码文件中截取函数定义手动添加,我自己单独添加在add_comp.c文件中

 

 

5. 移植动态库

将生成的ROHC库通过tftp工具下载到开发板

Tftp  -g  -r  *.so  /usr/lib

 

将对应的头文件下载到/usr/include下的,自己创建的rohc目录里

Mkdir  /usr/include/rohc

Tftp  -g -r  rohc.h/rohc_comp.h/rohc_decomp.h   /usr/icnlude/rohc

 

6. 编译程序

与一般动态库的使用一致

4. 编译项目

l 新建项目目录

在项目目录下创建include头文件,存放所需头文件

n Config.h

n Rohc.h

n Rohc_buf.h

n Rohc_comp.h

n Rohc_decomp.h

n Rohc_packet.h

n Rohc_time.h

n Rohc_traces.h

l 在项目目录下存放动态库文件

n Librohc_common.so

n Librohc_comp.so

n Librohc_decomp.so

l 交叉编译

5. 遇到问题

Ø 压缩端和解压端之间反馈信息交互(已解决)

l 问题描述

第一次发送压缩包时,压缩端需要先检查自己的压缩上下文,看看是否存在上下文,如不存在,发送一个完整的信息头,等到解压端收到后发送确认,压缩端再进行后续的压缩。那么,压缩与解压之间的信息反馈是通过library来完成的,还是需要程序员字节介入完成

l 验证方法

由于压缩端的状态变化是由解压端的信息反馈决定的,因此在解压端创建解压器的时候,选择工作模式是双向还是单向。

因此,先让解压器选择U模式,再选择O模式,每种模式下都连续发送数据包,比较每次压缩轨迹以及压缩后的包的大小。

结果每次压缩端均发生状态迁移

l 验证结果

压缩端的状态迁移接收的反馈信息,来自于解压端但是并不需要手动输入

Ø 编写程序与内核程序关系(已解决)

l 问题描述

实际项目中肯定存在很多需要网络通讯的应用进程,那我们是不是要自己修改内核中关于网络包传输部分,在根源处实现岁数据包的压缩和解压。

l 暂时解决方案

根据《基于Linux平台的ROHC报头压缩系统的研究与实现》论文描述,ROHC的执行触发点有两个:一是发送数据包的时候,对数据包进行压缩;二是对接收到的压缩包进行解压,再提交给上层。

因此,对于发送端,先调用函数返回网络设备的结构体指针,将结构体中的关于数据包发送的函数指针修改为自己写的专门压缩的函数,之后再调用原来的数据包发送函数。

对于接收端,添加ROHC协议(0x8020)到数组packet_ptype_base中,代表ROHC协议包,并添加自己写的,对应ROHC的处理函数进行解压,将解压的数据包交付cpu输入队列,等候再次的中断处理。

 

l 解决

本项目暂时在Linux系统下,编写应用程序实现报头的压缩,至于是否编写内核模块是今后情形而定。

Ø 内核代码与ROHC库的关系(已解决)

l 问题描述

我们在压缩和解压的代码中都调用了ROHC库中的函数,那么如何将自己写的压缩解压代码在内核源码中编译

l 解决

本项目暂时在Linux系统下,编写应用程序实现报头的压缩,至于是否编写内核模块是今后情形而定。

 

Ø 关于超过MRRU时的分段问题(未解决)

l 问题描述

设置MRRU实现包长控制的域值

Ø 编译安装内核模块(已解决)

l 问题描述

Linux-3.7版本之后,添加了内核模块签名验证功能,用来防止运行环境不一样时,禁止加载模块

l 原因

在普通权限下编译模块,在root权限下运行,环境不一样

l 解决

使用root权限,执行Makefile

Ø Dev_get_by_name()使用(已解决)

l 问题描述

调用函数,得到设备结构体,linux可以使用dev_get_by_name函数取得设备指针,但是使用是需要注意,使用过dev_get_by_name函数后一定要使用dev_put(pDev)函数取消设备引用,不然可能导致GET的设备无法正常卸载。一般在将设备指针赋值给SKB->dev后就可以dev_put(pDev)

但使用__dev_get_by_name就不需要调用dev_put(pDev)

struct net_device * __dev_get_by_name(struct net * net, const char * name);

习惯了使用之前的dev_get_by_name,现在多出个struct net *net参数,感觉不知所措 了。 后来发现可以使用init_net,来用做第一个参数。init_net为全局变量 [Linux/net/core/net_namespace.c]

l 解决

例如

#include

__dev_get_by_name(&init_net,”dev_name”)

得到设备的结构体

 

Ø 新版内核取消dev->hard_start_xmit(已解决)

l 问题描述

新版网络设备结构体的成员函数指针hard_start_xmit取消了。

l 解决

使用netdev_ops结构体指针,在netdev_ops结构体里面使用了ndo_start_xmit()函数。

Ø 编写程序测试(未解决)

l 问题描述

./snd 192.168.237.128(本机IP) 1234

出现recvfrom()函数接收到杂包

 

Ø 鉴别UDP包流中的RTP包(未解决)

l 问题描述

根据ROHC库的说明,在ROHC库中通过UDP端口号来区分是UDP包还是RTP包,因为UDP提供了专门用于传输RTP包的UDP专用端口列表














你可能感兴趣的:(其他)