1 /* $NetBSD: ip_trans.c,v 1.4 2014/01/26 21:43:45 christos Exp $ */ 2 /*- 3 * Copyright (c) 1996 4 * Keith Bostic. All rights reserved. 5 * 6 * See the LICENSE file for redistribution information. 7 */ 8 9 #include "config.h" 10 11 #include <sys/cdefs.h> 12 #if 0 13 #ifndef lint 14 static const char sccsid[] = "Id: ip_trans.c,v 8.18 2001/06/25 15:19:25 skimo Exp (Berkeley) Date: 2001/06/25 15:19:25 "; 15 #endif /* not lint */ 16 #else 17 __RCSID("$NetBSD: ip_trans.c,v 1.4 2014/01/26 21:43:45 christos Exp $"); 18 #endif 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #ifdef HAVE_SYS_SELECT_H 23 #include <sys/select.h> 24 #endif 25 26 #include <bitstring.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <netinet/in.h> 31 32 #ifdef __STDC__ 33 #include <stdarg.h> 34 #else 35 #include <varargs.h> 36 #endif 37 38 #include "../common/common.h" 39 #include "ip.h" 40 #include "ipc_def.h" 41 42 static char ibuf[2048]; /* Input buffer. */ 43 static size_t ibuf_len; /* Length of current input. */ 44 45 extern IPFUNLIST const ipfuns[]; 46 47 /* 48 * vi_input -- 49 * Read from the vi message queue. 50 * 51 * PUBLIC: int vi_input __P((IPVIWIN *, int)); 52 */ 53 int 54 vi_input(IPVIWIN *ipviwin, int fd) 55 { 56 ssize_t nr; 57 58 /* Read waiting vi messages and translate to X calls. */ 59 switch (nr = read(fd, ibuf + ibuf_len, sizeof(ibuf) - ibuf_len)) { 60 case 0: 61 return (0); 62 case -1: 63 return (-1); 64 default: 65 break; 66 } 67 ibuf_len += nr; 68 69 /* Parse to data end or partial message. */ 70 (void)vi_translate(ipviwin, ibuf, &ibuf_len, NULL); 71 72 return (ibuf_len > 0); 73 } 74 75 /* 76 * vi_wsend -- 77 * Construct and send an IP buffer, and wait for an answer. 78 * 79 * PUBLIC: int vi_wsend __P((IPVIWIN*, char *, IP_BUF *)); 80 */ 81 int 82 vi_wsend(IPVIWIN *ipviwin, char *fmt, IP_BUF *ipbp) 83 { 84 fd_set rdfd; 85 ssize_t nr; 86 87 if (vi_send(ipviwin->ofd, fmt, ipbp)) 88 return (1); 89 90 FD_ZERO(&rdfd); 91 ipbp->code = CODE_OOB; 92 93 for (;;) { 94 FD_SET(ipviwin->ifd, &rdfd); 95 if (select(ipviwin->ifd + 1, &rdfd, NULL, NULL, NULL) != 0) 96 return (-1); 97 98 /* Read waiting vi messages and translate to X calls. */ 99 switch (nr = 100 read(ipviwin->ifd, ibuf + ibuf_len, sizeof(ibuf) - ibuf_len)) { 101 case 0: 102 return (0); 103 case -1: 104 return (-1); 105 default: 106 break; 107 } 108 ibuf_len += nr; 109 110 /* Parse to data end or partial message. */ 111 (void)vi_translate(ipviwin, ibuf, &ibuf_len, ipbp); 112 113 if (ipbp->code != CODE_OOB) 114 break; 115 } 116 return (0); 117 } 118 119 /* 120 * vi_translate -- 121 * Translate vi messages into function calls. 122 * 123 * PUBLIC: int vi_translate __P((IPVIWIN *, char *, size_t *, IP_BUF *)); 124 */ 125 int 126 vi_translate(IPVIWIN *ipviwin, char *bp, size_t *lenp, IP_BUF *ipbp) 127 { 128 IP_BUF ipb; 129 size_t len, needlen; 130 u_int32_t *vp; 131 const char *fmt; 132 char *p, *s_bp; 133 const char **vsp; 134 IPFunc fun; 135 136 memset(&ipb, 0, sizeof(ipb)); 137 for (s_bp = bp, len = *lenp; len > 0;) { 138 fmt = ipfuns[(ipb.code = bp[0])-1].format; 139 140 p = bp + IPO_CODE_LEN; 141 needlen = IPO_CODE_LEN; 142 for (; *fmt != '\0'; ++fmt) 143 switch (*fmt) { 144 case '1': /* Value #1. */ 145 vp = &ipb.val1; 146 goto value; 147 case '2': /* Value #2. */ 148 vp = &ipb.val2; 149 goto value; 150 case '3': /* Value #3. */ 151 vp = &ipb.val3; 152 value: needlen += IPO_INT_LEN; 153 if (len < needlen) 154 goto partial; 155 memcpy(vp, p, IPO_INT_LEN); 156 *vp = ntohl(*vp); 157 p += IPO_INT_LEN; 158 break; 159 case 'a': /* String #1. */ 160 vp = &ipb.len1; 161 vsp = &ipb.str1; 162 goto string; 163 case 'b': /* String #2. */ 164 vp = &ipb.len2; 165 vsp = &ipb.str2; 166 string: needlen += IPO_INT_LEN; 167 if (len < needlen) 168 goto partial; 169 memcpy(vp, p, IPO_INT_LEN); 170 *vp = ntohl(*vp); 171 p += IPO_INT_LEN; 172 needlen += *vp; 173 if (len < needlen) 174 goto partial; 175 *vsp = p; 176 p += *vp; 177 break; 178 } 179 bp += needlen; 180 len -= needlen; 181 182 /* 183 * XXX 184 * Protocol error!?!? 185 */ 186 if (ipb.code >= SI_EVENT_SUP) { 187 len = 0; 188 break; 189 } 190 191 /* 192 * If we're waiting for a reply and we got it, return it, and 193 * leave any unprocessed data in the buffer. If we got a reply 194 * and we're not waiting for one, discard it -- callers wait 195 * for responses. 196 */ 197 if (ipb.code == SI_REPLY) { 198 if (ipbp == NULL) 199 continue; 200 *ipbp = ipb; 201 break; 202 } 203 204 /* Call the underlying routine. */ 205 fun = *(IPFunc *) 206 (((char *)ipviwin->si_ops)+ipfuns[ipb.code - 1].offset); 207 if (fun != NULL && 208 ipfuns[ipb.code - 1].unmarshall(ipviwin, &ipb, fun)) 209 break; 210 } 211 partial: 212 if ((*lenp = len) != 0) 213 memmove(s_bp, bp, len); 214 return (0); 215 } 216