阅读Sofia-SIP源码 - su模块 - su.h
来源:互联网 发布:淘宝女装logo图片 编辑:程序博客网 时间:2024/05/16 01:46
此头文件最开始部分都是约定俗成的内容,这里就不再多啰嗦了。然后是包含自身软件包内的头文件,以及针对BSD平台或WINDOWS平台包含不同的头文件。这些都很好理解。
然后是常量定义。首先,为BSD平台定义INVALID_SOCKET和SOCKET_ERROR这两个windows平台下特有的常量,以及定义软件包特有的两个常量:su_sucess和su_failure。再为上述最后两个常量各定义一个别名:SU_SUCESS和SU_FAILURE。以及其他一些常用的长度常量。
/* ---------------------------------------------------------------------- *//* Constant definitions */#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLYenum { /** Invalid socket descriptor, error from socket() or accept() */ INVALID_SOCKET = -1,#define INVALID_SOCKET ((su_socket_t)INVALID_SOCKET) /** Error from other socket calls */ SOCKET_ERROR = -1,#define SOCKET_ERROR SOCKET_ERROR /** Return code for a successful call */ su_success = 0, /** Return code for an unsuccessful call */ su_failure = -1};#if SYMBIAN && !defined(MSG_NOSIGNAL)#define MSG_NOSIGNAL (0)#endif#elif SU_HAVE_WINSOCKenum { su_success = 0, su_failure = 0xffffffffUL};#define MSG_NOSIGNAL (0)#endif/**@HI Maximum size of host name. */#define SU_MAXHOST (1025)/**@HI Maximum size of service name. */#define SU_MAXSERV (25)/**@HI Maximum size of address in text format. */#define SU_ADDRSIZE (48)/**@HI Maximum size of port number in text format. */#define SU_SERVSIZE (16)#define SU_SUCCESS su_success#define SU_FAILURE su_failure
紧接着是socket描述符类型。
#if SU_HAVE_BSDSOCK || DOCUMENTATION_ONLYtypedef int su_socket_t;#elif SU_HAVE_WINSOCKtypedef SOCKET su_socket_t;#endif我们都知道windows平台和其他平台下的socket描述符不一致。windows平台的描述符类型是SOCKET,而其他平台是int。为了抹平不同平台下的差异,Sofia软件包又定义了一个su_socket_t类型作为socket描述符类型。
之前在阅读su_configure.h头文件时,遇到过SU_HAVE_SOCKADDR_STORAGE宏,不知道它的具体含义。这次在这个头文件中看到了使用它的地方。当初在头文件中我是这么注释的:
/** Define as 1 if you have struct sockaddr_storage */ #define SU_HAVE_SOCKADDR_STORAGE 1 widnows平台下看到有这个结构体,因此为1。含义很明显,因为有这个结构体所以这个宏为1。但这个结构体有什么作用呢?因此我上网仔细查了查。找到了MSDN网页:https://msdn.microsoft.com/en-us/library/windows/desktop/ms740504(v=vs.85).aspx。网页上第一段就是对这个结构体的描述:
The SOCKADDR_STORAGE structure stores socket address information. Since the SOCKADDR_STORAGE structure is sufficiently large to store address information for IPv4, IPv6, or other address families, its use promotes protocol-family and protocol-version independence and simplifies cross-platform development. Use the SOCKADDR_STORAGE structure in place of the sockaddr structure.
typedef struct sockaddr_storage { short ss_family; char __ss_pad1[_SS_PAD1SIZE]; __int64 __ss_align; char __ss_pad2[_SS_PAD2SIZE];} SOCKADDR_STORAGE, *PSOCKADDR_STORAGE;说的很明白了,引入这个结构体是为了跨平台而用。而且它空间足够大,能够容纳任何地址家族的地址信息。再来看su.h头文件中接下来的代码:
#if !SU_HAVE_SOCKADDR_STORAGE/* * RFC 2553: protocol-independent placeholder for socket addresses */#define _SS_MAXSIZE128#define _SS_ALIGNSIZE(sizeof(int64_t))#define _SS_PAD1SIZE(_SS_ALIGNSIZE - sizeof(u_char) * 2)#define _SS_PAD2SIZE(_SS_MAXSIZE - sizeof(u_char) * 2 - \_SS_PAD1SIZE - _SS_ALIGNSIZE)struct sockaddr_storage {#if SU_HAVE_SOCKADDR_SA_LENunsigned char ss_len;/* address length */unsigned char ss_family;/* address family */#elseunsigned short ss_family;/* address family */#endifchar__ss_pad1[_SS_PAD1SIZE];int64_t __ss_align;/* force desired structure storage alignment */char__ss_pad2[_SS_PAD2SIZE];};#endif目的很明确,如果系统中没有sockaddr_storage结构体,那么Sofia就自己定义一个。在这之前定义了一些结构体会用到的宏。关于sockaddr结构体的其他一些信息,这里有一篇文章可以参考下:http://blog.chinaunix.net/uid-7596647-id-2607376.html。
然后是定义了一个大的union类型。
/** Common socket address structure. */union su_sockaddr_u {#ifdef DOCUMENTATION_ONLY uint8_t su_len; /**< Length of structure */ uint8_t su_family; /**< Address family. */ uint16_t su_port; /**< Port number. */#else short su_dummy; /**< Dummy member to initialize */#if SU_HAVE_SOCKADDR_SA_LEN#define su_len su_sa.sa_len#else#define su_len su_array[0]#endif#define su_family su_sa.sa_family#define su_port su_sin.sin_port#endif char su_array[32]; /**< Presented as chars */ uint16_t su_array16[16]; /**< Presented as 16-bit ints */ uint32_t su_array32[8]; /**< Presented as 32-bit ints */ struct sockaddr su_sa; /**< Address in struct sockaddr format */ struct sockaddr_in su_sin; /**< Address in IPv4 format */#if SU_HAVE_IN6 struct sockaddr_in6 su_sin6; /**< Address in IPv6 format */#endif#ifdef DOCUMENTATION_ONLY uint32_t su_scope_id; /**< Scope ID. */#else#define su_scope_id su_array32[6]#endif};注释文字显示这是一个通用的socket地址结构体。看到union内放入了很多其他的结构体类型:sockaddr、sockaddr_in和sockaddr_in6。不知为何要放这么多结构体类在一个union内。
接下来是:I/O vector for scatter-gather I/O。关于scatter-gather I/O是什么见后面的附录。应该就是一个针对scatter-gather I/O DMA模式的结构体。它在windows平台下的定义不同于其他平台。因为scatter-gather I/O DMA模式使用了不连续的空间,所以我认为这里的vector解释成向量也行,这个单词也有载体的意思。这个结构体将会被su_vsend()和su_vrecv()两个函数使用。
typedef u_long su_ioveclen_t;
typedef struct su_iovec_s { su_ioveclen_t siv_len; void *siv_base;} su_iovec_t;
typedef struct __WSABUF { u_long len; char FAR* buf; } WSABUF, *LPWSABUF;这个结构体在windows平台下被定义成上面第二张图。仔细观察会发现它与WSABUF结构体一致。
typedef size_t su_ioveclen_t;
typedef struct su_iovec_s { void *siv_base;/**< Pointer to buffer. */ su_ioveclen_t siv_len;/**< Size of buffer. */} su_iovec_t;
struct iovec { void *iov_base; // Pointer to data. size_t iov_len; // Length of data. };这个结构体在非windows平台下被定义成上面第二张图。仔细观察会发现它与POSIX sockets下的iovec结构体一致。
最后各自又定义了SU_IOVECLEN_MAX:
/*non widows*/#define SU_IOVECLEN_MAX SIZE_MAX/*windows*/#define SU_IOVECLEN_MAX ULONG_MAX还有一点不同之处在于windows平台下结构体的成员顺序是颠倒的。长度成员在前,数据成员在后。注释里并没有给出具体的原因,但注释指出了一点:不要整体初始化这个结构体,而是分别给各个成员赋值。
最后一部分,是为了跨平台用又定义了一套socket相关的api。这里有初始化(su_init),有退出时调用的清理函数(su_deinit)等等。具体如何实现跨平台的,得看su.c文件了。除了这些引起我关注的是这个函数:
SOFIAPUBFUN int su_is_blocking(int errcode);申明它并没有在任何平台相关的宏判断下,也就是说所有平台都会申明这个函数。在这之后,又看到了这样一些代码:
#if SU_HAVE_BSDSOCK#define su_ioctl ioctl/* * Note: before 1.12.2, there was su_isblocking() which did not take argument * and which was missing from WINSOCK */#define su_is_blocking(e) \ ((e) == EINPROGRESS || (e) == EAGAIN || (e) == EWOULDBLOCK)#endif
这段代码的意思是如果这是在非windows平台下,再定义这两个宏。综合这两处代码,是否可以得出:在非windows平台下,先申明一个函数,然后还可以用一个宏来覆盖之前这个函数申明。特意去su.c文件内查看了下,su_is_blocking函数定义确实是在特定条件下才出现,即在windows平台下编译su_is_blocking函数定义才会出现。
#if SU_HAVE_WINSOCKSOFIAPUBFUN int su_inet_pton(int af, char const *src, void *dst);SOFIAPUBFUN const char *su_inet_ntop(int af, void const *src, char *dst, size_t size);SOFIAPUBFUN ssize_t su_send(su_socket_t s, void *buffer, size_t length, int flags), su_sendto(su_socket_t s, void *buffer, size_t length, int flags, su_sockaddr_t const *to, socklen_t tolen), su_recv(su_socket_t s, void *buffer, size_t length, int flags), su_recvfrom(su_socket_t s, void *buffer, size_t length, int flags, su_sockaddr_t *from, socklen_t *fromlen);static __inlineuint16_t su_ntohs(uint16_t s){ return (uint16_t)(((s & 255) << 8) | ((s & 0xff00) >> 8));}static __inlineuint32_t su_ntohl(uint32_t l){ return ((l & 0xff) << 24) | ((l & 0xff00) << 8) | ((l & 0xff0000) >> 8) | ((l & 0xff000000U) >> 24);}#define ntohs su_ntohs#define htons su_ntohs#define ntohl su_ntohl#define htonl su_ntohl#else#define su_inet_pton inet_pton#define su_inet_ntop inet_ntop#define su_send(s,b,l,f) send((s),(b),(l),(f))#define su_sendto(s,b,l,f,a,L) sendto((s),(b),(l),(f),(void const*)(a),(L))#define su_recv(s,b,l,f) recv((s),(b),(l),(f))#define su_recvfrom(s,b,l,f,a,L) recvfrom((s),(b),(l),(f),(void *)(a),(L))#endif上述这段代码也是非常有意思,我想大部分的跨平台C代码可能都会这些写。首先su模块内申明的通用接口一般与类linux接口相同。所以通用接口在非windows平台下都可以像上述#else部分一样,定义一些宏即可。windows平台下通用API的接口定义成与Linux接口一致,然后再在.c文件内完成具体实现。
附
scatter/gather I/O
- 阅读Sofia-SIP源码 - su模块 - su.h
- 阅读Sofia-SIP源码 - su模块 - su_debug.h/su_module_debug.h
- 阅读Sofia-SIP源码 - su模块 - su_log.c/su_log.h
- 阅读Sofia-SIP源码 - su模块 - su_alloc.c/h
- 阅读Sofia-SIP源码 - su模块 - su.c
- 阅读Sofia-SIP源码 - su模块 - su_configure.h/su_config.h/su_types.h
- 阅读Sofia-SIP源码 - su模块 - su_default_log.c/su_global_log.c
- Sofia-SIP辅助文档七 - Sofia SIP用户代理库 - "su" - 操作系统功能和工具
- freeswitch源码阅读 之 sofia模块
- 阅读Sofia-SIP源码三 源码文件结构
- 阅读Sofia-SIP源码一 全局宏定义
- su
- SU
- Su
- su
- su
- su
- su
- 深度链接、延迟深度链接、App Links以及关于LinkedME实现深度链接的原理解析
- 文章标题
- 带返回值的线程:Callable、Future和FutureTask
- NYOJ_119_士兵杀敌(三)
- Android Sensor传感器系统架构初探
- 阅读Sofia-SIP源码 - su模块 - su.h
- sqlite3 在arm板上的编译
- 采用CreateThread()创建多线程程序
- 修改Tomcat的默认主页为你自己项目的主页
- A tale of two viewports
- hd 1872 稳定排序(结构体+sort)
- 【NYOJ】[845]无主之地1
- MarkdownPad2.5 注册码
- Android定制出厂默认输入法(其他设置类似)