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