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