From d024bcc4d35bc104a64072b0d398725914b97b93 Mon Sep 17 00:00:00 2001 From: Gregory Minshall Date: Mon, 15 Jun 1987 21:55:24 -0800 Subject: [PATCH] Name changes, send/receive sequence numbers, conversation flow, api_exch_flush(). SCCS-vsn: usr.bin/tn3270/api/apilib.c 1.5 SCCS-vsn: usr.bin/tn3270/api/test.c 1.4 SCCS-vsn: usr.bin/tn3270/api/api_bsd.c 1.4 SCCS-vsn: usr.bin/tn3270/api/api_exch.c 1.4 SCCS-vsn: usr.bin/tn3270/api/api_exch.h 1.4 --- usr/src/usr.bin/tn3270/api/api_bsd.c | 38 ++-- usr/src/usr.bin/tn3270/api/api_exch.c | 262 ++++++++++++++++++++++---- usr/src/usr.bin/tn3270/api/api_exch.h | 83 ++++++-- usr/src/usr.bin/tn3270/api/apilib.c | 16 ++ usr/src/usr.bin/tn3270/api/test.c | 2 + 5 files changed, 337 insertions(+), 64 deletions(-) diff --git a/usr/src/usr.bin/tn3270/api/api_bsd.c b/usr/src/usr.bin/tn3270/api/api_bsd.c index 10a664b37f..0eb5304e92 100644 --- a/usr/src/usr.bin/tn3270/api/api_bsd.c +++ b/usr/src/usr.bin/tn3270/api/api_bsd.c @@ -8,6 +8,20 @@ #include "api_exch.h" +int +api_close_api() +{ + if (api_exch_outcommand(EXCH_CMD_DISASSOCIATE) == -1) { + return -1; + } else if (api_exch_flush() == -1) { + return -1; + } else { + return 0; + } +} + + +int api_open_api(string) char *string; /* if non-zero, where to connect to */ { @@ -52,20 +66,20 @@ char *string; /* if non-zero, where to connect to */ return -1; } /* Now, try application level connection */ - if (api_exch_init(sock) == -1) { + if (api_exch_init(sock, "client") == -1) { return -1; } - if (api_exch_outcommand(EXCH_ASSOCIATE) == -1) { + if (api_exch_outcommand(EXCH_CMD_ASSOCIATE) == -1) { return -1; } - while ((i = api_exch_inbyte()) != EXCH_ASSOCIATED) { + while ((i = api_exch_nextcommand()) != EXCH_CMD_ASSOCIATED) { struct storage_descriptor sd; int passwd_length; char *passwd, *getpass(); char buffer[200]; switch (i) { - case EXCH_REJECTED: + case EXCH_CMD_REJECTED: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { return -1; @@ -76,11 +90,11 @@ char *string; /* if non-zero, where to connect to */ } buffer[sd.length] = 0; fprintf(stderr, "%s\n", buffer); - if (api_exch_outcommand(EXCH_ASSOCIATE) == -1) { + if (api_exch_outcommand(EXCH_CMD_ASSOCIATE) == -1) { return -1; } break; - case EXCH_SEND_AUTH: + case EXCH_CMD_SEND_AUTH: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { return -1; } @@ -112,7 +126,7 @@ char *string; /* if non-zero, where to connect to */ } } sd.length = htons(passwd_length); - if (api_exch_outcommand(EXCH_AUTH) == -1) { + if (api_exch_outcommand(EXCH_CMD_AUTH) == -1) { return -1; } if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { @@ -142,7 +156,7 @@ struct SREGS *sregs; struct storage_descriptor sd; int i; - if (api_exch_outcommand(EXCH_REQUEST) == -1) { + if (api_exch_outcommand(EXCH_CMD_REQUEST) == -1) { return -1; } if (api_exch_outtype(EXCH_TYPE_REGS, sizeof *regs, (char *)regs) == -1) { @@ -155,15 +169,15 @@ struct SREGS *sregs; if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { return -1; } - while ((i = api_exch_inbyte()) != EXCH_REPLY) { + while ((i = api_exch_nextcommand()) != EXCH_CMD_REPLY) { switch (i) { - case EXCH_GIMME: + case EXCH_CMD_GIMME: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { return -1; } /*XXX validity check GIMME? */ - if (api_exch_outcommand(EXCH_HEREIS) == -1) { + if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) { return -1; } if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) @@ -175,7 +189,7 @@ struct SREGS *sregs; return -1; } break; - case EXCH_HEREIS: + case EXCH_CMD_HEREIS: if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { return -1; diff --git a/usr/src/usr.bin/tn3270/api/api_exch.c b/usr/src/usr.bin/tn3270/api/api_exch.c index 5c38b1a74b..b6f80d9a22 100644 --- a/usr/src/usr.bin/tn3270/api/api_exch.c +++ b/usr/src/usr.bin/tn3270/api/api_exch.c @@ -5,11 +5,21 @@ static int sock; /* Socket number */ static char whoarewe[40] = ""; +#define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); + +static enum {CONTENTION, SEND, RECEIVE } conversation; + +static struct exch_exch exch_state; + +static unsigned int + my_sequence, + your_sequence; static char ibuffer[40], *ibuf_next, *ibuf_last; #define IBUFADDED(i) ibuf_last += (i) #define IBUFAVAILABLE() (ibuf_last -ibuf_next) #define IBUFFER() ibuffer +#define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } #define IBUFGETCHAR() (*ibuf_next++) #define IBUFGETSHORT() ((*ibuf_next++<<8)|(*ibuf_next++&0xff)) #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) @@ -31,7 +41,7 @@ outflush() if (length != 0) { if (write(sock, OBUFFER(), length) != length) { - fprintf(stderr, "(API %s) ", whoarewe); + WHO_ARE_WE(); perror("write"); return -1; } @@ -55,15 +65,19 @@ int count; if (ibuf_next == ibuf_last) { IBUFRESET(); } + if ((count -= IBUFAVAILABLE()) < 0) { + return 0; + } while (count) { if ((i = read(sock, IBUFFER(), count)) < 0) { - fprintf(stderr, "(API %s) ", whoarewe); + WHO_ARE_WE(); perror("read"); return -1; } if (i == 0) { /* Reading past end-of-file */ - fprintf(stderr, "(API %s) End of file read\r\n", whoarewe); + WHO_ARE_WE(); + fprintf(stderr, "End of file read\r\n"); return -1; } count -= i; @@ -72,15 +86,157 @@ int count; return 0; } +static char * +exch_to_ascii(exch) +int exch; /* opcode to decode */ +{ + switch (exch) { + case EXCH_EXCH_COMMAND: + return "Command"; + case EXCH_EXCH_TYPE: + return "Type"; + case EXCH_EXCH_TURNAROUND: + return "Turnaround"; + case EXCH_EXCH_RTS: + return "Request to Send"; + default: + { + static char unknown[40]; + + sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); + return unknown; + } + } +} + +/* + * Send the exch structure, updating the sequnce number field. + */ + +static int +send_state() +{ + if (OBUFROOM() < sizeof exch_state) { + if (outflush() == -1) { + return -1; + } + } + exch_state.my_sequence = ++my_sequence; + exch_state.your_sequence = your_sequence; + OBUFADDBYTES((char *)&exch_state, sizeof exch_state); + return 0; +} + +/* + * Receive the exch structure from the other side, checking + * sequence numbering. + */ + +static int +receive_state() +{ + if (IBUFAVAILABLE() < sizeof exch_state) { + if (infill(sizeof exch_state) == -1) { + return -1; + } + } + IBUFGETBYTES((char *)&exch_state, sizeof exch_state); + if (conversation != CONTENTION) { + if (exch_state.your_sequence != my_sequence) { + WHO_ARE_WE(); + fprintf(stderr, "Send sequence number mismatch.\n"); + return -1; + } + if (exch_state.my_sequence != ++your_sequence) { + WHO_ARE_WE(); + fprintf(stderr, "Receive sequence number mismatch.\n"); + return -1; + } + } else { + /* In contention state, no sequence numbering */ + your_sequence = exch_state.my_sequence; + } + return 0; +} + +static int +enter_receive() +{ + switch (conversation) { + case CONTENTION: + exch_state.opcode = EXCH_EXCH_TURNAROUND; + if (send_state() == -1) { + return -1; + } + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_RTS) { + WHO_ARE_WE(); + fprintf(stderr, "In CONTENTION state: "); + if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { + fprintf(stderr, + "Both sides tried to enter RECEIVE state.\n"); + } else { + fprintf(stderr, + "Protocol error trying to enter RECEIVE state.\n"); + } + return -1; + } + break; + case SEND: + exch_state.opcode = EXCH_EXCH_TURNAROUND; + if (send_state() == -1) { + return -1; + } + break; + } + conversation = RECEIVE; + return 0; +} + +static int +enter_send() +{ + switch (conversation) { + case CONTENTION: + exch_state.opcode = EXCH_EXCH_RTS; + if (send_state() == -1) { + return -1; + } + /* fall through */ + case RECEIVE: + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { + WHO_ARE_WE(); + fprintf(stderr, "Conversation error - both sides in SEND state.\n"); + return -1; + } + } + conversation = SEND; + return 0; +} + int -api_exch_inbyte() +api_exch_nextcommand() { - if (IBUFAVAILABLE() < 1) { - if (infill(1) == -1) { + if (conversation != RECEIVE) { + if (enter_receive() == -1) { return -1; } } - return IBUFGETCHAR(); + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_COMMAND) { + WHO_ARE_WE(); + fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", + exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); + return -1; + } + return exch_state.command_or_type; } @@ -90,13 +246,11 @@ int command; { int i; - if (IBUFAVAILABLE() < 1) { - if (infill(1) == -1) { - return -1; - } + if ((i = api_exch_nextcommand()) == -1) { + return -1; } - i = IBUFGETCHAR(); if (i != command) { + WHO_ARE_WE(); fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", command, i); return -1; @@ -109,13 +263,18 @@ int api_exch_outcommand(command) int command; { - if (OBUFROOM() < 1) { - if (outflush() == -1) { + if (conversation != SEND) { + if (enter_send() == -1) { return -1; } } - OBUFADDCHAR(command); - return 0; + exch_state.command_or_type = command; + exch_state.opcode = EXCH_EXCH_COMMAND; + if (send_state() == -1) { + return -1; + } else { + return 0; + } } @@ -129,25 +288,32 @@ char { int netleng = htons(length); - if (OBUFROOM() < 3) { - if (outflush() == -1) { + if (conversation != SEND) { + if (enter_send() == -1) { return -1; } } - OBUFADDCHAR(type); - OBUFADDSHORT(netleng); - if (OBUFROOM() > length) { - OBUFADDBYTES(location, length); - } else { - if (outflush() == -1) { - return -1; - } - if (write(sock, location, length) != length) { - fprintf(stderr, "(API %s) ", whoarewe); - perror("write"); - return -1; + exch_state.opcode = EXCH_EXCH_TYPE; + exch_state.command_or_type = type; + exch_state.length = netleng; + if (send_state() == -1) { + return -1; + } + if (length) { + if (OBUFROOM() > length) { + OBUFADDBYTES(location, length); + } else { + if (outflush() == -1) { + return -1; + } + if (write(sock, location, length) != length) { + WHO_ARE_WE(); + perror("write"); + return -1; + } } } + return 0; } @@ -161,23 +327,35 @@ char { int i, netleng = htons(length); - if (IBUFAVAILABLE() < 3) { - if (infill(3) == -1) { + if (conversation != RECEIVE) { + if (enter_receive() == -1) { return -1; } } - if ((i = IBUFGETCHAR()) != type) { - fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", type, i); + if (receive_state() == -1) { + return -1; + } + if (exch_state.opcode != EXCH_EXCH_TYPE) { + WHO_ARE_WE(); + fprintf(stderr, + "Expected to receive a %s exchange, received a %s exchange.\n", + exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); return -1; } - if ((i = IBUFGETSHORT()) != netleng) { + if (exch_state.command_or_type != type) { + WHO_ARE_WE(); + fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", + type, exch_state.command_or_type); + return -1; + } + if (exch_state.length != netleng) { fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", - type, length, ntohs(i)); + type, length, ntohs(exch_state.length)); return -1; } while (length) { if ((i = read(sock, location, length)) < 0) { - fprintf(stderr, "(API %s) ", whoarewe); + WHO_ARE_WE(); perror("read"); return -1; } @@ -187,6 +365,12 @@ char return 0; } +int +api_exch_flush() +{ + return outflush(); +} + int api_exch_init(sock_number, ourname) int sock_number; @@ -195,6 +379,10 @@ char *ourname; sock = sock_number; strcpy(whoarewe, ourname); /* For error messages */ + my_sequence = your_sequence = 0; + + conversation = CONTENTION; /* We don't know which direction */ + IBUFRESET(); OBUFRESET(); diff --git a/usr/src/usr.bin/tn3270/api/api_exch.h b/usr/src/usr.bin/tn3270/api/api_exch.h index 22e99f0eec..8200b9f072 100644 --- a/usr/src/usr.bin/tn3270/api/api_exch.h +++ b/usr/src/usr.bin/tn3270/api/api_exch.h @@ -3,57 +3,110 @@ * between the API client and API server on a Unix-based * tn3270 implementation. * - * A command is: * + */ + +/* + * The following are the low-level opcodes exchanged between the + * two sides. These are designed to allow for type, sequence number, + * and direction checking. + * + * We enforce conversation flow. There are three states: CONTENTION, + * SEND, and RECEIVE. Both sides start in CONTENTION. + * We never leave RECEIVE state without first reading a TURNAROUND + * opcode. We never leave SEND state without first writing a TURNAROUND + * opcode. This scheme ensures that we always have conversation flowing + * in a synchronized direction (or detect an application error), and that + * we never hang with both sides trying to read from the "wire". * + * State event action + * + * CONTENTION read request send TURNAROUND + * read RTS + * enter RECEIVE + * CONTENTION write request send RTS + * read TURNAROUND + * enter SEND + * + * RECEIVE read request read whatever + * RECEIVE write request read TURNAROUND + * + * SEND read request send TURNAROUND + * SEND write write whatever */ +#define EXCH_EXCH_COMMAND 0 /* The following is a command */ +#define EXCH_EXCH_TURNAROUND 1 /* Your turn to send */ +#define EXCH_EXCH_RTS 2 /* Request to send */ +#define EXCH_EXCH_TYPE 3 /* The following is a type */ + +struct exch_exch { + unsigned char + opcode, /* COMMAND, TURNAROUND, or TYPE */ + my_sequence, /* 0-ff, initially zero */ + your_sequence, /* 0-ff, initially zero */ + command_or_type; /* Application level command or type */ + unsigned short + length; /* The length of any following data */ +}; + +/* + * The following are the command codes which the higher level protocols + * send and receive. + */ -#define EXCH_ASSOCIATE 23 /* Connect [client->server] */ -#define EXCH_DISASSOCIATE 39 /* Disconnect [client->server] */ -#define EXCH_SEND_AUTH 44 /* Send password [server->client] */ +#define EXCH_CMD_ASSOCIATE 0 /* Connect [client->server] */ +#define EXCH_CMD_DISASSOCIATE 1 /* Disconnect [client->server] */ +#define EXCH_CMD_SEND_AUTH 2 /* Send password [server->client] */ /* * struct storeage_desc * char prompt[] * struct storeage_desc * char seed[] */ -#define EXCH_AUTH 65 /* Authorization [client->server] */ +#define EXCH_CMD_AUTH 3 /* Authorization [client->server] */ /* * struct storeage_desc * char authenticator[] */ -#define EXCH_ASSOCIATED 78 /* Connected [server->client] */ -#define EXCH_REJECTED 93 /* Too bad [server->client] */ +#define EXCH_CMD_ASSOCIATED 4 /* Connected [server->client] */ +#define EXCH_CMD_REJECTED 5 /* Too bad [server->client] */ /* * struct storeage_desc * char message[] */ -#define EXCH_REQUEST 19 /* A request [client->server] */ +#define EXCH_CMD_REQUEST 6 /* A request [client->server] */ /* struct regs, * struct sregs, * struct storage_desc * char bytes[] */ -#define EXCH_GIMME 20 /* Send storage [server->client] */ +#define EXCH_CMD_GIMME 7 /* Send storage [server->client] */ /* * struct storage_desc */ -#define EXCH_HEREIS 49 /* Here is storage [BOTH WAYS] */ +#define EXCH_CMD_HEREIS 8 /* Here is storage [BOTH WAYS] */ /* * struct storage_desc * char bytes[] */ -#define EXCH_REPLY 87 /* End of discussion */ +#define EXCH_CMD_REPLY 9 /* End of discussion */ /* * struct regs, * struct sregs, */ -#define EXCH_TYPE_REGS 13 -#define EXCH_TYPE_SREGS 27 -#define EXCH_TYPE_STORE_DESC 33 -#define EXCH_TYPE_BYTES 67 +/* + * The following are typed parameters sent across the wire. + * + * This should be done much more generally, with some form of + * XDR or mapped conversation ability. + */ + +#define EXCH_TYPE_REGS 0 +#define EXCH_TYPE_SREGS 1 +#define EXCH_TYPE_STORE_DESC 2 +#define EXCH_TYPE_BYTES 3 /* * each parameter that comes over looks like: diff --git a/usr/src/usr.bin/tn3270/api/apilib.c b/usr/src/usr.bin/tn3270/api/apilib.c index 19de438b1b..550067b381 100644 --- a/usr/src/usr.bin/tn3270/api/apilib.c +++ b/usr/src/usr.bin/tn3270/api/apilib.c @@ -295,6 +295,22 @@ ReadOiaGroupParms *parms; } } +/* + * The "we are done" routine. This gets called last. + */ + +api_finish() +{ +#if defined(unix) + if (api_close_api() == -1) { + return -1; + } else { + return 0; + } +#endif /* defined(unix) */ +} + + /* * The initialization routine. Be sure to call this first. */ diff --git a/usr/src/usr.bin/tn3270/api/test.c b/usr/src/usr.bin/tn3270/api/test.c index 3433dbd955..928d9bc55f 100644 --- a/usr/src/usr.bin/tn3270/api/test.c +++ b/usr/src/usr.bin/tn3270/api/test.c @@ -205,5 +205,7 @@ main() printf("Disconnected from keyboard.\n"); } + (void) api_finish(); + return 0; } -- 2.20.1