LwIP之套接字接口
生活随笔
收集整理的這篇文章主要介紹了
LwIP之套接字接口
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
/* 套接字結構體 */
struct lwip_sock
{/* API連接指針 */struct netconn *conn;/* 前一次讀剩下的數據 */void *lastdata;/* 前一次讀數據的偏移量 */u16_t lastoffset;/* 接收數據的次數 */s16_t rcvevent;/* 發送成功的次數 */u16_t sendevent;/* 錯誤發生次數 */u16_t errevent; /* 最近發生的錯誤 */int err;/* 所有select描述符個數 */int select_waiting;
};/* select控制塊 */
struct lwip_select_cb
{/* 用于將所有控制塊連接起來 */struct lwip_select_cb *next;struct lwip_select_cb *prev;/* 讀描述符集合 */fd_set *readset;/* 寫描述符集合 */fd_set *writeset;/* 異常描述符集合 */fd_set *exceptset;/* 觸發事件設1 */int sem_signalled;/* 信號量 */sys_sem_t sem;
};/* 套接字屬性數據 */
struct lwip_setgetsockopt_data
{/* 所屬套接字 */struct lwip_sock *sock;int level; //層int optname; //選項名字void *optval; //數據socklen_t *optlen; //數據長度err_t err;
};/* 套接字數組 */
static struct lwip_sock sockets[NUM_SOCKETS];
/* select鏈表 */
static struct lwip_select_cb *select_cb_list;
/* 鏈表發生改變時就加一 */
static volatile int select_cb_ctr;/* 錯誤類型 */
static const int err_to_errno_table[] = {0, /* ERR_OK 0 No error, everything OK. */ENOMEM, /* ERR_MEM -1 Out of memory error. */ENOBUFS, /* 內存不足 */EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */EINVAL, /* 參數錯誤 */EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */EADDRINUSE, /* ERR_USE -8 Address in use. */EALREADY, /* ERR_ISCONN -9 Already connected. */ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ECONNRESET, /* ERR_RST -11 Connection reset. */ENOTCONN, /* ERR_CLSD -12 Connection closed. */ENOTCONN, /* ERR_CONN -13 Not connected. */EIO, /* 內部錯誤 */-1, /* ERR_IF -15 Low-level netif error */
};#define ERR_TO_ERRNO_TABLE_SIZE \(sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))#define err_to_errno(err) \((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \err_to_errno_table[-(err)] : EIO)#define set_errno(err)/* 套接字設置錯誤 */
#define sock_set_errno(sk, e) do { \sk->err = (e); \set_errno(sk->err); \
} while (0)static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
static void lwip_getsockopt_internal(void *arg);
static void lwip_setsockopt_internal(void *arg);/* socket編程初始化 */
void lwip_socket_init(void)
{
}/* 根據套接字描述符獲取套接字結構體指針 */
static struct lwip_sock *get_socket(int s)
{struct lwip_sock *sock;if((s < 0) || (s >= NUM_SOCKETS)) {set_errno(EBADF);return NULL;}sock = &sockets[s];if(!sock->conn) {set_errno(EBADF);return NULL;}return sock;
}/* 通過套接字描述符獲取套接字 */
static struct lwip_sock *tryget_socket(int s)
{if((s < 0) || (s >= NUM_SOCKETS)) {return NULL;}if(!sockets[s].conn) {return NULL;}return &sockets[s];
}/* 創建套接字描述符 */
static int alloc_socket(struct netconn *newconn, int accepted)
{int i;/* 找一個空的套接字描述符 */for(i = 0; i < NUM_SOCKETS; ++i) {if(!sockets[i].conn) {/* 初始化所有參數 */sockets[i].conn = newconn;SYS_ARCH_UNPROTECT(lev);sockets[i].lastdata = NULL;sockets[i].lastoffset = 0;sockets[i].rcvevent = 0;sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);sockets[i].errevent = 0;sockets[i].err = 0;sockets[i].select_waiting = 0;return i;}}return -1;
}/* 釋放套接字 */
static void free_socket(struct lwip_sock *sock, int is_tcp)
{void *lastdata;lastdata = sock->lastdata;sock->lastdata = NULL;sock->lastoffset = 0;sock->err = 0;sock->conn = NULL;/* 釋放已經收到未取用的數據 */if(lastdata != NULL) {if(is_tcp) {pbuf_free((struct pbuf *)lastdata);} else {netbuf_delete((struct netbuf *)lastdata);}}
}/* 接受連接 */
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{struct lwip_sock *sock, *nsock;struct netconn *newconn;ip_addr_t naddr;u16_t port;int newsock;struct sockaddr_in sin;err_t err;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 非阻塞,并且沒有連接事件,返回錯誤 */if(netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {sock_set_errno(sock, EWOULDBLOCK);return -1;}/* 接受連接 */err = netconn_accept(sock->conn, &newconn);if(err != ERR_OK) {if(netconn_type(sock->conn) != NETCONN_TCP) {sock_set_errno(sock, EOPNOTSUPP);return EOPNOTSUPP;}sock_set_errno(sock, err_to_errno(err));return -1;}/* 設置不自動接收數據 */netconn_set_noautorecved(newconn, 1);/* 獲取本地IP和端口號 */err = netconn_peer(newconn, &naddr, &port);if(err != ERR_OK) {netconn_delete(newconn);sock_set_errno(sock, err_to_errno(err));return -1;}/* 填充sockaddr_in結構體 */if(NULL != addr) {memset(&sin, 0, sizeof(sin));sin.sin_len = sizeof(sin);sin.sin_family = AF_INET;sin.sin_port = htons(port);inet_addr_from_ipaddr(&sin.sin_addr, &naddr);if(*addrlen > sizeof(sin))*addrlen = sizeof(sin);MEMCPY(addr, &sin, *addrlen);}/* 為新連接創建新的套接字描述符 */newsock = alloc_socket(newconn, 1);if(newsock == -1) {netconn_delete(newconn);sock_set_errno(sock, ENFILE);return -1;}nsock = &sockets[newsock];nsock->rcvevent += (s16_t)(-1 - newconn->socket);newconn->socket = newsock;sock_set_errno(sock, 0);/* 返回套接字描述符 */return newsock;
}/* 綁定本地端口 */
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{struct lwip_sock *sock;ip_addr_t local_addr;u16_t local_port;err_t err;const struct sockaddr_in *name_in;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 類型轉換 */name_in = (const struct sockaddr_in *)(void *)name;/* 取出IP地址和端口號 */inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);local_port = name_in->sin_port;/* 綁定本地端口 */err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));if(err != ERR_OK) {sock_set_errno(sock, err_to_errno(err));return -1;}sock_set_errno(sock, 0);return 0;
}/* 關閉套接字 */
int lwip_close(int s)
{struct lwip_sock *sock;int is_tcp = 0;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}if(sock->conn != NULL) {is_tcp = netconn_type(sock->conn) == NETCONN_TCP;} /* 刪除連接 */netconn_delete(sock->conn);/* 釋放套接字 */free_socket(sock, is_tcp);set_errno(0);return 0;
}/* 連接遠程端口 */
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{struct lwip_sock *sock;err_t err;const struct sockaddr_in *name_in;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 類型轉換 */name_in = (const struct sockaddr_in *)(void*)name;if(name_in->sin_family == AF_UNSPEC) {err = netconn_disconnect(sock->conn);} else {ip_addr_t remote_addr;u16_t remote_port;/* 取出IP和端口號 */inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);remote_port = name_in->sin_port;/* 連接遠程端口 */err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));}if(err != ERR_OK) {sock_set_errno(sock, err_to_errno(err));return -1;}sock_set_errno(sock, 0);return 0;
}/* 偵聽 */
int lwip_listen(int s, int backlog)
{struct lwip_sock *sock;err_t err;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 監聽隊列最大數 */backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);/* 開始偵聽 */err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);if(err != ERR_OK) {if(netconn_type(sock->conn) != NETCONN_TCP) {sock_set_errno(sock, EOPNOTSUPP);return EOPNOTSUPP;}sock_set_errno(sock, err_to_errno(err));return -1;}sock_set_errno(sock, 0);return 0;
}/* 接收數據(可選非阻塞/數據接收后不刪除,返回遠程IP和端口號) */
int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
{struct lwip_sock *sock;void *buf = NULL;struct pbuf *p;u16_t buflen, copylen;int off = 0;ip_addr_t *addr;u16_t port;u8_t done = 0;err_t err;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}do {/* 前一次讀剩下數據 */if(sock->lastdata) {buf = sock->lastdata;}/* 前一次沒有讀剩下數據 */else {/* 非阻塞態,且沒有數據 */if(((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && (sock->rcvevent <= 0)) {if(off > 0) {netconn_recved(sock->conn, (u32_t)off);sock_set_errno(sock, 0);return off;}sock_set_errno(sock, EWOULDBLOCK);return -1;}/* 接收數據 */if(netconn_type(sock->conn) == NETCONN_TCP) {err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);} else {err = netconn_recv(sock->conn, (struct netbuf **)&buf);}/* 更新接收窗口 */if(err != ERR_OK) {if(off > 0) {netconn_recved(sock->conn, (u32_t)off);sock_set_errno(sock, 0);return off;}sock_set_errno(sock, err_to_errno(err));if(err == ERR_CLSD) {return 0;} else {return -1;}}sock->lastdata = buf;}/* 取出數據pbuf */if(netconn_type(sock->conn) == NETCONN_TCP) {p = (struct pbuf *)buf;} else {p = ((struct netbuf *)buf)->p;}/* 數據長度 */buflen = p->tot_len;buflen -= sock->lastoffset;if(len > buflen) {copylen = buflen;} else{copylen = (u16_t)len;}/* 將數據拷貝出來 */pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);off += copylen;/* 數據是否讀完 */if(netconn_type(sock->conn) == NETCONN_TCP) {len -= copylen;if((len <= 0) || (p->flags & PBUF_FLAG_PUSH) || (sock->rcvevent <= 0) || ((flags & MSG_PEEK) != 0)) {done = 1;}} else {done = 1;}/* 數據讀完 */if(done) {ip_addr_t fromaddr;if(from && fromlen) {struct sockaddr_in sin;/* 獲取遠程IP和端口號 */if(netconn_type(sock->conn) == NETCONN_TCP) {addr = &fromaddr;netconn_getaddr(sock->conn, addr, &port, 0);} else {addr = netbuf_fromaddr((struct netbuf *)buf);port = netbuf_fromport((struct netbuf *)buf);}memset(&sin, 0, sizeof(sin));sin.sin_len = sizeof(sin);sin.sin_family = AF_INET;sin.sin_port = htons(port);inet_addr_from_ipaddr(&sin.sin_addr, addr);if(*fromlen > sizeof(sin)) {*fromlen = sizeof(sin);}MEMCPY(from, &sin, *fromlen);} }/* 釋放已經讀取的數據 */if((flags & MSG_PEEK) == 0) {if((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {sock->lastdata = buf;sock->lastoffset += copylen;} else {sock->lastdata = NULL;sock->lastoffset = 0;if(netconn_type(sock->conn) == NETCONN_TCP) {pbuf_free((struct pbuf *)buf);} else {netbuf_delete((struct netbuf *)buf);}}}}while(!done);/* 更新接收窗口 */if(off > 0) {netconn_recved(sock->conn, (u32_t)off);}sock_set_errno(sock, 0);return off;
}/* 接收數據 */
int lwip_read(int s, void *mem, size_t len)
{return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}/* 接收數據 */
int lwip_recv(int s, void *mem, size_t len, int flags)
{return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}/* 發送數據(用于已經綁定遠程IP和端口號) */
int lwip_send(int s, const void *data, size_t size, int flags)
{struct lwip_sock *sock;err_t err;u8_t write_flags;size_t written;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 發送非TCP數據 */if(sock->conn->type != NETCONN_TCP) {return lwip_sendto(s, data, size, flags, NULL, 0);}/* TCP發送數據 */write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);written = 0;err = netconn_write_partly(sock->conn, data, size, write_flags, &written);sock_set_errno(sock, err_to_errno(err));return (err == ERR_OK ? (int)written : -1);
}/* 發送數據(用于未綁定遠程IP和端口號) */
int lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen)
{struct lwip_sock *sock;err_t err;u16_t short_size;const struct sockaddr_in *to_in;u16_t remote_port;struct netbuf buf;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* TCP發送數據 */if(sock->conn->type == NETCONN_TCP) {return lwip_send(s, data, size, flags);}short_size = (u16_t)size;to_in = (const struct sockaddr_in *)(void*)to;buf.p = buf.ptr = NULL;/* 設置netbuf遠程IP和端口號 */if(to) {inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);remote_port = ntohs(to_in->sin_port);netbuf_fromport(&buf) = remote_port;} else {remote_port = 0;ip_addr_set_any(&buf.addr);netbuf_fromport(&buf) = 0;}/* 為netbuf申請PBUF_REF型pbuf內存,指向已存在RAM */err = netbuf_ref(&buf, data, short_size);/* UDP或RAW發送數據 */if(err == ERR_OK) {err = netconn_send(sock->conn, &buf);}/* 釋放netbuf */netbuf_free(&buf);sock_set_errno(sock, err_to_errno(err));return (err == ERR_OK ? short_size : -1);
}/* 創建套接字 */
int lwip_socket(int domain, int type, int protocol)
{struct netconn *conn;int i;/* 判斷套接字類型 */switch(type) {/* 原始套接字 */case SOCK_RAW:/* 創建一個原始IP連接并且設置回調函數 */conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);break;/* 數據報套接字 */case SOCK_DGRAM:/* 創建一個UDP連接結構體并且設置回調函數 */conn = netconn_new_with_callback((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP, event_callback);break;/* 流式套接字 */case SOCK_STREAM:/* 創建一個TCP連接結構體并且設置回調函數 */conn = netconn_new_with_callback(NETCONN_TCP, event_callback);if(conn != NULL) {/* 設置不自動接收數據 */netconn_set_noautorecved(conn, 1);}break;default:set_errno(EINVAL);return -1;}if(!conn) {set_errno(ENOBUFS);return -1;}/* 創建套接字描述符 */i = alloc_socket(conn, 0);/* 失敗 */if(i == -1) {/* 刪除連接 */netconn_delete(conn);set_errno(ENFILE);return -1;}/* 套接字描述符 */conn->socket = i;set_errno(0);return i;
}/* 發送數據(用于已經綁定遠程IP和端口號) */
int lwip_write(int s, const void *data, size_t size)
{return lwip_send(s, data, size, 0);
}/* 掃描讀寫錯誤集合有沒有事件發生 */
static int lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
{int i, nready = 0;fd_set lreadset, lwriteset, lexceptset;struct lwip_sock *sock;/* 清空所有集合 */FD_ZERO(&lreadset);FD_ZERO(&lwriteset);FD_ZERO(&lexceptset);/* 檢查所有描述符 */for(i = 0; i < maxfdp1; i++) {void* lastdata = NULL;s16_t rcvevent = 0;u16_t sendevent = 0;u16_t errevent = 0;/* 通過套接字描述符獲取套接字 */sock = tryget_socket(i);/* 獲取套接字已經發生的事件數 */if(sock != NULL) {lastdata = sock->lastdata;rcvevent = sock->rcvevent;sendevent = sock->sendevent;errevent = sock->errevent;}/* 該描述符發生讀事件且屬于讀集合 */if(readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {/* 設置讀事件 */FD_SET(i, &lreadset);nready++;}/* 該描述符發生寫事件且屬于寫集合 */if(writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {/* 設置寫事件 */FD_SET(i, &lwriteset);nready++;}/* 該描述符發生異常事件且屬于異常集合 */if(exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {/* 設置異常事件 */FD_SET(i, &lexceptset);nready++;}}/* 返回讀寫異常事件集合 */*readset_out = lreadset;*writeset_out = lwriteset;*exceptset_out = lexceptset;return nready;
}/* 多路復用 */
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout)
{u32_t waitres = 0;int nready;fd_set lreadset, lwriteset, lexceptset;u32_t msectimeout;struct lwip_select_cb select_cb;err_t err;int i;/* 掃描讀寫錯誤集合有沒有事件發生 */nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);/* 沒有事件發生 */if(!nready) {/* 阻塞時間0 */if(timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {goto return_copy_fdsets;}/* 創建select信號 */select_cb.next = NULL;select_cb.prev = NULL;select_cb.readset = readset;select_cb.writeset = writeset;select_cb.exceptset = exceptset;select_cb.sem_signalled = 0;err = sys_sem_new(&select_cb.sem, 0);if(err != ERR_OK) {set_errno(ENOMEM);return -1;}/* 插入select鏈表 */select_cb.next = select_cb_list;if(select_cb_list != NULL) {select_cb_list->prev = &select_cb;}select_cb_list = &select_cb;select_cb_ctr++;/* 統計需要select描述符個數 */for(i = 0; i < maxfdp1; i++) {if((readset && FD_ISSET(i, readset)) ||(writeset && FD_ISSET(i, writeset)) ||(exceptset && FD_ISSET(i, exceptset))) {struct lwip_sock *sock = tryget_socket(i);sock->select_waiting++;}}/* 掃描讀寫錯誤集合有沒有事件發生 */nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);/* 沒有事件發生 */if(!nready) {/* 永遠阻塞 */if(timeout == 0) {msectimeout = 0;} /* 阻塞時間 */else {msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));if(msectimeout == 0) {msectimeout = 1;}}/* 等待事件發生 */waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);}/* 檢查是否有改變 */for(i = 0; i < maxfdp1; i++) {if((readset && FD_ISSET(i, readset)) ||(writeset && FD_ISSET(i, writeset)) ||(exceptset && FD_ISSET(i, exceptset))) {struct lwip_sock *sock = tryget_socket(i);sock->select_waiting--;}}/* 將select控制塊從鏈表刪除 */if(select_cb.next != NULL) {select_cb.next->prev = select_cb.prev;}if(select_cb_list == &select_cb) {select_cb_list = select_cb.next;} else {select_cb.prev->next = select_cb.next;}select_cb_ctr++;/* 釋放信號量 */sys_sem_free(&select_cb.sem);/* 超時 */if(waitres == SYS_ARCH_TIMEOUT) {goto return_copy_fdsets;}/* 掃描讀寫錯誤集合有沒有事件發生 */nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);}return_copy_fdsets:set_errno(0);/* 返回發生事件集合 */if(readset) {*readset = lreadset;}if(writeset) {*writeset = lwriteset;}if(exceptset) {*exceptset = lexceptset;}return nready;
}/* 套接字回調函數 */
static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
{int s;struct lwip_sock *sock;struct lwip_select_cb *scb;int last_select_cb_ctr;if(conn) {s = conn->socket;if(s < 0) {if(conn->socket < 0) {if(evt == NETCONN_EVT_RCVPLUS) {conn->socket--;}return;}s = conn->socket;}/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return;}} else {return;}/* 事件處理 */switch(evt) {case NETCONN_EVT_RCVPLUS:sock->rcvevent++;break;case NETCONN_EVT_RCVMINUS:sock->rcvevent--;break;case NETCONN_EVT_SENDPLUS:sock->sendevent = 1;break;case NETCONN_EVT_SENDMINUS:sock->sendevent = 0;break;case NETCONN_EVT_ERROR:sock->errevent = 1;break;default:break;}if(sock->select_waiting == 0) {return;}again:/* 檢查是否存在select事件 */for(scb = select_cb_list; scb != NULL; scb = scb->next) {if(scb->sem_signalled == 0) {int do_signal = 0;if(sock->rcvevent > 0){if(scb->readset && FD_ISSET(s, scb->readset)) {do_signal = 1;}}if(sock->sendevent != 0) {if(!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {do_signal = 1;}}if(sock->errevent != 0) {if(!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {do_signal = 1;}}/* 存在則解除阻塞 */if(do_signal) {scb->sem_signalled = 1;sys_sem_signal(&scb->sem);}}last_select_cb_ctr = select_cb_ctr;if(last_select_cb_ctr != select_cb_ctr) {goto again;}}
}/* 關閉套接字連接方向 */
int lwip_shutdown(int s, int how)
{struct lwip_sock *sock;err_t err;u8_t shut_rx = 0, shut_tx = 0;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}if(sock->conn != NULL) {if(netconn_type(sock->conn) != NETCONN_TCP) {sock_set_errno(sock, EOPNOTSUPP);return EOPNOTSUPP;}} else {sock_set_errno(sock, ENOTCONN);return ENOTCONN;}/* 關閉連接方向 */if(how == SHUT_RD) {shut_rx = 1;} else if(how == SHUT_WR) {shut_tx = 1;} else if(how == SHUT_RDWR) {shut_rx = 1;shut_tx = 1;} else {sock_set_errno(sock, EINVAL);return EINVAL;}err = netconn_shutdown(sock->conn, shut_rx, shut_tx);sock_set_errno(sock, err_to_errno(err));return (err == ERR_OK ? 0 : -1);
}/* 獲取本地或者遠程IP和端口號 */
static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
{struct lwip_sock *sock;struct sockaddr_in sin;ip_addr_t naddr;/* 根據套接字描述符獲取套接字結構體指針 */sock = get_socket(s);if(!sock) {return -1;}/* 獲取本地或者遠程IP和端口號 */memset(&sin, 0, sizeof(sin));sin.sin_len = sizeof(sin);sin.sin_family = AF_INET;netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);sin.sin_port = htons(sin.sin_port);inet_addr_from_ipaddr(&sin.sin_addr, &naddr);if(*namelen > sizeof(sin)) {*namelen = sizeof(sin);}MEMCPY(name, &sin, *namelen);sock_set_errno(sock, 0);return 0;
}/* 獲取遠程IP和端口號 */
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{return lwip_getaddrname(s, name, namelen, 0);
}/* 獲取本地IP和端口號 */
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{return lwip_getaddrname(s, name, namelen, 1);
}/* 獲取套接字屬性 */
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{err_t err = ERR_OK;struct lwip_sock *sock = get_socket(s);struct lwip_setgetsockopt_data data;if(!sock) {return -1;}if((NULL == optval) || (NULL == optlen)) {sock_set_errno(sock, EFAULT);return -1;}/* 判斷參數合不合理 */switch(level) {/* 套接字層 */case SOL_SOCKET:/* 選項名 */switch (optname) {case SO_ACCEPTCONN:case SO_BROADCAST:/* UNIMPL case SO_DEBUG: *//* UNIMPL case SO_DONTROUTE: */case SO_ERROR:case SO_KEEPALIVE:/* UNIMPL case SO_CONTIMEO: *//* UNIMPL case SO_OOBINLINE: *//* UNIMPL case SO_SNDBUF: *//* UNIMPL case SO_RCVLOWAT: *//* UNIMPL case SO_SNDLOWAT: */case SO_TYPE:/* UNIMPL case SO_USELOOPBACK: */if(*optlen < sizeof(int)) {err = EINVAL;}break;case SO_NO_CHECK:if(*optlen < sizeof(int)) {err = EINVAL;}if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {err = EAFNOSUPPORT;}break;default:err = ENOPROTOOPT;}break;/* IP層 */case IPPROTO_IP:switch(optname) {/* UNIMPL case IP_HDRINCL: *//* UNIMPL case IP_RCVDSTADDR: *//* UNIMPL case IP_RCVIF: */case IP_TTL:case IP_TOS:if(*optlen < sizeof(int)) {err = EINVAL;}break;default:err = ENOPROTOOPT;}break;/* TCP層 */case IPPROTO_TCP:if(*optlen < sizeof(int)) {err = EINVAL;break;}if(sock->conn->type != NETCONN_TCP)return 0;/* 選項名 */switch(optname) {case TCP_NODELAY:case TCP_KEEPALIVE:break;default:err = ENOPROTOOPT;}break;/* Level: IPPROTO_UDPLITE */case IPPROTO_UDPLITE:if(*optlen < sizeof(int)) {err = EINVAL;break;}if(sock->conn->type != NETCONN_UDPLITE) {return 0;}switch(optname) {case UDPLITE_SEND_CSCOV:case UDPLITE_RECV_CSCOV:break;default:err = ENOPROTOOPT;}break;/* UNDEFINED LEVEL */default:err = ENOPROTOOPT;}if(err != ERR_OK) {sock_set_errno(sock, err);return -1;}/* 通知內核調用lwip_getsockopt_internal函數來處理套接字選項 */data.sock = sock;data.level = level;data.optname = optname;data.optval = optval;data.optlen = optlen;data.err = err;tcpip_callback(lwip_getsockopt_internal, &data);sys_arch_sem_wait(&sock->conn->op_completed, 0);err = data.err;sock_set_errno(sock, err);return err ? -1 : 0;
}/* 獲取套接字選項 */
static void lwip_getsockopt_internal(void *arg)
{struct lwip_sock *sock;int level, optname;void *optval;struct lwip_setgetsockopt_data *data;data = (struct lwip_setgetsockopt_data *)arg;sock = data->sock;level = data->level;optname = data->optname;optval = data->optval;switch(level) {/* 套接字層 */case SOL_SOCKET:switch(optname) {case SO_ACCEPTCONN:case SO_BROADCAST:/* UNIMPL case SO_DEBUG: *//* UNIMPL case SO_DONTROUTE: */case SO_KEEPALIVE:/* UNIMPL case SO_OOBINCLUDE: *//*case SO_USELOOPBACK: UNIMPL */*(int *)optval = ip_get_option(sock->conn->pcb.ip, optname);break;case SO_TYPE:switch(NETCONNTYPE_GROUP(sock->conn->type)) {case NETCONN_RAW:*(int*)optval = SOCK_RAW;break;case NETCONN_TCP:*(int*)optval = SOCK_STREAM;break;case NETCONN_UDP:*(int*)optval = SOCK_DGRAM;break;default:*(int*)optval = sock->conn->type;}break;case SO_ERROR:if((sock->err == 0) || (sock->err == EINPROGRESS)) {sock_set_errno(sock, err_to_errno(sock->conn->last_err));} *(int *)optval = sock->err;sock->err = 0;break;case SO_NO_CHECK:*(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;break;default:break;}break;/* Level: IPPROTO_IP */case IPPROTO_IP:switch(optname) {case IP_TTL:*(int*)optval = sock->conn->pcb.ip->ttl;break;case IP_TOS:*(int*)optval = sock->conn->pcb.ip->tos;break;default:break;}break;case IPPROTO_TCP:switch(optname) {case TCP_NODELAY:*(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);break;case TCP_KEEPALIVE:*(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;break;default:LWIP_ASSERT("unhandled optname", 0);break;}break;case IPPROTO_UDPLITE:switch(optname) {case UDPLITE_SEND_CSCOV:*(int*)optval = sock->conn->pcb.udp->chksum_len_tx;break;case UDPLITE_RECV_CSCOV:*(int*)optval = sock->conn->pcb.udp->chksum_len_rx;break;default:break;}break;default:break;}sys_sem_signal(&sock->conn->op_completed);
}/* 設置套接字屬性 */
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{struct lwip_sock *sock = get_socket(s);err_t err = ERR_OK;struct lwip_setgetsockopt_data data;if(!sock) {return -1;}if(NULL == optval) {sock_set_errno(sock, EFAULT);return -1;}/* 判斷參數合不合理 */switch(level) {
/* Level: SOL_SOCKET */case SOL_SOCKET:switch (optname) {case SO_BROADCAST:/* UNIMPL case SO_DEBUG: *//* UNIMPL case SO_DONTROUTE: */case SO_KEEPALIVE:/* UNIMPL case case SO_CONTIMEO: *//* UNIMPL case SO_OOBINLINE: *//* UNIMPL case SO_SNDBUF: *//* UNIMPL case SO_RCVLOWAT: *//* UNIMPL case SO_SNDLOWAT: *//* UNIMPL case SO_USELOOPBACK: */if(optlen < sizeof(int)) {err = EINVAL;}break;case SO_NO_CHECK:if(optlen < sizeof(int)) {err = EINVAL;}if((sock->conn->type != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {err = EAFNOSUPPORT;}break;default:err = ENOPROTOOPT;}break;/* Level: IPPROTO_IP */case IPPROTO_IP:switch(optname) {/* UNIMPL case IP_HDRINCL: *//* UNIMPL case IP_RCVDSTADDR: *//* UNIMPL case IP_RCVIF: */case IP_TTL:case IP_TOS:if(optlen < sizeof(int)) {err = EINVAL;}break;default:err = ENOPROTOOPT;}break;/* Level: IPPROTO_TCP */case IPPROTO_TCP:if(optlen < sizeof(int)) {err = EINVAL;break;}if(sock->conn->type != NETCONN_TCP)return 0;switch(optname) {case TCP_NODELAY:case TCP_KEEPALIVE:break;default:err = ENOPROTOOPT;}break;/* Level: IPPROTO_UDPLITE */case IPPROTO_UDPLITE:if(optlen < sizeof(int)) {err = EINVAL;break;}if(sock->conn->type != NETCONN_UDPLITE)return 0;switch(optname) {case UDPLITE_SEND_CSCOV:case UDPLITE_RECV_CSCOV:break;default:err = ENOPROTOOPT;}break;/* UNDEFINED LEVEL */default:err = ENOPROTOOPT;}if(err != ERR_OK) {sock_set_errno(sock, err);return -1;}/* 通知內核調用lwip_setsockopt_internal函數來處理套接字選項 */data.sock = sock;data.level = level;data.optname = optname;data.optval = (void*)optval;data.optlen = &optlen;data.err = err;tcpip_callback(lwip_setsockopt_internal, &data);sys_arch_sem_wait(&sock->conn->op_completed, 0);err = data.err;sock_set_errno(sock, err);return err ? -1 : 0;
}/* 設置套接字選項 */
static void lwip_setsockopt_internal(void *arg)
{struct lwip_sock *sock;int level, optname;const void *optval;struct lwip_setgetsockopt_data *data;data = (struct lwip_setgetsockopt_data*)arg;sock = data->sock;level = data->level;optname = data->optname;optval = data->optval;switch(level) {
/* Level: SOL_SOCKET */case SOL_SOCKET:switch(optname) {/* The option flags */case SO_BROADCAST:/* UNIMPL case SO_DEBUG: *//* UNIMPL case SO_DONTROUTE: */case SO_KEEPALIVE:/* UNIMPL case SO_OOBINCLUDE: *//* UNIMPL case SO_USELOOPBACK: */if(*(int*)optval) {ip_set_option(sock->conn->pcb.ip, optname);} else {ip_reset_option(sock->conn->pcb.ip, optname);}break;case SO_NO_CHECK:if(*(int*)optval) {udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);} else {udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);}break;default:break;} /* switch (optname) */break;/* Level: IPPROTO_IP */case IPPROTO_IP:switch(optname) {case IP_TTL:sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", s, sock->conn->pcb.ip->ttl));break;case IP_TOS:sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos));break;default:break;}break;/* Level: IPPROTO_TCP */case IPPROTO_TCP:switch(optname) {case TCP_NODELAY:if(*(int*)optval) {tcp_nagle_disable(sock->conn->pcb.tcp);} else {tcp_nagle_enable(sock->conn->pcb.tcp);}break;case TCP_KEEPALIVE:sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);break;default:break;}break;case IPPROTO_UDPLITE:switch (optname) {case UDPLITE_SEND_CSCOV:if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {sock->conn->pcb.udp->chksum_len_tx = 8;} else {sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;}break;case UDPLITE_RECV_CSCOV:if((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {sock->conn->pcb.udp->chksum_len_rx = 8;} else {sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;}break;default:break;}break;default:break;}/* 通知完成 */sys_sem_signal(&sock->conn->op_completed);
}/* 設置IO屬性 */
int lwip_ioctl(int s, long cmd, void *argp)
{/* 根據套接字描述符獲取套接字結構體指針 */struct lwip_sock *sock = get_socket(s);u8_t val;if(!sock) {return -1;}switch(cmd) {/* 設置非阻塞 */case FIONBIO:val = 0;if(argp && *(u32_t*)argp) {val = 1;}netconn_set_nonblocking(sock->conn, val);sock_set_errno(sock, 0);return 0;default:sock_set_errno(sock, ENOSYS); /* not yet implemented */return -1;}
}/* 文件屬性操作 */
int lwip_fcntl(int s, int cmd, int val)
{struct lwip_sock *sock = get_socket(s);int ret = -1;if(!sock || !sock->conn) {return -1;}switch(cmd) {case F_GETFL:ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;break;case F_SETFL:if((val & ~O_NONBLOCK) == 0) {netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);ret = 0;}break;default:break;}return ret;
}
?
總結
以上是生活随笔為你收集整理的LwIP之套接字接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CANOpen服务数据对象报文
- 下一篇: 为什么开源在计算机专业的学生中不那么流行