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