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 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 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 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 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 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 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 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