您的位置:首页 > 理论基础 > 计算机网络

看明白在uclibc中网络系统调用是如何实现的

2011-05-26 12:26 621 查看
目标: 看明白在uclibc中网络系统调用是如何实现的,和普通的Linux有什么区别

0. 将uClibc-0.9.30.1/libc/inet目录下的文件按文件大小排列一下,会发出100多字节的文件有很多,都是调用的。呵呵。

1. 代码文件:uClibc-0.9.30.1/libc/inet/socketcall.c 代码如下:

#ifdef L_recv

extern __typeof(recv) __libc_recv;

#ifdef __NR_recv

#define __NR___libc_recv __NR_recv

_syscall4(ssize_t, __libc_recv, int, sockfd, __ptr_t, buffer, size_t, len,

int, flags)

#elif defined(__NR_socketcall)

/* recv, recvfrom added by bir7@leland.stanford.edu */

ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)

{

unsigned long args[4];



args[0] = sockfd;

args[1] = (unsigned long) buffer;

args[2] = len;

args[3] = flags;

return (__socketcall(SYS_RECV, args));

}

#elif defined(__NR_recvfrom)

libc_hidden_proto(recvfrom)

ssize_t __libc_recv(int sockfd, __ptr_t buffer, size_t len, int flags)

{

return (recvfrom(sockfd, buffer, len, flags, NULL, NULL));

}

#endif

libc_hidden_proto(recv)

weak_alias(__libc_recv,recv)

libc_hidden_weak(recv)

#endif



#ifdef L_connect

extern __typeof(connect) __libc_connect;

#ifdef __NR_connect

#define __NR___libc_connect __NR_connect

_syscall3(int, __libc_connect, int, sockfd, const struct sockaddr *, saddr, socklen_t, addrlen)

#elif defined(__NR_socketcall)

int __libc_connect(int sockfd, const struct sockaddr *saddr, socklen_t addrlen)

{

unsigned long args[3];



args[0] = sockfd;

args[1] = (unsigned long) saddr;

args[2] = addrlen;

return __socketcall(SYS_CONNECT, args);

}

#endif

libc_hidden_proto(connect)

weak_alias(__libc_connect,connect)

libc_hidden_weak(connect)

#endif



#ifdef L_getpeername

#ifdef __NR_getpeername

_syscall3(int, getpeername, int, sockfd, struct sockaddr *, addr, socklen_t *,paddrlen)

#elif defined(__NR_socketcall)

int getpeername(int sockfd, struct sockaddr *addr, socklen_t * paddrlen)

{

unsigned long args[3];



args[0] = sockfd;

args[1] = (unsigned long) addr;

args[2] = (unsigned long) paddrlen;

return __socketcall(SYS_GETPEERNAME, args);

}

#endif

#endif



2. 对上面代码的分析:

A. 将网络系统调用传送过来的参数放到一个unsigned long 型参数数组中, 再将这些参数传递给内核的__开头的函数库。

B. 注意:为什么是unsigned long ? 因为unsigned long 可以存储指针的地址。 还有这里有不同的recv版本的,这个和当时编译的环境相关

C. 不过这里没有对入口参数进行判断,会不会被黑客利用?



3. ntohl.c

#if __BYTE_ORDER == __BIG_ENDIAN

uint32_t ntohl (uint32_t x)

{

return x;

}



uint16_t ntohs (uint16_t x)

{

return x;

}



uint32_t htonl (uint32_t x)

{

return x;

}



uint16_t htons (uint16_t x)

{

return x;

}

#elif __BYTE_ORDER == __LITTLE_ENDIAN

uint32_t ntohl (uint32_t x)

{

return __bswap_32(x);

}



uint16_t ntohs (uint16_t x)

{

return __bswap_16(x);

}



uint32_t htonl (uint32_t x)

{

return __bswap_32(x);

}



uint16_t htons (uint16_t x)

{

return __bswap_16(x);

}

#else

#error "You seem to have an unsupported byteorder"

#endif

4. 对上面代码分析: 三种模式: 大端,小端,不可识别的。

大端的时候是uclinux默认的,而小端就需要用函数转换一下了



5. getaddrinfo.c

libc_hidden_proto(getaddrinfo)

int

getaddrinfo(const char *name, const char *service,

const struct addrinfo *hints, struct addrinfo **pai)

{

int i = 0, j, last_i = 0;

struct addrinfo *p = NULL, **end;

const struct gaih *g = gaih, *pg = NULL;

struct gaih_service gaih_service, *pservice;

struct addrinfo default_hints;



if (name != NULL && name[0] == '*' && name[1] == 0)

name = NULL;



if (service != NULL && service[0] == '*' && service[1] == 0)

service = NULL;



if (name == NULL && service == NULL)

return EAI_NONAME;



if (hints == NULL) {

memset(&default_hints, 0, sizeof(default_hints));

if (AF_UNSPEC)

default_hints.ai_family = AF_UNSPEC;

hints = &default_hints;

}



if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|

AI_ADDRCONFIG|AI_V4MAPPED|AI_NUMERICSERV|AI_ALL))

return EAI_BADFLAGS;



if ((hints->ai_flags & AI_CANONNAME) && name == NULL)

return EAI_BADFLAGS;



if (service && service[0]) {

char *c;

gaih_service.name = service;

gaih_service.num = strtoul(gaih_service.name, &c, 10);

if (*c != '/0') {

if (hints->ai_flags & AI_NUMERICSERV)

return EAI_NONAME;

gaih_service.num = -1;

} else {

/*

* Can't specify a numerical socket unless a protocol

* family was given.

*/

if (hints->ai_socktype == 0 && hints->ai_protocol == 0)

return EAI_SERVICE;

}

pservice = &gaih_service;

} else

pservice = NULL;



end = NULL;

if (pai)

end = &p;



j = 0;

while (g->gaih) {

if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) {

if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family)) {

++g;

continue;

}

j++;

if (pg == NULL || pg->gaih != g->gaih) {

pg = g;

i = g->gaih(name, pservice, hints, end);

if (i != 0) {

last_i = i;

if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))

continue;

if (p)

freeaddrinfo(p);

return -(i & GAIH_EAI);

}

if (end)

while (*end)

end = &((*end)->ai_next);

}

}

++g;

}



if (j == 0)

return EAI_FAMILY;



if (p) {

*pai = p;

return 0;

}



if (pai == NULL && last_i == 0)

return 0;



/* if (p) - never happens, see above */

/* freeaddrinfo(p); */



return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;

}

libc_hidden_def(getaddrinfo)

6. 对上面代码的分析:

A. 比较复杂

B. 太懒了,不想看,也看不懂



7. 对这些代码阅读之后的感想。

怎样才是一个合格或者是熟练的uclinux 上的软件开发工程师?这里只说C。。 我想应该要用熟练这个库里提供的所有函数,这样应该就OK了,有心人的话,也可以把这些函数库全部读一遍,有个一两年Linux平台下C开发经验的人,读这个应该很快的吧,而且会得心应手,发现uclibc的库真简单,难点不是太多,但是全部掌握这个库也要花点心血的。

应该没有必要去重写这个库,不过,用这个库去做一些实事,倒是最为重要的。这个目标和大部分库的目标是一样的。 为了让更多人使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐