Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.bin / tn3270 / api / api_exch.c
blob592c32ef413535439a1db8352cffc6abcf3e9935
1 /* $NetBSD: api_exch.c,v 1.7 2002/06/13 23:41:16 wiz Exp $ */
3 /*-
4 * Copyright (c) 1988 The Regents of the University of California.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #if defined(__RCSID) && !defined(lint)
34 #if 0
35 static char sccsid[] = "@(#)api_exch.c 4.2 (Berkeley) 4/26/91";
36 #else
37 __RCSID("$NetBSD: api_exch.c,v 1.7 2002/06/13 23:41:16 wiz Exp $");
38 #endif
39 #endif /* not lint */
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
46 #include "../general/general.h"
48 #include "api_exch.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;
59 static unsigned int
60 my_sequence,
61 your_sequence;
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);
87 static int
88 outflush()
90 int length = OBUFAVAILABLE();
92 if (length != 0) {
93 if (write(sock, OBUFFER(), length) != length) {
94 WHO_ARE_WE();
95 perror("write");
96 return -1;
98 OBUFRESET();
100 return 0; /* All OK */
104 static int
105 iget(location, length)
106 char *location;
107 int length;
109 int count;
111 if (OBUFAVAILABLE()) {
112 if (outflush() == -1) {
113 return -1;
116 if ((count = IBUFAVAILABLE()) != 0) {
117 if (count > length) {
118 count = length;
120 IBUFGETBYTES(location, count);
121 length -= count;
122 location += count;
124 while (length) {
125 if (ibuf_next == ibuf_last) {
126 IBUFRESET();
128 if ((count = read(sock, IBUFFER(), IBUFFREE())) < 0) {
129 WHO_ARE_WE();
130 perror("read");
131 return -1;
133 if (count == 0) {
134 /* Reading past end-of-file */
135 WHO_ARE_WE();
136 fprintf(stderr, "End of file read\r\n");
137 return -1;
139 IBUFADDED(count);
140 if (count > length) {
141 count = length;
143 IBUFGETBYTES(location, count);
144 length -= count;
145 location += count;
147 return 0;
150 static char *
151 exch_to_ascii(exch)
152 int exch; /* opcode to decode */
154 switch (exch) {
155 case EXCH_EXCH_COMMAND:
156 return "Command";
157 case EXCH_EXCH_TYPE:
158 return "Type";
159 case EXCH_EXCH_TURNAROUND:
160 return "Turnaround";
161 case EXCH_EXCH_RTS:
162 return "Request to Send";
163 default:
165 static char unknown[40];
167 sprintf(unknown, "(Unknown exchange 0x%02x)", exch&0xff);
168 return unknown;
174 * Send the exch structure, updating the sequnce number field.
177 static int
178 send_state()
180 if (OBUFROOM() < sizeof exch_state) {
181 if (outflush() == -1) {
182 return -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);
189 return 0;
193 * Receive the exch structure from the other side, checking
194 * sequence numbering.
197 static int
198 receive_state()
200 if (iget((char *)&exch_state, sizeof exch_state) == -1) {
201 return -1;
203 if (conversation != CONTENTION) {
204 if (exch_state.your_sequence != my_sequence) {
205 WHO_ARE_WE();
206 fprintf(stderr, "Send sequence number mismatch.\n");
207 return -1;
209 if (exch_state.my_sequence != ((++your_sequence)&0xff)) {
210 WHO_ARE_WE();
211 fprintf(stderr, "Receive sequence number mismatch.\n");
212 return -1;
215 your_sequence = exch_state.my_sequence;
216 return 0;
219 static int
220 enter_receive()
222 switch (conversation) {
223 case CONTENTION:
224 exch_state.opcode = EXCH_EXCH_TURNAROUND;
225 if (send_state() == -1) {
226 return -1;
228 if (receive_state() == -1) {
229 return -1;
231 if (exch_state.opcode != EXCH_EXCH_RTS) {
232 WHO_ARE_WE();
233 fprintf(stderr, "In CONTENTION state: ");
234 if (exch_state.opcode == EXCH_EXCH_TURNAROUND) {
235 fprintf(stderr,
236 "Both sides tried to enter RECEIVE state.\n");
237 } else {
238 fprintf(stderr,
239 "Protocol error trying to enter RECEIVE state.\n");
241 return -1;
243 break;
244 case SEND:
245 exch_state.opcode = EXCH_EXCH_TURNAROUND;
246 if (send_state() == -1) {
247 return -1;
249 break;
250 case RECEIVE:
251 abort(); /* Unhandled case; remove abort if we die here */
253 conversation = RECEIVE;
254 return 0;
257 static int
258 enter_send()
260 switch (conversation) {
261 case CONTENTION:
262 exch_state.opcode = EXCH_EXCH_RTS;
263 if (send_state() == -1) {
264 return -1;
266 /* fall through */
267 case RECEIVE:
268 if (receive_state() == -1) {
269 return -1;
271 if (exch_state.opcode != EXCH_EXCH_TURNAROUND) {
272 WHO_ARE_WE();
273 fprintf(stderr, "Conversation error - both sides in SEND state.\n");
274 return -1;
276 case SEND:
277 abort(); /* Unhandled case; remove abort if we die here */
279 conversation = SEND;
280 return 0;
284 api_exch_nextcommand()
286 if (conversation != RECEIVE) {
287 if (enter_receive() == -1) {
288 return -1;
291 if (receive_state() == -1) {
292 return -1;
294 if (exch_state.opcode != EXCH_EXCH_COMMAND) {
295 WHO_ARE_WE();
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));
298 return -1;
300 return exch_state.command_or_type;
305 api_exch_incommand(command)
306 int command;
308 int i;
310 if ((i = api_exch_nextcommand()) == -1) {
311 return -1;
313 if (i != command) {
314 WHO_ARE_WE();
315 fprintf(stderr, "Expected API command 0x%x, got API command 0x%x.\n",
316 command, i);
317 return -1;
319 return 0;
324 api_exch_outcommand(command)
325 int command;
327 if (conversation != SEND) {
328 if (enter_send() == -1) {
329 return -1;
332 exch_state.command_or_type = command;
333 exch_state.opcode = EXCH_EXCH_COMMAND;
334 if (send_state() == -1) {
335 return -1;
336 } else {
337 return 0;
343 api_exch_outtype(type, length, location)
345 type,
346 length;
347 const char
348 *location;
350 int netleng = length;
352 if (conversation != SEND) {
353 if (enter_send() == -1) {
354 return -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) {
361 return -1;
363 if (length) {
364 if (OBUFROOM() > length) {
365 OBUFADDBYTES(location, length);
366 } else {
367 if (outflush() == -1) {
368 return -1;
370 if (write(sock, location, length) != length) {
371 WHO_ARE_WE();
372 perror("write");
373 return -1;
377 return 0;
382 api_exch_intype(type, length, location)
384 type,
385 length;
386 char
387 *location;
389 int netleng = length;
391 if (conversation != RECEIVE) {
392 if (enter_receive() == -1) {
393 return -1;
396 if (receive_state() == -1) {
397 return -1;
399 if (exch_state.opcode != EXCH_EXCH_TYPE) {
400 WHO_ARE_WE();
401 fprintf(stderr,
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));
404 return -1;
406 if (exch_state.command_or_type != type) {
407 WHO_ARE_WE();
408 fprintf(stderr, "Expected type 0x%x, got type 0x%x.\n",
409 type, exch_state.command_or_type);
410 return -1;
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);
415 return -1;
417 if (iget(location, length) == -1) {
418 return -1;
420 return 0;
424 api_exch_flush()
426 return outflush();
430 api_exch_init(sock_number, ourname)
431 int sock_number;
432 char *ourname;
434 sock = sock_number;
435 (void) strcpy(whoarewe, ourname); /* For error messages */
437 my_sequence = your_sequence = 0;
439 conversation = CONTENTION; /* We don't know which direction */
441 IBUFRESET();
442 OBUFRESET();
444 return 0;