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