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