148754Sbostic /*-
2*62317Sbostic * Copyright (c) 1988, 1993
3*62317Sbostic * The Regents of the University of California. All rights reserved.
431890Sminshall *
548754Sbostic * %sccs.include.redist.c%
631890Sminshall */
731890Sminshall
831890Sminshall #ifndef lint
9*62317Sbostic static char sccsid[] = "@(#)api_exch.c 8.1 (Berkeley) 06/06/93";
1033820Sbostic #endif /* not lint */
1131890Sminshall
1231460Sminshall #include <stdio.h>
1331460Sminshall
1431801Sminshall #include "../general/general.h"
1531801Sminshall
1631460Sminshall #include "api_exch.h"
1731460Sminshall
1831467Sminshall static int sock; /* Socket number */
1931467Sminshall
2031474Sminshall static char whoarewe[40] = "";
2131493Sminshall #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe);
2231474Sminshall
2331493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation;
2431493Sminshall
2531493Sminshall static struct exch_exch exch_state;
2631493Sminshall
2731493Sminshall static unsigned int
2831493Sminshall my_sequence,
2931493Sminshall your_sequence;
3031493Sminshall
3131499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last;
3231460Sminshall #define IBUFADDED(i) ibuf_last += (i)
3331499Sminshall #define IBUFAVAILABLE() (ibuf_last-ibuf_next)
3431460Sminshall #define IBUFFER() ibuffer
3531499Sminshall #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1)
3631493Sminshall #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; }
3731460Sminshall #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer)
3831460Sminshall
3931499Sminshall char obuffer[4000], *obuf_next;
4031460Sminshall #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; }
4131460Sminshall #define OBUFAVAILABLE() (obuf_next - obuffer)
4231460Sminshall #define OBUFFER() obuffer
4331460Sminshall #define OBUFRESET() obuf_next = obuffer
4431460Sminshall #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next)
4531460Sminshall
4631460Sminshall
4731460Sminshall static int
outflush()4831460Sminshall outflush()
4931460Sminshall {
5031460Sminshall int length = OBUFAVAILABLE();
5131460Sminshall
5231460Sminshall if (length != 0) {
5331460Sminshall if (write(sock, OBUFFER(), length) != length) {
5431493Sminshall WHO_ARE_WE();
5531474Sminshall perror("write");
5631460Sminshall return -1;
5731460Sminshall }
5831460Sminshall OBUFRESET();
5931460Sminshall }
6031460Sminshall return 0; /* All OK */
6131460Sminshall }
6231460Sminshall
6331460Sminshall
6431460Sminshall static int
iget(location,length)6531499Sminshall iget(location, length)
6631499Sminshall char *location;
6731499Sminshall int length;
6831460Sminshall {
6931499Sminshall int count;
7031460Sminshall
7131460Sminshall if (OBUFAVAILABLE()) {
7231460Sminshall if (outflush() == -1) {
7331460Sminshall return -1;
7431460Sminshall }
7531460Sminshall }
7631499Sminshall if ((count = IBUFAVAILABLE()) != 0) {
7731499Sminshall if (count > length) {
7831499Sminshall count = length;
7931499Sminshall }
8031499Sminshall IBUFGETBYTES(location, count);
8131499Sminshall length -= count;
8231499Sminshall location += count;
8331460Sminshall }
8431499Sminshall while (length) {
8531499Sminshall if (ibuf_next == ibuf_last) {
8631499Sminshall IBUFRESET();
8731499Sminshall }
8831499Sminshall if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
8931493Sminshall WHO_ARE_WE();
9031474Sminshall perror("read");
9131460Sminshall return -1;
9231460Sminshall }
9331499Sminshall if (count == 0) {
9431474Sminshall /* Reading past end-of-file */
9531493Sminshall WHO_ARE_WE();
9631493Sminshall fprintf(stderr, "End of file read\r\n");
9731474Sminshall return -1;
9831474Sminshall }
9931499Sminshall IBUFADDED(count);
10031499Sminshall if (count > length) {
10131499Sminshall count = length;
10231499Sminshall }
10331499Sminshall IBUFGETBYTES(location, count);
10431499Sminshall length -= count;
10531499Sminshall location += count;
10631460Sminshall }
10731460Sminshall return 0;
10831460Sminshall }
10931460Sminshall
11031493Sminshall static char *
exch_to_ascii(exch)11131493Sminshall exch_to_ascii(exch)
11231493Sminshall int exch; /* opcode to decode */
11331493Sminshall {
11431493Sminshall switch (exch) {
11531493Sminshall case EXCH_EXCH_COMMAND:
11631493Sminshall return "Command";
11731493Sminshall case EXCH_EXCH_TYPE:
11831493Sminshall return "Type";
11931493Sminshall case EXCH_EXCH_TURNAROUND:
12031493Sminshall return "Turnaround";
12131493Sminshall case EXCH_EXCH_RTS:
12231493Sminshall return "Request to Send";
12331493Sminshall default:
12431493Sminshall {
12531493Sminshall static char unknown[40];
12631493Sminshall
12731493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
12831493Sminshall return unknown;
12931493Sminshall }
13031493Sminshall }
13131493Sminshall }
13231493Sminshall
13331493Sminshall /*
13431493Sminshall * Send the exch structure, updating the sequnce number field.
13531493Sminshall */
13631493Sminshall
13731493Sminshall static int
send_state()13831493Sminshall send_state()
13931493Sminshall {
14031493Sminshall if (OBUFROOM() < sizeof exch_state) {
14131493Sminshall if (outflush() == -1) {
14231493Sminshall return -1;
14331493Sminshall }
14431493Sminshall }
14531498Sminshall my_sequence = (my_sequence+1)&0xff;
14631498Sminshall exch_state.my_sequence = my_sequence;
14731493Sminshall exch_state.your_sequence = your_sequence;
14831493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state);
14931493Sminshall return 0;
15031493Sminshall }
15131493Sminshall
15231493Sminshall /*
15331493Sminshall * Receive the exch structure from the other side, checking
15431493Sminshall * sequence numbering.
15531493Sminshall */
15631493Sminshall
15731493Sminshall static int
receive_state()15831493Sminshall receive_state()
15931493Sminshall {
16031499Sminshall if (iget((char *)&exch_state, sizeof exch_state) == -1) {
16131499Sminshall return -1;
16231493Sminshall }
16331493Sminshall if (conversation != CONTENTION) {
16431493Sminshall if (exch_state.your_sequence != my_sequence) {
16531493Sminshall WHO_ARE_WE();
16631493Sminshall fprintf(stderr, "Send sequence number mismatch.\n");
16731493Sminshall return -1;
16831493Sminshall }
16931498Sminshall if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
17031493Sminshall WHO_ARE_WE();
17131493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n");
17231493Sminshall return -1;
17331493Sminshall }
17431493Sminshall }
17531498Sminshall your_sequence = exch_state.my_sequence;
17631493Sminshall return 0;
17731493Sminshall }
17831493Sminshall
17931493Sminshall static int
enter_receive()18031493Sminshall enter_receive()
18131493Sminshall {
18231493Sminshall switch (conversation) {
18331493Sminshall case CONTENTION:
18431493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND;
18531493Sminshall if (send_state() == -1) {
18631493Sminshall return -1;
18731493Sminshall }
18831493Sminshall if (receive_state() == -1) {
18931493Sminshall return -1;
19031493Sminshall }
19131493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) {
19231493Sminshall WHO_ARE_WE();
19331493Sminshall fprintf(stderr, "In CONTENTION state: ");
19431493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
19531493Sminshall fprintf(stderr,
19631493Sminshall "Both sides tried to enter RECEIVE state.\n");
19731493Sminshall } else {
19831493Sminshall fprintf(stderr,
19931493Sminshall "Protocol error trying to enter RECEIVE state.\n");
20031493Sminshall }
20131493Sminshall return -1;
20231493Sminshall }
20331493Sminshall break;
20431493Sminshall case SEND:
20531493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND;
20631493Sminshall if (send_state() == -1) {
20731493Sminshall return -1;
20831493Sminshall }
20931493Sminshall break;
21031493Sminshall }
21131493Sminshall conversation = RECEIVE;
21231493Sminshall return 0;
21331493Sminshall }
21431493Sminshall
21531493Sminshall static int
enter_send()21631493Sminshall enter_send()
21731493Sminshall {
21831493Sminshall switch (conversation) {
21931493Sminshall case CONTENTION:
22031493Sminshall exch_state.opcode = EXCH_EXCH_RTS;
22131493Sminshall if (send_state() == -1) {
22231493Sminshall return -1;
22331493Sminshall }
22431493Sminshall /* fall through */
22531493Sminshall case RECEIVE:
22631493Sminshall if (receive_state() == -1) {
22731493Sminshall return -1;
22831493Sminshall }
22931493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
23031493Sminshall WHO_ARE_WE();
23131493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n");
23231493Sminshall return -1;
23331493Sminshall }
23431493Sminshall }
23531493Sminshall conversation = SEND;
23631493Sminshall return 0;
23731493Sminshall }
23831493Sminshall
23931467Sminshall int
api_exch_nextcommand()24031493Sminshall api_exch_nextcommand()
24131467Sminshall {
24231493Sminshall if (conversation != RECEIVE) {
24331493Sminshall if (enter_receive() == -1) {
24431467Sminshall return -1;
24531467Sminshall }
24631467Sminshall }
24731493Sminshall if (receive_state() == -1) {
24831493Sminshall return -1;
24931493Sminshall }
25031493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) {
25131493Sminshall WHO_ARE_WE();
25231493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n",
25331493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode));
25431493Sminshall return -1;
25531493Sminshall }
25631493Sminshall return exch_state.command_or_type;
25731467Sminshall }
25831467Sminshall
25931467Sminshall
26031467Sminshall int
api_exch_incommand(command)26131460Sminshall api_exch_incommand(command)
26231460Sminshall int command;
26331460Sminshall {
26431460Sminshall int i;
26531460Sminshall
26631493Sminshall if ((i = api_exch_nextcommand()) == -1) {
26731493Sminshall return -1;
26831460Sminshall }
26931460Sminshall if (i != command) {
27031493Sminshall WHO_ARE_WE();
27131460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
27231460Sminshall command, i);
27331460Sminshall return -1;
27431460Sminshall }
27531460Sminshall return 0;
27631460Sminshall }
27731460Sminshall
27831460Sminshall
27931467Sminshall int
api_exch_outcommand(command)28031460Sminshall api_exch_outcommand(command)
28131460Sminshall int command;
28231460Sminshall {
28331493Sminshall if (conversation != SEND) {
28431493Sminshall if (enter_send() == -1) {
28531460Sminshall return -1;
28631460Sminshall }
28731460Sminshall }
28831493Sminshall exch_state.command_or_type = command;
28931493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND;
29031493Sminshall if (send_state() == -1) {
29131493Sminshall return -1;
29231493Sminshall } else {
29331493Sminshall return 0;
29431493Sminshall }
29531460Sminshall }
29631460Sminshall
29731460Sminshall
29831467Sminshall int
api_exch_outtype(type,length,location)29931460Sminshall api_exch_outtype(type, length, location)
30031460Sminshall int
30131460Sminshall type,
30231460Sminshall length;
30331460Sminshall char
30431460Sminshall *location;
30531460Sminshall {
30631801Sminshall int netleng = length;
30731460Sminshall
30831493Sminshall if (conversation != SEND) {
30931493Sminshall if (enter_send() == -1) {
31031460Sminshall return -1;
31131460Sminshall }
31231460Sminshall }
31331493Sminshall exch_state.opcode = EXCH_EXCH_TYPE;
31431493Sminshall exch_state.command_or_type = type;
31531493Sminshall exch_state.length = netleng;
31631493Sminshall if (send_state() == -1) {
31731493Sminshall return -1;
31831493Sminshall }
31931493Sminshall if (length) {
32031493Sminshall if (OBUFROOM() > length) {
32131493Sminshall OBUFADDBYTES(location, length);
32231493Sminshall } else {
32331493Sminshall if (outflush() == -1) {
32431493Sminshall return -1;
32531493Sminshall }
32631493Sminshall if (write(sock, location, length) != length) {
32731493Sminshall WHO_ARE_WE();
32831493Sminshall perror("write");
32931493Sminshall return -1;
33031493Sminshall }
33131460Sminshall }
33231460Sminshall }
33331493Sminshall return 0;
33431460Sminshall }
33531460Sminshall
33631460Sminshall
33731467Sminshall int
api_exch_intype(type,length,location)33831460Sminshall api_exch_intype(type, length, location)
33931460Sminshall int
34031460Sminshall type,
34131460Sminshall length;
34231460Sminshall char
34331460Sminshall *location;
34431460Sminshall {
34535418Sminshall int netleng = length;
34631460Sminshall
34731493Sminshall if (conversation != RECEIVE) {
34831493Sminshall if (enter_receive() == -1) {
34931460Sminshall return -1;
35031460Sminshall }
35131460Sminshall }
35231493Sminshall if (receive_state() == -1) {
35331460Sminshall return -1;
35431460Sminshall }
35531493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) {
35631493Sminshall WHO_ARE_WE();
35731493Sminshall fprintf(stderr,
35831493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n",
35931493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode));
36031493Sminshall return -1;
36131493Sminshall }
36231493Sminshall if (exch_state.command_or_type != type) {
36331493Sminshall WHO_ARE_WE();
36431493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
36531493Sminshall type, exch_state.command_or_type);
36631493Sminshall return -1;
36731493Sminshall }
36831493Sminshall if (exch_state.length != netleng) {
36935418Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %u.\n",
37031801Sminshall type, length, exch_state.length);
37131460Sminshall return -1;
37231460Sminshall }
37331499Sminshall if (iget(location, length) == -1) {
37431499Sminshall return -1;
37531460Sminshall }
37631460Sminshall return 0;
37731460Sminshall }
37831467Sminshall
37931467Sminshall int
api_exch_flush()38031493Sminshall api_exch_flush()
38131493Sminshall {
38231493Sminshall return outflush();
38331493Sminshall }
38431493Sminshall
38531493Sminshall int
api_exch_init(sock_number,ourname)38631474Sminshall api_exch_init(sock_number, ourname)
38731467Sminshall int sock_number;
38831474Sminshall char *ourname;
38931467Sminshall {
39035418Sminshall extern char *strcpy();
39135418Sminshall
39231467Sminshall sock = sock_number;
39335418Sminshall (void) strcpy(whoarewe, ourname); /* For error messages */
39431467Sminshall
39531493Sminshall my_sequence = your_sequence = 0;
39631493Sminshall
39731493Sminshall conversation = CONTENTION; /* We don't know which direction */
39831493Sminshall
39931467Sminshall IBUFRESET();
40031467Sminshall OBUFRESET();
40131467Sminshall
40231467Sminshall return 0;
40331467Sminshall }
404