131460Sminshall #include <stdio.h> 231460Sminshall 331460Sminshall #include "api_exch.h" 431460Sminshall 531467Sminshall static int sock; /* Socket number */ 631467Sminshall 731474Sminshall static char whoarewe[40] = ""; 831493Sminshall #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); 931474Sminshall 1031493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation; 1131493Sminshall 1231493Sminshall static struct exch_exch exch_state; 1331493Sminshall 1431493Sminshall static unsigned int 1531493Sminshall my_sequence, 1631493Sminshall your_sequence; 1731493Sminshall 18*31499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last; 1931460Sminshall #define IBUFADDED(i) ibuf_last += (i) 20*31499Sminshall #define IBUFAVAILABLE() (ibuf_last-ibuf_next) 2131460Sminshall #define IBUFFER() ibuffer 22*31499Sminshall #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1) 2331493Sminshall #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } 2431460Sminshall #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) 2531460Sminshall 26*31499Sminshall char obuffer[4000], *obuf_next; 2731460Sminshall #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } 2831460Sminshall #define OBUFAVAILABLE() (obuf_next - obuffer) 2931460Sminshall #define OBUFFER() obuffer 3031460Sminshall #define OBUFRESET() obuf_next = obuffer 3131460Sminshall #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) 3231460Sminshall 3331460Sminshall 3431460Sminshall static int 3531460Sminshall outflush() 3631460Sminshall { 3731460Sminshall int length = OBUFAVAILABLE(); 3831460Sminshall 3931460Sminshall if (length != 0) { 4031460Sminshall if (write(sock, OBUFFER(), length) != length) { 4131493Sminshall WHO_ARE_WE(); 4231474Sminshall perror("write"); 4331460Sminshall return -1; 4431460Sminshall } 4531460Sminshall OBUFRESET(); 4631460Sminshall } 4731460Sminshall return 0; /* All OK */ 4831460Sminshall } 4931460Sminshall 5031460Sminshall 5131460Sminshall static int 52*31499Sminshall iget(location, length) 53*31499Sminshall char *location; 54*31499Sminshall int length; 5531460Sminshall { 5631460Sminshall int i; 57*31499Sminshall int count; 5831460Sminshall 5931460Sminshall if (OBUFAVAILABLE()) { 6031460Sminshall if (outflush() == -1) { 6131460Sminshall return -1; 6231460Sminshall } 6331460Sminshall } 64*31499Sminshall if ((count = IBUFAVAILABLE()) != 0) { 65*31499Sminshall if (count > length) { 66*31499Sminshall count = length; 67*31499Sminshall } 68*31499Sminshall IBUFGETBYTES(location, count); 69*31499Sminshall length -= count; 70*31499Sminshall location += count; 7131460Sminshall } 72*31499Sminshall while (length) { 73*31499Sminshall if (ibuf_next == ibuf_last) { 74*31499Sminshall IBUFRESET(); 75*31499Sminshall } 76*31499Sminshall if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) { 7731493Sminshall WHO_ARE_WE(); 7831474Sminshall perror("read"); 7931460Sminshall return -1; 8031460Sminshall } 81*31499Sminshall if (count == 0) { 8231474Sminshall /* Reading past end-of-file */ 8331493Sminshall WHO_ARE_WE(); 8431493Sminshall fprintf(stderr, "End of file read\r\n"); 8531474Sminshall return -1; 8631474Sminshall } 87*31499Sminshall IBUFADDED(count); 88*31499Sminshall if (count > length) { 89*31499Sminshall count = length; 90*31499Sminshall } 91*31499Sminshall IBUFGETBYTES(location, count); 92*31499Sminshall length -= count; 93*31499Sminshall location += count; 9431460Sminshall } 9531460Sminshall return 0; 9631460Sminshall } 9731460Sminshall 9831493Sminshall static char * 9931493Sminshall exch_to_ascii(exch) 10031493Sminshall int exch; /* opcode to decode */ 10131493Sminshall { 10231493Sminshall switch (exch) { 10331493Sminshall case EXCH_EXCH_COMMAND: 10431493Sminshall return "Command"; 10531493Sminshall case EXCH_EXCH_TYPE: 10631493Sminshall return "Type"; 10731493Sminshall case EXCH_EXCH_TURNAROUND: 10831493Sminshall return "Turnaround"; 10931493Sminshall case EXCH_EXCH_RTS: 11031493Sminshall return "Request to Send"; 11131493Sminshall default: 11231493Sminshall { 11331493Sminshall static char unknown[40]; 11431493Sminshall 11531493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 11631493Sminshall return unknown; 11731493Sminshall } 11831493Sminshall } 11931493Sminshall } 12031493Sminshall 12131493Sminshall /* 12231493Sminshall * Send the exch structure, updating the sequnce number field. 12331493Sminshall */ 12431493Sminshall 12531493Sminshall static int 12631493Sminshall send_state() 12731493Sminshall { 12831493Sminshall if (OBUFROOM() < sizeof exch_state) { 12931493Sminshall if (outflush() == -1) { 13031493Sminshall return -1; 13131493Sminshall } 13231493Sminshall } 13331498Sminshall my_sequence = (my_sequence+1)&0xff; 13431498Sminshall exch_state.my_sequence = my_sequence; 13531493Sminshall exch_state.your_sequence = your_sequence; 13631493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 13731493Sminshall return 0; 13831493Sminshall } 13931493Sminshall 14031493Sminshall /* 14131493Sminshall * Receive the exch structure from the other side, checking 14231493Sminshall * sequence numbering. 14331493Sminshall */ 14431493Sminshall 14531493Sminshall static int 14631493Sminshall receive_state() 14731493Sminshall { 148*31499Sminshall if (iget((char *)&exch_state, sizeof exch_state) == -1) { 149*31499Sminshall return -1; 15031493Sminshall } 15131493Sminshall if (conversation != CONTENTION) { 15231493Sminshall if (exch_state.your_sequence != my_sequence) { 15331493Sminshall WHO_ARE_WE(); 15431493Sminshall fprintf(stderr, "Send sequence number mismatch.\n"); 15531493Sminshall return -1; 15631493Sminshall } 15731498Sminshall if (exch_state.my_sequence != ((++your_sequence)&0xff)) { 15831493Sminshall WHO_ARE_WE(); 15931493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n"); 16031493Sminshall return -1; 16131493Sminshall } 16231493Sminshall } 16331498Sminshall your_sequence = exch_state.my_sequence; 16431493Sminshall return 0; 16531493Sminshall } 16631493Sminshall 16731493Sminshall static int 16831493Sminshall enter_receive() 16931493Sminshall { 17031493Sminshall switch (conversation) { 17131493Sminshall case CONTENTION: 17231493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 17331493Sminshall if (send_state() == -1) { 17431493Sminshall return -1; 17531493Sminshall } 17631493Sminshall if (receive_state() == -1) { 17731493Sminshall return -1; 17831493Sminshall } 17931493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) { 18031493Sminshall WHO_ARE_WE(); 18131493Sminshall fprintf(stderr, "In CONTENTION state: "); 18231493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 18331493Sminshall fprintf(stderr, 18431493Sminshall "Both sides tried to enter RECEIVE state.\n"); 18531493Sminshall } else { 18631493Sminshall fprintf(stderr, 18731493Sminshall "Protocol error trying to enter RECEIVE state.\n"); 18831493Sminshall } 18931493Sminshall return -1; 19031493Sminshall } 19131493Sminshall break; 19231493Sminshall case SEND: 19331493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 19431493Sminshall if (send_state() == -1) { 19531493Sminshall return -1; 19631493Sminshall } 19731493Sminshall break; 19831493Sminshall } 19931493Sminshall conversation = RECEIVE; 20031493Sminshall return 0; 20131493Sminshall } 20231493Sminshall 20331493Sminshall static int 20431493Sminshall enter_send() 20531493Sminshall { 20631493Sminshall switch (conversation) { 20731493Sminshall case CONTENTION: 20831493Sminshall exch_state.opcode = EXCH_EXCH_RTS; 20931493Sminshall if (send_state() == -1) { 21031493Sminshall return -1; 21131493Sminshall } 21231493Sminshall /* fall through */ 21331493Sminshall case RECEIVE: 21431493Sminshall if (receive_state() == -1) { 21531493Sminshall return -1; 21631493Sminshall } 21731493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 21831493Sminshall WHO_ARE_WE(); 21931493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 22031493Sminshall return -1; 22131493Sminshall } 22231493Sminshall } 22331493Sminshall conversation = SEND; 22431493Sminshall return 0; 22531493Sminshall } 22631493Sminshall 22731467Sminshall int 22831493Sminshall api_exch_nextcommand() 22931467Sminshall { 23031493Sminshall if (conversation != RECEIVE) { 23131493Sminshall if (enter_receive() == -1) { 23231467Sminshall return -1; 23331467Sminshall } 23431467Sminshall } 23531493Sminshall if (receive_state() == -1) { 23631493Sminshall return -1; 23731493Sminshall } 23831493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) { 23931493Sminshall WHO_ARE_WE(); 24031493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 24131493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 24231493Sminshall return -1; 24331493Sminshall } 24431493Sminshall return exch_state.command_or_type; 24531467Sminshall } 24631467Sminshall 24731467Sminshall 24831467Sminshall int 24931460Sminshall api_exch_incommand(command) 25031460Sminshall int command; 25131460Sminshall { 25231460Sminshall int i; 25331460Sminshall 25431493Sminshall if ((i = api_exch_nextcommand()) == -1) { 25531493Sminshall return -1; 25631460Sminshall } 25731460Sminshall if (i != command) { 25831493Sminshall WHO_ARE_WE(); 25931460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 26031460Sminshall command, i); 26131460Sminshall return -1; 26231460Sminshall } 26331460Sminshall return 0; 26431460Sminshall } 26531460Sminshall 26631460Sminshall 26731467Sminshall int 26831460Sminshall api_exch_outcommand(command) 26931460Sminshall int command; 27031460Sminshall { 27131493Sminshall if (conversation != SEND) { 27231493Sminshall if (enter_send() == -1) { 27331460Sminshall return -1; 27431460Sminshall } 27531460Sminshall } 27631493Sminshall exch_state.command_or_type = command; 27731493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND; 27831493Sminshall if (send_state() == -1) { 27931493Sminshall return -1; 28031493Sminshall } else { 28131493Sminshall return 0; 28231493Sminshall } 28331460Sminshall } 28431460Sminshall 28531460Sminshall 28631467Sminshall int 28731460Sminshall api_exch_outtype(type, length, location) 28831460Sminshall int 28931460Sminshall type, 29031460Sminshall length; 29131460Sminshall char 29231460Sminshall *location; 29331460Sminshall { 29431460Sminshall int netleng = htons(length); 29531460Sminshall 29631493Sminshall if (conversation != SEND) { 29731493Sminshall if (enter_send() == -1) { 29831460Sminshall return -1; 29931460Sminshall } 30031460Sminshall } 30131493Sminshall exch_state.opcode = EXCH_EXCH_TYPE; 30231493Sminshall exch_state.command_or_type = type; 30331493Sminshall exch_state.length = netleng; 30431493Sminshall if (send_state() == -1) { 30531493Sminshall return -1; 30631493Sminshall } 30731493Sminshall if (length) { 30831493Sminshall if (OBUFROOM() > length) { 30931493Sminshall OBUFADDBYTES(location, length); 31031493Sminshall } else { 31131493Sminshall if (outflush() == -1) { 31231493Sminshall return -1; 31331493Sminshall } 31431493Sminshall if (write(sock, location, length) != length) { 31531493Sminshall WHO_ARE_WE(); 31631493Sminshall perror("write"); 31731493Sminshall return -1; 31831493Sminshall } 31931460Sminshall } 32031460Sminshall } 32131493Sminshall return 0; 32231460Sminshall } 32331460Sminshall 32431460Sminshall 32531467Sminshall int 32631460Sminshall api_exch_intype(type, length, location) 32731460Sminshall int 32831460Sminshall type, 32931460Sminshall length; 33031460Sminshall char 33131460Sminshall *location; 33231460Sminshall { 33331460Sminshall int i, netleng = htons(length); 33431460Sminshall 33531493Sminshall if (conversation != RECEIVE) { 33631493Sminshall if (enter_receive() == -1) { 33731460Sminshall return -1; 33831460Sminshall } 33931460Sminshall } 34031493Sminshall if (receive_state() == -1) { 34131460Sminshall return -1; 34231460Sminshall } 34331493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) { 34431493Sminshall WHO_ARE_WE(); 34531493Sminshall fprintf(stderr, 34631493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n", 34731493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 34831493Sminshall return -1; 34931493Sminshall } 35031493Sminshall if (exch_state.command_or_type != type) { 35131493Sminshall WHO_ARE_WE(); 35231493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 35331493Sminshall type, exch_state.command_or_type); 35431493Sminshall return -1; 35531493Sminshall } 35631493Sminshall if (exch_state.length != netleng) { 35731460Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", 35831493Sminshall type, length, ntohs(exch_state.length)); 35931460Sminshall return -1; 36031460Sminshall } 361*31499Sminshall if (iget(location, length) == -1) { 362*31499Sminshall return -1; 36331460Sminshall } 36431460Sminshall return 0; 36531460Sminshall } 36631467Sminshall 36731467Sminshall int 36831493Sminshall api_exch_flush() 36931493Sminshall { 37031493Sminshall return outflush(); 37131493Sminshall } 37231493Sminshall 37331493Sminshall int 37431474Sminshall api_exch_init(sock_number, ourname) 37531467Sminshall int sock_number; 37631474Sminshall char *ourname; 37731467Sminshall { 37831467Sminshall sock = sock_number; 37931474Sminshall strcpy(whoarewe, ourname); /* For error messages */ 38031467Sminshall 38131493Sminshall my_sequence = your_sequence = 0; 38231493Sminshall 38331493Sminshall conversation = CONTENTION; /* We don't know which direction */ 38431493Sminshall 38531467Sminshall IBUFRESET(); 38631467Sminshall OBUFRESET(); 38731467Sminshall 38831467Sminshall return 0; 38931467Sminshall } 390