xref: /csrg-svn/usr.bin/tn3270/api/api_exch.c (revision 33820)
131890Sminshall /*
2*33820Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33820Sbostic  * All rights reserved.
431890Sminshall  *
5*33820Sbostic  * Redistribution and use in source and binary forms are permitted
6*33820Sbostic  * provided that this notice is preserved and that due credit is given
7*33820Sbostic  * to the University of California at Berkeley. The name of the University
8*33820Sbostic  * may not be used to endorse or promote products derived from this
9*33820Sbostic  * software without specific prior written permission. This software
10*33820Sbostic  * is provided ``as is'' without express or implied warranty.
1131890Sminshall  */
1231890Sminshall 
1331890Sminshall #ifndef lint
14*33820Sbostic static char sccsid[] = "@(#)api_exch.c	3.2 (Berkeley) 03/28/88";
15*33820Sbostic #endif /* not lint */
1631890Sminshall 
1731460Sminshall #include <stdio.h>
1831460Sminshall 
1931801Sminshall #include "../general/general.h"
2031801Sminshall 
2131460Sminshall #include "api_exch.h"
2231460Sminshall 
2331467Sminshall static int sock;		/* Socket number */
2431467Sminshall 
2531474Sminshall static char whoarewe[40] = "";
2631493Sminshall #define	WHO_ARE_WE()	fprintf(stderr, "(API %s) ", whoarewe);
2731474Sminshall 
2831493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation;
2931493Sminshall 
3031493Sminshall static struct exch_exch exch_state;
3131493Sminshall 
3231493Sminshall static unsigned int
3331493Sminshall     my_sequence,
3431493Sminshall     your_sequence;
3531493Sminshall 
3631499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last;
3731460Sminshall #define	IBUFADDED(i)		ibuf_last += (i)
3831499Sminshall #define	IBUFAVAILABLE()		(ibuf_last-ibuf_next)
3931460Sminshall #define	IBUFFER()		ibuffer
4031499Sminshall #define	IBUFFREE()		(ibuffer+sizeof ibuffer-ibuf_last-1)
4131493Sminshall #define	IBUFGETBYTES(w,l)	{ memcpy(w, ibuf_next, l); ibuf_next += l; }
4231460Sminshall #define	IBUFRESET()		(ibuf_next = ibuf_last = ibuffer)
4331460Sminshall 
4431499Sminshall char obuffer[4000], *obuf_next;
4531460Sminshall #define	OBUFADDBYTES(w,l)	{ memcpy(obuf_next, w, l); obuf_next += l; }
4631460Sminshall #define	OBUFAVAILABLE()		(obuf_next - obuffer)
4731460Sminshall #define	OBUFFER()		obuffer
4831460Sminshall #define	OBUFRESET()		obuf_next = obuffer
4931460Sminshall #define	OBUFROOM()		(obuffer+sizeof obuffer-obuf_next)
5031460Sminshall 
5131460Sminshall 
5231460Sminshall static int
5331460Sminshall outflush()
5431460Sminshall {
5531460Sminshall     int length = OBUFAVAILABLE();
5631460Sminshall 
5731460Sminshall     if (length != 0) {
5831460Sminshall 	if (write(sock, OBUFFER(), length) != length) {
5931493Sminshall 	    WHO_ARE_WE();
6031474Sminshall 	    perror("write");
6131460Sminshall 	    return -1;
6231460Sminshall 	}
6331460Sminshall 	OBUFRESET();
6431460Sminshall     }
6531460Sminshall     return 0;				/* All OK */
6631460Sminshall }
6731460Sminshall 
6831460Sminshall 
6931460Sminshall static int
7031499Sminshall iget(location, length)
7131499Sminshall char	*location;
7231499Sminshall int	length;
7331460Sminshall {
7431460Sminshall     int i;
7531499Sminshall     int count;
7631460Sminshall 
7731460Sminshall     if (OBUFAVAILABLE()) {
7831460Sminshall 	if (outflush() == -1) {
7931460Sminshall 	    return -1;
8031460Sminshall 	}
8131460Sminshall     }
8231499Sminshall     if ((count = IBUFAVAILABLE()) != 0) {
8331499Sminshall 	if (count > length) {
8431499Sminshall 	    count = length;
8531499Sminshall 	}
8631499Sminshall 	IBUFGETBYTES(location, count);
8731499Sminshall 	length -= count;
8831499Sminshall 	location += count;
8931460Sminshall     }
9031499Sminshall     while (length) {
9131499Sminshall 	if (ibuf_next == ibuf_last) {
9231499Sminshall 	    IBUFRESET();
9331499Sminshall 	}
9431499Sminshall 	if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
9531493Sminshall 	    WHO_ARE_WE();
9631474Sminshall 	    perror("read");
9731460Sminshall 	    return -1;
9831460Sminshall 	}
9931499Sminshall 	if (count == 0) {
10031474Sminshall 	    /* Reading past end-of-file */
10131493Sminshall 	    WHO_ARE_WE();
10231493Sminshall 	    fprintf(stderr, "End of file read\r\n");
10331474Sminshall 	    return -1;
10431474Sminshall 	}
10531499Sminshall 	IBUFADDED(count);
10631499Sminshall 	if (count > length) {
10731499Sminshall 	    count = length;
10831499Sminshall 	}
10931499Sminshall 	IBUFGETBYTES(location, count);
11031499Sminshall 	length -= count;
11131499Sminshall 	location += count;
11231460Sminshall     }
11331460Sminshall     return 0;
11431460Sminshall }
11531460Sminshall 
11631493Sminshall static char *
11731493Sminshall exch_to_ascii(exch)
11831493Sminshall int exch;			/* opcode to decode */
11931493Sminshall {
12031493Sminshall     switch (exch) {
12131493Sminshall     case EXCH_EXCH_COMMAND:
12231493Sminshall 	return "Command";
12331493Sminshall     case EXCH_EXCH_TYPE:
12431493Sminshall 	return "Type";
12531493Sminshall     case EXCH_EXCH_TURNAROUND:
12631493Sminshall 	return "Turnaround";
12731493Sminshall     case EXCH_EXCH_RTS:
12831493Sminshall 	return "Request to Send";
12931493Sminshall     default:
13031493Sminshall 	{
13131493Sminshall 	    static char unknown[40];
13231493Sminshall 
13331493Sminshall 	    sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
13431493Sminshall 	    return unknown;
13531493Sminshall 	}
13631493Sminshall     }
13731493Sminshall }
13831493Sminshall 
13931493Sminshall /*
14031493Sminshall  * Send the exch structure, updating the sequnce number field.
14131493Sminshall  */
14231493Sminshall 
14331493Sminshall static int
14431493Sminshall send_state()
14531493Sminshall {
14631493Sminshall     if (OBUFROOM() < sizeof exch_state) {
14731493Sminshall 	if (outflush() == -1) {
14831493Sminshall 	    return -1;
14931493Sminshall 	}
15031493Sminshall     }
15131498Sminshall     my_sequence = (my_sequence+1)&0xff;
15231498Sminshall     exch_state.my_sequence = my_sequence;
15331493Sminshall     exch_state.your_sequence = your_sequence;
15431493Sminshall     OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
15531493Sminshall     return 0;
15631493Sminshall }
15731493Sminshall 
15831493Sminshall /*
15931493Sminshall  * Receive the exch structure from the other side, checking
16031493Sminshall  * sequence numbering.
16131493Sminshall  */
16231493Sminshall 
16331493Sminshall static int
16431493Sminshall receive_state()
16531493Sminshall {
16631499Sminshall     if (iget((char *)&exch_state, sizeof exch_state) == -1) {
16731499Sminshall 	return -1;
16831493Sminshall     }
16931493Sminshall     if (conversation != CONTENTION) {
17031493Sminshall 	if (exch_state.your_sequence != my_sequence) {
17131493Sminshall 	    WHO_ARE_WE();
17231493Sminshall 	    fprintf(stderr, "Send sequence number mismatch.\n");
17331493Sminshall 	    return -1;
17431493Sminshall 	}
17531498Sminshall 	if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
17631493Sminshall 	    WHO_ARE_WE();
17731493Sminshall 	    fprintf(stderr, "Receive sequence number mismatch.\n");
17831493Sminshall 	    return -1;
17931493Sminshall 	}
18031493Sminshall     }
18131498Sminshall     your_sequence = exch_state.my_sequence;
18231493Sminshall     return 0;
18331493Sminshall }
18431493Sminshall 
18531493Sminshall static int
18631493Sminshall enter_receive()
18731493Sminshall {
18831493Sminshall     switch (conversation) {
18931493Sminshall     case CONTENTION:
19031493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
19131493Sminshall 	if (send_state() == -1) {
19231493Sminshall 	    return -1;
19331493Sminshall 	}
19431493Sminshall 	if (receive_state() == -1) {
19531493Sminshall 	    return -1;
19631493Sminshall 	}
19731493Sminshall 	if (exch_state.opcode != EXCH_EXCH_RTS) {
19831493Sminshall 	    WHO_ARE_WE();
19931493Sminshall 	    fprintf(stderr, "In CONTENTION state:  ");
20031493Sminshall 	    if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
20131493Sminshall 		fprintf(stderr,
20231493Sminshall 		    "Both sides tried to enter RECEIVE state.\n");
20331493Sminshall 	    } else {
20431493Sminshall 		fprintf(stderr,
20531493Sminshall 		    "Protocol error trying to enter RECEIVE state.\n");
20631493Sminshall 	    }
20731493Sminshall 	    return -1;
20831493Sminshall 	}
20931493Sminshall 	break;
21031493Sminshall     case SEND:
21131493Sminshall 	exch_state.opcode = EXCH_EXCH_TURNAROUND;
21231493Sminshall 	if (send_state() == -1) {
21331493Sminshall 	    return -1;
21431493Sminshall 	}
21531493Sminshall 	break;
21631493Sminshall     }
21731493Sminshall     conversation = RECEIVE;
21831493Sminshall     return 0;
21931493Sminshall }
22031493Sminshall 
22131493Sminshall static int
22231493Sminshall enter_send()
22331493Sminshall {
22431493Sminshall     switch (conversation) {
22531493Sminshall     case CONTENTION:
22631493Sminshall 	exch_state.opcode = EXCH_EXCH_RTS;
22731493Sminshall 	if (send_state() == -1) {
22831493Sminshall 	    return -1;
22931493Sminshall 	}
23031493Sminshall 	 /* fall through */
23131493Sminshall     case RECEIVE:
23231493Sminshall 	if (receive_state() == -1) {
23331493Sminshall 	    return -1;
23431493Sminshall 	}
23531493Sminshall 	if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
23631493Sminshall 	    WHO_ARE_WE();
23731493Sminshall 	    fprintf(stderr, "Conversation error - both sides in SEND state.\n");
23831493Sminshall 	    return -1;
23931493Sminshall 	}
24031493Sminshall     }
24131493Sminshall     conversation = SEND;
24231493Sminshall     return 0;
24331493Sminshall }
24431493Sminshall 
24531467Sminshall int
24631493Sminshall api_exch_nextcommand()
24731467Sminshall {
24831493Sminshall     if (conversation != RECEIVE) {
24931493Sminshall 	if (enter_receive() == -1) {
25031467Sminshall 	    return -1;
25131467Sminshall 	}
25231467Sminshall     }
25331493Sminshall     if (receive_state() == -1) {
25431493Sminshall 	return -1;
25531493Sminshall     }
25631493Sminshall     if (exch_state.opcode != EXCH_EXCH_COMMAND) {
25731493Sminshall 	WHO_ARE_WE();
25831493Sminshall 	fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
25931493Sminshall 	    exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
26031493Sminshall 	return -1;
26131493Sminshall     }
26231493Sminshall     return exch_state.command_or_type;
26331467Sminshall }
26431467Sminshall 
26531467Sminshall 
26631467Sminshall int
26731460Sminshall api_exch_incommand(command)
26831460Sminshall int command;
26931460Sminshall {
27031460Sminshall     int i;
27131460Sminshall 
27231493Sminshall     if ((i = api_exch_nextcommand()) == -1) {
27331493Sminshall 	return -1;
27431460Sminshall     }
27531460Sminshall     if (i != command) {
27631493Sminshall 	WHO_ARE_WE();
27731460Sminshall 	fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
27831460Sminshall 				command, i);
27931460Sminshall 	return -1;
28031460Sminshall     }
28131460Sminshall     return 0;
28231460Sminshall }
28331460Sminshall 
28431460Sminshall 
28531467Sminshall int
28631460Sminshall api_exch_outcommand(command)
28731460Sminshall int command;
28831460Sminshall {
28931493Sminshall     if (conversation != SEND) {
29031493Sminshall 	if (enter_send() == -1) {
29131460Sminshall 	    return -1;
29231460Sminshall 	}
29331460Sminshall     }
29431493Sminshall     exch_state.command_or_type = command;
29531493Sminshall     exch_state.opcode = EXCH_EXCH_COMMAND;
29631493Sminshall     if (send_state() == -1) {
29731493Sminshall 	return -1;
29831493Sminshall     } else {
29931493Sminshall 	return 0;
30031493Sminshall     }
30131460Sminshall }
30231460Sminshall 
30331460Sminshall 
30431467Sminshall int
30531460Sminshall api_exch_outtype(type, length, location)
30631460Sminshall int
30731460Sminshall     type,
30831460Sminshall     length;
30931460Sminshall char
31031460Sminshall     *location;
31131460Sminshall {
31231801Sminshall     int netleng = length;
31331460Sminshall 
31431493Sminshall     if (conversation != SEND) {
31531493Sminshall 	if (enter_send() == -1) {
31631460Sminshall 	    return -1;
31731460Sminshall 	}
31831460Sminshall     }
31931493Sminshall     exch_state.opcode = EXCH_EXCH_TYPE;
32031493Sminshall     exch_state.command_or_type = type;
32131493Sminshall     exch_state.length = netleng;
32231493Sminshall     if (send_state() == -1) {
32331493Sminshall 	return -1;
32431493Sminshall     }
32531493Sminshall     if (length) {
32631493Sminshall 	if (OBUFROOM() > length) {
32731493Sminshall 	    OBUFADDBYTES(location, length);
32831493Sminshall 	} else {
32931493Sminshall 	    if (outflush() == -1) {
33031493Sminshall 		return -1;
33131493Sminshall 	    }
33231493Sminshall 	    if (write(sock, location, length) != length) {
33331493Sminshall 		WHO_ARE_WE();
33431493Sminshall 		perror("write");
33531493Sminshall 		return -1;
33631493Sminshall 	    }
33731460Sminshall 	}
33831460Sminshall     }
33931493Sminshall     return 0;
34031460Sminshall }
34131460Sminshall 
34231460Sminshall 
34331467Sminshall int
34431460Sminshall api_exch_intype(type, length, location)
34531460Sminshall int
34631460Sminshall     type,
34731460Sminshall     length;
34831460Sminshall char
34931460Sminshall     *location;
35031460Sminshall {
35131801Sminshall     int i, netleng = length;
35231460Sminshall 
35331493Sminshall     if (conversation != RECEIVE) {
35431493Sminshall 	if (enter_receive() == -1) {
35531460Sminshall 	    return -1;
35631460Sminshall 	}
35731460Sminshall     }
35831493Sminshall     if (receive_state() == -1) {
35931460Sminshall 	return -1;
36031460Sminshall     }
36131493Sminshall     if (exch_state.opcode != EXCH_EXCH_TYPE) {
36231493Sminshall 	WHO_ARE_WE();
36331493Sminshall 	fprintf(stderr,
36431493Sminshall 	    "Expected to receive a %s exchange, received a %s exchange.\n",
36531493Sminshall 	    exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
36631493Sminshall 	return -1;
36731493Sminshall     }
36831493Sminshall     if (exch_state.command_or_type != type) {
36931493Sminshall 	WHO_ARE_WE();
37031493Sminshall 	fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
37131493Sminshall 	    type, exch_state.command_or_type);
37231493Sminshall 	return -1;
37331493Sminshall     }
37431493Sminshall     if (exch_state.length != netleng) {
37531460Sminshall 	fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n",
37631801Sminshall 		type, length, exch_state.length);
37731460Sminshall 	return -1;
37831460Sminshall     }
37931499Sminshall     if (iget(location, length) == -1) {
38031499Sminshall 	return -1;
38131460Sminshall     }
38231460Sminshall     return 0;
38331460Sminshall }
38431467Sminshall 
38531467Sminshall int
38631493Sminshall api_exch_flush()
38731493Sminshall {
38831493Sminshall     return outflush();
38931493Sminshall }
39031493Sminshall 
39131493Sminshall int
39231474Sminshall api_exch_init(sock_number, ourname)
39331467Sminshall int sock_number;
39431474Sminshall char *ourname;
39531467Sminshall {
39631467Sminshall     sock = sock_number;
39731474Sminshall     strcpy(whoarewe, ourname);		/* For error messages */
39831467Sminshall 
39931493Sminshall     my_sequence = your_sequence = 0;
40031493Sminshall 
40131493Sminshall     conversation = CONTENTION;		/* We don't know which direction */
40231493Sminshall 
40331467Sminshall     IBUFRESET();
40431467Sminshall     OBUFRESET();
40531467Sminshall 
40631467Sminshall     return 0;
40731467Sminshall }
408