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