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