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