1 #include <stdio.h> 2 3 #include "api_exch.h" 4 5 static int sock; /* Socket number */ 6 7 static char whoarewe[40] = ""; 8 #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe); 9 10 static enum {CONTENTION, SEND, RECEIVE } conversation; 11 12 static struct exch_exch exch_state; 13 14 static unsigned int 15 my_sequence, 16 your_sequence; 17 18 static char ibuffer[40], *ibuf_next, *ibuf_last; 19 #define IBUFADDED(i) ibuf_last += (i) 20 #define IBUFAVAILABLE() (ibuf_last -ibuf_next) 21 #define IBUFFER() ibuffer 22 #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; } 23 #define IBUFGETCHAR() (*ibuf_next++) 24 #define IBUFGETSHORT() ((*ibuf_next++<<8)|(*ibuf_next++&0xff)) 25 #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer) 26 27 char obuffer[40], *obuf_next; 28 #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; } 29 #define OBUFADDCHAR(c) (*obuf_next++ = c) 30 #define OBUFADDSHORT(s) {*obuf_next++ = (s)>>8; *obuf_next++ = s; } 31 #define OBUFAVAILABLE() (obuf_next - obuffer) 32 #define OBUFFER() obuffer 33 #define OBUFRESET() obuf_next = obuffer 34 #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next) 35 36 37 static int 38 outflush() 39 { 40 int length = OBUFAVAILABLE(); 41 42 if (length != 0) { 43 if (write(sock, OBUFFER(), length) != length) { 44 WHO_ARE_WE(); 45 perror("write"); 46 return -1; 47 } 48 OBUFRESET(); 49 } 50 return 0; /* All OK */ 51 } 52 53 54 static int 55 infill(count) 56 int count; 57 { 58 int i; 59 60 if (OBUFAVAILABLE()) { 61 if (outflush() == -1) { 62 return -1; 63 } 64 } 65 if (ibuf_next == ibuf_last) { 66 IBUFRESET(); 67 } 68 if ((count -= IBUFAVAILABLE()) < 0) { 69 return 0; 70 } 71 while (count) { 72 if ((i = read(sock, IBUFFER(), count)) < 0) { 73 WHO_ARE_WE(); 74 perror("read"); 75 return -1; 76 } 77 if (i == 0) { 78 /* Reading past end-of-file */ 79 WHO_ARE_WE(); 80 fprintf(stderr, "End of file read\r\n"); 81 return -1; 82 } 83 count -= i; 84 IBUFADDED(i); 85 } 86 return 0; 87 } 88 89 static char * 90 exch_to_ascii(exch) 91 int exch; /* opcode to decode */ 92 { 93 switch (exch) { 94 case EXCH_EXCH_COMMAND: 95 return "Command"; 96 case EXCH_EXCH_TYPE: 97 return "Type"; 98 case EXCH_EXCH_TURNAROUND: 99 return "Turnaround"; 100 case EXCH_EXCH_RTS: 101 return "Request to Send"; 102 default: 103 { 104 static char unknown[40]; 105 106 sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff); 107 return unknown; 108 } 109 } 110 } 111 112 /* 113 * Send the exch structure, updating the sequnce number field. 114 */ 115 116 static int 117 send_state() 118 { 119 if (OBUFROOM() < sizeof exch_state) { 120 if (outflush() == -1) { 121 return -1; 122 } 123 } 124 my_sequence = (my_sequence+1)&0xff; 125 exch_state.my_sequence = my_sequence; 126 exch_state.your_sequence = your_sequence; 127 OBUFADDBYTES((char *)&exch_state, sizeof exch_state); 128 return 0; 129 } 130 131 /* 132 * Receive the exch structure from the other side, checking 133 * sequence numbering. 134 */ 135 136 static int 137 receive_state() 138 { 139 if (IBUFAVAILABLE() < sizeof exch_state) { 140 if (infill(sizeof exch_state) == -1) { 141 return -1; 142 } 143 } 144 IBUFGETBYTES((char *)&exch_state, sizeof exch_state); 145 if (conversation != CONTENTION) { 146 if (exch_state.your_sequence != my_sequence) { 147 WHO_ARE_WE(); 148 fprintf(stderr, "Send sequence number mismatch.\n"); 149 return -1; 150 } 151 if (exch_state.my_sequence != ((++your_sequence)&0xff)) { 152 WHO_ARE_WE(); 153 fprintf(stderr, "Receive sequence number mismatch.\n"); 154 return -1; 155 } 156 } 157 your_sequence = exch_state.my_sequence; 158 return 0; 159 } 160 161 static int 162 enter_receive() 163 { 164 switch (conversation) { 165 case CONTENTION: 166 exch_state.opcode = EXCH_EXCH_TURNAROUND; 167 if (send_state() == -1) { 168 return -1; 169 } 170 if (receive_state() == -1) { 171 return -1; 172 } 173 if (exch_state.opcode != EXCH_EXCH_RTS) { 174 WHO_ARE_WE(); 175 fprintf(stderr, "In CONTENTION state: "); 176 if (exch_state.opcode == EXCH_EXCH_TURNAROUND) { 177 fprintf(stderr, 178 "Both sides tried to enter RECEIVE state.\n"); 179 } else { 180 fprintf(stderr, 181 "Protocol error trying to enter RECEIVE state.\n"); 182 } 183 return -1; 184 } 185 break; 186 case SEND: 187 exch_state.opcode = EXCH_EXCH_TURNAROUND; 188 if (send_state() == -1) { 189 return -1; 190 } 191 break; 192 } 193 conversation = RECEIVE; 194 return 0; 195 } 196 197 static int 198 enter_send() 199 { 200 switch (conversation) { 201 case CONTENTION: 202 exch_state.opcode = EXCH_EXCH_RTS; 203 if (send_state() == -1) { 204 return -1; 205 } 206 /* fall through */ 207 case RECEIVE: 208 if (receive_state() == -1) { 209 return -1; 210 } 211 if (exch_state.opcode != EXCH_EXCH_TURNAROUND) { 212 WHO_ARE_WE(); 213 fprintf(stderr, "Conversation error - both sides in SEND state.\n"); 214 return -1; 215 } 216 } 217 conversation = SEND; 218 return 0; 219 } 220 221 int 222 api_exch_nextcommand() 223 { 224 if (conversation != RECEIVE) { 225 if (enter_receive() == -1) { 226 return -1; 227 } 228 } 229 if (receive_state() == -1) { 230 return -1; 231 } 232 if (exch_state.opcode != EXCH_EXCH_COMMAND) { 233 WHO_ARE_WE(); 234 fprintf(stderr, "Expected a %s exchange, received a %s exchange.\n", 235 exch_to_ascii(EXCH_EXCH_COMMAND), exch_to_ascii(exch_state.opcode)); 236 return -1; 237 } 238 return exch_state.command_or_type; 239 } 240 241 242 int 243 api_exch_incommand(command) 244 int command; 245 { 246 int i; 247 248 if ((i = api_exch_nextcommand()) == -1) { 249 return -1; 250 } 251 if (i != command) { 252 WHO_ARE_WE(); 253 fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n", 254 command, i); 255 return -1; 256 } 257 return 0; 258 } 259 260 261 int 262 api_exch_outcommand(command) 263 int command; 264 { 265 if (conversation != SEND) { 266 if (enter_send() == -1) { 267 return -1; 268 } 269 } 270 exch_state.command_or_type = command; 271 exch_state.opcode = EXCH_EXCH_COMMAND; 272 if (send_state() == -1) { 273 return -1; 274 } else { 275 return 0; 276 } 277 } 278 279 280 int 281 api_exch_outtype(type, length, location) 282 int 283 type, 284 length; 285 char 286 *location; 287 { 288 int netleng = htons(length); 289 290 if (conversation != SEND) { 291 if (enter_send() == -1) { 292 return -1; 293 } 294 } 295 exch_state.opcode = EXCH_EXCH_TYPE; 296 exch_state.command_or_type = type; 297 exch_state.length = netleng; 298 if (send_state() == -1) { 299 return -1; 300 } 301 if (length) { 302 if (OBUFROOM() > length) { 303 OBUFADDBYTES(location, length); 304 } else { 305 if (outflush() == -1) { 306 return -1; 307 } 308 if (write(sock, location, length) != length) { 309 WHO_ARE_WE(); 310 perror("write"); 311 return -1; 312 } 313 } 314 } 315 return 0; 316 } 317 318 319 int 320 api_exch_intype(type, length, location) 321 int 322 type, 323 length; 324 char 325 *location; 326 { 327 int i, netleng = htons(length); 328 329 if (conversation != RECEIVE) { 330 if (enter_receive() == -1) { 331 return -1; 332 } 333 } 334 if (receive_state() == -1) { 335 return -1; 336 } 337 if (exch_state.opcode != EXCH_EXCH_TYPE) { 338 WHO_ARE_WE(); 339 fprintf(stderr, 340 "Expected to receive a %s exchange, received a %s exchange.\n", 341 exch_to_ascii(EXCH_EXCH_TYPE), exch_to_ascii(exch_state.opcode)); 342 return -1; 343 } 344 if (exch_state.command_or_type != type) { 345 WHO_ARE_WE(); 346 fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n", 347 type, exch_state.command_or_type); 348 return -1; 349 } 350 if (exch_state.length != netleng) { 351 fprintf(stderr, "Type 0x%x - expected length %d, received length %d.\n", 352 type, length, ntohs(exch_state.length)); 353 return -1; 354 } 355 while (length) { 356 if ((i = read(sock, location, length)) < 0) { 357 WHO_ARE_WE(); 358 perror("read"); 359 return -1; 360 } 361 length -= i; 362 location += i; 363 } 364 return 0; 365 } 366 367 int 368 api_exch_flush() 369 { 370 return outflush(); 371 } 372 373 int 374 api_exch_init(sock_number, ourname) 375 int sock_number; 376 char *ourname; 377 { 378 sock = sock_number; 379 strcpy(whoarewe, ourname); /* For error messages */ 380 381 my_sequence = your_sequence = 0; 382 383 conversation = CONTENTION; /* We don't know which direction */ 384 385 IBUFRESET(); 386 OBUFRESET(); 387 388 return 0; 389 } 390