xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31801)
1 #include <stdio.h>
2 
3 #include "../general/general.h"
4 
5 #include "api_exch.h"
6 
7 static int sock;		/* Socket number */
8 
9 static char whoarewe[40] = "";
10 #define	WHO_ARE_WE()	fprintf(stderr, "(API %s) ", whoarewe);
11 
12 static enum {CONTENTION, SEND, RECEIVE } conversation;
13 
14 static struct exch_exch exch_state;
15 
16 static unsigned int
17     my_sequence,
18     your_sequence;
19 
20 static char ibuffer[4000], *ibuf_next, *ibuf_last;
21 #define	IBUFADDED(i)		ibuf_last += (i)
22 #define	IBUFAVAILABLE()		(ibuf_last-ibuf_next)
23 #define	IBUFFER()		ibuffer
24 #define	IBUFFREE()		(ibuffer+sizeof ibuffer-ibuf_last-1)
25 #define	IBUFGETBYTES(w,l)	{ memcpy(w, ibuf_next, l); ibuf_next += l; }
26 #define	IBUFRESET()		(ibuf_next = ibuf_last = ibuffer)
27 
28 char obuffer[4000], *obuf_next;
29 #define	OBUFADDBYTES(w,l)	{ memcpy(obuf_next, w, l); obuf_next += l; }
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 
36 static int
37 outflush()
38 {
39     int length = OBUFAVAILABLE();
40 
41     if (length != 0) {
42 	if (write(sock, OBUFFER(), length) != length) {
43 	    WHO_ARE_WE();
44 	    perror("write");
45 	    return -1;
46 	}
47 	OBUFRESET();
48     }
49     return 0;				/* All OK */
50 }
51 
52 
53 static int
54 iget(location, length)
55 char	*location;
56 int	length;
57 {
58     int i;
59     int count;
60 
61     if (OBUFAVAILABLE()) {
62 	if (outflush() == -1) {
63 	    return -1;
64 	}
65     }
66     if ((count = IBUFAVAILABLE()) != 0) {
67 	if (count > length) {
68 	    count = length;
69 	}
70 	IBUFGETBYTES(location, count);
71 	length -= count;
72 	location += count;
73     }
74     while (length) {
75 	if (ibuf_next == ibuf_last) {
76 	    IBUFRESET();
77 	}
78 	if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
79 	    WHO_ARE_WE();
80 	    perror("read");
81 	    return -1;
82 	}
83 	if (count == 0) {
84 	    /* Reading past end-of-file */
85 	    WHO_ARE_WE();
86 	    fprintf(stderr, "End of file read\r\n");
87 	    return -1;
88 	}
89 	IBUFADDED(count);
90 	if (count > length) {
91 	    count = length;
92 	}
93 	IBUFGETBYTES(location, count);
94 	length -= count;
95 	location += count;
96     }
97     return 0;
98 }
99 
100 static char *
101 exch_to_ascii(exch)
102 int 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 
127 static int
128 send_state()
129 {
130     if (OBUFROOM() < sizeof exch_state) {
131 	if (outflush() == -1) {
132 	    return -1;
133 	}
134     }
135     my_sequence = (my_sequence+1)&0xff;
136     exch_state.my_sequence = my_sequence;
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 
147 static int
148 receive_state()
149 {
150     if (iget((char *)&exch_state, sizeof exch_state) == -1) {
151 	return -1;
152     }
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 	}
159 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
160 	    WHO_ARE_WE();
161 	    fprintf(stderr, "Receive sequence number mismatch.\n");
162 	    return -1;
163 	}
164     }
165     your_sequence = exch_state.my_sequence;
166     return 0;
167 }
168 
169 static int
170 enter_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 
205 static int
206 enter_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 
229 int
230 api_exch_nextcommand()
231 {
232     if (conversation != RECEIVE) {
233 	if (enter_receive() == -1) {
234 	    return -1;
235 	}
236     }
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;
247 }
248 
249 
250 int
251 api_exch_incommand(command)
252 int command;
253 {
254     int i;
255 
256     if ((i = api_exch_nextcommand()) == -1) {
257 	return -1;
258     }
259     if (i != command) {
260 	WHO_ARE_WE();
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 
269 int
270 api_exch_outcommand(command)
271 int command;
272 {
273     if (conversation != SEND) {
274 	if (enter_send() == -1) {
275 	    return -1;
276 	}
277     }
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     }
285 }
286 
287 
288 int
289 api_exch_outtype(type, length, location)
290 int
291     type,
292     length;
293 char
294     *location;
295 {
296     int netleng = length;
297 
298     if (conversation != SEND) {
299 	if (enter_send() == -1) {
300 	    return -1;
301 	}
302     }
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 	    }
321 	}
322     }
323     return 0;
324 }
325 
326 
327 int
328 api_exch_intype(type, length, location)
329 int
330     type,
331     length;
332 char
333     *location;
334 {
335     int i, netleng = length;
336 
337     if (conversation != RECEIVE) {
338 	if (enter_receive() == -1) {
339 	    return -1;
340 	}
341     }
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));
350 	return -1;
351     }
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) {
359 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
360 		type, length, exch_state.length);
361 	return -1;
362     }
363     if (iget(location, length) == -1) {
364 	return -1;
365     }
366     return 0;
367 }
368 
369 int
370 api_exch_flush()
371 {
372     return outflush();
373 }
374 
375 int
376 api_exch_init(sock_number, ourname)
377 int sock_number;
378 char *ourname;
379 {
380     sock = sock_number;
381     strcpy(whoarewe, ourname);		/* For error messages */
382 
383     my_sequence = your_sequence = 0;
384 
385     conversation = CONTENTION;		/* We don't know which direction */
386 
387     IBUFRESET();
388     OBUFRESET();
389 
390     return 0;
391 }
392