1 /*
2 * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 *
26 */
27
28
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/sysproto.h>
32 #include <string.h>
33
34 #include "ff_api.h"
35 #include "ff_ipc.h"
36 #include "netgraph.h"
37
38 static int
ngctl(int cmd,void * data,size_t len)39 ngctl(int cmd, void *data, size_t len)
40 {
41 struct ff_msg *msg, *retmsg = NULL;
42
43 msg = ff_ipc_msg_alloc();
44 if (msg == NULL) {
45 errno = ENOMEM;
46 return -1;
47 }
48
49 if (len > msg->buf_len) {
50 errno = EINVAL;
51 ff_ipc_msg_free(msg);
52 return -1;
53 }
54
55 msg->msg_type = FF_NGCTL;
56 msg->ngctl.cmd = cmd;
57 msg->ngctl.data = msg->buf_addr;
58
59 switch (cmd) {
60 case NGCTL_SOCKET:
61 case NGCTL_CLOSE:
62 memcpy(msg->ngctl.data, data, len);
63 break;
64 case NGCTL_BIND:
65 case NGCTL_CONNECT:
66 {
67 struct bind_args *src = (struct bind_args *)data;
68 struct bind_args *dst = (struct bind_args *)(msg->ngctl.data);
69 dst->s = src->s;
70 dst->name = (char *)msg->buf_addr + sizeof(struct bind_args);
71 dst->namelen = src->namelen;
72 memcpy(dst->name, src->name, src->namelen);
73 break;
74 }
75 case NGCTL_SEND:
76 {
77 struct sendto_args *src = (struct sendto_args *)data;
78 struct sendto_args *dst = (struct sendto_args *)(msg->ngctl.data);
79 dst->s = src->s;
80 dst->buf = (char *)msg->buf_addr + sizeof(struct sendto_args);
81 dst->len = src->len;
82 dst->flags = src->flags;
83 dst->to = dst->buf + src->len;
84 dst->tolen = src->tolen;
85 memcpy(dst->buf, src->buf, src->len);
86 memcpy(dst->to, src->to, src->tolen);
87 break;
88 }
89 case NGCTL_RECV:
90 {
91 struct recvfrom_args *src = (struct recvfrom_args *)data;
92 struct recvfrom_args *dst = (struct recvfrom_args *)(msg->ngctl.data);
93 dst->s = src->s;
94 dst->buf = msg->buf_addr + sizeof(struct recvfrom_args);
95 dst->len = src->len;
96 dst->flags = src->flags;
97 dst->from = (struct sockaddr *)dst->buf + src->len;
98 dst->fromlenaddr = (socklen_t *)dst->buf + src->len + *(src->fromlenaddr);
99 memcpy(dst->buf, src->buf, src->len);
100 memcpy(dst->from, src->from, *(src->fromlenaddr));
101 memcpy(dst->fromlenaddr, src->fromlenaddr, sizeof(socklen_t));
102 break;
103 }
104 default:
105 errno = EINVAL;
106 ff_ipc_msg_free(msg);
107 return -1;
108 }
109
110 int ret = ff_ipc_send(msg);
111 if (ret < 0) {
112 errno = EPIPE;
113 ff_ipc_msg_free(msg);
114 return -1;
115 }
116
117 do {
118 if (retmsg != NULL) {
119 ff_ipc_msg_free(retmsg);
120 }
121 ret = ff_ipc_recv(&retmsg, msg->msg_type);
122 if (ret < 0) {
123 errno = EPIPE;
124 return -1;
125 }
126 } while (msg != retmsg);
127
128 if (retmsg->result != 0) {
129 ret = -1;
130 errno = retmsg->result;
131 } else {
132 ret = msg->ngctl.ret;
133
134 if (cmd == NGCTL_RECV) {
135 struct recvfrom_args *dst = (struct recvfrom_args *)data;
136 struct recvfrom_args *src = (struct recvfrom_args *)(msg->ngctl.data);
137 memcpy(dst->buf, src->buf, src->len);
138 memcpy(dst->from, src->from, *(src->fromlenaddr));
139 memcpy(dst->fromlenaddr, src->fromlenaddr, sizeof(socklen_t));
140 }
141 }
142
143 ff_ipc_msg_free(msg);
144
145 return ret;
146 }
147
148 int
ng_socket(int domain,int type,int protocol)149 ng_socket(int domain, int type, int protocol)
150 {
151 struct socket_args sa;
152 sa.domain = domain;
153 sa.type = type;
154 sa.protocol = protocol;
155
156 return ngctl(NGCTL_SOCKET, (void *)&sa, sizeof(sa));
157 }
158
159 int
ng_bind(int sockfd,const struct sockaddr * addr,socklen_t addrlen)160 ng_bind(int sockfd, const struct sockaddr *addr,
161 socklen_t addrlen)
162 {
163 size_t len;
164 struct bind_args ba;
165
166 ba.s = sockfd;
167 ba.name = (char *)addr;
168 ba.namelen = addrlen;
169
170 len = sizeof(ba) + addrlen;
171
172 return ngctl(NGCTL_BIND, (void *)&ba, len);
173 }
174
175 int
ng_connect(int sockfd,const struct sockaddr * addr,socklen_t addrlen)176 ng_connect(int sockfd, const struct sockaddr *addr,
177 socklen_t addrlen)
178 {
179 size_t len;
180 struct connect_args ca;
181
182 ca.s = sockfd;
183 ca.name = (char *)addr;
184 ca.namelen = addrlen;
185
186 len = sizeof(ca) + addrlen;
187
188 return ngctl(NGCTL_CONNECT, (void *)&ca, len);
189 }
190
191 ssize_t
ng_sendto(int sockfd,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)192 ng_sendto(int sockfd, const void *buf, size_t len, int flags,
193 const struct sockaddr *dest_addr, socklen_t addrlen)
194 {
195 size_t datalen;
196
197 struct sendto_args sa;
198 sa.s = sockfd;
199 sa.buf = (void *)buf;
200 sa.len = len;
201 sa.flags = flags;
202 sa.to = (char *)dest_addr;
203 sa.tolen = addrlen;
204
205 datalen = sizeof(sa) + len + addrlen;
206 return ngctl(NGCTL_SEND, (void *)&sa, datalen);
207 }
208
209 ssize_t
ng_recvfrom(int sockfd,void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen)210 ng_recvfrom(int sockfd, void *buf, size_t len, int flags,
211 struct sockaddr *src_addr, socklen_t *addrlen)
212 {
213 size_t datalen;
214
215 struct recvfrom_args ra;
216 ra.s = sockfd;
217 ra.buf = buf;
218 ra.len = len;
219 ra.flags = flags;
220 ra.from = src_addr;
221 ra.fromlenaddr = addrlen;
222
223 datalen = sizeof(ra) + len + (*addrlen) + sizeof(socklen_t);
224 return ngctl(NGCTL_RECV, (void *)&ra, datalen);
225 }
226
227 int
ng_close(int fd)228 ng_close(int fd)
229 {
230 struct close_args ca;
231 ca.fd = fd;
232
233 return ngctl(NGCTL_CLOSE, (void *)&ca, sizeof(ca));
234 }
235
236