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