date and time created 87/06/19 12:57:58 by minshall
[unix-history] / usr / src / usr.bin / tn3270 / api / api_exch.c
CommitLineData
ba212048
GM
1#include <stdio.h>
2
3#include "api_exch.h"
4
62946391
GM
5static int sock; /* Socket number */
6
224a681b 7static char whoarewe[40] = "";
d024bcc4
GM
8#define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe);
9
10static enum {CONTENTION, SEND, RECEIVE } conversation;
11
12static struct exch_exch exch_state;
13
14static unsigned int
15 my_sequence,
16 your_sequence;
224a681b 17
8d951982 18static 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 26char 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
34static int
35outflush()
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
51static int
8d951982
GM
52iget(location, length)
53char *location;
54int 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
98static char *
99exch_to_ascii(exch)
100int 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
125static int
126send_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
145static int
146receive_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
167static int
168enter_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
203static int
204enter_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 227int
d024bcc4 228api_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
248int
ba212048
GM
249api_exch_incommand(command)
250int 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 267int
ba212048
GM
268api_exch_outcommand(command)
269int 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 286int
ba212048
GM
287api_exch_outtype(type, length, location)
288int
289 type,
290 length;
291char
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 325int
ba212048
GM
326api_exch_intype(type, length, location)
327int
328 type,
329 length;
330char
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
367int
368api_exch_flush()
369{
370 return outflush();
371}
372
62946391 373int
224a681b 374api_exch_init(sock_number, ourname)
62946391 375int sock_number;
224a681b 376char *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}