xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31498)
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     my_sequence = (my_sequence+1)&0xff;
125     exch_state.my_sequence = my_sequence;
126     exch_state.your_sequence = your_sequence;
127     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
128     return 0;
129 }
130 
131 /*
132  * Receive the exch structure from the other side, checking
133  * sequence numbering.
134  */
135 
136 static int
137 receive_state()
138 {
139     if (IBUFAVAILABLE() < sizeof exch_state) {
140 	if (infill(sizeof exch_state) == -1) {
141 	    return -1;
142 	}
143     }
144     IBUFGETBYTES((char *)&exch_state, sizeof exch_state);
145     if (conversation != CONTENTION) {
146 	if (exch_state.your_sequence != my_sequence) {
147 	    WHO_ARE_WE();
148 	    fprintf(stderr, "Send sequence number mismatch.\n");
149 	    return -1;
150 	}
151 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
152 	    WHO_ARE_WE();
153 	    fprintf(stderr, "Receive sequence number mismatch.\n");
154 	    return -1;
155 	}
156     }
157     your_sequence = exch_state.my_sequence;
158     return 0;
159 }
160 
161 static int
162 enter_receive()
163 {
164     switch (conversation) {
165     case CONTENTION:
166 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
167 	if (send_state() == -1) {
168 	    return -1;
169 	}
170 	if (receive_state() == -1) {
171 	    return -1;
172 	}
173 	if (exch_state.opcode != EXCH_EXCH_RTS) {
174 	    WHO_ARE_WE();
175 	    fprintf(stderr, "In CONTENTION state:  ");
176 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
177 		fprintf(stderr,
178 		    "Both sides tried to enter RECEIVE state.\n");
179 	    } else {
180 		fprintf(stderr,
181 		    "Protocol error trying to enter RECEIVE state.\n");
182 	    }
183 	    return -1;
184 	}
185 	break;
186     case SEND:
187 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
188 	if (send_state() == -1) {
189 	    return -1;
190 	}
191 	break;
192     }
193     conversation = RECEIVE;
194     return 0;
195 }
196 
197 static int
198 enter_send()
199 {
200     switch (conversation) {
201     case CONTENTION:
202 	exch_state.opcode = EXCH_EXCH_RTS;
203 	if (send_state() == -1) {
204 	    return -1;
205 	}
206 	 /* fall through */
207     case RECEIVE:
208 	if (receive_state() == -1) {
209 	    return -1;
210 	}
211 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
212 	    WHO_ARE_WE();
213 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
214 	    return -1;
215 	}
216     }
217     conversation = SEND;
218     return 0;
219 }
220 
221 int
222 api_exch_nextcommand()
223 {
224     if (conversation != RECEIVE) {
225 	if (enter_receive() == -1) {
226 	    return -1;
227 	}
228     }
229     if (receive_state() == -1) {
230 	return -1;
231     }
232     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
233 	WHO_ARE_WE();
234 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
235 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
236 	return -1;
237     }
238     return exch_state.command_or_type;
239 }
240 
241 
242 int
243 api_exch_incommand(command)
244 int command;
245 {
246     int i;
247 
248     if ((i = api_exch_nextcommand()) == -1) {
249 	return -1;
250     }
251     if (i != command) {
252 	WHO_ARE_WE();
253 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
254 				command, i);
255 	return -1;
256     }
257     return 0;
258 }
259 
260 
261 int
262 api_exch_outcommand(command)
263 int command;
264 {
265     if (conversation != SEND) {
266 	if (enter_send() == -1) {
267 	    return -1;
268 	}
269     }
270     exch_state.command_or_type = command;
271     exch_state.opcode = EXCH_EXCH_COMMAND;
272     if (send_state() == -1) {
273 	return -1;
274     } else {
275 	return 0;
276     }
277 }
278 
279 
280 int
281 api_exch_outtype(type, length, location)
282 int
283     type,
284     length;
285 char
286     *location;
287 {
288     int netleng = htons(length);
289 
290     if (conversation != SEND) {
291 	if (enter_send() == -1) {
292 	    return -1;
293 	}
294     }
295     exch_state.opcode = EXCH_EXCH_TYPE;
296     exch_state.command_or_type = type;
297     exch_state.length = netleng;
298     if (send_state() == -1) {
299 	return -1;
300     }
301     if (length) {
302 	if (OBUFROOM() > length) {
303 	    OBUFADDBYTES(location, length);
304 	} else {
305 	    if (outflush() == -1) {
306 		return -1;
307 	    }
308 	    if (write(sock, location, length) != length) {
309 		WHO_ARE_WE();
310 		perror("write");
311 		return -1;
312 	    }
313 	}
314     }
315     return 0;
316 }
317 
318 
319 int
320 api_exch_intype(type, length, location)
321 int
322     type,
323     length;
324 char
325     *location;
326 {
327     int i, netleng = htons(length);
328 
329     if (conversation != RECEIVE) {
330 	if (enter_receive() == -1) {
331 	    return -1;
332 	}
333     }
334     if (receive_state() == -1) {
335 	return -1;
336     }
337     if (exch_state.opcode != EXCH_EXCH_TYPE) {
338 	WHO_ARE_WE();
339 	fprintf(stderr,
340 	    "Expected to receive a %s exchange, received a %s exchange.\n",
341 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
342 	return -1;
343     }
344     if (exch_state.command_or_type != type) {
345 	WHO_ARE_WE();
346 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
347 	    type, exch_state.command_or_type);
348 	return -1;
349     }
350     if (exch_state.length != netleng) {
351 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
352 		type, length, ntohs(exch_state.length));
353 	return -1;
354     }
355     while (length) {
356 	if ((i = read(sock, location, length)) < 0) {
357 	    WHO_ARE_WE();
358 	    perror("read");
359 	    return -1;
360 	}
361 	length -= i;
362 	location += i;
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