标签:
1 int
2 lwip_socket(int domain, int type, int protocol)
3 {
4 struct netconn *conn;
5 int i;
6
7 LWIP_UNUSED_ARG(domain);
8
9 /* create a netconn */
10 switch (type) { // 根据用户传入的type区分TCP、UDP和RAW
11 case SOCK_RAW:
12 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
13 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
14 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
15 break;
16 case SOCK_DGRAM:
17 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
18 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
19 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
20 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
21 break;
22 case SOCK_STREAM:
23 conn = netconn_new_with_callback(NETCONN_TCP, event_callback); // 例如TCP在这个case里。这里新建一个netconn结构体。netconn是用户可见的socket和协议栈内部的protocol control block之间的桥梁,这里下文会分析
24 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
25 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
26 break;
27 default:
28 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
29 domain, type, protocol));
30 set_errno(EINVAL);
31 return -1;
32 }
33
34 if (!conn) {
35 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
36 set_errno(ENOBUFS);
37 return -1;
38 }
39
40 i = alloc_socket(conn); // 开辟一个socket,这个函数也很重要
41
42 if (i == -1) {
43 netconn_delete(conn);
44 set_errno(ENFILE);
45 return -1;
46 }
47 conn->socket = i;
48 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
49 set_errno(0);
50 return i;
51 }
1 /**
2 * Create a new netconn (of a specific type) that has a callback function.
3 * The corresponding pcb is also created.
4 *
5 * @param t the type of ‘connection‘ to create (@see enum netconn_type)
6 * @param proto the IP protocol for RAW IP pcbs
7 * @param callback a function to call on status changes (RX available, TX‘ed)
8 * @return a newly allocated struct netconn or
9 * NULL on memory error
10 */
11 struct netconn*
12 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
13 {
14 struct netconn *conn;
15 struct api_msg msg;
16
17 conn = netconn_alloc(t, callback); // 开辟一个netconn
18 if (conn != NULL ) {
19 msg.function = do_newconn; // do_newconn这个函数以msg的形式送给tcpip_thread()去处理,我们随后会分析。这里需要知道do_newconn会开辟一个pcb,并和已有的conn绑定。
20 msg.msg.msg.n.proto = proto;
21 msg.msg.conn = conn;
22 TCPIP_APIMSG(&msg);
23
24 if (conn->err != ERR_OK) {
25 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
26 LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
27 LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
28 LWIP_ASSERT("conn->acceptmbox shouldn‘t exist", conn->acceptmbox == SYS_MBOX_NULL);
29 sys_sem_free(conn->op_completed);
30 sys_mbox_free(conn->recvmbox);
31 memp_free(MEMP_NETCONN, conn);
32 return NULL;
33 }
34 }
35 return conn;
36 }
api_msg做了什么
1 msg.function = do_newconn; 2 msg.msg.msg.n.proto = proto; 3 msg.msg.conn = conn; 4 TCPIP_APIMSG(&msg);
首先来看TCPIP_APIMSG这个宏做了什么:1 #define TCPIP_APIMSG(m) tcpip_apimsg(m)
1 /** 2 * Call the lower part of a netconn_* function 3 * This function is then running in the thread context 4 * of tcpip_thread and has exclusive access to lwIP core code. 5 * 6 * @param apimsg a struct containing the function to call and its parameters 7 * @return ERR_OK if the function was called, another err_t if not 8 */ 9 err_t 10 tcpip_apimsg(struct api_msg *apimsg) 11 { 12 struct tcpip_msg msg; 13 14 if (mbox != SYS_MBOX_NULL) { 15 msg.type = TCPIP_MSG_API; // 随后在tcpip_thread()里解析这个msg时需要根据这个type确定走哪个分支 16 msg.msg.apimsg = apimsg; 17 sys_mbox_post(mbox, &msg); // mbox是一个全局mailbox,实际上是一个数组,元素是void*型指针,在tcpip_init里被初始化。这里把msg地址放到mbox里 18 sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0); 19 return ERR_OK; 20 } 21 return ERR_VAL; 22 }
至此,一个TCPIP_MSG_API type的msg被放到了mbox这个mailbox里,接下来tcpip_thread要从这个mailbox里取msg并对其进行处理,主要就是调用msg里的function。如下:
1 /** 2 * The main lwIP thread. This thread has exclusive access to lwIP core functions 3 * (unless access to them is not locked). Other threads communicate with this 4 * thread using message boxes. 5 * 6 * It also starts all the timers to make sure they are running in the right 7 * thread context. 8 * 9 * @param arg unused argument 10 */ 11 static void 12 tcpip_thread(void *arg) 13 { 14 struct tcpip_msg *msg; 15 LWIP_UNUSED_ARG(arg); 16 17 ...................... 18 19 LOCK_TCPIP_CORE(); 20 while (1) { /* MAIN Loop */ 21 sys_mbox_fetch(mbox, (void *)&msg); 22 switch (msg->type) { 23 #if LWIP_NETCONN 24 case TCPIP_MSG_API: 25 LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); 26 msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); // 这个function就是netconn_write()函数里赋值的do_newconn 27 break; 28 #endif /* LWIP_NETCONN */ 29 30 .............. 31 32 default: 33 break; 34 } 35 } 36 }
注意tcpip_thread()函数在tcpip.c(component\common\network\lwip\lwip_v1.3.2\src\api)里,可以认为是lwip api层的函数,只不过虽然名字叫api,但应用层并不是直接调用,应用层实际上是借mailbox与其交互的。当然用户并不知道mailbox的存在,应用层只需要直接调用send()这个lwip api,后续放入mailbox以及tcpip_thread从mailbox取走,都是lwip自己完成的。
1 void
2 do_newconn(struct api_msg_msg *msg)
3 {
4 if(msg->conn->pcb.tcp == NULL) {
5 pcb_new(msg);
6 }
7 ..........
8 }
1 static err_t
2 pcb_new(struct api_msg_msg *msg)
3 {
4 ....................
5 /* Allocate a PCB for this connection */
6 switch(NETCONNTYPE_GROUP(msg->conn->type)) {
7 ...................
8 #if LWIP_TCP
9 case NETCONN_TCP:
10 msg->conn->pcb.tcp = tcp_new(); // 新建一个tcp_pcb结构体,并把这个pcb与conn绑定起来
11 if(msg->conn->pcb.tcp == NULL) {
12 msg->conn->err = ERR_MEM;
13 break;
14 }
15 setup_tcp(msg->conn);
16 break;
17 #endif /* LWIP_TCP */
18 .................
19 }
20 ................
21 }
1 /**
2 * Allocate a new socket for a given netconn.
3 *
4 * @param newconn the netconn for which to allocate a socket
5 * @return the index of the new socket; -1 on error
6 */
7 static int
8 alloc_socket(struct netconn *newconn)
9 {
10 int i;
11
12 /* Protect socket array */
13 sys_sem_wait(socksem);
14
15 /* allocate a new socket identifier */
16 for (i = 0; i < NUM_SOCKETS; ++i) {
17 if (!sockets[i].conn) { // 从系统socket列表:sockets[]里寻找还没有被使用的
18 sockets[i].conn = newconn; // 找出一个未被使用的socket结构体,作为用户调用socket() API申请到的socket结构体,并把它和新建的netconn绑定。
19 sockets[i].lastdata = NULL;
20 sockets[i].lastoffset = 0;
21 sockets[i].rcvevent = 0;
22 sockets[i].sendevent = 1; /* TCP send buf is empty */
23 sockets[i].flags = 0;
24 sockets[i].err = 0;
25 sys_sem_signal(socksem);
26 return i; // 仅返回一个int型的i,即用户看不到这个socket结构体,只能socket结构体在socket列表里的index值,用户能使用的也就是这个int值
27 }
28 }
29 sys_sem_signal(socksem);
30 return -1;
31 }
1 /** The global array of available sockets */
2 static struct lwip_socket sockets[NUM_SOCKETS];
标签:
原文地址:http://www.cnblogs.com/codingfun/p/4187120.html