xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31499)
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 
18*31499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last;
1931460Sminshall #define	IBUFADDED(i)		ibuf_last += (i)
20*31499Sminshall #define	IBUFAVAILABLE()		(ibuf_last-ibuf_next)
2131460Sminshall #define	IBUFFER()		ibuffer
22*31499Sminshall #define	IBUFFREE()		(ibuffer+sizeof ibuffer-ibuf_last-1)
2331493Sminshall #define	IBUFGETBYTES(w,l)	{ memcpy(w, ibuf_next, l); ibuf_next += l; }
2431460Sminshall #define	IBUFRESET()		(ibuf_next = ibuf_last = ibuffer)
2531460Sminshall 
26*31499Sminshall char obuffer[4000], *obuf_next;
2731460Sminshall #define	OBUFADDBYTES(w,l)	{ memcpy(obuf_next, w, l); obuf_next += l; }
2831460Sminshall #define	OBUFAVAILABLE()		(obuf_next - obuffer)
2931460Sminshall #define	OBUFFER()		obuffer
3031460Sminshall #define	OBUFRESET()		obuf_next = obuffer
3131460Sminshall #define	OBUFROOM()		(obuffer+sizeof obuffer-obuf_next)
3231460Sminshall 
3331460Sminshall 
3431460Sminshall static int
3531460Sminshall outflush()
3631460Sminshall {
3731460Sminshall     int length = OBUFAVAILABLE();
3831460Sminshall 
3931460Sminshall     if (length != 0) {
4031460Sminshall 	if (write(sock, OBUFFER(), length) != length) {
4131493Sminshall 	    WHO_ARE_WE();
4231474Sminshall 	    perror("write");
4331460Sminshall 	    return -1;
4431460Sminshall 	}
4531460Sminshall 	OBUFRESET();
4631460Sminshall     }
4731460Sminshall     return 0;				/* All OK */
4831460Sminshall }
4931460Sminshall 
5031460Sminshall 
5131460Sminshall static int
52*31499Sminshall iget(location, length)
53*31499Sminshall char	*location;
54*31499Sminshall int	length;
5531460Sminshall {
5631460Sminshall     int i;
57*31499Sminshall     int count;
5831460Sminshall 
5931460Sminshall     if (OBUFAVAILABLE()) {
6031460Sminshall 	if (outflush() == -1) {
6131460Sminshall 	    return -1;
6231460Sminshall 	}
6331460Sminshall     }
64*31499Sminshall     if ((count = IBUFAVAILABLE()) != 0) {
65*31499Sminshall 	if (count > length) {
66*31499Sminshall 	    count = length;
67*31499Sminshall 	}
68*31499Sminshall 	IBUFGETBYTES(location, count);
69*31499Sminshall 	length -= count;
70*31499Sminshall 	location += count;
7131460Sminshall     }
72*31499Sminshall     while (length) {
73*31499Sminshall 	if (ibuf_next == ibuf_last) {
74*31499Sminshall 	    IBUFRESET();
75*31499Sminshall 	}
76*31499Sminshall 	if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
7731493Sminshall 	    WHO_ARE_WE();
7831474Sminshall 	    perror("read");
7931460Sminshall 	    return -1;
8031460Sminshall 	}
81*31499Sminshall 	if (count == 0) {
8231474Sminshall 	    /* Reading past end-of-file */
8331493Sminshall 	    WHO_ARE_WE();
8431493Sminshall 	    fprintf(stderr, "End of file read\r\n");
8531474Sminshall 	    return -1;
8631474Sminshall 	}
87*31499Sminshall 	IBUFADDED(count);
88*31499Sminshall 	if (count > length) {
89*31499Sminshall 	    count = length;
90*31499Sminshall 	}
91*31499Sminshall 	IBUFGETBYTES(location, count);
92*31499Sminshall 	length -= count;
93*31499Sminshall 	location += count;
9431460Sminshall     }
9531460Sminshall     return 0;
9631460Sminshall }
9731460Sminshall 
9831493Sminshall static char *
9931493Sminshall exch_to_ascii(exch)
10031493Sminshall int exch;			/* opcode to decode */
10131493Sminshall {
10231493Sminshall     switch (exch) {
10331493Sminshall     case EXCH_EXCH_COMMAND:
10431493Sminshall 	return "Command";
10531493Sminshall     case EXCH_EXCH_TYPE:
10631493Sminshall 	return "Type";
10731493Sminshall     case EXCH_EXCH_TURNAROUND:
10831493Sminshall 	return "Turnaround";
10931493Sminshall     case EXCH_EXCH_RTS:
11031493Sminshall 	return "Request to Send";
11131493Sminshall     default:
11231493Sminshall 	{
11331493Sminshall 	    static char unknown[40];
11431493Sminshall 
11531493Sminshall 	    sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
11631493Sminshall 	    return unknown;
11731493Sminshall 	}
11831493Sminshall     }
11931493Sminshall }
12031493Sminshall 
12131493Sminshall /*
12231493Sminshall  * Send the exch structure, updating the sequnce number field.
12331493Sminshall  */
12431493Sminshall 
12531493Sminshall static int
12631493Sminshall send_state()
12731493Sminshall {
12831493Sminshall     if (OBUFROOM() < sizeof exch_state) {
12931493Sminshall 	if (outflush() == -1) {
13031493Sminshall 	    return -1;
13131493Sminshall 	}
13231493Sminshall     }
13331498Sminshall     my_sequence = (my_sequence+1)&0xff;
13431498Sminshall     exch_state.my_sequence = my_sequence;
13531493Sminshall     exch_state.your_sequence = your_sequence;
13631493Sminshall     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
13731493Sminshall     return 0;
13831493Sminshall }
13931493Sminshall 
14031493Sminshall /*
14131493Sminshall  * Receive the exch structure from the other side, checking
14231493Sminshall  * sequence numbering.
14331493Sminshall  */
14431493Sminshall 
14531493Sminshall static int
14631493Sminshall receive_state()
14731493Sminshall {
148*31499Sminshall     if (iget((char *)&exch_state, sizeof exch_state) == -1) {
149*31499Sminshall 	return -1;
15031493Sminshall     }
15131493Sminshall     if (conversation != CONTENTION) {
15231493Sminshall 	if (exch_state.your_sequence != my_sequence) {
15331493Sminshall 	    WHO_ARE_WE();
15431493Sminshall 	    fprintf(stderr, "Send sequence number mismatch.\n");
15531493Sminshall 	    return -1;
15631493Sminshall 	}
15731498Sminshall 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
15831493Sminshall 	    WHO_ARE_WE();
15931493Sminshall 	    fprintf(stderr, "Receive sequence number mismatch.\n");
16031493Sminshall 	    return -1;
16131493Sminshall 	}
16231493Sminshall     }
16331498Sminshall     your_sequence = exch_state.my_sequence;
16431493Sminshall     return 0;
16531493Sminshall }
16631493Sminshall 
16731493Sminshall static int
16831493Sminshall enter_receive()
16931493Sminshall {
17031493Sminshall     switch (conversation) {
17131493Sminshall     case CONTENTION:
17231493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
17331493Sminshall 	if (send_state() == -1) {
17431493Sminshall 	    return -1;
17531493Sminshall 	}
17631493Sminshall 	if (receive_state() == -1) {
17731493Sminshall 	    return -1;
17831493Sminshall 	}
17931493Sminshall 	if (exch_state.opcode != EXCH_EXCH_RTS) {
18031493Sminshall 	    WHO_ARE_WE();
18131493Sminshall 	    fprintf(stderr, "In CONTENTION state:  ");
18231493Sminshall 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
18331493Sminshall 		fprintf(stderr,
18431493Sminshall 		    "Both sides tried to enter RECEIVE state.\n");
18531493Sminshall 	    } else {
18631493Sminshall 		fprintf(stderr,
18731493Sminshall 		    "Protocol error trying to enter RECEIVE state.\n");
18831493Sminshall 	    }
18931493Sminshall 	    return -1;
19031493Sminshall 	}
19131493Sminshall 	break;
19231493Sminshall     case SEND:
19331493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
19431493Sminshall 	if (send_state() == -1) {
19531493Sminshall 	    return -1;
19631493Sminshall 	}
19731493Sminshall 	break;
19831493Sminshall     }
19931493Sminshall     conversation = RECEIVE;
20031493Sminshall     return 0;
20131493Sminshall }
20231493Sminshall 
20331493Sminshall static int
20431493Sminshall enter_send()
20531493Sminshall {
20631493Sminshall     switch (conversation) {
20731493Sminshall     case CONTENTION:
20831493Sminshall 	exch_state.opcode = EXCH_EXCH_RTS;
20931493Sminshall 	if (send_state() == -1) {
21031493Sminshall 	    return -1;
21131493Sminshall 	}
21231493Sminshall 	 /* fall through */
21331493Sminshall     case RECEIVE:
21431493Sminshall 	if (receive_state() == -1) {
21531493Sminshall 	    return -1;
21631493Sminshall 	}
21731493Sminshall 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
21831493Sminshall 	    WHO_ARE_WE();
21931493Sminshall 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
22031493Sminshall 	    return -1;
22131493Sminshall 	}
22231493Sminshall     }
22331493Sminshall     conversation = SEND;
22431493Sminshall     return 0;
22531493Sminshall }
22631493Sminshall 
22731467Sminshall int
22831493Sminshall api_exch_nextcommand()
22931467Sminshall {
23031493Sminshall     if (conversation != RECEIVE) {
23131493Sminshall 	if (enter_receive() == -1) {
23231467Sminshall 	    return -1;
23331467Sminshall 	}
23431467Sminshall     }
23531493Sminshall     if (receive_state() == -1) {
23631493Sminshall 	return -1;
23731493Sminshall     }
23831493Sminshall     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
23931493Sminshall 	WHO_ARE_WE();
24031493Sminshall 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
24131493Sminshall 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
24231493Sminshall 	return -1;
24331493Sminshall     }
24431493Sminshall     return exch_state.command_or_type;
24531467Sminshall }
24631467Sminshall 
24731467Sminshall 
24831467Sminshall int
24931460Sminshall api_exch_incommand(command)
25031460Sminshall int command;
25131460Sminshall {
25231460Sminshall     int i;
25331460Sminshall 
25431493Sminshall     if ((i = api_exch_nextcommand()) == -1) {
25531493Sminshall 	return -1;
25631460Sminshall     }
25731460Sminshall     if (i != command) {
25831493Sminshall 	WHO_ARE_WE();
25931460Sminshall 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
26031460Sminshall 				command, i);
26131460Sminshall 	return -1;
26231460Sminshall     }
26331460Sminshall     return 0;
26431460Sminshall }
26531460Sminshall 
26631460Sminshall 
26731467Sminshall int
26831460Sminshall api_exch_outcommand(command)
26931460Sminshall int command;
27031460Sminshall {
27131493Sminshall     if (conversation != SEND) {
27231493Sminshall 	if (enter_send() == -1) {
27331460Sminshall 	    return -1;
27431460Sminshall 	}
27531460Sminshall     }
27631493Sminshall     exch_state.command_or_type = command;
27731493Sminshall     exch_state.opcode = EXCH_EXCH_COMMAND;
27831493Sminshall     if (send_state() == -1) {
27931493Sminshall 	return -1;
28031493Sminshall     } else {
28131493Sminshall 	return 0;
28231493Sminshall     }
28331460Sminshall }
28431460Sminshall 
28531460Sminshall 
28631467Sminshall int
28731460Sminshall api_exch_outtype(type, length, location)
28831460Sminshall int
28931460Sminshall     type,
29031460Sminshall     length;
29131460Sminshall char
29231460Sminshall     *location;
29331460Sminshall {
29431460Sminshall     int netleng = htons(length);
29531460Sminshall 
29631493Sminshall     if (conversation != SEND) {
29731493Sminshall 	if (enter_send() == -1) {
29831460Sminshall 	    return -1;
29931460Sminshall 	}
30031460Sminshall     }
30131493Sminshall     exch_state.opcode = EXCH_EXCH_TYPE;
30231493Sminshall     exch_state.command_or_type = type;
30331493Sminshall     exch_state.length = netleng;
30431493Sminshall     if (send_state() == -1) {
30531493Sminshall 	return -1;
30631493Sminshall     }
30731493Sminshall     if (length) {
30831493Sminshall 	if (OBUFROOM() > length) {
30931493Sminshall 	    OBUFADDBYTES(location, length);
31031493Sminshall 	} else {
31131493Sminshall 	    if (outflush() == -1) {
31231493Sminshall 		return -1;
31331493Sminshall 	    }
31431493Sminshall 	    if (write(sock, location, length) != length) {
31531493Sminshall 		WHO_ARE_WE();
31631493Sminshall 		perror("write");
31731493Sminshall 		return -1;
31831493Sminshall 	    }
31931460Sminshall 	}
32031460Sminshall     }
32131493Sminshall     return 0;
32231460Sminshall }
32331460Sminshall 
32431460Sminshall 
32531467Sminshall int
32631460Sminshall api_exch_intype(type, length, location)
32731460Sminshall int
32831460Sminshall     type,
32931460Sminshall     length;
33031460Sminshall char
33131460Sminshall     *location;
33231460Sminshall {
33331460Sminshall     int i, netleng = htons(length);
33431460Sminshall 
33531493Sminshall     if (conversation != RECEIVE) {
33631493Sminshall 	if (enter_receive() == -1) {
33731460Sminshall 	    return -1;
33831460Sminshall 	}
33931460Sminshall     }
34031493Sminshall     if (receive_state() == -1) {
34131460Sminshall 	return -1;
34231460Sminshall     }
34331493Sminshall     if (exch_state.opcode != EXCH_EXCH_TYPE) {
34431493Sminshall 	WHO_ARE_WE();
34531493Sminshall 	fprintf(stderr,
34631493Sminshall 	    "Expected to receive a %s exchange, received a %s exchange.\n",
34731493Sminshall 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
34831493Sminshall 	return -1;
34931493Sminshall     }
35031493Sminshall     if (exch_state.command_or_type != type) {
35131493Sminshall 	WHO_ARE_WE();
35231493Sminshall 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
35331493Sminshall 	    type, exch_state.command_or_type);
35431493Sminshall 	return -1;
35531493Sminshall     }
35631493Sminshall     if (exch_state.length != netleng) {
35731460Sminshall 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
35831493Sminshall 		type, length, ntohs(exch_state.length));
35931460Sminshall 	return -1;
36031460Sminshall     }
361*31499Sminshall     if (iget(location, length) == -1) {
362*31499Sminshall 	return -1;
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