date and time created 87/07/16 20:38:06 by denise
[unix-history] / usr / src / usr.bin / tn3270 / api / api_exch.c
CommitLineData
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
7static int sock; /* Socket number */
8
224a681b 9static char whoarewe[40] = "";
d024bcc4
GM
10#define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe);
11
12static enum {CONTENTION, SEND, RECEIVE } conversation;
13
14static struct exch_exch exch_state;
15
16static unsigned int
17 my_sequence,
18 your_sequence;
224a681b 19
8d951982 20static 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 28char 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
36static int
37outflush()
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
53static int
8d951982
GM
54iget(location, length)
55char *location;
56int 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
100static char *
101exch_to_ascii(exch)
102int 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
127static int
128send_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
147static int
148receive_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
169static int
170enter_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
205static int
206enter_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 229int
d024bcc4 230api_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
250int
ba212048
GM
251api_exch_incommand(command)
252int 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 269int
ba212048
GM
270api_exch_outcommand(command)
271int 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 288int
ba212048
GM
289api_exch_outtype(type, length, location)
290int
291 type,
292 length;
293char
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 327int
ba212048
GM
328api_exch_intype(type, length, location)
329int
330 type,
331 length;
332char
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
369int
370api_exch_flush()
371{
372 return outflush();
373}
374
62946391 375int
224a681b 376api_exch_init(sock_number, ourname)
62946391 377int sock_number;
224a681b 378char *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}