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