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