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