131890Sminshall /* 233820Sbostic * Copyright (c) 1988 Regents of the University of California. 333820Sbostic * All rights reserved. 431890Sminshall * 533820Sbostic * Redistribution and use in source and binary forms are permitted 6*35418Sminshall * provided that the above copyright notice and this paragraph are 7*35418Sminshall * duplicated in all such forms and that any documentation, 8*35418Sminshall * advertising materials, and other materials related to such 9*35418Sminshall * distribution and use acknowledge that the software was developed 10*35418Sminshall * by the University of California, Berkeley. The name of the 11*35418Sminshall * University may not be used to endorse or promote products derived 12*35418Sminshall * from this software without specific prior written permission. 13*35418Sminshall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35418Sminshall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35418Sminshall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1631890Sminshall */ 1731890Sminshall 1831890Sminshall #ifndef lint 19*35418Sminshall static char sccsid[] = "@(#)api_exch.c 3.3 (Berkeley) 08/28/88"; 2033820Sbostic #endif /* not lint */ 2131890Sminshall 2231460Sminshall #include <stdio.h> 2331460Sminshall 2431801Sminshall #include "../general/general.h" 2531801Sminshall 2631460Sminshall #include "api_exch.h" 2731460Sminshall 2831467Sminshall static int sock; /* Socket number */ 2931467Sminshall 3031474Sminshall static char whoarewe[40] = ""; 3131493Sminshall #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); 3231474Sminshall 3331493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation; 3431493Sminshall 3531493Sminshall static struct exch_exch exch_state; 3631493Sminshall 3731493Sminshall static unsigned int 3831493Sminshall my_sequence, 3931493Sminshall your_sequence; 4031493Sminshall 4131499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last; 4231460Sminshall #define IBUFADDED(i) ibuf_last += (i) 4331499Sminshall #define IBUFAVAILABLE() (ibuf_last-ibuf_next) 4431460Sminshall #define IBUFFER() ibuffer 4531499Sminshall #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1) 4631493Sminshall #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } 4731460Sminshall #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) 4831460Sminshall 4931499Sminshall char obuffer[4000], *obuf_next; 5031460Sminshall #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } 5131460Sminshall #define OBUFAVAILABLE() (obuf_next - obuffer) 5231460Sminshall #define OBUFFER() obuffer 5331460Sminshall #define OBUFRESET() obuf_next = obuffer 5431460Sminshall #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) 5531460Sminshall 5631460Sminshall 5731460Sminshall static int 5831460Sminshall outflush() 5931460Sminshall { 6031460Sminshall int length = OBUFAVAILABLE(); 6131460Sminshall 6231460Sminshall if (length != 0) { 6331460Sminshall if (write(sock, OBUFFER(), length) != length) { 6431493Sminshall WHO_ARE_WE(); 6531474Sminshall perror("write"); 6631460Sminshall return -1; 6731460Sminshall } 6831460Sminshall OBUFRESET(); 6931460Sminshall } 7031460Sminshall return 0; /* All OK */ 7131460Sminshall } 7231460Sminshall 7331460Sminshall 7431460Sminshall static int 7531499Sminshall iget(location, length) 7631499Sminshall char *location; 7731499Sminshall int length; 7831460Sminshall { 7931499Sminshall int count; 8031460Sminshall 8131460Sminshall if (OBUFAVAILABLE()) { 8231460Sminshall if (outflush() == -1) { 8331460Sminshall return -1; 8431460Sminshall } 8531460Sminshall } 8631499Sminshall if ((count = IBUFAVAILABLE()) != 0) { 8731499Sminshall if (count > length) { 8831499Sminshall count = length; 8931499Sminshall } 9031499Sminshall IBUFGETBYTES(location, count); 9131499Sminshall length -= count; 9231499Sminshall location += count; 9331460Sminshall } 9431499Sminshall while (length) { 9531499Sminshall if (ibuf_next == ibuf_last) { 9631499Sminshall IBUFRESET(); 9731499Sminshall } 9831499Sminshall if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) { 9931493Sminshall WHO_ARE_WE(); 10031474Sminshall perror("read"); 10131460Sminshall return -1; 10231460Sminshall } 10331499Sminshall if (count == 0) { 10431474Sminshall /* Reading past end-of-file */ 10531493Sminshall WHO_ARE_WE(); 10631493Sminshall fprintf(stderr, "End of file read\r\n"); 10731474Sminshall return -1; 10831474Sminshall } 10931499Sminshall IBUFADDED(count); 11031499Sminshall if (count > length) { 11131499Sminshall count = length; 11231499Sminshall } 11331499Sminshall IBUFGETBYTES(location, count); 11431499Sminshall length -= count; 11531499Sminshall location += count; 11631460Sminshall } 11731460Sminshall return 0; 11831460Sminshall } 11931460Sminshall 12031493Sminshall static char * 12131493Sminshall exch_to_ascii(exch) 12231493Sminshall int exch; /* opcode to decode */ 12331493Sminshall { 12431493Sminshall switch (exch) { 12531493Sminshall case EXCH_EXCH_COMMAND: 12631493Sminshall return "Command"; 12731493Sminshall case EXCH_EXCH_TYPE: 12831493Sminshall return "Type"; 12931493Sminshall case EXCH_EXCH_TURNAROUND: 13031493Sminshall return "Turnaround"; 13131493Sminshall case EXCH_EXCH_RTS: 13231493Sminshall return "Request to Send"; 13331493Sminshall default: 13431493Sminshall { 13531493Sminshall static char unknown[40]; 13631493Sminshall 13731493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 13831493Sminshall return unknown; 13931493Sminshall } 14031493Sminshall } 14131493Sminshall } 14231493Sminshall 14331493Sminshall /* 14431493Sminshall * Send the exch structure, updating the sequnce number field. 14531493Sminshall */ 14631493Sminshall 14731493Sminshall static int 14831493Sminshall send_state() 14931493Sminshall { 15031493Sminshall if (OBUFROOM() < sizeof exch_state) { 15131493Sminshall if (outflush() == -1) { 15231493Sminshall return -1; 15331493Sminshall } 15431493Sminshall } 15531498Sminshall my_sequence = (my_sequence+1)&0xff; 15631498Sminshall exch_state.my_sequence = my_sequence; 15731493Sminshall exch_state.your_sequence = your_sequence; 15831493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 15931493Sminshall return 0; 16031493Sminshall } 16131493Sminshall 16231493Sminshall /* 16331493Sminshall * Receive the exch structure from the other side, checking 16431493Sminshall * sequence numbering. 16531493Sminshall */ 16631493Sminshall 16731493Sminshall static int 16831493Sminshall receive_state() 16931493Sminshall { 17031499Sminshall if (iget((char *)&exch_state, sizeof exch_state) == -1) { 17131499Sminshall return -1; 17231493Sminshall } 17331493Sminshall if (conversation != CONTENTION) { 17431493Sminshall if (exch_state.your_sequence != my_sequence) { 17531493Sminshall WHO_ARE_WE(); 17631493Sminshall fprintf(stderr, "Send sequence number mismatch.\n"); 17731493Sminshall return -1; 17831493Sminshall } 17931498Sminshall if (exch_state.my_sequence != ((++your_sequence)&0xff)) { 18031493Sminshall WHO_ARE_WE(); 18131493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n"); 18231493Sminshall return -1; 18331493Sminshall } 18431493Sminshall } 18531498Sminshall your_sequence = exch_state.my_sequence; 18631493Sminshall return 0; 18731493Sminshall } 18831493Sminshall 18931493Sminshall static int 19031493Sminshall enter_receive() 19131493Sminshall { 19231493Sminshall switch (conversation) { 19331493Sminshall case CONTENTION: 19431493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 19531493Sminshall if (send_state() == -1) { 19631493Sminshall return -1; 19731493Sminshall } 19831493Sminshall if (receive_state() == -1) { 19931493Sminshall return -1; 20031493Sminshall } 20131493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) { 20231493Sminshall WHO_ARE_WE(); 20331493Sminshall fprintf(stderr, "In CONTENTION state: "); 20431493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 20531493Sminshall fprintf(stderr, 20631493Sminshall "Both sides tried to enter RECEIVE state.\n"); 20731493Sminshall } else { 20831493Sminshall fprintf(stderr, 20931493Sminshall "Protocol error trying to enter RECEIVE state.\n"); 21031493Sminshall } 21131493Sminshall return -1; 21231493Sminshall } 21331493Sminshall break; 21431493Sminshall case SEND: 21531493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 21631493Sminshall if (send_state() == -1) { 21731493Sminshall return -1; 21831493Sminshall } 21931493Sminshall break; 22031493Sminshall } 22131493Sminshall conversation = RECEIVE; 22231493Sminshall return 0; 22331493Sminshall } 22431493Sminshall 22531493Sminshall static int 22631493Sminshall enter_send() 22731493Sminshall { 22831493Sminshall switch (conversation) { 22931493Sminshall case CONTENTION: 23031493Sminshall exch_state.opcode = EXCH_EXCH_RTS; 23131493Sminshall if (send_state() == -1) { 23231493Sminshall return -1; 23331493Sminshall } 23431493Sminshall /* fall through */ 23531493Sminshall case RECEIVE: 23631493Sminshall if (receive_state() == -1) { 23731493Sminshall return -1; 23831493Sminshall } 23931493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 24031493Sminshall WHO_ARE_WE(); 24131493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 24231493Sminshall return -1; 24331493Sminshall } 24431493Sminshall } 24531493Sminshall conversation = SEND; 24631493Sminshall return 0; 24731493Sminshall } 24831493Sminshall 24931467Sminshall int 25031493Sminshall api_exch_nextcommand() 25131467Sminshall { 25231493Sminshall if (conversation != RECEIVE) { 25331493Sminshall if (enter_receive() == -1) { 25431467Sminshall return -1; 25531467Sminshall } 25631467Sminshall } 25731493Sminshall if (receive_state() == -1) { 25831493Sminshall return -1; 25931493Sminshall } 26031493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) { 26131493Sminshall WHO_ARE_WE(); 26231493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 26331493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 26431493Sminshall return -1; 26531493Sminshall } 26631493Sminshall return exch_state.command_or_type; 26731467Sminshall } 26831467Sminshall 26931467Sminshall 27031467Sminshall int 27131460Sminshall api_exch_incommand(command) 27231460Sminshall int command; 27331460Sminshall { 27431460Sminshall int i; 27531460Sminshall 27631493Sminshall if ((i = api_exch_nextcommand()) == -1) { 27731493Sminshall return -1; 27831460Sminshall } 27931460Sminshall if (i != command) { 28031493Sminshall WHO_ARE_WE(); 28131460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 28231460Sminshall command, i); 28331460Sminshall return -1; 28431460Sminshall } 28531460Sminshall return 0; 28631460Sminshall } 28731460Sminshall 28831460Sminshall 28931467Sminshall int 29031460Sminshall api_exch_outcommand(command) 29131460Sminshall int command; 29231460Sminshall { 29331493Sminshall if (conversation != SEND) { 29431493Sminshall if (enter_send() == -1) { 29531460Sminshall return -1; 29631460Sminshall } 29731460Sminshall } 29831493Sminshall exch_state.command_or_type = command; 29931493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND; 30031493Sminshall if (send_state() == -1) { 30131493Sminshall return -1; 30231493Sminshall } else { 30331493Sminshall return 0; 30431493Sminshall } 30531460Sminshall } 30631460Sminshall 30731460Sminshall 30831467Sminshall int 30931460Sminshall api_exch_outtype(type, length, location) 31031460Sminshall int 31131460Sminshall type, 31231460Sminshall length; 31331460Sminshall char 31431460Sminshall *location; 31531460Sminshall { 31631801Sminshall int netleng = length; 31731460Sminshall 31831493Sminshall if (conversation != SEND) { 31931493Sminshall if (enter_send() == -1) { 32031460Sminshall return -1; 32131460Sminshall } 32231460Sminshall } 32331493Sminshall exch_state.opcode = EXCH_EXCH_TYPE; 32431493Sminshall exch_state.command_or_type = type; 32531493Sminshall exch_state.length = netleng; 32631493Sminshall if (send_state() == -1) { 32731493Sminshall return -1; 32831493Sminshall } 32931493Sminshall if (length) { 33031493Sminshall if (OBUFROOM() > length) { 33131493Sminshall OBUFADDBYTES(location, length); 33231493Sminshall } else { 33331493Sminshall if (outflush() == -1) { 33431493Sminshall return -1; 33531493Sminshall } 33631493Sminshall if (write(sock, location, length) != length) { 33731493Sminshall WHO_ARE_WE(); 33831493Sminshall perror("write"); 33931493Sminshall return -1; 34031493Sminshall } 34131460Sminshall } 34231460Sminshall } 34331493Sminshall return 0; 34431460Sminshall } 34531460Sminshall 34631460Sminshall 34731467Sminshall int 34831460Sminshall api_exch_intype(type, length, location) 34931460Sminshall int 35031460Sminshall type, 35131460Sminshall length; 35231460Sminshall char 35331460Sminshall *location; 35431460Sminshall { 355*35418Sminshall int netleng = length; 35631460Sminshall 35731493Sminshall if (conversation != RECEIVE) { 35831493Sminshall if (enter_receive() == -1) { 35931460Sminshall return -1; 36031460Sminshall } 36131460Sminshall } 36231493Sminshall if (receive_state() == -1) { 36331460Sminshall return -1; 36431460Sminshall } 36531493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) { 36631493Sminshall WHO_ARE_WE(); 36731493Sminshall fprintf(stderr, 36831493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n", 36931493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 37031493Sminshall return -1; 37131493Sminshall } 37231493Sminshall if (exch_state.command_or_type != type) { 37331493Sminshall WHO_ARE_WE(); 37431493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 37531493Sminshall type, exch_state.command_or_type); 37631493Sminshall return -1; 37731493Sminshall } 37831493Sminshall if (exch_state.length != netleng) { 379*35418Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %u.\n", 38031801Sminshall type, length, exch_state.length); 38131460Sminshall return -1; 38231460Sminshall } 38331499Sminshall if (iget(location, length) == -1) { 38431499Sminshall return -1; 38531460Sminshall } 38631460Sminshall return 0; 38731460Sminshall } 38831467Sminshall 38931467Sminshall int 39031493Sminshall api_exch_flush() 39131493Sminshall { 39231493Sminshall return outflush(); 39331493Sminshall } 39431493Sminshall 39531493Sminshall int 39631474Sminshall api_exch_init(sock_number, ourname) 39731467Sminshall int sock_number; 39831474Sminshall char *ourname; 39931467Sminshall { 400*35418Sminshall extern char *strcpy(); 401*35418Sminshall 40231467Sminshall sock = sock_number; 403*35418Sminshall (void) strcpy(whoarewe, ourname); /* For error messages */ 40431467Sminshall 40531493Sminshall my_sequence = your_sequence = 0; 40631493Sminshall 40731493Sminshall conversation = CONTENTION; /* We don't know which direction */ 40831493Sminshall 40931467Sminshall IBUFRESET(); 41031467Sminshall OBUFRESET(); 41131467Sminshall 41231467Sminshall return 0; 41331467Sminshall } 414