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 1831460Sminshall static char ibuffer[40], *ibuf_next, *ibuf_last; 1931460Sminshall #define IBUFADDED(i) ibuf_last += (i) 2031460Sminshall #define IBUFAVAILABLE() (ibuf_last -ibuf_next) 2131460Sminshall #define IBUFFER() ibuffer 2231493Sminshall #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } 2331460Sminshall #define IBUFGETCHAR() (*ibuf_next++) 2431460Sminshall #define IBUFGETSHORT() ((*ibuf_next++<<8)|(*ibuf_next++&0xff)) 2531460Sminshall #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) 2631460Sminshall 2731460Sminshall char obuffer[40], *obuf_next; 2831460Sminshall #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } 2931460Sminshall #define OBUFADDCHAR(c) (*obuf_next++ = c) 3031460Sminshall #define OBUFADDSHORT(s) {*obuf_next++ = (s)>>8; *obuf_next++ = s; } 3131460Sminshall #define OBUFAVAILABLE() (obuf_next - obuffer) 3231460Sminshall #define OBUFFER() obuffer 3331460Sminshall #define OBUFRESET() obuf_next = obuffer 3431460Sminshall #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) 3531460Sminshall 3631460Sminshall 3731460Sminshall static int 3831460Sminshall outflush() 3931460Sminshall { 4031460Sminshall int length = OBUFAVAILABLE(); 4131460Sminshall 4231460Sminshall if (length != 0) { 4331460Sminshall if (write(sock, OBUFFER(), length) != length) { 4431493Sminshall WHO_ARE_WE(); 4531474Sminshall perror("write"); 4631460Sminshall return -1; 4731460Sminshall } 4831460Sminshall OBUFRESET(); 4931460Sminshall } 5031460Sminshall return 0; /* All OK */ 5131460Sminshall } 5231460Sminshall 5331460Sminshall 5431460Sminshall static int 5531460Sminshall infill(count) 5631460Sminshall int count; 5731460Sminshall { 5831460Sminshall int i; 5931460Sminshall 6031460Sminshall if (OBUFAVAILABLE()) { 6131460Sminshall if (outflush() == -1) { 6231460Sminshall return -1; 6331460Sminshall } 6431460Sminshall } 6531460Sminshall if (ibuf_next == ibuf_last) { 6631460Sminshall IBUFRESET(); 6731460Sminshall } 6831493Sminshall if ((count -= IBUFAVAILABLE()) < 0) { 6931493Sminshall return 0; 7031493Sminshall } 7131460Sminshall while (count) { 7231460Sminshall if ((i = read(sock, IBUFFER(), count)) < 0) { 7331493Sminshall WHO_ARE_WE(); 7431474Sminshall perror("read"); 7531460Sminshall return -1; 7631460Sminshall } 7731474Sminshall if (i == 0) { 7831474Sminshall /* Reading past end-of-file */ 7931493Sminshall WHO_ARE_WE(); 8031493Sminshall fprintf(stderr, "End of file read\r\n"); 8131474Sminshall return -1; 8231474Sminshall } 8331460Sminshall count -= i; 8431460Sminshall IBUFADDED(i); 8531460Sminshall } 8631460Sminshall return 0; 8731460Sminshall } 8831460Sminshall 8931493Sminshall static char * 9031493Sminshall exch_to_ascii(exch) 9131493Sminshall int exch; /* opcode to decode */ 9231493Sminshall { 9331493Sminshall switch (exch) { 9431493Sminshall case EXCH_EXCH_COMMAND: 9531493Sminshall return "Command"; 9631493Sminshall case EXCH_EXCH_TYPE: 9731493Sminshall return "Type"; 9831493Sminshall case EXCH_EXCH_TURNAROUND: 9931493Sminshall return "Turnaround"; 10031493Sminshall case EXCH_EXCH_RTS: 10131493Sminshall return "Request to Send"; 10231493Sminshall default: 10331493Sminshall { 10431493Sminshall static char unknown[40]; 10531493Sminshall 10631493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 10731493Sminshall return unknown; 10831493Sminshall } 10931493Sminshall } 11031493Sminshall } 11131493Sminshall 11231493Sminshall /* 11331493Sminshall * Send the exch structure, updating the sequnce number field. 11431493Sminshall */ 11531493Sminshall 11631493Sminshall static int 11731493Sminshall send_state() 11831493Sminshall { 11931493Sminshall if (OBUFROOM() < sizeof exch_state) { 12031493Sminshall if (outflush() == -1) { 12131493Sminshall return -1; 12231493Sminshall } 12331493Sminshall } 124*31498Sminshall my_sequence = (my_sequence+1)&0xff; 125*31498Sminshall exch_state.my_sequence = my_sequence; 12631493Sminshall exch_state.your_sequence = your_sequence; 12731493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 12831493Sminshall return 0; 12931493Sminshall } 13031493Sminshall 13131493Sminshall /* 13231493Sminshall * Receive the exch structure from the other side, checking 13331493Sminshall * sequence numbering. 13431493Sminshall */ 13531493Sminshall 13631493Sminshall static int 13731493Sminshall receive_state() 13831493Sminshall { 13931493Sminshall if (IBUFAVAILABLE() < sizeof exch_state) { 14031493Sminshall if (infill(sizeof exch_state) == -1) { 14131493Sminshall return -1; 14231493Sminshall } 14331493Sminshall } 14431493Sminshall IBUFGETBYTES((char *)&exch_state, sizeof exch_state); 14531493Sminshall if (conversation != CONTENTION) { 14631493Sminshall if (exch_state.your_sequence != my_sequence) { 14731493Sminshall WHO_ARE_WE(); 14831493Sminshall fprintf(stderr, "Send sequence number mismatch.\n"); 14931493Sminshall return -1; 15031493Sminshall } 151*31498Sminshall if (exch_state.my_sequence != ((++your_sequence)&0xff)) { 15231493Sminshall WHO_ARE_WE(); 15331493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n"); 15431493Sminshall return -1; 15531493Sminshall } 15631493Sminshall } 157*31498Sminshall your_sequence = exch_state.my_sequence; 15831493Sminshall return 0; 15931493Sminshall } 16031493Sminshall 16131493Sminshall static int 16231493Sminshall enter_receive() 16331493Sminshall { 16431493Sminshall switch (conversation) { 16531493Sminshall case CONTENTION: 16631493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 16731493Sminshall if (send_state() == -1) { 16831493Sminshall return -1; 16931493Sminshall } 17031493Sminshall if (receive_state() == -1) { 17131493Sminshall return -1; 17231493Sminshall } 17331493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) { 17431493Sminshall WHO_ARE_WE(); 17531493Sminshall fprintf(stderr, "In CONTENTION state: "); 17631493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 17731493Sminshall fprintf(stderr, 17831493Sminshall "Both sides tried to enter RECEIVE state.\n"); 17931493Sminshall } else { 18031493Sminshall fprintf(stderr, 18131493Sminshall "Protocol error trying to enter RECEIVE state.\n"); 18231493Sminshall } 18331493Sminshall return -1; 18431493Sminshall } 18531493Sminshall break; 18631493Sminshall case SEND: 18731493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 18831493Sminshall if (send_state() == -1) { 18931493Sminshall return -1; 19031493Sminshall } 19131493Sminshall break; 19231493Sminshall } 19331493Sminshall conversation = RECEIVE; 19431493Sminshall return 0; 19531493Sminshall } 19631493Sminshall 19731493Sminshall static int 19831493Sminshall enter_send() 19931493Sminshall { 20031493Sminshall switch (conversation) { 20131493Sminshall case CONTENTION: 20231493Sminshall exch_state.opcode = EXCH_EXCH_RTS; 20331493Sminshall if (send_state() == -1) { 20431493Sminshall return -1; 20531493Sminshall } 20631493Sminshall /* fall through */ 20731493Sminshall case RECEIVE: 20831493Sminshall if (receive_state() == -1) { 20931493Sminshall return -1; 21031493Sminshall } 21131493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 21231493Sminshall WHO_ARE_WE(); 21331493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 21431493Sminshall return -1; 21531493Sminshall } 21631493Sminshall } 21731493Sminshall conversation = SEND; 21831493Sminshall return 0; 21931493Sminshall } 22031493Sminshall 22131467Sminshall int 22231493Sminshall api_exch_nextcommand() 22331467Sminshall { 22431493Sminshall if (conversation != RECEIVE) { 22531493Sminshall if (enter_receive() == -1) { 22631467Sminshall return -1; 22731467Sminshall } 22831467Sminshall } 22931493Sminshall if (receive_state() == -1) { 23031493Sminshall return -1; 23131493Sminshall } 23231493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) { 23331493Sminshall WHO_ARE_WE(); 23431493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 23531493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 23631493Sminshall return -1; 23731493Sminshall } 23831493Sminshall return exch_state.command_or_type; 23931467Sminshall } 24031467Sminshall 24131467Sminshall 24231467Sminshall int 24331460Sminshall api_exch_incommand(command) 24431460Sminshall int command; 24531460Sminshall { 24631460Sminshall int i; 24731460Sminshall 24831493Sminshall if ((i = api_exch_nextcommand()) == -1) { 24931493Sminshall return -1; 25031460Sminshall } 25131460Sminshall if (i != command) { 25231493Sminshall WHO_ARE_WE(); 25331460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 25431460Sminshall command, i); 25531460Sminshall return -1; 25631460Sminshall } 25731460Sminshall return 0; 25831460Sminshall } 25931460Sminshall 26031460Sminshall 26131467Sminshall int 26231460Sminshall api_exch_outcommand(command) 26331460Sminshall int command; 26431460Sminshall { 26531493Sminshall if (conversation != SEND) { 26631493Sminshall if (enter_send() == -1) { 26731460Sminshall return -1; 26831460Sminshall } 26931460Sminshall } 27031493Sminshall exch_state.command_or_type = command; 27131493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND; 27231493Sminshall if (send_state() == -1) { 27331493Sminshall return -1; 27431493Sminshall } else { 27531493Sminshall return 0; 27631493Sminshall } 27731460Sminshall } 27831460Sminshall 27931460Sminshall 28031467Sminshall int 28131460Sminshall api_exch_outtype(type, length, location) 28231460Sminshall int 28331460Sminshall type, 28431460Sminshall length; 28531460Sminshall char 28631460Sminshall *location; 28731460Sminshall { 28831460Sminshall int netleng = htons(length); 28931460Sminshall 29031493Sminshall if (conversation != SEND) { 29131493Sminshall if (enter_send() == -1) { 29231460Sminshall return -1; 29331460Sminshall } 29431460Sminshall } 29531493Sminshall exch_state.opcode = EXCH_EXCH_TYPE; 29631493Sminshall exch_state.command_or_type = type; 29731493Sminshall exch_state.length = netleng; 29831493Sminshall if (send_state() == -1) { 29931493Sminshall return -1; 30031493Sminshall } 30131493Sminshall if (length) { 30231493Sminshall if (OBUFROOM() > length) { 30331493Sminshall OBUFADDBYTES(location, length); 30431493Sminshall } else { 30531493Sminshall if (outflush() == -1) { 30631493Sminshall return -1; 30731493Sminshall } 30831493Sminshall if (write(sock, location, length) != length) { 30931493Sminshall WHO_ARE_WE(); 31031493Sminshall perror("write"); 31131493Sminshall return -1; 31231493Sminshall } 31331460Sminshall } 31431460Sminshall } 31531493Sminshall return 0; 31631460Sminshall } 31731460Sminshall 31831460Sminshall 31931467Sminshall int 32031460Sminshall api_exch_intype(type, length, location) 32131460Sminshall int 32231460Sminshall type, 32331460Sminshall length; 32431460Sminshall char 32531460Sminshall *location; 32631460Sminshall { 32731460Sminshall int i, netleng = htons(length); 32831460Sminshall 32931493Sminshall if (conversation != RECEIVE) { 33031493Sminshall if (enter_receive() == -1) { 33131460Sminshall return -1; 33231460Sminshall } 33331460Sminshall } 33431493Sminshall if (receive_state() == -1) { 33531460Sminshall return -1; 33631460Sminshall } 33731493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) { 33831493Sminshall WHO_ARE_WE(); 33931493Sminshall fprintf(stderr, 34031493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n", 34131493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 34231493Sminshall return -1; 34331493Sminshall } 34431493Sminshall if (exch_state.command_or_type != type) { 34531493Sminshall WHO_ARE_WE(); 34631493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 34731493Sminshall type, exch_state.command_or_type); 34831493Sminshall return -1; 34931493Sminshall } 35031493Sminshall if (exch_state.length != netleng) { 35131460Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", 35231493Sminshall type, length, ntohs(exch_state.length)); 35331460Sminshall return -1; 35431460Sminshall } 35531460Sminshall while (length) { 35631460Sminshall if ((i = read(sock, location, length)) < 0) { 35731493Sminshall WHO_ARE_WE(); 35831474Sminshall perror("read"); 35931460Sminshall return -1; 36031460Sminshall } 36131460Sminshall length -= i; 36231460Sminshall location += i; 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