1 /* 2 * Copyright (C) 2017 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); 122 if (ret < 0) { 123 errno = EPIPE; 124 ff_ipc_msg_free(msg); 125 return -1; 126 } 127 } while (msg != retmsg); 128 129 if (retmsg->result != 0) { 130 ret = -1; 131 errno = retmsg->result; 132 } else { 133 ret = msg->ngctl.ret; 134 135 if (cmd == NGCTL_RECV) { 136 struct recvfrom_args *dst = (struct recvfrom_args *)data; 137 struct recvfrom_args *src = (struct recvfrom_args *)(msg->ngctl.data); 138 memcpy(dst->buf, src->buf, src->len); 139 memcpy(dst->from, src->from, *(src->fromlenaddr)); 140 memcpy(dst->fromlenaddr, src->fromlenaddr, sizeof(socklen_t)); 141 } 142 } 143 144 ff_ipc_msg_free(msg); 145 146 return ret; 147 } 148 149 int 150 ng_socket(int domain, int type, int protocol) 151 { 152 struct socket_args sa; 153 sa.domain = domain; 154 sa.type = type; 155 sa.protocol = protocol; 156 157 return ngctl(NGCTL_SOCKET, (void *)&sa, sizeof(sa)); 158 } 159 160 int 161 ng_bind(int sockfd, const struct sockaddr *addr, 162 socklen_t addrlen) 163 { 164 size_t len; 165 struct bind_args ba; 166 167 ba.s = sockfd; 168 ba.name = (char *)addr; 169 ba.namelen = addrlen; 170 171 len = sizeof(ba) + addrlen; 172 173 return ngctl(NGCTL_BIND, (void *)&ba, len); 174 } 175 176 int 177 ng_connect(int sockfd, const struct sockaddr *addr, 178 socklen_t addrlen) 179 { 180 size_t len; 181 struct connect_args ca; 182 183 ca.s = sockfd; 184 ca.name = (char *)addr; 185 ca.namelen = addrlen; 186 187 len = sizeof(ca) + addrlen; 188 189 return ngctl(NGCTL_CONNECT, (void *)&ca, len); 190 } 191 192 ssize_t 193 ng_sendto(int sockfd, const void *buf, size_t len, int flags, 194 const struct sockaddr *dest_addr, socklen_t addrlen) 195 { 196 size_t datalen; 197 198 struct sendto_args sa; 199 sa.s = sockfd; 200 sa.buf = (void *)buf; 201 sa.len = len; 202 sa.flags = flags; 203 sa.to = (char *)dest_addr; 204 sa.tolen = addrlen; 205 206 datalen = sizeof(sa) + len + addrlen; 207 return ngctl(NGCTL_SEND, (void *)&sa, datalen); 208 } 209 210 ssize_t 211 ng_recvfrom(int sockfd, void *buf, size_t len, int flags, 212 struct sockaddr *src_addr, socklen_t *addrlen) 213 { 214 size_t datalen; 215 216 struct recvfrom_args ra; 217 ra.s = sockfd; 218 ra.buf = buf; 219 ra.len = len; 220 ra.flags = flags; 221 ra.from = src_addr; 222 ra.fromlenaddr = addrlen; 223 224 datalen = sizeof(ra) + len + (*addrlen) + sizeof(socklen_t); 225 return ngctl(NGCTL_RECV, (void *)&ra, datalen); 226 } 227 228 int 229 ng_close(int fd) 230 { 231 struct close_args ca; 232 ca.fd = fd; 233 234 return ngctl(NGCTL_CLOSE, (void *)&ca, sizeof(ca)); 235 } 236 237