xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 31801)
131460Sminshall #include <stdio.h>
231460Sminshall 
3*31801Sminshall #include "../general/general.h"
4*31801Sminshall 
531460Sminshall #include "api_exch.h"
631460Sminshall 
731467Sminshall static int sock;		/* Socket number */
831467Sminshall 
931474Sminshall static char whoarewe[40] = "";
1031493Sminshall #define	WHO_ARE_WE()	fprintf(stderr, "(API %s) ", whoarewe);
1131474Sminshall 
1231493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation;
1331493Sminshall 
1431493Sminshall static struct exch_exch exch_state;
1531493Sminshall 
1631493Sminshall static unsigned int
1731493Sminshall     my_sequence,
1831493Sminshall     your_sequence;
1931493Sminshall 
2031499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last;
2131460Sminshall #define	IBUFADDED(i)		ibuf_last += (i)
2231499Sminshall #define	IBUFAVAILABLE()		(ibuf_last-ibuf_next)
2331460Sminshall #define	IBUFFER()		ibuffer
2431499Sminshall #define	IBUFFREE()		(ibuffer+sizeof ibuffer-ibuf_last-1)
2531493Sminshall #define	IBUFGETBYTES(w,l)	{ memcpy(w, ibuf_next, l); ibuf_next += l; }
2631460Sminshall #define	IBUFRESET()		(ibuf_next = ibuf_last = ibuffer)
2731460Sminshall 
2831499Sminshall char obuffer[4000], *obuf_next;
2931460Sminshall #define	OBUFADDBYTES(w,l)	{ memcpy(obuf_next, w, l); obuf_next += l; }
3031460Sminshall #define	OBUFAVAILABLE()		(obuf_next - obuffer)
3131460Sminshall #define	OBUFFER()		obuffer
3231460Sminshall #define	OBUFRESET()		obuf_next = obuffer
3331460Sminshall #define	OBUFROOM()		(obuffer+sizeof obuffer-obuf_next)
3431460Sminshall 
3531460Sminshall 
3631460Sminshall static int
3731460Sminshall outflush()
3831460Sminshall {
3931460Sminshall     int length = OBUFAVAILABLE();
4031460Sminshall 
4131460Sminshall     if (length != 0) {
4231460Sminshall 	if (write(sock, OBUFFER(), length) != length) {
4331493Sminshall 	    WHO_ARE_WE();
4431474Sminshall 	    perror("write");
4531460Sminshall 	    return -1;
4631460Sminshall 	}
4731460Sminshall 	OBUFRESET();
4831460Sminshall     }
4931460Sminshall     return 0;				/* All OK */
5031460Sminshall }
5131460Sminshall 
5231460Sminshall 
5331460Sminshall static int
5431499Sminshall iget(location, length)
5531499Sminshall char	*location;
5631499Sminshall int	length;
5731460Sminshall {
5831460Sminshall     int i;
5931499Sminshall     int count;
6031460Sminshall 
6131460Sminshall     if (OBUFAVAILABLE()) {
6231460Sminshall 	if (outflush() == -1) {
6331460Sminshall 	    return -1;
6431460Sminshall 	}
6531460Sminshall     }
6631499Sminshall     if ((count = IBUFAVAILABLE()) != 0) {
6731499Sminshall 	if (count > length) {
6831499Sminshall 	    count = length;
6931499Sminshall 	}
7031499Sminshall 	IBUFGETBYTES(location, count);
7131499Sminshall 	length -= count;
7231499Sminshall 	location += count;
7331460Sminshall     }
7431499Sminshall     while (length) {
7531499Sminshall 	if (ibuf_next == ibuf_last) {
7631499Sminshall 	    IBUFRESET();
7731499Sminshall 	}
7831499Sminshall 	if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
7931493Sminshall 	    WHO_ARE_WE();
8031474Sminshall 	    perror("read");
8131460Sminshall 	    return -1;
8231460Sminshall 	}
8331499Sminshall 	if (count == 0) {
8431474Sminshall 	    /* Reading past end-of-file */
8531493Sminshall 	    WHO_ARE_WE();
8631493Sminshall 	    fprintf(stderr, "End of file read\r\n");
8731474Sminshall 	    return -1;
8831474Sminshall 	}
8931499Sminshall 	IBUFADDED(count);
9031499Sminshall 	if (count > length) {
9131499Sminshall 	    count = length;
9231499Sminshall 	}
9331499Sminshall 	IBUFGETBYTES(location, count);
9431499Sminshall 	length -= count;
9531499Sminshall 	location += count;
9631460Sminshall     }
9731460Sminshall     return 0;
9831460Sminshall }
9931460Sminshall 
10031493Sminshall static char *
10131493Sminshall exch_to_ascii(exch)
10231493Sminshall int exch;			/* opcode to decode */
10331493Sminshall {
10431493Sminshall     switch (exch) {
10531493Sminshall     case EXCH_EXCH_COMMAND:
10631493Sminshall 	return "Command";
10731493Sminshall     case EXCH_EXCH_TYPE:
10831493Sminshall 	return "Type";
10931493Sminshall     case EXCH_EXCH_TURNAROUND:
11031493Sminshall 	return "Turnaround";
11131493Sminshall     case EXCH_EXCH_RTS:
11231493Sminshall 	return "Request to Send";
11331493Sminshall     default:
11431493Sminshall 	{
11531493Sminshall 	    static char unknown[40];
11631493Sminshall 
11731493Sminshall 	    sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
11831493Sminshall 	    return unknown;
11931493Sminshall 	}
12031493Sminshall     }
12131493Sminshall }
12231493Sminshall 
12331493Sminshall /*
12431493Sminshall  * Send the exch structure, updating the sequnce number field.
12531493Sminshall  */
12631493Sminshall 
12731493Sminshall static int
12831493Sminshall send_state()
12931493Sminshall {
13031493Sminshall     if (OBUFROOM() < sizeof exch_state) {
13131493Sminshall 	if (outflush() == -1) {
13231493Sminshall 	    return -1;
13331493Sminshall 	}
13431493Sminshall     }
13531498Sminshall     my_sequence = (my_sequence+1)&0xff;
13631498Sminshall     exch_state.my_sequence = my_sequence;
13731493Sminshall     exch_state.your_sequence = your_sequence;
13831493Sminshall     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
13931493Sminshall     return 0;
14031493Sminshall }
14131493Sminshall 
14231493Sminshall /*
14331493Sminshall  * Receive the exch structure from the other side, checking
14431493Sminshall  * sequence numbering.
14531493Sminshall  */
14631493Sminshall 
14731493Sminshall static int
14831493Sminshall receive_state()
14931493Sminshall {
15031499Sminshall     if (iget((char *)&exch_state, sizeof exch_state) == -1) {
15131499Sminshall 	return -1;
15231493Sminshall     }
15331493Sminshall     if (conversation != CONTENTION) {
15431493Sminshall 	if (exch_state.your_sequence != my_sequence) {
15531493Sminshall 	    WHO_ARE_WE();
15631493Sminshall 	    fprintf(stderr, "Send sequence number mismatch.\n");
15731493Sminshall 	    return -1;
15831493Sminshall 	}
15931498Sminshall 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
16031493Sminshall 	    WHO_ARE_WE();
16131493Sminshall 	    fprintf(stderr, "Receive sequence number mismatch.\n");
16231493Sminshall 	    return -1;
16331493Sminshall 	}
16431493Sminshall     }
16531498Sminshall     your_sequence = exch_state.my_sequence;
16631493Sminshall     return 0;
16731493Sminshall }
16831493Sminshall 
16931493Sminshall static int
17031493Sminshall enter_receive()
17131493Sminshall {
17231493Sminshall     switch (conversation) {
17331493Sminshall     case CONTENTION:
17431493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
17531493Sminshall 	if (send_state() == -1) {
17631493Sminshall 	    return -1;
17731493Sminshall 	}
17831493Sminshall 	if (receive_state() == -1) {
17931493Sminshall 	    return -1;
18031493Sminshall 	}
18131493Sminshall 	if (exch_state.opcode != EXCH_EXCH_RTS) {
18231493Sminshall 	    WHO_ARE_WE();
18331493Sminshall 	    fprintf(stderr, "In CONTENTION state:  ");
18431493Sminshall 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
18531493Sminshall 		fprintf(stderr,
18631493Sminshall 		    "Both sides tried to enter RECEIVE state.\n");
18731493Sminshall 	    } else {
18831493Sminshall 		fprintf(stderr,
18931493Sminshall 		    "Protocol error trying to enter RECEIVE state.\n");
19031493Sminshall 	    }
19131493Sminshall 	    return -1;
19231493Sminshall 	}
19331493Sminshall 	break;
19431493Sminshall     case SEND:
19531493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
19631493Sminshall 	if (send_state() == -1) {
19731493Sminshall 	    return -1;
19831493Sminshall 	}
19931493Sminshall 	break;
20031493Sminshall     }
20131493Sminshall     conversation = RECEIVE;
20231493Sminshall     return 0;
20331493Sminshall }
20431493Sminshall 
20531493Sminshall static int
20631493Sminshall enter_send()
20731493Sminshall {
20831493Sminshall     switch (conversation) {
20931493Sminshall     case CONTENTION:
21031493Sminshall 	exch_state.opcode = EXCH_EXCH_RTS;
21131493Sminshall 	if (send_state() == -1) {
21231493Sminshall 	    return -1;
21331493Sminshall 	}
21431493Sminshall 	 /* fall through */
21531493Sminshall     case RECEIVE:
21631493Sminshall 	if (receive_state() == -1) {
21731493Sminshall 	    return -1;
21831493Sminshall 	}
21931493Sminshall 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
22031493Sminshall 	    WHO_ARE_WE();
22131493Sminshall 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
22231493Sminshall 	    return -1;
22331493Sminshall 	}
22431493Sminshall     }
22531493Sminshall     conversation = SEND;
22631493Sminshall     return 0;
22731493Sminshall }
22831493Sminshall 
22931467Sminshall int
23031493Sminshall api_exch_nextcommand()
23131467Sminshall {
23231493Sminshall     if (conversation != RECEIVE) {
23331493Sminshall 	if (enter_receive() == -1) {
23431467Sminshall 	    return -1;
23531467Sminshall 	}
23631467Sminshall     }
23731493Sminshall     if (receive_state() == -1) {
23831493Sminshall 	return -1;
23931493Sminshall     }
24031493Sminshall     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
24131493Sminshall 	WHO_ARE_WE();
24231493Sminshall 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
24331493Sminshall 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
24431493Sminshall 	return -1;
24531493Sminshall     }
24631493Sminshall     return exch_state.command_or_type;
24731467Sminshall }
24831467Sminshall 
24931467Sminshall 
25031467Sminshall int
25131460Sminshall api_exch_incommand(command)
25231460Sminshall int command;
25331460Sminshall {
25431460Sminshall     int i;
25531460Sminshall 
25631493Sminshall     if ((i = api_exch_nextcommand()) == -1) {
25731493Sminshall 	return -1;
25831460Sminshall     }
25931460Sminshall     if (i != command) {
26031493Sminshall 	WHO_ARE_WE();
26131460Sminshall 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
26231460Sminshall 				command, i);
26331460Sminshall 	return -1;
26431460Sminshall     }
26531460Sminshall     return 0;
26631460Sminshall }
26731460Sminshall 
26831460Sminshall 
26931467Sminshall int
27031460Sminshall api_exch_outcommand(command)
27131460Sminshall int command;
27231460Sminshall {
27331493Sminshall     if (conversation != SEND) {
27431493Sminshall 	if (enter_send() == -1) {
27531460Sminshall 	    return -1;
27631460Sminshall 	}
27731460Sminshall     }
27831493Sminshall     exch_state.command_or_type = command;
27931493Sminshall     exch_state.opcode = EXCH_EXCH_COMMAND;
28031493Sminshall     if (send_state() == -1) {
28131493Sminshall 	return -1;
28231493Sminshall     } else {
28331493Sminshall 	return 0;
28431493Sminshall     }
28531460Sminshall }
28631460Sminshall 
28731460Sminshall 
28831467Sminshall int
28931460Sminshall api_exch_outtype(type, length, location)
29031460Sminshall int
29131460Sminshall     type,
29231460Sminshall     length;
29331460Sminshall char
29431460Sminshall     *location;
29531460Sminshall {
296*31801Sminshall     int netleng = length;
29731460Sminshall 
29831493Sminshall     if (conversation != SEND) {
29931493Sminshall 	if (enter_send() == -1) {
30031460Sminshall 	    return -1;
30131460Sminshall 	}
30231460Sminshall     }
30331493Sminshall     exch_state.opcode = EXCH_EXCH_TYPE;
30431493Sminshall     exch_state.command_or_type = type;
30531493Sminshall     exch_state.length = netleng;
30631493Sminshall     if (send_state() == -1) {
30731493Sminshall 	return -1;
30831493Sminshall     }
30931493Sminshall     if (length) {
31031493Sminshall 	if (OBUFROOM() > length) {
31131493Sminshall 	    OBUFADDBYTES(location, length);
31231493Sminshall 	} else {
31331493Sminshall 	    if (outflush() == -1) {
31431493Sminshall 		return -1;
31531493Sminshall 	    }
31631493Sminshall 	    if (write(sock, location, length) != length) {
31731493Sminshall 		WHO_ARE_WE();
31831493Sminshall 		perror("write");
31931493Sminshall 		return -1;
32031493Sminshall 	    }
32131460Sminshall 	}
32231460Sminshall     }
32331493Sminshall     return 0;
32431460Sminshall }
32531460Sminshall 
32631460Sminshall 
32731467Sminshall int
32831460Sminshall api_exch_intype(type, length, location)
32931460Sminshall int
33031460Sminshall     type,
33131460Sminshall     length;
33231460Sminshall char
33331460Sminshall     *location;
33431460Sminshall {
335*31801Sminshall     int i, netleng = length;
33631460Sminshall 
33731493Sminshall     if (conversation != RECEIVE) {
33831493Sminshall 	if (enter_receive() == -1) {
33931460Sminshall 	    return -1;
34031460Sminshall 	}
34131460Sminshall     }
34231493Sminshall     if (receive_state() == -1) {
34331460Sminshall 	return -1;
34431460Sminshall     }
34531493Sminshall     if (exch_state.opcode != EXCH_EXCH_TYPE) {
34631493Sminshall 	WHO_ARE_WE();
34731493Sminshall 	fprintf(stderr,
34831493Sminshall 	    "Expected to receive a %s exchange, received a %s exchange.\n",
34931493Sminshall 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
35031493Sminshall 	return -1;
35131493Sminshall     }
35231493Sminshall     if (exch_state.command_or_type != type) {
35331493Sminshall 	WHO_ARE_WE();
35431493Sminshall 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
35531493Sminshall 	    type, exch_state.command_or_type);
35631493Sminshall 	return -1;
35731493Sminshall     }
35831493Sminshall     if (exch_state.length != netleng) {
35931460Sminshall 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
360*31801Sminshall 		type, length, exch_state.length);
36131460Sminshall 	return -1;
36231460Sminshall     }
36331499Sminshall     if (iget(location, length) == -1) {
36431499Sminshall 	return -1;
36531460Sminshall     }
36631460Sminshall     return 0;
36731460Sminshall }
36831467Sminshall 
36931467Sminshall int
37031493Sminshall api_exch_flush()
37131493Sminshall {
37231493Sminshall     return outflush();
37331493Sminshall }
37431493Sminshall 
37531493Sminshall int
37631474Sminshall api_exch_init(sock_number, ourname)
37731467Sminshall int sock_number;
37831474Sminshall char *ourname;
37931467Sminshall {
38031467Sminshall     sock = sock_number;
38131474Sminshall     strcpy(whoarewe, ourname);		/* For error messages */
38231467Sminshall 
38331493Sminshall     my_sequence = your_sequence = 0;
38431493Sminshall 
38531493Sminshall     conversation = CONTENTION;		/* We don't know which direction */
38631493Sminshall 
38731467Sminshall     IBUFRESET();
38831467Sminshall     OBUFRESET();
38931467Sminshall 
39031467Sminshall     return 0;
39131467Sminshall }
392