xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31493)
131460Sminshall #include <stdio.h>
231460Sminshall 
331460Sminshall #include "api_exch.h"
431460Sminshall 
531467Sminshall static int sock;		/* Socket number */
631467Sminshall 
731474Sminshall static char whoarewe[40] = "";
8*31493Sminshall #define	WHO_ARE_WE()	fprintf(stderr, "(API %s) ", whoarewe);
931474Sminshall 
10*31493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation;
11*31493Sminshall 
12*31493Sminshall static struct exch_exch exch_state;
13*31493Sminshall 
14*31493Sminshall static unsigned int
15*31493Sminshall     my_sequence,
16*31493Sminshall     your_sequence;
17*31493Sminshall 
1831460Sminshall static char ibuffer[40], *ibuf_next, *ibuf_last;
1931460Sminshall #define	IBUFADDED(i)		ibuf_last += (i)
2031460Sminshall #define	IBUFAVAILABLE()		(ibuf_last -ibuf_next)
2131460Sminshall #define	IBUFFER()		ibuffer
22*31493Sminshall #define	IBUFGETBYTES(w,l)	{ memcpy(w, ibuf_next, l); ibuf_next += l; }
2331460Sminshall #define	IBUFGETCHAR()		(*ibuf_next++)
2431460Sminshall #define	IBUFGETSHORT()		((*ibuf_next++<<8)|(*ibuf_next++&0xff))
2531460Sminshall #define	IBUFRESET()		(ibuf_next = ibuf_last = ibuffer)
2631460Sminshall 
2731460Sminshall char obuffer[40], *obuf_next;
2831460Sminshall #define	OBUFADDBYTES(w,l)	{ memcpy(obuf_next, w, l); obuf_next += l; }
2931460Sminshall #define	OBUFADDCHAR(c)		(*obuf_next++ = c)
3031460Sminshall #define	OBUFADDSHORT(s)		{*obuf_next++ = (s)>>8; *obuf_next++ = s; }
3131460Sminshall #define	OBUFAVAILABLE()		(obuf_next - obuffer)
3231460Sminshall #define	OBUFFER()		obuffer
3331460Sminshall #define	OBUFRESET()		obuf_next = obuffer
3431460Sminshall #define	OBUFROOM()		(obuffer+sizeof obuffer-obuf_next)
3531460Sminshall 
3631460Sminshall 
3731460Sminshall static int
3831460Sminshall outflush()
3931460Sminshall {
4031460Sminshall     int length = OBUFAVAILABLE();
4131460Sminshall 
4231460Sminshall     if (length != 0) {
4331460Sminshall 	if (write(sock, OBUFFER(), length) != length) {
44*31493Sminshall 	    WHO_ARE_WE();
4531474Sminshall 	    perror("write");
4631460Sminshall 	    return -1;
4731460Sminshall 	}
4831460Sminshall 	OBUFRESET();
4931460Sminshall     }
5031460Sminshall     return 0;				/* All OK */
5131460Sminshall }
5231460Sminshall 
5331460Sminshall 
5431460Sminshall static int
5531460Sminshall infill(count)
5631460Sminshall int count;
5731460Sminshall {
5831460Sminshall     int i;
5931460Sminshall 
6031460Sminshall     if (OBUFAVAILABLE()) {
6131460Sminshall 	if (outflush() == -1) {
6231460Sminshall 	    return -1;
6331460Sminshall 	}
6431460Sminshall     }
6531460Sminshall     if (ibuf_next == ibuf_last) {
6631460Sminshall 	IBUFRESET();
6731460Sminshall     }
68*31493Sminshall     if ((count -= IBUFAVAILABLE()) < 0) {
69*31493Sminshall 	return 0;
70*31493Sminshall     }
7131460Sminshall     while (count) {
7231460Sminshall 	if ((i = read(sock, IBUFFER(), count)) < 0) {
73*31493Sminshall 	    WHO_ARE_WE();
7431474Sminshall 	    perror("read");
7531460Sminshall 	    return -1;
7631460Sminshall 	}
7731474Sminshall 	if (i == 0) {
7831474Sminshall 	    /* Reading past end-of-file */
79*31493Sminshall 	    WHO_ARE_WE();
80*31493Sminshall 	    fprintf(stderr, "End of file read\r\n");
8131474Sminshall 	    return -1;
8231474Sminshall 	}
8331460Sminshall 	count -= i;
8431460Sminshall 	IBUFADDED(i);
8531460Sminshall     }
8631460Sminshall     return 0;
8731460Sminshall }
8831460Sminshall 
89*31493Sminshall static char *
90*31493Sminshall exch_to_ascii(exch)
91*31493Sminshall int exch;			/* opcode to decode */
92*31493Sminshall {
93*31493Sminshall     switch (exch) {
94*31493Sminshall     case EXCH_EXCH_COMMAND:
95*31493Sminshall 	return "Command";
96*31493Sminshall     case EXCH_EXCH_TYPE:
97*31493Sminshall 	return "Type";
98*31493Sminshall     case EXCH_EXCH_TURNAROUND:
99*31493Sminshall 	return "Turnaround";
100*31493Sminshall     case EXCH_EXCH_RTS:
101*31493Sminshall 	return "Request to Send";
102*31493Sminshall     default:
103*31493Sminshall 	{
104*31493Sminshall 	    static char unknown[40];
105*31493Sminshall 
106*31493Sminshall 	    sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
107*31493Sminshall 	    return unknown;
108*31493Sminshall 	}
109*31493Sminshall     }
110*31493Sminshall }
111*31493Sminshall 
112*31493Sminshall /*
113*31493Sminshall  * Send the exch structure, updating the sequnce number field.
114*31493Sminshall  */
115*31493Sminshall 
116*31493Sminshall static int
117*31493Sminshall send_state()
118*31493Sminshall {
119*31493Sminshall     if (OBUFROOM() < sizeof exch_state) {
120*31493Sminshall 	if (outflush() == -1) {
121*31493Sminshall 	    return -1;
122*31493Sminshall 	}
123*31493Sminshall     }
124*31493Sminshall     exch_state.my_sequence = ++my_sequence;
125*31493Sminshall     exch_state.your_sequence = your_sequence;
126*31493Sminshall     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
127*31493Sminshall     return 0;
128*31493Sminshall }
129*31493Sminshall 
130*31493Sminshall /*
131*31493Sminshall  * Receive the exch structure from the other side, checking
132*31493Sminshall  * sequence numbering.
133*31493Sminshall  */
134*31493Sminshall 
135*31493Sminshall static int
136*31493Sminshall receive_state()
137*31493Sminshall {
138*31493Sminshall     if (IBUFAVAILABLE() < sizeof exch_state) {
139*31493Sminshall 	if (infill(sizeof exch_state) == -1) {
140*31493Sminshall 	    return -1;
141*31493Sminshall 	}
142*31493Sminshall     }
143*31493Sminshall     IBUFGETBYTES((char *)&exch_state, sizeof exch_state);
144*31493Sminshall     if (conversation != CONTENTION) {
145*31493Sminshall 	if (exch_state.your_sequence != my_sequence) {
146*31493Sminshall 	    WHO_ARE_WE();
147*31493Sminshall 	    fprintf(stderr, "Send sequence number mismatch.\n");
148*31493Sminshall 	    return -1;
149*31493Sminshall 	}
150*31493Sminshall 	if (exch_state.my_sequence != ++your_sequence) {
151*31493Sminshall 	    WHO_ARE_WE();
152*31493Sminshall 	    fprintf(stderr, "Receive sequence number mismatch.\n");
153*31493Sminshall 	    return -1;
154*31493Sminshall 	}
155*31493Sminshall     } else {
156*31493Sminshall 	/* In contention state, no sequence numbering */
157*31493Sminshall 	your_sequence = exch_state.my_sequence;
158*31493Sminshall     }
159*31493Sminshall     return 0;
160*31493Sminshall }
161*31493Sminshall 
162*31493Sminshall static int
163*31493Sminshall enter_receive()
164*31493Sminshall {
165*31493Sminshall     switch (conversation) {
166*31493Sminshall     case CONTENTION:
167*31493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
168*31493Sminshall 	if (send_state() == -1) {
169*31493Sminshall 	    return -1;
170*31493Sminshall 	}
171*31493Sminshall 	if (receive_state() == -1) {
172*31493Sminshall 	    return -1;
173*31493Sminshall 	}
174*31493Sminshall 	if (exch_state.opcode != EXCH_EXCH_RTS) {
175*31493Sminshall 	    WHO_ARE_WE();
176*31493Sminshall 	    fprintf(stderr, "In CONTENTION state:  ");
177*31493Sminshall 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
178*31493Sminshall 		fprintf(stderr,
179*31493Sminshall 		    "Both sides tried to enter RECEIVE state.\n");
180*31493Sminshall 	    } else {
181*31493Sminshall 		fprintf(stderr,
182*31493Sminshall 		    "Protocol error trying to enter RECEIVE state.\n");
183*31493Sminshall 	    }
184*31493Sminshall 	    return -1;
185*31493Sminshall 	}
186*31493Sminshall 	break;
187*31493Sminshall     case SEND:
188*31493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
189*31493Sminshall 	if (send_state() == -1) {
190*31493Sminshall 	    return -1;
191*31493Sminshall 	}
192*31493Sminshall 	break;
193*31493Sminshall     }
194*31493Sminshall     conversation = RECEIVE;
195*31493Sminshall     return 0;
196*31493Sminshall }
197*31493Sminshall 
198*31493Sminshall static int
199*31493Sminshall enter_send()
200*31493Sminshall {
201*31493Sminshall     switch (conversation) {
202*31493Sminshall     case CONTENTION:
203*31493Sminshall 	exch_state.opcode = EXCH_EXCH_RTS;
204*31493Sminshall 	if (send_state() == -1) {
205*31493Sminshall 	    return -1;
206*31493Sminshall 	}
207*31493Sminshall 	 /* fall through */
208*31493Sminshall     case RECEIVE:
209*31493Sminshall 	if (receive_state() == -1) {
210*31493Sminshall 	    return -1;
211*31493Sminshall 	}
212*31493Sminshall 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
213*31493Sminshall 	    WHO_ARE_WE();
214*31493Sminshall 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
215*31493Sminshall 	    return -1;
216*31493Sminshall 	}
217*31493Sminshall     }
218*31493Sminshall     conversation = SEND;
219*31493Sminshall     return 0;
220*31493Sminshall }
221*31493Sminshall 
22231467Sminshall int
223*31493Sminshall api_exch_nextcommand()
22431467Sminshall {
225*31493Sminshall     if (conversation != RECEIVE) {
226*31493Sminshall 	if (enter_receive() == -1) {
22731467Sminshall 	    return -1;
22831467Sminshall 	}
22931467Sminshall     }
230*31493Sminshall     if (receive_state() == -1) {
231*31493Sminshall 	return -1;
232*31493Sminshall     }
233*31493Sminshall     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
234*31493Sminshall 	WHO_ARE_WE();
235*31493Sminshall 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
236*31493Sminshall 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
237*31493Sminshall 	return -1;
238*31493Sminshall     }
239*31493Sminshall     return exch_state.command_or_type;
24031467Sminshall }
24131467Sminshall 
24231467Sminshall 
24331467Sminshall int
24431460Sminshall api_exch_incommand(command)
24531460Sminshall int command;
24631460Sminshall {
24731460Sminshall     int i;
24831460Sminshall 
249*31493Sminshall     if ((i = api_exch_nextcommand()) == -1) {
250*31493Sminshall 	return -1;
25131460Sminshall     }
25231460Sminshall     if (i != command) {
253*31493Sminshall 	WHO_ARE_WE();
25431460Sminshall 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
25531460Sminshall 				command, i);
25631460Sminshall 	return -1;
25731460Sminshall     }
25831460Sminshall     return 0;
25931460Sminshall }
26031460Sminshall 
26131460Sminshall 
26231467Sminshall int
26331460Sminshall api_exch_outcommand(command)
26431460Sminshall int command;
26531460Sminshall {
266*31493Sminshall     if (conversation != SEND) {
267*31493Sminshall 	if (enter_send() == -1) {
26831460Sminshall 	    return -1;
26931460Sminshall 	}
27031460Sminshall     }
271*31493Sminshall     exch_state.command_or_type = command;
272*31493Sminshall     exch_state.opcode = EXCH_EXCH_COMMAND;
273*31493Sminshall     if (send_state() == -1) {
274*31493Sminshall 	return -1;
275*31493Sminshall     } else {
276*31493Sminshall 	return 0;
277*31493Sminshall     }
27831460Sminshall }
27931460Sminshall 
28031460Sminshall 
28131467Sminshall int
28231460Sminshall api_exch_outtype(type, length, location)
28331460Sminshall int
28431460Sminshall     type,
28531460Sminshall     length;
28631460Sminshall char
28731460Sminshall     *location;
28831460Sminshall {
28931460Sminshall     int netleng = htons(length);
29031460Sminshall 
291*31493Sminshall     if (conversation != SEND) {
292*31493Sminshall 	if (enter_send() == -1) {
29331460Sminshall 	    return -1;
29431460Sminshall 	}
29531460Sminshall     }
296*31493Sminshall     exch_state.opcode = EXCH_EXCH_TYPE;
297*31493Sminshall     exch_state.command_or_type = type;
298*31493Sminshall     exch_state.length = netleng;
299*31493Sminshall     if (send_state() == -1) {
300*31493Sminshall 	return -1;
301*31493Sminshall     }
302*31493Sminshall     if (length) {
303*31493Sminshall 	if (OBUFROOM() > length) {
304*31493Sminshall 	    OBUFADDBYTES(location, length);
305*31493Sminshall 	} else {
306*31493Sminshall 	    if (outflush() == -1) {
307*31493Sminshall 		return -1;
308*31493Sminshall 	    }
309*31493Sminshall 	    if (write(sock, location, length) != length) {
310*31493Sminshall 		WHO_ARE_WE();
311*31493Sminshall 		perror("write");
312*31493Sminshall 		return -1;
313*31493Sminshall 	    }
31431460Sminshall 	}
31531460Sminshall     }
316*31493Sminshall     return 0;
31731460Sminshall }
31831460Sminshall 
31931460Sminshall 
32031467Sminshall int
32131460Sminshall api_exch_intype(type, length, location)
32231460Sminshall int
32331460Sminshall     type,
32431460Sminshall     length;
32531460Sminshall char
32631460Sminshall     *location;
32731460Sminshall {
32831460Sminshall     int i, netleng = htons(length);
32931460Sminshall 
330*31493Sminshall     if (conversation != RECEIVE) {
331*31493Sminshall 	if (enter_receive() == -1) {
33231460Sminshall 	    return -1;
33331460Sminshall 	}
33431460Sminshall     }
335*31493Sminshall     if (receive_state() == -1) {
33631460Sminshall 	return -1;
33731460Sminshall     }
338*31493Sminshall     if (exch_state.opcode != EXCH_EXCH_TYPE) {
339*31493Sminshall 	WHO_ARE_WE();
340*31493Sminshall 	fprintf(stderr,
341*31493Sminshall 	    "Expected to receive a %s exchange, received a %s exchange.\n",
342*31493Sminshall 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
343*31493Sminshall 	return -1;
344*31493Sminshall     }
345*31493Sminshall     if (exch_state.command_or_type != type) {
346*31493Sminshall 	WHO_ARE_WE();
347*31493Sminshall 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
348*31493Sminshall 	    type, exch_state.command_or_type);
349*31493Sminshall 	return -1;
350*31493Sminshall     }
351*31493Sminshall     if (exch_state.length != netleng) {
35231460Sminshall 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
353*31493Sminshall 		type, length, ntohs(exch_state.length));
35431460Sminshall 	return -1;
35531460Sminshall     }
35631460Sminshall     while (length) {
35731460Sminshall 	if ((i = read(sock, location, length)) < 0) {
358*31493Sminshall 	    WHO_ARE_WE();
35931474Sminshall 	    perror("read");
36031460Sminshall 	    return -1;
36131460Sminshall 	}
36231460Sminshall 	length -= i;
36331460Sminshall 	location += i;
36431460Sminshall     }
36531460Sminshall     return 0;
36631460Sminshall }
36731467Sminshall 
36831467Sminshall int
369*31493Sminshall api_exch_flush()
370*31493Sminshall {
371*31493Sminshall     return outflush();
372*31493Sminshall }
373*31493Sminshall 
374*31493Sminshall int
37531474Sminshall api_exch_init(sock_number, ourname)
37631467Sminshall int sock_number;
37731474Sminshall char *ourname;
37831467Sminshall {
37931467Sminshall     sock = sock_number;
38031474Sminshall     strcpy(whoarewe, ourname);		/* For error messages */
38131467Sminshall 
382*31493Sminshall     my_sequence = your_sequence = 0;
383*31493Sminshall 
384*31493Sminshall     conversation = CONTENTION;		/* We don't know which direction */
385*31493Sminshall 
38631467Sminshall     IBUFRESET();
38731467Sminshall     OBUFRESET();
38831467Sminshall 
38931467Sminshall     return 0;
39031467Sminshall }
391