xref: /original-bsd/usr.bin/tn3270/api/api_exch.c (revision 542201aa)
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) 03/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 }
408