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