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