131460Sminshall #include <stdio.h> 231460Sminshall 331460Sminshall #include "api_exch.h" 431460Sminshall 531467Sminshall static int sock; /* Socket number */ 631467Sminshall 731474Sminshall static char whoarewe[40] = ""; 8*31493Sminshall #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); 931474Sminshall 10*31493Sminshall static enum {CONTENTION, SEND, RECEIVE } conversation; 11*31493Sminshall 12*31493Sminshall static struct exch_exch exch_state; 13*31493Sminshall 14*31493Sminshall static unsigned int 15*31493Sminshall my_sequence, 16*31493Sminshall your_sequence; 17*31493Sminshall 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 22*31493Sminshall #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) { 44*31493Sminshall 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 } 68*31493Sminshall if ((count -= IBUFAVAILABLE()) < 0) { 69*31493Sminshall return 0; 70*31493Sminshall } 7131460Sminshall while (count) { 7231460Sminshall if ((i = read(sock, IBUFFER(), count)) < 0) { 73*31493Sminshall WHO_ARE_WE(); 7431474Sminshall perror("read"); 7531460Sminshall return -1; 7631460Sminshall } 7731474Sminshall if (i == 0) { 7831474Sminshall /* Reading past end-of-file */ 79*31493Sminshall WHO_ARE_WE(); 80*31493Sminshall fprintf(stderr, "End of file read\r\n"); 8131474Sminshall return -1; 8231474Sminshall } 8331460Sminshall count -= i; 8431460Sminshall IBUFADDED(i); 8531460Sminshall } 8631460Sminshall return 0; 8731460Sminshall } 8831460Sminshall 89*31493Sminshall static char * 90*31493Sminshall exch_to_ascii(exch) 91*31493Sminshall int exch; /* opcode to decode */ 92*31493Sminshall { 93*31493Sminshall switch (exch) { 94*31493Sminshall case EXCH_EXCH_COMMAND: 95*31493Sminshall return "Command"; 96*31493Sminshall case EXCH_EXCH_TYPE: 97*31493Sminshall return "Type"; 98*31493Sminshall case EXCH_EXCH_TURNAROUND: 99*31493Sminshall return "Turnaround"; 100*31493Sminshall case EXCH_EXCH_RTS: 101*31493Sminshall return "Request to Send"; 102*31493Sminshall default: 103*31493Sminshall { 104*31493Sminshall static char unknown[40]; 105*31493Sminshall 106*31493Sminshall sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 107*31493Sminshall return unknown; 108*31493Sminshall } 109*31493Sminshall } 110*31493Sminshall } 111*31493Sminshall 112*31493Sminshall /* 113*31493Sminshall * Send the exch structure, updating the sequnce number field. 114*31493Sminshall */ 115*31493Sminshall 116*31493Sminshall static int 117*31493Sminshall send_state() 118*31493Sminshall { 119*31493Sminshall if (OBUFROOM() < sizeof exch_state) { 120*31493Sminshall if (outflush() == -1) { 121*31493Sminshall return -1; 122*31493Sminshall } 123*31493Sminshall } 124*31493Sminshall exch_state.my_sequence = ++my_sequence; 125*31493Sminshall exch_state.your_sequence = your_sequence; 126*31493Sminshall OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 127*31493Sminshall return 0; 128*31493Sminshall } 129*31493Sminshall 130*31493Sminshall /* 131*31493Sminshall * Receive the exch structure from the other side, checking 132*31493Sminshall * sequence numbering. 133*31493Sminshall */ 134*31493Sminshall 135*31493Sminshall static int 136*31493Sminshall receive_state() 137*31493Sminshall { 138*31493Sminshall if (IBUFAVAILABLE() < sizeof exch_state) { 139*31493Sminshall if (infill(sizeof exch_state) == -1) { 140*31493Sminshall return -1; 141*31493Sminshall } 142*31493Sminshall } 143*31493Sminshall IBUFGETBYTES((char *)&exch_state, sizeof exch_state); 144*31493Sminshall if (conversation != CONTENTION) { 145*31493Sminshall if (exch_state.your_sequence != my_sequence) { 146*31493Sminshall WHO_ARE_WE(); 147*31493Sminshall fprintf(stderr, "Send sequence number mismatch.\n"); 148*31493Sminshall return -1; 149*31493Sminshall } 150*31493Sminshall if (exch_state.my_sequence != ++your_sequence) { 151*31493Sminshall WHO_ARE_WE(); 152*31493Sminshall fprintf(stderr, "Receive sequence number mismatch.\n"); 153*31493Sminshall return -1; 154*31493Sminshall } 155*31493Sminshall } else { 156*31493Sminshall /* In contention state, no sequence numbering */ 157*31493Sminshall your_sequence = exch_state.my_sequence; 158*31493Sminshall } 159*31493Sminshall return 0; 160*31493Sminshall } 161*31493Sminshall 162*31493Sminshall static int 163*31493Sminshall enter_receive() 164*31493Sminshall { 165*31493Sminshall switch (conversation) { 166*31493Sminshall case CONTENTION: 167*31493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 168*31493Sminshall if (send_state() == -1) { 169*31493Sminshall return -1; 170*31493Sminshall } 171*31493Sminshall if (receive_state() == -1) { 172*31493Sminshall return -1; 173*31493Sminshall } 174*31493Sminshall if (exch_state.opcode != EXCH_EXCH_RTS) { 175*31493Sminshall WHO_ARE_WE(); 176*31493Sminshall fprintf(stderr, "In CONTENTION state: "); 177*31493Sminshall if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 178*31493Sminshall fprintf(stderr, 179*31493Sminshall "Both sides tried to enter RECEIVE state.\n"); 180*31493Sminshall } else { 181*31493Sminshall fprintf(stderr, 182*31493Sminshall "Protocol error trying to enter RECEIVE state.\n"); 183*31493Sminshall } 184*31493Sminshall return -1; 185*31493Sminshall } 186*31493Sminshall break; 187*31493Sminshall case SEND: 188*31493Sminshall exch_state.opcode = EXCH_EXCH_TURNAROUND; 189*31493Sminshall if (send_state() == -1) { 190*31493Sminshall return -1; 191*31493Sminshall } 192*31493Sminshall break; 193*31493Sminshall } 194*31493Sminshall conversation = RECEIVE; 195*31493Sminshall return 0; 196*31493Sminshall } 197*31493Sminshall 198*31493Sminshall static int 199*31493Sminshall enter_send() 200*31493Sminshall { 201*31493Sminshall switch (conversation) { 202*31493Sminshall case CONTENTION: 203*31493Sminshall exch_state.opcode = EXCH_EXCH_RTS; 204*31493Sminshall if (send_state() == -1) { 205*31493Sminshall return -1; 206*31493Sminshall } 207*31493Sminshall /* fall through */ 208*31493Sminshall case RECEIVE: 209*31493Sminshall if (receive_state() == -1) { 210*31493Sminshall return -1; 211*31493Sminshall } 212*31493Sminshall if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 213*31493Sminshall WHO_ARE_WE(); 214*31493Sminshall fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 215*31493Sminshall return -1; 216*31493Sminshall } 217*31493Sminshall } 218*31493Sminshall conversation = SEND; 219*31493Sminshall return 0; 220*31493Sminshall } 221*31493Sminshall 22231467Sminshall int 223*31493Sminshall api_exch_nextcommand() 22431467Sminshall { 225*31493Sminshall if (conversation != RECEIVE) { 226*31493Sminshall if (enter_receive() == -1) { 22731467Sminshall return -1; 22831467Sminshall } 22931467Sminshall } 230*31493Sminshall if (receive_state() == -1) { 231*31493Sminshall return -1; 232*31493Sminshall } 233*31493Sminshall if (exch_state.opcode != EXCH_EXCH_COMMAND) { 234*31493Sminshall WHO_ARE_WE(); 235*31493Sminshall fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 236*31493Sminshall exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 237*31493Sminshall return -1; 238*31493Sminshall } 239*31493Sminshall return exch_state.command_or_type; 24031467Sminshall } 24131467Sminshall 24231467Sminshall 24331467Sminshall int 24431460Sminshall api_exch_incommand(command) 24531460Sminshall int command; 24631460Sminshall { 24731460Sminshall int i; 24831460Sminshall 249*31493Sminshall if ((i = api_exch_nextcommand()) == -1) { 250*31493Sminshall return -1; 25131460Sminshall } 25231460Sminshall if (i != command) { 253*31493Sminshall WHO_ARE_WE(); 25431460Sminshall fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 25531460Sminshall command, i); 25631460Sminshall return -1; 25731460Sminshall } 25831460Sminshall return 0; 25931460Sminshall } 26031460Sminshall 26131460Sminshall 26231467Sminshall int 26331460Sminshall api_exch_outcommand(command) 26431460Sminshall int command; 26531460Sminshall { 266*31493Sminshall if (conversation != SEND) { 267*31493Sminshall if (enter_send() == -1) { 26831460Sminshall return -1; 26931460Sminshall } 27031460Sminshall } 271*31493Sminshall exch_state.command_or_type = command; 272*31493Sminshall exch_state.opcode = EXCH_EXCH_COMMAND; 273*31493Sminshall if (send_state() == -1) { 274*31493Sminshall return -1; 275*31493Sminshall } else { 276*31493Sminshall return 0; 277*31493Sminshall } 27831460Sminshall } 27931460Sminshall 28031460Sminshall 28131467Sminshall int 28231460Sminshall api_exch_outtype(type, length, location) 28331460Sminshall int 28431460Sminshall type, 28531460Sminshall length; 28631460Sminshall char 28731460Sminshall *location; 28831460Sminshall { 28931460Sminshall int netleng = htons(length); 29031460Sminshall 291*31493Sminshall if (conversation != SEND) { 292*31493Sminshall if (enter_send() == -1) { 29331460Sminshall return -1; 29431460Sminshall } 29531460Sminshall } 296*31493Sminshall exch_state.opcode = EXCH_EXCH_TYPE; 297*31493Sminshall exch_state.command_or_type = type; 298*31493Sminshall exch_state.length = netleng; 299*31493Sminshall if (send_state() == -1) { 300*31493Sminshall return -1; 301*31493Sminshall } 302*31493Sminshall if (length) { 303*31493Sminshall if (OBUFROOM() > length) { 304*31493Sminshall OBUFADDBYTES(location, length); 305*31493Sminshall } else { 306*31493Sminshall if (outflush() == -1) { 307*31493Sminshall return -1; 308*31493Sminshall } 309*31493Sminshall if (write(sock, location, length) != length) { 310*31493Sminshall WHO_ARE_WE(); 311*31493Sminshall perror("write"); 312*31493Sminshall return -1; 313*31493Sminshall } 31431460Sminshall } 31531460Sminshall } 316*31493Sminshall return 0; 31731460Sminshall } 31831460Sminshall 31931460Sminshall 32031467Sminshall int 32131460Sminshall api_exch_intype(type, length, location) 32231460Sminshall int 32331460Sminshall type, 32431460Sminshall length; 32531460Sminshall char 32631460Sminshall *location; 32731460Sminshall { 32831460Sminshall int i, netleng = htons(length); 32931460Sminshall 330*31493Sminshall if (conversation != RECEIVE) { 331*31493Sminshall if (enter_receive() == -1) { 33231460Sminshall return -1; 33331460Sminshall } 33431460Sminshall } 335*31493Sminshall if (receive_state() == -1) { 33631460Sminshall return -1; 33731460Sminshall } 338*31493Sminshall if (exch_state.opcode != EXCH_EXCH_TYPE) { 339*31493Sminshall WHO_ARE_WE(); 340*31493Sminshall fprintf(stderr, 341*31493Sminshall "Expected to receive a %s exchange, received a %s exchange.\n", 342*31493Sminshall exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 343*31493Sminshall return -1; 344*31493Sminshall } 345*31493Sminshall if (exch_state.command_or_type != type) { 346*31493Sminshall WHO_ARE_WE(); 347*31493Sminshall fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 348*31493Sminshall type, exch_state.command_or_type); 349*31493Sminshall return -1; 350*31493Sminshall } 351*31493Sminshall if (exch_state.length != netleng) { 35231460Sminshall fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", 353*31493Sminshall type, length, ntohs(exch_state.length)); 35431460Sminshall return -1; 35531460Sminshall } 35631460Sminshall while (length) { 35731460Sminshall if ((i = read(sock, location, length)) < 0) { 358*31493Sminshall WHO_ARE_WE(); 35931474Sminshall perror("read"); 36031460Sminshall return -1; 36131460Sminshall } 36231460Sminshall length -= i; 36331460Sminshall location += i; 36431460Sminshall } 36531460Sminshall return 0; 36631460Sminshall } 36731467Sminshall 36831467Sminshall int 369*31493Sminshall api_exch_flush() 370*31493Sminshall { 371*31493Sminshall return outflush(); 372*31493Sminshall } 373*31493Sminshall 374*31493Sminshall int 37531474Sminshall api_exch_init(sock_number, ourname) 37631467Sminshall int sock_number; 37731474Sminshall char *ourname; 37831467Sminshall { 37931467Sminshall sock = sock_number; 38031474Sminshall strcpy(whoarewe, ourname); /* For error messages */ 38131467Sminshall 382*31493Sminshall my_sequence = your_sequence = 0; 383*31493Sminshall 384*31493Sminshall conversation = CONTENTION; /* We don't know which direction */ 385*31493Sminshall 38631467Sminshall IBUFRESET(); 38731467Sminshall OBUFRESET(); 38831467Sminshall 38931467Sminshall return 0; 39031467Sminshall } 391