4.1 物理层的实现
在本节简单分析下用UDP报文模拟传输的实现。
在Dynamips中使用了一个udp_connect函数来实现创建一个新的socket连接到指定的主机,其中的getaddrinfo函数返回的结构体struct addrinfo类型的成员包含了一个ai_addr的成员,该成员的类型是struct sockaddr,同时,addrinfo中还包含了ai_family, ai_socktype, ai_protocol成员,因此可以直接通过该返回结构来进行socket等函数的套接口调用。
通过getaddrinfo函数得到该主机对应服务的所有的IP,然后尝试与其中一个IP来建立套接口进行连接。
具体函数实现如下:
/* 创建一个新的socket连接到指定的主机 */
/* local_port即本地端口,remote_host即远程主机,remote_port即远程端口 */
int udp_connect(int local_port,char *remote_host,int remote_port)
{
struct addrinfo hints,*res,*res0;
struct sockaddr_storage st;
int error, sck = -1;
char port_str[20]; /* 定义了port_str数组及大小 */
memset(&hints,0,sizeof(hints)); /* 初始化内存空间 */
hints.ai_family = PF_UNSPEC; /* IPv4,IPv6都支持,将返回这2中类型的地址 */
hints.ai_socktype = SOCK_DGRAM;
snprintf(port_str,sizeof(port_str),"%d",remote_port);
/* 将参数远程端口remote_port按照整数的格式格式化,然后将其复制到port_str中,如果格式化后的长度<sizeof(port_str),则将此字符串全部复制到port_str中,并给其后添加一个字符串结束符('\0'),如果格式化后的长度=>sizeof(port_str),则只将其中的(sizeof(port_str)-1)个字符复制到port_str中,并给其后添加一个字符串结束符('\0')。*/
if ((error = getaddrinfo(remote_host,port_str,&hints,&res0)) != 0) {
fprintf(stderr,"%s\n",gai_strerror(error));
return(-1);
}
/* 遍历 */
for(res=res0;res;res=res->ai_next)
{
/* 仅要IPv4和IPv6 */
if ((res->ai_family != PF_INET) && (res->ai_family != PF_INET6))
continue;
/* 创建新的socket */
if ((sck = socket(res->ai_family,SOCK_DGRAM,res->ai_protocol)) < 0) {
perror("udp_connect: socket");
continue;
}
/* 绑定到本地端口 */
memset(&st,0,sizeof(st)); /* 初始化内存空间 */
/* 以下语句判断IPv4,IPv6,或其它情况 */
switch(res->ai_family) {
case PF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)&st;
sin->sin_family = PF_INET;
sin->sin_port = htons(local_port);
break;
} /* IPv4 */
case PF_INET6: {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&st;
#ifdef SIN6_LEN
sin6->sin6_len = res->ai_addrlen;
#endif
sin6->sin6_family = PF_INET6;
sin6->sin6_port = htons(local_port);
break;
} /* IPv6 */
default:
/* 不应该发生 */
close(sck);
sck = -1;
continue;
}
/* 尝试连接到远程主机 */
if (!bind(sck,(struct sockaddr *)&st,res->ai_addrlen) &&
!connect(sck,res->ai_addr,res->ai_addrlen))
break;
close(sck);
sck = -1;
}
freeaddrinfo(res0); /* 此处调用来释放getaddrinfo函数动态分配的内存 */
return(sck);
}
4.2 数据链路层的实现
在本层主要实现两个:虚拟帧中继交换机,虚拟以太网交换机。
4.2.1 虚拟帧中继交换机的实现
在这里主要分析如下几个部分:
创建一个帧中继交换机
删除一个帧中继交换机
创建一个交换机连接
删除一个交换机连接
保存帧中继的配置信息
读取帧中继交换机配置文件
启动一个帧中继交换机
1.创建一个虚拟交换机表
要想创建一个虚拟交换机表,首先要为要创建的这个表分配空间,初始化内存,初始化互斥锁对象,然后在固定的内存里面创建一个池,这里命名为Frame-Relay Switch,内存大小是t->mp占用空间的大小,然后进行命名,并且在注册表中增加一个记录,这样就创建了一个虚拟交换要表。
此函数实现如下:
frsw_table_t *frsw_create_table(char *name)
{
frsw_table_t *t;
if (!(t = malloc(sizeof(*t))))
return NULL;
memset(t,0,sizeof(*t)); /* 初始化内存 */
pthread_mutex_init(&t->lock,NULL); /* 初始化一个互斥锁对象 */
mp_strdup(&t->mp,name)))
goto err_name;
if (registry_add(t->name,OBJ_TYPE_FRSW,t) == -1) {
fprintf(stderr,"frsw_create_table: unable to create switch '%s'\n",name);
goto err_reg;
}
return t;
err_reg: /* 出错处理 */
err_name:
mp_free_pool(&t->mp);
free(t);
return NULL;
}
<< 上一页 [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] ... 下一页 >>