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