13b2bd0f6Slogwang /* 23b2bd0f6Slogwang * msg.c 33b2bd0f6Slogwang * 43b2bd0f6Slogwang * Copyright (c) 1996-1999 Whistle Communications, Inc. 53b2bd0f6Slogwang * All rights reserved. 63b2bd0f6Slogwang * 73b2bd0f6Slogwang * Subject to the following obligations and disclaimer of warranty, use and 83b2bd0f6Slogwang * redistribution of this software, in source or object code forms, with or 93b2bd0f6Slogwang * without modifications are expressly permitted by Whistle Communications; 103b2bd0f6Slogwang * provided, however, that: 113b2bd0f6Slogwang * 1. Any and all reproductions of the source or object code must include the 123b2bd0f6Slogwang * copyright notice above and the following disclaimer of warranties; and 133b2bd0f6Slogwang * 2. No rights are granted, in any manner or form, to use Whistle 143b2bd0f6Slogwang * Communications, Inc. trademarks, including the mark "WHISTLE 153b2bd0f6Slogwang * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 163b2bd0f6Slogwang * such appears in the above copyright notice or in the software. 173b2bd0f6Slogwang * 183b2bd0f6Slogwang * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 193b2bd0f6Slogwang * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 203b2bd0f6Slogwang * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 213b2bd0f6Slogwang * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 223b2bd0f6Slogwang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 233b2bd0f6Slogwang * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 243b2bd0f6Slogwang * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 253b2bd0f6Slogwang * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 263b2bd0f6Slogwang * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 273b2bd0f6Slogwang * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 283b2bd0f6Slogwang * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 293b2bd0f6Slogwang * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 303b2bd0f6Slogwang * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 313b2bd0f6Slogwang * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 323b2bd0f6Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 333b2bd0f6Slogwang * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 343b2bd0f6Slogwang * OF SUCH DAMAGE. 353b2bd0f6Slogwang * 363b2bd0f6Slogwang * Author: Archie Cobbs <[email protected]> 373b2bd0f6Slogwang * 383b2bd0f6Slogwang * $Whistle: msg.c,v 1.9 1999/01/20 00:57:23 archie Exp $ 393b2bd0f6Slogwang */ 403b2bd0f6Slogwang 413b2bd0f6Slogwang #include <sys/cdefs.h> 423b2bd0f6Slogwang __FBSDID("$FreeBSD$"); 433b2bd0f6Slogwang 443b2bd0f6Slogwang #include <sys/types.h> 453b2bd0f6Slogwang #include <sys/socket.h> 463b2bd0f6Slogwang #include <stdarg.h> 47*22ce4affSfengbojiang #include <stdatomic.h> 483b2bd0f6Slogwang #include <netgraph/ng_message.h> 493b2bd0f6Slogwang #include <netgraph/ng_socket.h> 503b2bd0f6Slogwang 513b2bd0f6Slogwang #include "netgraph.h" 523b2bd0f6Slogwang #include "internal.h" 533b2bd0f6Slogwang 543b2bd0f6Slogwang /* Next message token value */ 55*22ce4affSfengbojiang static _Atomic(unsigned int) gMsgId; 563b2bd0f6Slogwang 573b2bd0f6Slogwang /* For delivering both messages and replies */ 583b2bd0f6Slogwang static int NgDeliverMsg(int cs, const char *path, 593b2bd0f6Slogwang const struct ng_mesg *hdr, const void *args, size_t arglen); 603b2bd0f6Slogwang 613b2bd0f6Slogwang /* 623b2bd0f6Slogwang * Send a message to a node using control socket node "cs". 633b2bd0f6Slogwang * Returns -1 if error and sets errno appropriately. 643b2bd0f6Slogwang * If successful, returns the message ID (token) used. 653b2bd0f6Slogwang */ 663b2bd0f6Slogwang int 673b2bd0f6Slogwang NgSendMsg(int cs, const char *path, 683b2bd0f6Slogwang int cookie, int cmd, const void *args, size_t arglen) 693b2bd0f6Slogwang { 703b2bd0f6Slogwang struct ng_mesg msg; 713b2bd0f6Slogwang 723b2bd0f6Slogwang /* Prepare message header */ 733b2bd0f6Slogwang memset(&msg, 0, sizeof(msg)); 743b2bd0f6Slogwang msg.header.version = NG_VERSION; 753b2bd0f6Slogwang msg.header.typecookie = cookie; 76*22ce4affSfengbojiang msg.header.token = atomic_fetch_add(&gMsgId, 1) & INT_MAX; 773b2bd0f6Slogwang msg.header.flags = NGF_ORIG; 783b2bd0f6Slogwang msg.header.cmd = cmd; 793b2bd0f6Slogwang snprintf((char *)msg.header.cmdstr, NG_CMDSTRSIZ, "cmd%d", cmd); 803b2bd0f6Slogwang 813b2bd0f6Slogwang /* Deliver message */ 823b2bd0f6Slogwang if (NgDeliverMsg(cs, path, &msg, args, arglen) < 0) 833b2bd0f6Slogwang return (-1); 843b2bd0f6Slogwang return (msg.header.token); 853b2bd0f6Slogwang } 863b2bd0f6Slogwang 873b2bd0f6Slogwang /* 883b2bd0f6Slogwang * Send a message given in ASCII format. We first ask the node to translate 893b2bd0f6Slogwang * the command into binary, and then we send the binary. 903b2bd0f6Slogwang */ 913b2bd0f6Slogwang int 923b2bd0f6Slogwang NgSendAsciiMsg(int cs, const char *path, const char *fmt, ...) 933b2bd0f6Slogwang { 943b2bd0f6Slogwang struct ng_mesg *reply, *binary, *ascii; 953b2bd0f6Slogwang char *buf, *cmd, *args; 963b2bd0f6Slogwang va_list fmtargs; 973b2bd0f6Slogwang int token; 983b2bd0f6Slogwang 993b2bd0f6Slogwang /* Parse out command and arguments */ 1003b2bd0f6Slogwang va_start(fmtargs, fmt); 1013b2bd0f6Slogwang vasprintf(&buf, fmt, fmtargs); 1023b2bd0f6Slogwang va_end(fmtargs); 1033b2bd0f6Slogwang if (buf == NULL) 1043b2bd0f6Slogwang return (-1); 1053b2bd0f6Slogwang 1063b2bd0f6Slogwang /* Parse out command, arguments */ 1073b2bd0f6Slogwang for (cmd = buf; isspace(*cmd); cmd++) 1083b2bd0f6Slogwang ; 1093b2bd0f6Slogwang for (args = cmd; *args != '\0' && !isspace(*args); args++) 1103b2bd0f6Slogwang ; 1113b2bd0f6Slogwang if (*args != '\0') { 1123b2bd0f6Slogwang while (isspace(*args)) 1133b2bd0f6Slogwang *args++ = '\0'; 1143b2bd0f6Slogwang } 1153b2bd0f6Slogwang 1163b2bd0f6Slogwang /* Get a bigger buffer to hold inner message header plus arg string */ 1173b2bd0f6Slogwang if ((ascii = malloc(sizeof(struct ng_mesg) 1183b2bd0f6Slogwang + strlen(args) + 1)) == NULL) { 1193b2bd0f6Slogwang free(buf); 1203b2bd0f6Slogwang return (-1); 1213b2bd0f6Slogwang } 1223b2bd0f6Slogwang memset(ascii, 0, sizeof(*ascii)); 1233b2bd0f6Slogwang 1243b2bd0f6Slogwang /* Build inner header (only need cmdstr, arglen, and data fields) */ 1253b2bd0f6Slogwang strncpy((char *)ascii->header.cmdstr, cmd, 1263b2bd0f6Slogwang sizeof(ascii->header.cmdstr) - 1); 1273b2bd0f6Slogwang strcpy(ascii->data, args); 1283b2bd0f6Slogwang ascii->header.arglen = strlen(ascii->data) + 1; 1293b2bd0f6Slogwang free(buf); 1303b2bd0f6Slogwang 1313b2bd0f6Slogwang /* Send node a request to convert ASCII to binary */ 1323b2bd0f6Slogwang if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_ASCII2BINARY, 1333b2bd0f6Slogwang (u_char *)ascii, sizeof(*ascii) + ascii->header.arglen) < 0) { 1343b2bd0f6Slogwang free(ascii); 1353b2bd0f6Slogwang return (-1); 1363b2bd0f6Slogwang } 1373b2bd0f6Slogwang free(ascii); 1383b2bd0f6Slogwang 1393b2bd0f6Slogwang /* Get reply */ 1403b2bd0f6Slogwang if (NgAllocRecvMsg(cs, &reply, NULL) < 0) 1413b2bd0f6Slogwang return (-1); 1423b2bd0f6Slogwang 1433b2bd0f6Slogwang /* Now send binary version */ 1443b2bd0f6Slogwang binary = (struct ng_mesg *)reply->data; 145*22ce4affSfengbojiang binary->header.token = atomic_fetch_add(&gMsgId, 1) & INT_MAX; 1463b2bd0f6Slogwang binary->header.version = NG_VERSION; 1473b2bd0f6Slogwang if (NgDeliverMsg(cs, 1483b2bd0f6Slogwang path, binary, binary->data, binary->header.arglen) < 0) { 1493b2bd0f6Slogwang free(reply); 1503b2bd0f6Slogwang return (-1); 1513b2bd0f6Slogwang } 1523b2bd0f6Slogwang token = binary->header.token; 1533b2bd0f6Slogwang free(reply); 1543b2bd0f6Slogwang return (token); 1553b2bd0f6Slogwang } 1563b2bd0f6Slogwang 1573b2bd0f6Slogwang /* 1583b2bd0f6Slogwang * Send a message that is a reply to a previously received message. 1593b2bd0f6Slogwang * Returns -1 and sets errno on error, otherwise returns zero. 1603b2bd0f6Slogwang */ 1613b2bd0f6Slogwang int 1623b2bd0f6Slogwang NgSendReplyMsg(int cs, const char *path, 1633b2bd0f6Slogwang const struct ng_mesg *msg, const void *args, size_t arglen) 1643b2bd0f6Slogwang { 1653b2bd0f6Slogwang struct ng_mesg rep; 1663b2bd0f6Slogwang 1673b2bd0f6Slogwang /* Prepare message header */ 1683b2bd0f6Slogwang rep = *msg; 1693b2bd0f6Slogwang rep.header.flags = NGF_RESP; 1703b2bd0f6Slogwang 1713b2bd0f6Slogwang /* Deliver message */ 1723b2bd0f6Slogwang return (NgDeliverMsg(cs, path, &rep, args, arglen)); 1733b2bd0f6Slogwang } 1743b2bd0f6Slogwang 1753b2bd0f6Slogwang /* 1763b2bd0f6Slogwang * Send a message to a node using control socket node "cs". 1773b2bd0f6Slogwang * Returns -1 if error and sets errno appropriately, otherwise zero. 1783b2bd0f6Slogwang */ 1793b2bd0f6Slogwang static int 1803b2bd0f6Slogwang NgDeliverMsg(int cs, const char *path, 1813b2bd0f6Slogwang const struct ng_mesg *hdr, const void *args, size_t arglen) 1823b2bd0f6Slogwang { 1833b2bd0f6Slogwang u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; 1843b2bd0f6Slogwang struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 1853b2bd0f6Slogwang u_char *buf = NULL; 1863b2bd0f6Slogwang struct ng_mesg *msg; 1873b2bd0f6Slogwang int errnosv = 0; 1883b2bd0f6Slogwang int rtn = 0; 1893b2bd0f6Slogwang 1903b2bd0f6Slogwang /* Sanity check */ 1913b2bd0f6Slogwang if (args == NULL) 1923b2bd0f6Slogwang arglen = 0; 1933b2bd0f6Slogwang 1943b2bd0f6Slogwang /* Get buffer */ 1953b2bd0f6Slogwang if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) { 1963b2bd0f6Slogwang errnosv = errno; 1973b2bd0f6Slogwang if (_gNgDebugLevel >= 1) 1983b2bd0f6Slogwang NGLOG("malloc"); 1993b2bd0f6Slogwang rtn = -1; 2003b2bd0f6Slogwang goto done; 2013b2bd0f6Slogwang } 2023b2bd0f6Slogwang msg = (struct ng_mesg *) buf; 2033b2bd0f6Slogwang 2043b2bd0f6Slogwang /* Finalize message */ 2053b2bd0f6Slogwang *msg = *hdr; 2063b2bd0f6Slogwang msg->header.arglen = arglen; 2073b2bd0f6Slogwang memcpy(msg->data, args, arglen); 2083b2bd0f6Slogwang 2093b2bd0f6Slogwang /* Prepare socket address */ 2103b2bd0f6Slogwang sg->sg_family = AF_NETGRAPH; 2113b2bd0f6Slogwang /* XXX handle overflow */ 2123b2bd0f6Slogwang strlcpy(sg->sg_data, path, NG_PATHSIZ); 2133b2bd0f6Slogwang sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; 2143b2bd0f6Slogwang 2153b2bd0f6Slogwang /* Debugging */ 2163b2bd0f6Slogwang if (_gNgDebugLevel >= 2) { 2173b2bd0f6Slogwang NGLOGX("SENDING %s:", 2183b2bd0f6Slogwang (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); 2193b2bd0f6Slogwang _NgDebugSockaddr(sg); 2203b2bd0f6Slogwang _NgDebugMsg(msg, sg->sg_data); 2213b2bd0f6Slogwang } 2223b2bd0f6Slogwang 2233b2bd0f6Slogwang /* Send it */ 2243b2bd0f6Slogwang if (sendto(cs, msg, sizeof(*msg) + arglen, 2253b2bd0f6Slogwang 0, (struct sockaddr *) sg, sg->sg_len) < 0) { 2263b2bd0f6Slogwang errnosv = errno; 2273b2bd0f6Slogwang if (_gNgDebugLevel >= 1) 2283b2bd0f6Slogwang NGLOG("sendto(%s)", sg->sg_data); 2293b2bd0f6Slogwang rtn = -1; 2303b2bd0f6Slogwang goto done; 2313b2bd0f6Slogwang } 2323b2bd0f6Slogwang 2333b2bd0f6Slogwang /* Wait for reply if there should be one. */ 2343b2bd0f6Slogwang if (msg->header.cmd & NGM_HASREPLY && !(msg->header.flags & NGF_RESP)) { 2353b2bd0f6Slogwang struct pollfd rfds; 2363b2bd0f6Slogwang int n; 2373b2bd0f6Slogwang 2383b2bd0f6Slogwang rfds.fd = cs; 2393b2bd0f6Slogwang rfds.events = POLLIN; 2403b2bd0f6Slogwang rfds.revents = 0; 2413b2bd0f6Slogwang n = poll(&rfds, 1, INFTIM); 2423b2bd0f6Slogwang if (n == -1) { 2433b2bd0f6Slogwang errnosv = errno; 2443b2bd0f6Slogwang if (_gNgDebugLevel >= 1) 2453b2bd0f6Slogwang NGLOG("poll"); 2463b2bd0f6Slogwang rtn = -1; 2473b2bd0f6Slogwang } 2483b2bd0f6Slogwang } 2493b2bd0f6Slogwang 2503b2bd0f6Slogwang done: 2513b2bd0f6Slogwang /* Done */ 2523b2bd0f6Slogwang free(buf); /* OK if buf is NULL */ 2533b2bd0f6Slogwang errno = errnosv; 2543b2bd0f6Slogwang return (rtn); 2553b2bd0f6Slogwang } 2563b2bd0f6Slogwang 2573b2bd0f6Slogwang /* 2583b2bd0f6Slogwang * Receive a control message. 2593b2bd0f6Slogwang * 2603b2bd0f6Slogwang * On error, this returns -1 and sets errno. 2613b2bd0f6Slogwang * Otherwise, it returns the length of the received reply. 2623b2bd0f6Slogwang */ 2633b2bd0f6Slogwang int 2643b2bd0f6Slogwang NgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path) 2653b2bd0f6Slogwang { 2663b2bd0f6Slogwang u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; 2673b2bd0f6Slogwang struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; 2683b2bd0f6Slogwang socklen_t sglen = sizeof(sgbuf); 2693b2bd0f6Slogwang int len, errnosv; 2703b2bd0f6Slogwang 2713b2bd0f6Slogwang /* Read reply */ 2723b2bd0f6Slogwang len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen); 2733b2bd0f6Slogwang if (len < 0) { 2743b2bd0f6Slogwang errnosv = errno; 2753b2bd0f6Slogwang if (_gNgDebugLevel >= 1) 2763b2bd0f6Slogwang NGLOG("recvfrom"); 2773b2bd0f6Slogwang goto errout; 2783b2bd0f6Slogwang } 2793b2bd0f6Slogwang if (path != NULL) 2803b2bd0f6Slogwang strlcpy(path, sg->sg_data, NG_PATHSIZ); 2813b2bd0f6Slogwang 2823b2bd0f6Slogwang /* Debugging */ 2833b2bd0f6Slogwang if (_gNgDebugLevel >= 2) { 2843b2bd0f6Slogwang NGLOGX("RECEIVED %s:", 2853b2bd0f6Slogwang (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); 2863b2bd0f6Slogwang _NgDebugSockaddr(sg); 2873b2bd0f6Slogwang _NgDebugMsg(rep, sg->sg_data); 2883b2bd0f6Slogwang } 2893b2bd0f6Slogwang 2903b2bd0f6Slogwang /* Done */ 2913b2bd0f6Slogwang return (len); 2923b2bd0f6Slogwang 2933b2bd0f6Slogwang errout: 2943b2bd0f6Slogwang errno = errnosv; 2953b2bd0f6Slogwang return (-1); 2963b2bd0f6Slogwang } 2973b2bd0f6Slogwang 2983b2bd0f6Slogwang /* 2993b2bd0f6Slogwang * Identical to NgRecvMsg() except buffer is dynamically allocated. 3003b2bd0f6Slogwang */ 3013b2bd0f6Slogwang int 3023b2bd0f6Slogwang NgAllocRecvMsg(int cs, struct ng_mesg **rep, char *path) 3033b2bd0f6Slogwang { 3043b2bd0f6Slogwang int len; 3053b2bd0f6Slogwang socklen_t optlen; 3063b2bd0f6Slogwang 3073b2bd0f6Slogwang optlen = sizeof(len); 3083b2bd0f6Slogwang if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 3093b2bd0f6Slogwang (*rep = malloc(len)) == NULL) 3103b2bd0f6Slogwang return (-1); 3113b2bd0f6Slogwang if ((len = NgRecvMsg(cs, *rep, len, path)) < 0) 3123b2bd0f6Slogwang free(*rep); 3133b2bd0f6Slogwang return (len); 3143b2bd0f6Slogwang } 3153b2bd0f6Slogwang 3163b2bd0f6Slogwang /* 3173b2bd0f6Slogwang * Receive a control message and convert the arguments to ASCII 3183b2bd0f6Slogwang */ 3193b2bd0f6Slogwang int 3203b2bd0f6Slogwang NgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path) 3213b2bd0f6Slogwang { 3223b2bd0f6Slogwang struct ng_mesg *msg, *ascii; 3233b2bd0f6Slogwang int bufSize, errnosv; 3243b2bd0f6Slogwang u_char *buf; 3253b2bd0f6Slogwang 3263b2bd0f6Slogwang /* Allocate buffer */ 3273b2bd0f6Slogwang bufSize = 2 * sizeof(*reply) + replen; 3283b2bd0f6Slogwang if ((buf = malloc(bufSize)) == NULL) 3293b2bd0f6Slogwang return (-1); 3303b2bd0f6Slogwang msg = (struct ng_mesg *)buf; 3313b2bd0f6Slogwang ascii = (struct ng_mesg *)msg->data; 3323b2bd0f6Slogwang 3333b2bd0f6Slogwang /* Get binary message */ 3343b2bd0f6Slogwang if (NgRecvMsg(cs, msg, bufSize, path) < 0) 3353b2bd0f6Slogwang goto fail; 3363b2bd0f6Slogwang memcpy(reply, msg, sizeof(*msg)); 3373b2bd0f6Slogwang 3383b2bd0f6Slogwang /* Ask originating node to convert the arguments to ASCII */ 3393b2bd0f6Slogwang if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, 3403b2bd0f6Slogwang NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0) 3413b2bd0f6Slogwang goto fail; 3423b2bd0f6Slogwang if (NgRecvMsg(cs, msg, bufSize, NULL) < 0) 3433b2bd0f6Slogwang goto fail; 3443b2bd0f6Slogwang 3453b2bd0f6Slogwang /* Copy result to client buffer */ 3463b2bd0f6Slogwang if (sizeof(*ascii) + ascii->header.arglen > replen) { 3473b2bd0f6Slogwang errno = ERANGE; 3483b2bd0f6Slogwang fail: 3493b2bd0f6Slogwang errnosv = errno; 3503b2bd0f6Slogwang free(buf); 3513b2bd0f6Slogwang errno = errnosv; 3523b2bd0f6Slogwang return (-1); 3533b2bd0f6Slogwang } 3543b2bd0f6Slogwang strncpy(reply->data, ascii->data, ascii->header.arglen); 3553b2bd0f6Slogwang 3563b2bd0f6Slogwang /* Done */ 3573b2bd0f6Slogwang free(buf); 3583b2bd0f6Slogwang return (0); 3593b2bd0f6Slogwang } 3603b2bd0f6Slogwang 3613b2bd0f6Slogwang /* 3623b2bd0f6Slogwang * Identical to NgRecvAsciiMsg() except buffer is dynamically allocated. 3633b2bd0f6Slogwang */ 3643b2bd0f6Slogwang int 3653b2bd0f6Slogwang NgAllocRecvAsciiMsg(int cs, struct ng_mesg **reply, char *path) 3663b2bd0f6Slogwang { 3673b2bd0f6Slogwang int len; 3683b2bd0f6Slogwang socklen_t optlen; 3693b2bd0f6Slogwang 3703b2bd0f6Slogwang optlen = sizeof(len); 3713b2bd0f6Slogwang if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 || 3723b2bd0f6Slogwang (*reply = malloc(len)) == NULL) 3733b2bd0f6Slogwang return (-1); 3743b2bd0f6Slogwang if ((len = NgRecvAsciiMsg(cs, *reply, len, path)) < 0) 3753b2bd0f6Slogwang free(*reply); 3763b2bd0f6Slogwang return (len); 3773b2bd0f6Slogwang } 378