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