xref: /minix/external/bsd/nvi/dist/ipc/ip_trans.c (revision 84d9c625)
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