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