Commit | Line | Data |
---|---|---|
992de934 GM |
1 | /* |
2 | * Copyright (c) 1984-1987 by the Regents of the | |
3 | * University of California and by Gregory Glenn Minshall. | |
4 | * | |
5 | * Permission to use, copy, modify, and distribute these | |
6 | * programs and their documentation for any purpose and | |
7 | * without fee is hereby granted, provided that this | |
8 | * copyright and permission appear on all copies and | |
9 | * supporting documentation, the name of the Regents of | |
10 | * the University of California not be used in advertising | |
11 | * or publicity pertaining to distribution of the programs | |
12 | * without specific prior permission, and notice be given in | |
13 | * supporting documentation that copying and distribution is | |
14 | * by permission of the Regents of the University of California | |
15 | * and by Gregory Glenn Minshall. Neither the Regents of the | |
16 | * University of California nor Gregory Glenn Minshall make | |
17 | * representations about the suitability of this software | |
18 | * for any purpose. It is provided "as is" without | |
19 | * express or implied warranty. | |
20 | */ | |
21 | ||
22 | #ifndef lint | |
c578271f | 23 | static char sccsid[] = "@(#)api_exch.c 3.1 (Berkeley) %G%"; |
992de934 GM |
24 | #endif /* not lint */ |
25 | ||
ba212048 GM |
26 | #include <stdio.h> |
27 | ||
1117b0bd GM |
28 | #include "../general/general.h" |
29 | ||
ba212048 GM |
30 | #include "api_exch.h" |
31 | ||
62946391 GM |
32 | static int sock; /* Socket number */ |
33 | ||
224a681b | 34 | static char whoarewe[40] = ""; |
d024bcc4 GM |
35 | #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); |
36 | ||
37 | static enum {CONTENTION, SEND, RECEIVE } conversation; | |
38 | ||
39 | static struct exch_exch exch_state; | |
40 | ||
41 | static unsigned int | |
42 | my_sequence, | |
43 | your_sequence; | |
224a681b | 44 | |
8d951982 | 45 | static char ibuffer[4000], *ibuf_next, *ibuf_last; |
ba212048 | 46 | #define IBUFADDED(i) ibuf_last += (i) |
8d951982 | 47 | #define IBUFAVAILABLE() (ibuf_last-ibuf_next) |
ba212048 | 48 | #define IBUFFER() ibuffer |
8d951982 | 49 | #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1) |
d024bcc4 | 50 | #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } |
ba212048 GM |
51 | #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) |
52 | ||
8d951982 | 53 | char obuffer[4000], *obuf_next; |
ba212048 | 54 | #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } |
ba212048 GM |
55 | #define OBUFAVAILABLE() (obuf_next - obuffer) |
56 | #define OBUFFER() obuffer | |
57 | #define OBUFRESET() obuf_next = obuffer | |
58 | #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) | |
59 | ||
60 | ||
61 | static int | |
62 | outflush() | |
63 | { | |
64 | int length = OBUFAVAILABLE(); | |
65 | ||
66 | if (length != 0) { | |
67 | if (write(sock, OBUFFER(), length) != length) { | |
d024bcc4 | 68 | WHO_ARE_WE(); |
224a681b | 69 | perror("write"); |
ba212048 GM |
70 | return -1; |
71 | } | |
72 | OBUFRESET(); | |
73 | } | |
74 | return 0; /* All OK */ | |
75 | } | |
76 | ||
77 | ||
78 | static int | |
8d951982 GM |
79 | iget(location, length) |
80 | char *location; | |
81 | int length; | |
ba212048 GM |
82 | { |
83 | int i; | |
8d951982 | 84 | int count; |
ba212048 GM |
85 | |
86 | if (OBUFAVAILABLE()) { | |
87 | if (outflush() == -1) { | |
88 | return -1; | |
89 | } | |
90 | } | |
8d951982 GM |
91 | if ((count = IBUFAVAILABLE()) != 0) { |
92 | if (count > length) { | |
93 | count = length; | |
94 | } | |
95 | IBUFGETBYTES(location, count); | |
96 | length -= count; | |
97 | location += count; | |
d024bcc4 | 98 | } |
8d951982 GM |
99 | while (length) { |
100 | if (ibuf_next == ibuf_last) { | |
101 | IBUFRESET(); | |
102 | } | |
103 | if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) { | |
d024bcc4 | 104 | WHO_ARE_WE(); |
224a681b GM |
105 | perror("read"); |
106 | return -1; | |
107 | } | |
8d951982 | 108 | if (count == 0) { |
224a681b | 109 | /* Reading past end-of-file */ |
d024bcc4 GM |
110 | WHO_ARE_WE(); |
111 | fprintf(stderr, "End of file read\r\n"); | |
ba212048 GM |
112 | return -1; |
113 | } | |
8d951982 GM |
114 | IBUFADDED(count); |
115 | if (count > length) { | |
116 | count = length; | |
117 | } | |
118 | IBUFGETBYTES(location, count); | |
119 | length -= count; | |
120 | location += count; | |
ba212048 GM |
121 | } |
122 | return 0; | |
123 | } | |
124 | ||
d024bcc4 GM |
125 | static char * |
126 | exch_to_ascii(exch) | |
127 | int exch; /* opcode to decode */ | |
128 | { | |
129 | switch (exch) { | |
130 | case EXCH_EXCH_COMMAND: | |
131 | return "Command"; | |
132 | case EXCH_EXCH_TYPE: | |
133 | return "Type"; | |
134 | case EXCH_EXCH_TURNAROUND: | |
135 | return "Turnaround"; | |
136 | case EXCH_EXCH_RTS: | |
137 | return "Request to Send"; | |
138 | default: | |
139 | { | |
140 | static char unknown[40]; | |
141 | ||
142 | sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); | |
143 | return unknown; | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | /* | |
149 | * Send the exch structure, updating the sequnce number field. | |
150 | */ | |
151 | ||
152 | static int | |
153 | send_state() | |
154 | { | |
155 | if (OBUFROOM() < sizeof exch_state) { | |
156 | if (outflush() == -1) { | |
157 | return -1; | |
158 | } | |
159 | } | |
e1e082cf GM |
160 | my_sequence = (my_sequence+1)&0xff; |
161 | exch_state.my_sequence = my_sequence; | |
d024bcc4 GM |
162 | exch_state.your_sequence = your_sequence; |
163 | OBUFADDBYTES((char *)&exch_state, sizeof exch_state); | |
164 | return 0; | |
165 | } | |
166 | ||
167 | /* | |
168 | * Receive the exch structure from the other side, checking | |
169 | * sequence numbering. | |
170 | */ | |
171 | ||
172 | static int | |
173 | receive_state() | |
174 | { | |
8d951982 GM |
175 | if (iget((char *)&exch_state, sizeof exch_state) == -1) { |
176 | return -1; | |
d024bcc4 | 177 | } |
d024bcc4 GM |
178 | if (conversation != CONTENTION) { |
179 | if (exch_state.your_sequence != my_sequence) { | |
180 | WHO_ARE_WE(); | |
181 | fprintf(stderr, "Send sequence number mismatch.\n"); | |
182 | return -1; | |
183 | } | |
e1e082cf | 184 | if (exch_state.my_sequence != ((++your_sequence)&0xff)) { |
d024bcc4 GM |
185 | WHO_ARE_WE(); |
186 | fprintf(stderr, "Receive sequence number mismatch.\n"); | |
187 | return -1; | |
188 | } | |
d024bcc4 | 189 | } |
e1e082cf | 190 | your_sequence = exch_state.my_sequence; |
d024bcc4 GM |
191 | return 0; |
192 | } | |
193 | ||
194 | static int | |
195 | enter_receive() | |
196 | { | |
197 | switch (conversation) { | |
198 | case CONTENTION: | |
199 | exch_state.opcode = EXCH_EXCH_TURNAROUND; | |
200 | if (send_state() == -1) { | |
201 | return -1; | |
202 | } | |
203 | if (receive_state() == -1) { | |
204 | return -1; | |
205 | } | |
206 | if (exch_state.opcode != EXCH_EXCH_RTS) { | |
207 | WHO_ARE_WE(); | |
208 | fprintf(stderr, "In CONTENTION state: "); | |
209 | if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { | |
210 | fprintf(stderr, | |
211 | "Both sides tried to enter RECEIVE state.\n"); | |
212 | } else { | |
213 | fprintf(stderr, | |
214 | "Protocol error trying to enter RECEIVE state.\n"); | |
215 | } | |
216 | return -1; | |
217 | } | |
218 | break; | |
219 | case SEND: | |
220 | exch_state.opcode = EXCH_EXCH_TURNAROUND; | |
221 | if (send_state() == -1) { | |
222 | return -1; | |
223 | } | |
224 | break; | |
225 | } | |
226 | conversation = RECEIVE; | |
227 | return 0; | |
228 | } | |
229 | ||
230 | static int | |
231 | enter_send() | |
232 | { | |
233 | switch (conversation) { | |
234 | case CONTENTION: | |
235 | exch_state.opcode = EXCH_EXCH_RTS; | |
236 | if (send_state() == -1) { | |
237 | return -1; | |
238 | } | |
239 | /* fall through */ | |
240 | case RECEIVE: | |
241 | if (receive_state() == -1) { | |
242 | return -1; | |
243 | } | |
244 | if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { | |
245 | WHO_ARE_WE(); | |
246 | fprintf(stderr, "Conversation error - both sides in SEND state.\n"); | |
247 | return -1; | |
248 | } | |
249 | } | |
250 | conversation = SEND; | |
251 | return 0; | |
252 | } | |
253 | ||
62946391 | 254 | int |
d024bcc4 | 255 | api_exch_nextcommand() |
62946391 | 256 | { |
d024bcc4 GM |
257 | if (conversation != RECEIVE) { |
258 | if (enter_receive() == -1) { | |
62946391 GM |
259 | return -1; |
260 | } | |
261 | } | |
d024bcc4 GM |
262 | if (receive_state() == -1) { |
263 | return -1; | |
264 | } | |
265 | if (exch_state.opcode != EXCH_EXCH_COMMAND) { | |
266 | WHO_ARE_WE(); | |
267 | fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", | |
268 | exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); | |
269 | return -1; | |
270 | } | |
271 | return exch_state.command_or_type; | |
62946391 GM |
272 | } |
273 | ||
274 | ||
275 | int | |
ba212048 GM |
276 | api_exch_incommand(command) |
277 | int command; | |
278 | { | |
279 | int i; | |
280 | ||
d024bcc4 GM |
281 | if ((i = api_exch_nextcommand()) == -1) { |
282 | return -1; | |
ba212048 | 283 | } |
ba212048 | 284 | if (i != command) { |
d024bcc4 | 285 | WHO_ARE_WE(); |
ba212048 GM |
286 | fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", |
287 | command, i); | |
288 | return -1; | |
289 | } | |
290 | return 0; | |
291 | } | |
292 | ||
293 | ||
62946391 | 294 | int |
ba212048 GM |
295 | api_exch_outcommand(command) |
296 | int command; | |
297 | { | |
d024bcc4 GM |
298 | if (conversation != SEND) { |
299 | if (enter_send() == -1) { | |
ba212048 GM |
300 | return -1; |
301 | } | |
302 | } | |
d024bcc4 GM |
303 | exch_state.command_or_type = command; |
304 | exch_state.opcode = EXCH_EXCH_COMMAND; | |
305 | if (send_state() == -1) { | |
306 | return -1; | |
307 | } else { | |
308 | return 0; | |
309 | } | |
ba212048 GM |
310 | } |
311 | ||
312 | ||
62946391 | 313 | int |
ba212048 GM |
314 | api_exch_outtype(type, length, location) |
315 | int | |
316 | type, | |
317 | length; | |
318 | char | |
319 | *location; | |
320 | { | |
1117b0bd | 321 | int netleng = length; |
ba212048 | 322 | |
d024bcc4 GM |
323 | if (conversation != SEND) { |
324 | if (enter_send() == -1) { | |
ba212048 GM |
325 | return -1; |
326 | } | |
327 | } | |
d024bcc4 GM |
328 | exch_state.opcode = EXCH_EXCH_TYPE; |
329 | exch_state.command_or_type = type; | |
330 | exch_state.length = netleng; | |
331 | if (send_state() == -1) { | |
332 | return -1; | |
333 | } | |
334 | if (length) { | |
335 | if (OBUFROOM() > length) { | |
336 | OBUFADDBYTES(location, length); | |
337 | } else { | |
338 | if (outflush() == -1) { | |
339 | return -1; | |
340 | } | |
341 | if (write(sock, location, length) != length) { | |
342 | WHO_ARE_WE(); | |
343 | perror("write"); | |
344 | return -1; | |
345 | } | |
ba212048 GM |
346 | } |
347 | } | |
d024bcc4 | 348 | return 0; |
ba212048 GM |
349 | } |
350 | ||
351 | ||
62946391 | 352 | int |
ba212048 GM |
353 | api_exch_intype(type, length, location) |
354 | int | |
355 | type, | |
356 | length; | |
357 | char | |
358 | *location; | |
359 | { | |
1117b0bd | 360 | int i, netleng = length; |
ba212048 | 361 | |
d024bcc4 GM |
362 | if (conversation != RECEIVE) { |
363 | if (enter_receive() == -1) { | |
ba212048 GM |
364 | return -1; |
365 | } | |
366 | } | |
d024bcc4 GM |
367 | if (receive_state() == -1) { |
368 | return -1; | |
369 | } | |
370 | if (exch_state.opcode != EXCH_EXCH_TYPE) { | |
371 | WHO_ARE_WE(); | |
372 | fprintf(stderr, | |
373 | "Expected to receive a %s exchange, received a %s exchange.\n", | |
374 | exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); | |
ba212048 GM |
375 | return -1; |
376 | } | |
d024bcc4 GM |
377 | if (exch_state.command_or_type != type) { |
378 | WHO_ARE_WE(); | |
379 | fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", | |
380 | type, exch_state.command_or_type); | |
381 | return -1; | |
382 | } | |
383 | if (exch_state.length != netleng) { | |
ba212048 | 384 | fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", |
1117b0bd | 385 | type, length, exch_state.length); |
ba212048 GM |
386 | return -1; |
387 | } | |
8d951982 GM |
388 | if (iget(location, length) == -1) { |
389 | return -1; | |
ba212048 GM |
390 | } |
391 | return 0; | |
392 | } | |
62946391 | 393 | |
d024bcc4 GM |
394 | int |
395 | api_exch_flush() | |
396 | { | |
397 | return outflush(); | |
398 | } | |
399 | ||
62946391 | 400 | int |
224a681b | 401 | api_exch_init(sock_number, ourname) |
62946391 | 402 | int sock_number; |
224a681b | 403 | char *ourname; |
62946391 GM |
404 | { |
405 | sock = sock_number; | |
224a681b | 406 | strcpy(whoarewe, ourname); /* For error messages */ |
62946391 | 407 | |
d024bcc4 GM |
408 | my_sequence = your_sequence = 0; |
409 | ||
410 | conversation = CONTENTION; /* We don't know which direction */ | |
411 | ||
62946391 GM |
412 | IBUFRESET(); |
413 | OBUFRESET(); | |
414 | ||
415 | return 0; | |
416 | } |