xref: /netbsd-src/external/bsd/nvi/dist/ipc/ip_trans.c (revision 2f698edb5c1cb2dcd9e762b0abb50c41dde8b6b7)
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
vi_input(IPVIWIN * ipviwin,int fd)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
vi_wsend(IPVIWIN * ipviwin,char * fmt,IP_BUF * ipbp)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
vi_translate(IPVIWIN * ipviwin,char * bp,size_t * lenp,IP_BUF * ipbp)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