1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nstackx_socket.h"
17 #include "nstackx_log.h"
18 #include "nstackx_error.h"
19 #include "nstackx_util.h"
20 #include "nstackx_dev.h"
21 #include "securec.h"
22 
23 #define DEFAULT_UDP_MSS 1472
24 #define DEFAULT_MAX_BUF 4096
25 #define IOV_CNT 2
26 
27 #define TAG "nStackXSocket"
28 #ifndef SOL_UDP
29 #define SOL_UDP 17
30 #endif
31 
SocketModuleClean(void)32 void SocketModuleClean(void)
33 {
34     return;
35 }
36 
SocketModuleInit(void)37 int32_t SocketModuleInit(void)
38 {
39     return NSTACKX_EOK;
40 }
41 
SetSocketNonBlock(SocketDesc fd)42 int32_t SetSocketNonBlock(SocketDesc fd)
43 {
44     int32_t flag;
45 
46     flag = fcntl(fd, F_GETFL, 0);
47     if (flag < 0) {
48         LOGE(TAG, "fcntl GETFL error");
49         return NSTACKX_EFAILED;
50     }
51 
52     if (fcntl(fd, F_SETFL, (unsigned int)flag | O_NONBLOCK) < 0) {
53         LOGE(TAG, "fcntl SETFL error");
54         return NSTACKX_EFAILED;
55     }
56     return NSTACKX_EOK;
57 }
58 
SocketOpInProgress(void)59 int32_t SocketOpInProgress(void)
60 {
61     return errno == EINPROGRESS;
62 }
63 
SocketOpWouldBlock(void)64 int32_t SocketOpWouldBlock(void)
65 {
66     return errno == EAGAIN || errno == EWOULDBLOCK;
67 }
68 
SupportGSO(void)69 int32_t SupportGSO(void)
70 {
71     return 0;
72 }
73 
CheckGSOSupport(void)74 void CheckGSOSupport(void)
75 {
76     LOGI(TAG, "kernel does not support UDP GSO");
77 }
78 
79 #ifndef UDP_SEGMENT
80 #define UDP_SEGMENT     103
81 #endif
82 
SetupCmsg(struct cmsghdr * cm,uint16_t mss)83 static inline void SetupCmsg(struct cmsghdr *cm, uint16_t mss)
84 {
85     cm->cmsg_level = SOL_UDP;
86     cm->cmsg_type = UDP_SEGMENT;
87     cm->cmsg_len = CMSG_LEN(sizeof(mss));
88     *(uint16_t *)(void *)CMSG_DATA(cm) = mss;
89 }
90 
IsSocketValid(const Socket * s)91 static inline int32_t IsSocketValid(const Socket *s)
92 {
93     return !(s == NULL || s->protocol != NSTACKX_PROTOCOL_UDP);
94 }
95 
SocketSendEx(const Socket * s,uint16_t mss,const struct iovec * iov,uint32_t cnt)96 int32_t SocketSendEx(const Socket *s, uint16_t mss, const struct iovec *iov, uint32_t cnt)
97 {
98     int32_t ret = NSTACKX_EFAILED;
99     char ctrl[CMSG_SPACE(sizeof(uint16_t))] = {0};
100     struct msghdr mh;
101 
102     if (!IsSocketValid(s)) {
103         LOGE(TAG, "invalid socket input\n");
104         return ret;
105     }
106 
107     mh.msg_name = (struct sockaddr *)&s->dstAddr;
108     mh.msg_namelen = sizeof(struct sockaddr_in);
109     mh.msg_iov = (struct iovec *)iov;
110     mh.msg_iovlen = (size_t)cnt;
111     mh.msg_control = ctrl;
112     mh.msg_controllen = sizeof(ctrl);
113     mh.msg_flags = 0;
114 
115     SetupCmsg(CMSG_FIRSTHDR(&mh), mss);
116 
117     ret = (int32_t)sendmsg(s->sockfd, &mh, 0);
118     if (ret <= 0) {
119         ret = CheckSocketError();
120     }
121 
122     return ret;
123 }
124 
125