131460Sminshall #include <stdio.h> 231460Sminshall 3*31801Sminshall #include "../general/general.h" 4*31801Sminshall 531460Sminshall #include "api_exch.h" 631460Sminshall 731467Sminshall static int sock; /* Socket number */ 831467Sminshall 931474Sminshall static char whoarewe[40] = ""; 1031493Sminshall #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); 1131474Sminshall 1231493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation; 1331493Sminshall 1431493Sminshall static struct exch_exch exch_state; 1531493Sminshall 1631493Sminshall static unsigned int 1731493Sminshall my_sequence, 1831493Sminshall your_sequence; 1931493Sminshall 2031499Sminshall static char ibuffer[4000], *ibuf_next, *ibuf_last; 2131460Sminshall #define IBUFADDED(i) ibuf_last += (i) 2231499Sminshall #define IBUFAVAILABLE() (ibuf_last-ibuf_next) 2331460Sminshall #define IBUFFER() ibuffer 2431499Sminshall #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1) 2531493Sminshall #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } 2631460Sminshall #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) 2731460Sminshall 2831499Sminshall char obuffer[4000], *obuf_next; 2931460Sminshall #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } 3031460Sminshall #define OBUFAVAILABLE() (obuf_next - obuffer) 3131460Sminshall #define OBUFFER() obuffer 3231460Sminshall #define OBUFRESET() obuf_next = obuffer 3331460Sminshall #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) 3431460Sminshall 3531460Sminshall 3631460Sminshall static int 3731460Sminshall outflush() 3831460Sminshall { 3931460Sminshall int length = OBUFAVAILABLE(); 4031460Sminshall 4131460Sminshall if (length != 0) { 4231460Sminshall if (write(sock, OBUFFER(), length) != length) { 4331493Sminshall WHO_ARE_WE(); 4431474Sminshall perror("write"); 4531460Sminshall return -1; 4631460Sminshall } 4731460Sminshall OBUFRESET(); 4831460Sminshall } 4931460Sminshall return 0; /* All OK */ 5031460Sminshall } 5131460Sminshall 5231460Sminshall 5331460Sminshall static int 5431499Sminshall iget(location, length) 5531499Sminshall char *location; 5631499Sminshall int length; 5731460Sminshall { 5831460Sminshall int i; 5931499Sminshall int count; 6031460Sminshall 6131460Sminshall if (OBUFAVAILABLE()) { 6231460Sminshall if (outflush() == -1) { 6331460Sminshall return -1; 6431460Sminshall } 6531460Sminshall } 6631499Sminshall if ((count = IBUFAVAILABLE()) != 0) { 6731499Sminshall if (count > length) { 6831499Sminshall count = length; 6931499Sminshall } 7031499Sminshall IBUFGETBYTES(location, count); 7131499Sminshall length -= count; 7231499Sminshall location += count; 7331460Sminshall } 7431499Sminshall while (length) { 7531499Sminshall if (ibuf_next == ibuf_last) { 7631499Sminshall IBUFRESET(); 7731499Sminshall } 7831499Sminshall if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) { 7931493Sminshall WHO_ARE_WE(); 8031474Sminshall perror("read"); 8131460Sminshall return -1; 8231460Sminshall } 8331499Sminshall if (count == 0) { 8431474Sminshall /* Reading past end-of-file */ 8531493Sminshall WHO_ARE_WE(); 8631493Sminshall fprintf(stderr, "End of file read\r\n"); 8731474Sminshall return -1; 8831474Sminshall } 8931499Sminshall IBUFADDED(count); 9031499Sminshall if (count > length) { 9131499Sminshall count = length; 9231499Sminshall } 9331499Sminshall IBUFGETBYTES(location, count); 9431499Sminshall length -= count; 9531499Sminshall location += count; 9631460Sminshall } 9731460Sminshall return 0; 9831460Sminshall } 9931460Sminshall 10031493Sminshall static char * 10131493Sminshall exch_to_ascii(exch) 10231493Sminshall int exch; /* opcode to decode */ 10331493Sminshall { 10431493Sminshall switch (exch) { 10531493Sminshall case EXCH_EXCH_COMMAND: 10631493Sminshall return "Command"; 10731493Sminshall case EXCH_EXCH_TYPE: 10831493Sminshall return "Type"; 10931493Sminshall case EXCH_EXCH_TURNAROUND: 11031493Sminshall return "Turnaround"; 11131493Sminshall case EXCH_EXCH_RTS: 11231493Sminshall return "Request to Send"; 11331493Sminshall default: 11431493Sminshall { 11531493Sminshall static char unknown[40]; 11631493Sminshall 11731493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 11831493Sminshall return unknown; 11931493Sminshall } 12031493Sminshall } 12131493Sminshall } 12231493Sminshall 12331493Sminshall /* 12431493Sminshall * Send the exch structure, updating the sequnce number field. 12531493Sminshall */ 12631493Sminshall 12731493Sminshall static int 12831493Sminshall send_state() 12931493Sminshall { 13031493Sminshall if (OBUFROOM() < sizeof exch_state) { 13131493Sminshall if (outflush() == -1) { 13231493Sminshall return -1; 13331493Sminshall } 13431493Sminshall } 13531498Sminshall my_sequence = (my_sequence+1)&0xff; 13631498Sminshall exch_state.my_sequence = my_sequence; 13731493Sminshall exch_state.your_sequence = your_sequence; 13831493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 13931493Sminshall return 0; 14031493Sminshall } 14131493Sminshall 14231493Sminshall /* 14331493Sminshall * Receive the exch structure from the other side, checking 14431493Sminshall * sequence numbering. 14531493Sminshall */ 14631493Sminshall 14731493Sminshall static int 14831493Sminshall receive_state() 14931493Sminshall { 15031499Sminshall if (iget((char *)&exch_state, sizeof exch_state) == -1) { 15131499Sminshall return -1; 15231493Sminshall } 15331493Sminshall if (conversation != CONTENTION) { 15431493Sminshall if (exch_state.your_sequence != my_sequence) { 15531493Sminshall WHO_ARE_WE(); 15631493Sminshall fprintf(stderr, "Send sequence number mismatch.\n"); 15731493Sminshall return -1; 15831493Sminshall } 15931498Sminshall if (exch_state.my_sequence != ((++your_sequence)&0xff)) { 16031493Sminshall WHO_ARE_WE(); 16131493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n"); 16231493Sminshall return -1; 16331493Sminshall } 16431493Sminshall } 16531498Sminshall your_sequence = exch_state.my_sequence; 16631493Sminshall return 0; 16731493Sminshall } 16831493Sminshall 16931493Sminshall static int 17031493Sminshall enter_receive() 17131493Sminshall { 17231493Sminshall switch (conversation) { 17331493Sminshall case CONTENTION: 17431493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 17531493Sminshall if (send_state() == -1) { 17631493Sminshall return -1; 17731493Sminshall } 17831493Sminshall if (receive_state() == -1) { 17931493Sminshall return -1; 18031493Sminshall } 18131493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) { 18231493Sminshall WHO_ARE_WE(); 18331493Sminshall fprintf(stderr, "In CONTENTION state: "); 18431493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 18531493Sminshall fprintf(stderr, 18631493Sminshall "Both sides tried to enter RECEIVE state.\n"); 18731493Sminshall } else { 18831493Sminshall fprintf(stderr, 18931493Sminshall "Protocol error trying to enter RECEIVE state.\n"); 19031493Sminshall } 19131493Sminshall return -1; 19231493Sminshall } 19331493Sminshall break; 19431493Sminshall case SEND: 19531493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 19631493Sminshall if (send_state() == -1) { 19731493Sminshall return -1; 19831493Sminshall } 19931493Sminshall break; 20031493Sminshall } 20131493Sminshall conversation = RECEIVE; 20231493Sminshall return 0; 20331493Sminshall } 20431493Sminshall 20531493Sminshall static int 20631493Sminshall enter_send() 20731493Sminshall { 20831493Sminshall switch (conversation) { 20931493Sminshall case CONTENTION: 21031493Sminshall exch_state.opcode = EXCH_EXCH_RTS; 21131493Sminshall if (send_state() == -1) { 21231493Sminshall return -1; 21331493Sminshall } 21431493Sminshall /* fall through */ 21531493Sminshall case RECEIVE: 21631493Sminshall if (receive_state() == -1) { 21731493Sminshall return -1; 21831493Sminshall } 21931493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 22031493Sminshall WHO_ARE_WE(); 22131493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 22231493Sminshall return -1; 22331493Sminshall } 22431493Sminshall } 22531493Sminshall conversation = SEND; 22631493Sminshall return 0; 22731493Sminshall } 22831493Sminshall 22931467Sminshall int 23031493Sminshall api_exch_nextcommand() 23131467Sminshall { 23231493Sminshall if (conversation != RECEIVE) { 23331493Sminshall if (enter_receive() == -1) { 23431467Sminshall return -1; 23531467Sminshall } 23631467Sminshall } 23731493Sminshall if (receive_state() == -1) { 23831493Sminshall return -1; 23931493Sminshall } 24031493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) { 24131493Sminshall WHO_ARE_WE(); 24231493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 24331493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 24431493Sminshall return -1; 24531493Sminshall } 24631493Sminshall return exch_state.command_or_type; 24731467Sminshall } 24831467Sminshall 24931467Sminshall 25031467Sminshall int 25131460Sminshall api_exch_incommand(command) 25231460Sminshall int command; 25331460Sminshall { 25431460Sminshall int i; 25531460Sminshall 25631493Sminshall if ((i = api_exch_nextcommand()) == -1) { 25731493Sminshall return -1; 25831460Sminshall } 25931460Sminshall if (i != command) { 26031493Sminshall WHO_ARE_WE(); 26131460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 26231460Sminshall command, i); 26331460Sminshall return -1; 26431460Sminshall } 26531460Sminshall return 0; 26631460Sminshall } 26731460Sminshall 26831460Sminshall 26931467Sminshall int 27031460Sminshall api_exch_outcommand(command) 27131460Sminshall int command; 27231460Sminshall { 27331493Sminshall if (conversation != SEND) { 27431493Sminshall if (enter_send() == -1) { 27531460Sminshall return -1; 27631460Sminshall } 27731460Sminshall } 27831493Sminshall exch_state.command_or_type = command; 27931493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND; 28031493Sminshall if (send_state() == -1) { 28131493Sminshall return -1; 28231493Sminshall } else { 28331493Sminshall return 0; 28431493Sminshall } 28531460Sminshall } 28631460Sminshall 28731460Sminshall 28831467Sminshall int 28931460Sminshall api_exch_outtype(type, length, location) 29031460Sminshall int 29131460Sminshall type, 29231460Sminshall length; 29331460Sminshall char 29431460Sminshall *location; 29531460Sminshall { 296*31801Sminshall int netleng = length; 29731460Sminshall 29831493Sminshall if (conversation != SEND) { 29931493Sminshall if (enter_send() == -1) { 30031460Sminshall return -1; 30131460Sminshall } 30231460Sminshall } 30331493Sminshall exch_state.opcode = EXCH_EXCH_TYPE; 30431493Sminshall exch_state.command_or_type = type; 30531493Sminshall exch_state.length = netleng; 30631493Sminshall if (send_state() == -1) { 30731493Sminshall return -1; 30831493Sminshall } 30931493Sminshall if (length) { 31031493Sminshall if (OBUFROOM() > length) { 31131493Sminshall OBUFADDBYTES(location, length); 31231493Sminshall } else { 31331493Sminshall if (outflush() == -1) { 31431493Sminshall return -1; 31531493Sminshall } 31631493Sminshall if (write(sock, location, length) != length) { 31731493Sminshall WHO_ARE_WE(); 31831493Sminshall perror("write"); 31931493Sminshall return -1; 32031493Sminshall } 32131460Sminshall } 32231460Sminshall } 32331493Sminshall return 0; 32431460Sminshall } 32531460Sminshall 32631460Sminshall 32731467Sminshall int 32831460Sminshall api_exch_intype(type, length, location) 32931460Sminshall int 33031460Sminshall type, 33131460Sminshall length; 33231460Sminshall char 33331460Sminshall *location; 33431460Sminshall { 335*31801Sminshall int i, netleng = length; 33631460Sminshall 33731493Sminshall if (conversation != RECEIVE) { 33831493Sminshall if (enter_receive() == -1) { 33931460Sminshall return -1; 34031460Sminshall } 34131460Sminshall } 34231493Sminshall if (receive_state() == -1) { 34331460Sminshall return -1; 34431460Sminshall } 34531493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) { 34631493Sminshall WHO_ARE_WE(); 34731493Sminshall fprintf(stderr, 34831493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n", 34931493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 35031493Sminshall return -1; 35131493Sminshall } 35231493Sminshall if (exch_state.command_or_type != type) { 35331493Sminshall WHO_ARE_WE(); 35431493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 35531493Sminshall type, exch_state.command_or_type); 35631493Sminshall return -1; 35731493Sminshall } 35831493Sminshall if (exch_state.length != netleng) { 35931460Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", 360*31801Sminshall type, length, exch_state.length); 36131460Sminshall return -1; 36231460Sminshall } 36331499Sminshall if (iget(location, length) == -1) { 36431499Sminshall return -1; 36531460Sminshall } 36631460Sminshall return 0; 36731460Sminshall } 36831467Sminshall 36931467Sminshall int 37031493Sminshall api_exch_flush() 37131493Sminshall { 37231493Sminshall return outflush(); 37331493Sminshall } 37431493Sminshall 37531493Sminshall int 37631474Sminshall api_exch_init(sock_number, ourname) 37731467Sminshall int sock_number; 37831474Sminshall char *ourname; 37931467Sminshall { 38031467Sminshall sock = sock_number; 38131474Sminshall strcpy(whoarewe, ourname); /* For error messages */ 38231467Sminshall 38331493Sminshall my_sequence = your_sequence = 0; 38431493Sminshall 38531493Sminshall conversation = CONTENTION; /* We don't know which direction */ 38631493Sminshall 38731467Sminshall IBUFRESET(); 38831467Sminshall OBUFRESET(); 38931467Sminshall 39031467Sminshall return 0; 39131467Sminshall } 392