1*48754Sbostic /*- 2*48754Sbostic * Copyright (c) 1988 The Regents of the University of California. 333820Sbostic * All rights reserved. 431890Sminshall * 5*48754Sbostic * %sccs.include.redist.c% 631890Sminshall */ 731890Sminshall 831890Sminshall #ifndef lint 9*48754Sbostic static char sccsid[] = "@(#)api_exch.c 4.2 (Berkeley) 04/26/91"; 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 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 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 * 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 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 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 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 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 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 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 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 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 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 38031493Sminshall api_exch_flush() 38131493Sminshall { 38231493Sminshall return outflush(); 38331493Sminshall } 38431493Sminshall 38531493Sminshall int 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