1 /* $NetBSD: api_exch.c,v 1.7 2002/06/13 23:41:16 wiz Exp $ */
4 * Copyright (c) 1988 The Regents of the University of California.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 #if defined(__RCSID) && !defined(lint)
35 static char sccsid
[] = "@(#)api_exch.c 4.2 (Berkeley) 4/26/91";
37 __RCSID("$NetBSD: api_exch.c,v 1.7 2002/06/13 23:41:16 wiz Exp $");
46 #include "../general/general.h"
50 static int sock
; /* Socket number */
52 static char whoarewe
[40] = "";
53 #define WHO_ARE_WE() fprintf(stderr, "(API %s) ", whoarewe);
55 static enum {CONTENTION
, SEND
, RECEIVE
} conversation
;
57 static struct exch_exch exch_state
;
63 static char ibuffer
[4000], *ibuf_next
, *ibuf_last
;
64 #define IBUFADDED(i) ibuf_last += (i)
65 #define IBUFAVAILABLE() (ibuf_last-ibuf_next)
66 #define IBUFFER() ibuffer
67 #define IBUFFREE() (ibuffer+sizeof ibuffer-ibuf_last-1)
68 #define IBUFGETBYTES(w,l) { memcpy(w, ibuf_next, l); ibuf_next += l; }
69 #define IBUFRESET() (ibuf_next = ibuf_last = ibuffer)
71 char obuffer
[4000], *obuf_next
;
72 #define OBUFADDBYTES(w,l) { memcpy(obuf_next, w, l); obuf_next += l; }
73 #define OBUFAVAILABLE() (obuf_next - obuffer)
74 #define OBUFFER() obuffer
75 #define OBUFRESET() obuf_next = obuffer
76 #define OBUFROOM() (obuffer+sizeof obuffer-obuf_next)
79 static int outflush(void);
80 static int iget(char *, int);
81 static char *exch_to_ascii(int);
82 static int send_state(void);
83 static int receive_state(void);
84 static int enter_receive(void);
85 static int enter_send(void);
90 int length
= OBUFAVAILABLE();
93 if (write(sock
, OBUFFER(), length
) != length
) {
100 return 0; /* All OK */
105 iget(location
, length
)
111 if (OBUFAVAILABLE()) {
112 if (outflush() == -1) {
116 if ((count
= IBUFAVAILABLE()) != 0) {
117 if (count
> length
) {
120 IBUFGETBYTES(location
, count
);
125 if (ibuf_next
== ibuf_last
) {
128 if ((count
= read(sock
, IBUFFER(), IBUFFREE())) < 0) {
134 /* Reading past end-of-file */
136 fprintf(stderr
, "End of file read\r\n");
140 if (count
> length
) {
143 IBUFGETBYTES(location
, count
);
152 int exch
; /* opcode to decode */
155 case EXCH_EXCH_COMMAND
:
159 case EXCH_EXCH_TURNAROUND
:
162 return "Request to Send";
165 static char unknown
[40];
167 sprintf(unknown
, "(Unknown exchange 0x%02x)", exch
&0xff);
174 * Send the exch structure, updating the sequnce number field.
180 if (OBUFROOM() < sizeof exch_state
) {
181 if (outflush() == -1) {
185 my_sequence
= (my_sequence
+1)&0xff;
186 exch_state
.my_sequence
= my_sequence
;
187 exch_state
.your_sequence
= your_sequence
;
188 OBUFADDBYTES((char *)&exch_state
, sizeof exch_state
);
193 * Receive the exch structure from the other side, checking
194 * sequence numbering.
200 if (iget((char *)&exch_state
, sizeof exch_state
) == -1) {
203 if (conversation
!= CONTENTION
) {
204 if (exch_state
.your_sequence
!= my_sequence
) {
206 fprintf(stderr
, "Send sequence number mismatch.\n");
209 if (exch_state
.my_sequence
!= ((++your_sequence
)&0xff)) {
211 fprintf(stderr
, "Receive sequence number mismatch.\n");
215 your_sequence
= exch_state
.my_sequence
;
222 switch (conversation
) {
224 exch_state
.opcode
= EXCH_EXCH_TURNAROUND
;
225 if (send_state() == -1) {
228 if (receive_state() == -1) {
231 if (exch_state
.opcode
!= EXCH_EXCH_RTS
) {
233 fprintf(stderr
, "In CONTENTION state: ");
234 if (exch_state
.opcode
== EXCH_EXCH_TURNAROUND
) {
236 "Both sides tried to enter RECEIVE state.\n");
239 "Protocol error trying to enter RECEIVE state.\n");
245 exch_state
.opcode
= EXCH_EXCH_TURNAROUND
;
246 if (send_state() == -1) {
251 abort(); /* Unhandled case; remove abort if we die here */
253 conversation
= RECEIVE
;
260 switch (conversation
) {
262 exch_state
.opcode
= EXCH_EXCH_RTS
;
263 if (send_state() == -1) {
268 if (receive_state() == -1) {
271 if (exch_state
.opcode
!= EXCH_EXCH_TURNAROUND
) {
273 fprintf(stderr
, "Conversation error - both sides in SEND state.\n");
277 abort(); /* Unhandled case; remove abort if we die here */
284 api_exch_nextcommand()
286 if (conversation
!= RECEIVE
) {
287 if (enter_receive() == -1) {
291 if (receive_state() == -1) {
294 if (exch_state
.opcode
!= EXCH_EXCH_COMMAND
) {
296 fprintf(stderr
, "Expected a %s exchange, received a %s exchange.\n",
297 exch_to_ascii(EXCH_EXCH_COMMAND
), exch_to_ascii(exch_state
.opcode
));
300 return exch_state
.command_or_type
;
305 api_exch_incommand(command
)
310 if ((i
= api_exch_nextcommand()) == -1) {
315 fprintf(stderr
, "Expected API command 0x%x, got API command 0x%x.\n",
324 api_exch_outcommand(command
)
327 if (conversation
!= SEND
) {
328 if (enter_send() == -1) {
332 exch_state
.command_or_type
= command
;
333 exch_state
.opcode
= EXCH_EXCH_COMMAND
;
334 if (send_state() == -1) {
343 api_exch_outtype(type
, length
, location
)
350 int netleng
= length
;
352 if (conversation
!= SEND
) {
353 if (enter_send() == -1) {
357 exch_state
.opcode
= EXCH_EXCH_TYPE
;
358 exch_state
.command_or_type
= type
;
359 exch_state
.length
= netleng
;
360 if (send_state() == -1) {
364 if (OBUFROOM() > length
) {
365 OBUFADDBYTES(location
, length
);
367 if (outflush() == -1) {
370 if (write(sock
, location
, length
) != length
) {
382 api_exch_intype(type
, length
, location
)
389 int netleng
= length
;
391 if (conversation
!= RECEIVE
) {
392 if (enter_receive() == -1) {
396 if (receive_state() == -1) {
399 if (exch_state
.opcode
!= EXCH_EXCH_TYPE
) {
402 "Expected to receive a %s exchange, received a %s exchange.\n",
403 exch_to_ascii(EXCH_EXCH_TYPE
), exch_to_ascii(exch_state
.opcode
));
406 if (exch_state
.command_or_type
!= type
) {
408 fprintf(stderr
, "Expected type 0x%x, got type 0x%x.\n",
409 type
, exch_state
.command_or_type
);
412 if (exch_state
.length
!= netleng
) {
413 fprintf(stderr
, "Type 0x%x - expected length %d, received length %u.\n",
414 type
, length
, exch_state
.length
);
417 if (iget(location
, length
) == -1) {
430 api_exch_init(sock_number
, ourname
)
435 (void) strcpy(whoarewe
, ourname
); /* For error messages */
437 my_sequence
= your_sequence
= 0;
439 conversation
= CONTENTION
; /* We don't know which direction */