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