xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31498)
131460Sminshall #include <stdio.h>
231460Sminshall 
331460Sminshall #include "api_exch.h"
431460Sminshall 
531467Sminshall static int sock;		/* Socket number */
631467Sminshall 
731474Sminshall static char whoarewe[40] = "";
831493Sminshall #define	WHO_ARE_WE()	fprintf(stderr, "(API %s) ", whoarewe);
931474Sminshall 
1031493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation;
1131493Sminshall 
1231493Sminshall static struct exch_exch exch_state;
1331493Sminshall 
1431493Sminshall static unsigned int
1531493Sminshall     my_sequence,
1631493Sminshall     your_sequence;
1731493Sminshall 
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
2231493Sminshall #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) {
4431493Sminshall 	    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     }
6831493Sminshall     if ((count -= IBUFAVAILABLE()) < 0) {
6931493Sminshall 	return 0;
7031493Sminshall     }
7131460Sminshall     while (count) {
7231460Sminshall 	if ((i = read(sock, IBUFFER(), count)) < 0) {
7331493Sminshall 	    WHO_ARE_WE();
7431474Sminshall 	    perror("read");
7531460Sminshall 	    return -1;
7631460Sminshall 	}
7731474Sminshall 	if (i == 0) {
7831474Sminshall 	    /* Reading past end-of-file */
7931493Sminshall 	    WHO_ARE_WE();
8031493Sminshall 	    fprintf(stderr, "End of file read\r\n");
8131474Sminshall 	    return -1;
8231474Sminshall 	}
8331460Sminshall 	count -= i;
8431460Sminshall 	IBUFADDED(i);
8531460Sminshall     }
8631460Sminshall     return 0;
8731460Sminshall }
8831460Sminshall 
8931493Sminshall static char *
9031493Sminshall exch_to_ascii(exch)
9131493Sminshall int exch;			/* opcode to decode */
9231493Sminshall {
9331493Sminshall     switch (exch) {
9431493Sminshall     case EXCH_EXCH_COMMAND:
9531493Sminshall 	return "Command";
9631493Sminshall     case EXCH_EXCH_TYPE:
9731493Sminshall 	return "Type";
9831493Sminshall     case EXCH_EXCH_TURNAROUND:
9931493Sminshall 	return "Turnaround";
10031493Sminshall     case EXCH_EXCH_RTS:
10131493Sminshall 	return "Request to Send";
10231493Sminshall     default:
10331493Sminshall 	{
10431493Sminshall 	    static char unknown[40];
10531493Sminshall 
10631493Sminshall 	    sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
10731493Sminshall 	    return unknown;
10831493Sminshall 	}
10931493Sminshall     }
11031493Sminshall }
11131493Sminshall 
11231493Sminshall /*
11331493Sminshall  * Send the exch structure, updating the sequnce number field.
11431493Sminshall  */
11531493Sminshall 
11631493Sminshall static int
11731493Sminshall send_state()
11831493Sminshall {
11931493Sminshall     if (OBUFROOM() < sizeof exch_state) {
12031493Sminshall 	if (outflush() == -1) {
12131493Sminshall 	    return -1;
12231493Sminshall 	}
12331493Sminshall     }
124*31498Sminshall     my_sequence = (my_sequence+1)&0xff;
125*31498Sminshall     exch_state.my_sequence = my_sequence;
12631493Sminshall     exch_state.your_sequence = your_sequence;
12731493Sminshall     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
12831493Sminshall     return 0;
12931493Sminshall }
13031493Sminshall 
13131493Sminshall /*
13231493Sminshall  * Receive the exch structure from the other side, checking
13331493Sminshall  * sequence numbering.
13431493Sminshall  */
13531493Sminshall 
13631493Sminshall static int
13731493Sminshall receive_state()
13831493Sminshall {
13931493Sminshall     if (IBUFAVAILABLE() < sizeof exch_state) {
14031493Sminshall 	if (infill(sizeof exch_state) == -1) {
14131493Sminshall 	    return -1;
14231493Sminshall 	}
14331493Sminshall     }
14431493Sminshall     IBUFGETBYTES((char *)&exch_state, sizeof exch_state);
14531493Sminshall     if (conversation != CONTENTION) {
14631493Sminshall 	if (exch_state.your_sequence != my_sequence) {
14731493Sminshall 	    WHO_ARE_WE();
14831493Sminshall 	    fprintf(stderr, "Send sequence number mismatch.\n");
14931493Sminshall 	    return -1;
15031493Sminshall 	}
151*31498Sminshall 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
15231493Sminshall 	    WHO_ARE_WE();
15331493Sminshall 	    fprintf(stderr, "Receive sequence number mismatch.\n");
15431493Sminshall 	    return -1;
15531493Sminshall 	}
15631493Sminshall     }
157*31498Sminshall     your_sequence = exch_state.my_sequence;
15831493Sminshall     return 0;
15931493Sminshall }
16031493Sminshall 
16131493Sminshall static int
16231493Sminshall enter_receive()
16331493Sminshall {
16431493Sminshall     switch (conversation) {
16531493Sminshall     case CONTENTION:
16631493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
16731493Sminshall 	if (send_state() == -1) {
16831493Sminshall 	    return -1;
16931493Sminshall 	}
17031493Sminshall 	if (receive_state() == -1) {
17131493Sminshall 	    return -1;
17231493Sminshall 	}
17331493Sminshall 	if (exch_state.opcode != EXCH_EXCH_RTS) {
17431493Sminshall 	    WHO_ARE_WE();
17531493Sminshall 	    fprintf(stderr, "In CONTENTION state:  ");
17631493Sminshall 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
17731493Sminshall 		fprintf(stderr,
17831493Sminshall 		    "Both sides tried to enter RECEIVE state.\n");
17931493Sminshall 	    } else {
18031493Sminshall 		fprintf(stderr,
18131493Sminshall 		    "Protocol error trying to enter RECEIVE state.\n");
18231493Sminshall 	    }
18331493Sminshall 	    return -1;
18431493Sminshall 	}
18531493Sminshall 	break;
18631493Sminshall     case SEND:
18731493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
18831493Sminshall 	if (send_state() == -1) {
18931493Sminshall 	    return -1;
19031493Sminshall 	}
19131493Sminshall 	break;
19231493Sminshall     }
19331493Sminshall     conversation = RECEIVE;
19431493Sminshall     return 0;
19531493Sminshall }
19631493Sminshall 
19731493Sminshall static int
19831493Sminshall enter_send()
19931493Sminshall {
20031493Sminshall     switch (conversation) {
20131493Sminshall     case CONTENTION:
20231493Sminshall 	exch_state.opcode = EXCH_EXCH_RTS;
20331493Sminshall 	if (send_state() == -1) {
20431493Sminshall 	    return -1;
20531493Sminshall 	}
20631493Sminshall 	 /* fall through */
20731493Sminshall     case RECEIVE:
20831493Sminshall 	if (receive_state() == -1) {
20931493Sminshall 	    return -1;
21031493Sminshall 	}
21131493Sminshall 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
21231493Sminshall 	    WHO_ARE_WE();
21331493Sminshall 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
21431493Sminshall 	    return -1;
21531493Sminshall 	}
21631493Sminshall     }
21731493Sminshall     conversation = SEND;
21831493Sminshall     return 0;
21931493Sminshall }
22031493Sminshall 
22131467Sminshall int
22231493Sminshall api_exch_nextcommand()
22331467Sminshall {
22431493Sminshall     if (conversation != RECEIVE) {
22531493Sminshall 	if (enter_receive() == -1) {
22631467Sminshall 	    return -1;
22731467Sminshall 	}
22831467Sminshall     }
22931493Sminshall     if (receive_state() == -1) {
23031493Sminshall 	return -1;
23131493Sminshall     }
23231493Sminshall     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
23331493Sminshall 	WHO_ARE_WE();
23431493Sminshall 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
23531493Sminshall 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
23631493Sminshall 	return -1;
23731493Sminshall     }
23831493Sminshall     return exch_state.command_or_type;
23931467Sminshall }
24031467Sminshall 
24131467Sminshall 
24231467Sminshall int
24331460Sminshall api_exch_incommand(command)
24431460Sminshall int command;
24531460Sminshall {
24631460Sminshall     int i;
24731460Sminshall 
24831493Sminshall     if ((i = api_exch_nextcommand()) == -1) {
24931493Sminshall 	return -1;
25031460Sminshall     }
25131460Sminshall     if (i != command) {
25231493Sminshall 	WHO_ARE_WE();
25331460Sminshall 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
25431460Sminshall 				command, i);
25531460Sminshall 	return -1;
25631460Sminshall     }
25731460Sminshall     return 0;
25831460Sminshall }
25931460Sminshall 
26031460Sminshall 
26131467Sminshall int
26231460Sminshall api_exch_outcommand(command)
26331460Sminshall int command;
26431460Sminshall {
26531493Sminshall     if (conversation != SEND) {
26631493Sminshall 	if (enter_send() == -1) {
26731460Sminshall 	    return -1;
26831460Sminshall 	}
26931460Sminshall     }
27031493Sminshall     exch_state.command_or_type = command;
27131493Sminshall     exch_state.opcode = EXCH_EXCH_COMMAND;
27231493Sminshall     if (send_state() == -1) {
27331493Sminshall 	return -1;
27431493Sminshall     } else {
27531493Sminshall 	return 0;
27631493Sminshall     }
27731460Sminshall }
27831460Sminshall 
27931460Sminshall 
28031467Sminshall int
28131460Sminshall api_exch_outtype(type, length, location)
28231460Sminshall int
28331460Sminshall     type,
28431460Sminshall     length;
28531460Sminshall char
28631460Sminshall     *location;
28731460Sminshall {
28831460Sminshall     int netleng = htons(length);
28931460Sminshall 
29031493Sminshall     if (conversation != SEND) {
29131493Sminshall 	if (enter_send() == -1) {
29231460Sminshall 	    return -1;
29331460Sminshall 	}
29431460Sminshall     }
29531493Sminshall     exch_state.opcode = EXCH_EXCH_TYPE;
29631493Sminshall     exch_state.command_or_type = type;
29731493Sminshall     exch_state.length = netleng;
29831493Sminshall     if (send_state() == -1) {
29931493Sminshall 	return -1;
30031493Sminshall     }
30131493Sminshall     if (length) {
30231493Sminshall 	if (OBUFROOM() > length) {
30331493Sminshall 	    OBUFADDBYTES(location, length);
30431493Sminshall 	} else {
30531493Sminshall 	    if (outflush() == -1) {
30631493Sminshall 		return -1;
30731493Sminshall 	    }
30831493Sminshall 	    if (write(sock, location, length) != length) {
30931493Sminshall 		WHO_ARE_WE();
31031493Sminshall 		perror("write");
31131493Sminshall 		return -1;
31231493Sminshall 	    }
31331460Sminshall 	}
31431460Sminshall     }
31531493Sminshall     return 0;
31631460Sminshall }
31731460Sminshall 
31831460Sminshall 
31931467Sminshall int
32031460Sminshall api_exch_intype(type, length, location)
32131460Sminshall int
32231460Sminshall     type,
32331460Sminshall     length;
32431460Sminshall char
32531460Sminshall     *location;
32631460Sminshall {
32731460Sminshall     int i, netleng = htons(length);
32831460Sminshall 
32931493Sminshall     if (conversation != RECEIVE) {
33031493Sminshall 	if (enter_receive() == -1) {
33131460Sminshall 	    return -1;
33231460Sminshall 	}
33331460Sminshall     }
33431493Sminshall     if (receive_state() == -1) {
33531460Sminshall 	return -1;
33631460Sminshall     }
33731493Sminshall     if (exch_state.opcode != EXCH_EXCH_TYPE) {
33831493Sminshall 	WHO_ARE_WE();
33931493Sminshall 	fprintf(stderr,
34031493Sminshall 	    "Expected to receive a %s exchange, received a %s exchange.\n",
34131493Sminshall 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
34231493Sminshall 	return -1;
34331493Sminshall     }
34431493Sminshall     if (exch_state.command_or_type != type) {
34531493Sminshall 	WHO_ARE_WE();
34631493Sminshall 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
34731493Sminshall 	    type, exch_state.command_or_type);
34831493Sminshall 	return -1;
34931493Sminshall     }
35031493Sminshall     if (exch_state.length != netleng) {
35131460Sminshall 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
35231493Sminshall 		type, length, ntohs(exch_state.length));
35331460Sminshall 	return -1;
35431460Sminshall     }
35531460Sminshall     while (length) {
35631460Sminshall 	if ((i = read(sock, location, length)) < 0) {
35731493Sminshall 	    WHO_ARE_WE();
35831474Sminshall 	    perror("read");
35931460Sminshall 	    return -1;
36031460Sminshall 	}
36131460Sminshall 	length -= i;
36231460Sminshall 	location += i;
36331460Sminshall     }
36431460Sminshall     return 0;
36531460Sminshall }
36631467Sminshall 
36731467Sminshall int
36831493Sminshall api_exch_flush()
36931493Sminshall {
37031493Sminshall     return outflush();
37131493Sminshall }
37231493Sminshall 
37331493Sminshall int
37431474Sminshall api_exch_init(sock_number, ourname)
37531467Sminshall int sock_number;
37631474Sminshall char *ourname;
37731467Sminshall {
37831467Sminshall     sock = sock_number;
37931474Sminshall     strcpy(whoarewe, ourname);		/* For error messages */
38031467Sminshall 
38131493Sminshall     my_sequence = your_sequence = 0;
38231493Sminshall 
38331493Sminshall     conversation = CONTENTION;		/* We don't know which direction */
38431493Sminshall 
38531467Sminshall     IBUFRESET();
38631467Sminshall     OBUFRESET();
38731467Sminshall 
38831467Sminshall     return 0;
38931467Sminshall }
390