核心態socket程式設計
阿新 • • 發佈:2019-01-29
記不清從哪個kernel版本開始,核心態就不能直接使用系統呼叫了。當然,socket的系統呼叫也不能用了。不過好在kernel提供了一組核心態的socket API。在net/socket.c檔案中,可以看到這麼幾個匯出符號:
[cpp] view plaincopyprint?- EXPORT_SYMBOL(kernel_sendmsg);
- EXPORT_SYMBOL(kernel_recvmsg);
- EXPORT_SYMBOL(sock_create_kern);
- EXPORT_SYMBOL(sock_release);
-
EXPORT_SYMBOL(kernel_bind);
- EXPORT_SYMBOL(kernel_listen);
- EXPORT_SYMBOL(kernel_accept);
- EXPORT_SYMBOL(kernel_connect);
- EXPORT_SYMBOL(kernel_getsockname);
- EXPORT_SYMBOL(kernel_getpeername);
- EXPORT_SYMBOL(kernel_getsockopt);
- EXPORT_SYMBOL(kernel_setsockopt);
- EXPORT_SYMBOL(kernel_sendpage);
-
EXPORT_SYMBOL(kernel_sock_ioctl);
- EXPORT_SYMBOL(kernel_sock_shutdown);
基本上,在使用者態的socket的API,在核心態都有對應的API。
下面是一個專案中的程式碼,socket操作我加了注視。不用去關心程式碼功能,只要看一下socket部分的操作即可,非常簡單。
[cpp]view plaincopyprint?- #include <linux/socket.h>
- #include <linux/net.h>
- #include <linux/in.h>
- struct fsg_common{
- ....
-
struct
- struct msghdr encrypt_msg;
- struct sockaddr_in encrypt_servaddr;
- struct data_pkt *encrypt_pkt;
- }
- staticint encrypt_socket_init(struct fsg_common *common)
- {
- struct socket *sock;
- int ret;
- char *dst_addr = "111.111.111.111";
- /* init servaddr */
- memset(&common->encrypt_servaddr, 0, sizeof(common->encrypt_servaddr));
- common->encrypt_servaddr.sin_family = AF_INET;
- common->encrypt_servaddr.sin_port = htons(9999);
- //kernel態的IP地址轉換函式,有兩個函式in4_pton和in6_pton,分別用於IPv4和IPv6
- in4_pton(dst_addr, strlen(dst_addr), (u8*)&common->encrypt_servaddr.sin_addr, '\0', NULL);
- //核心態udp通訊地址使用struct msghdr封裝
- common->encrypt_msg.msg_name = &common->encrypt_servaddr;
- common->encrypt_msg.msg_namelen = sizeof(common->encrypt_servaddr);
- //建立套接字,類似socket()函式,返回的sock指標就是後面資料傳遞用的套接字了
- ret = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
- if (ret < 0 || NULL == sock) {
- ERROR(common, "init encrypt board socket fail\n");
- return ret;
- }
- common->encrypt_sock = sock;
- common->encrypt_pkt = kmalloc(sizeof(struct data_pkt), GFP_KERNEL);
- if (NULL == common->encrypt_pkt)
- return -1;
- return 0;
- }
- staticvoid encrypt_socket_close(struct fsg_common *common)
- {
- //關閉套接字,類似使用者態的close()函式
- sock_release(common->encrypt_sock);
- common->encrypt_sock = NULL;
- }
- staticint encrypt_data(struct fsg_common *common, u8* data, unsigned int size, loff_t offset)
- {
- struct socket *sock = common->encrypt_sock;
- struct data_pkt *pkt = common->encrypt_pkt;
- struct sockaddr *pservaddr = (struct sockaddr *)&common->encrypt_servaddr;
- int servlen = sizeof(common->encrypt_servaddr);
- if (unlikely(NULL == sock || NULL == pkt || NULL == pservaddr))
- return -1;
- memset(pkt, 0, sizeof(struct data_pkt));
- unsigned int copied_size = 0;
- struct kvec vec;
- struct msghdr msg;
- memset(&msg, 0, sizeof(msg));
- while (copied_size < size) {
- pkt->res=0xffffffff;
- pkt->file_offset = offset;
- memcpy(pkt->data, data + copied_size, SECTOR_SIZE);
- //配置udp傳送資料地址及長度
- vec.iov_base = (void *)pkt;
- vec.iov_len = sizeof(struct data_pkt);
- ret = kernel_sendmsg(sock, &common->encrypt_msg, &vec, 1, sizeof(struct data_pkt));
- printk("send data(return :%d):\n", ret);
- //接收udp報文
- ret = kernel_recvmsg(sock, &msg, &vec, 1, sizeof(struct data_pkt), 0);
- printk("recv data(return :%d):\n", ret);
- memcpy(data+copied_size, pkt->data, 512);
- copied_size += 512;
- }
- return 0;
- }