sscop_main.c revision 121663
1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Harti Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/sscop/sscop_main.c,v 1.3 2003/09/19 13:10:35 hbb Exp $
30 */
31
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <sys/uio.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <errno.h>
39#include <unistd.h>
40#include <time.h>
41#include <signal.h>
42#include <assert.h>
43#include <err.h>
44#include <isc/eventlib.h>
45
46#include <netnatm/unimsg.h>
47#include <netnatm/saal/sscop.h>
48#include "common.h"
49
50static int sigusr1;		/* got SIGUSR1 */
51static int unidir;		/* write only user */
52static int end_at_eof = 1;	/* send RELEASE_request at user EOF */
53
54static volatile int ready;	/* flag if connection is established */
55static volatile int finished;	/* got release confirm or indication */
56
57static const char usgtxt[] = "\
58SSCOP transport protocol\n\
59Usage: sscop [-h] [-Fbefirwx3] [-ap=v] [-lN] [-tt=m] [-v X] [-V X] [-W N]\n\
60Options:\n\
61  -F	  use framing for sscop also\n\
62  -V X	  set verbose flags to hex X\n\
63  -W N	  set initial window to N\n\
64  -a p=v  set parameter 'p' to 'v'\n\
65  -b	  enable robustness enhancement\n\
66  -e	  don't RELEASE_request on user EOF\n\
67  -f	  use begemot frame functions for user fd\n\
68  -h	  print this info\n\
69  -i	  use user fd only for output\n\
70  -lN	  loose every nth message\n\
71  -r	  reverse user and sscop file descriptors\n\
72  -t t=m  set timer 't' to 'm' milliseconds\n\
73  -v X	  set sscop verbose flags to hex X\n\
74  -w	  don't start conversation\n\
75  -x	  enable POLL after retransmission\n\
76  -3	  redirect output to fd 3\n\
77Timers are cc, poll, ka, nr or idle; parameters are j, k, cc, pd or stat.\n";
78
79static void sscop_send_manage(struct sscop *, void *,
80	enum sscop_maasig, struct uni_msg *, u_int, u_int);
81static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig,
82	struct SSCOP_MBUF_T *, u_int);
83static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *);
84
85static const struct sscop_funcs sscop_funcs = {
86	sscop_send_manage,
87	sscop_send_upper,
88	sscop_send_lower,
89	sscop_verbose,
90	sscop_start_timer,
91	sscop_stop_timer
92};
93
94/*
95 * SSCOP file descriptor is ready. Allocate and read one message
96 * and dispatch a signal.
97 */
98static void
99proto_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused)
100{
101	struct uni_msg *m;
102
103	if ((m = proto_msgin(fd)) != NULL)
104		sscop_input((struct sscop *)uap, m);
105}
106
107/*
108 * User input. Allocate and read message and dispatch signal.
109 */
110static void
111user_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused)
112{
113	struct uni_msg *m;
114
115	if ((m = user_msgin(fd)) != NULL)
116		sscop_aasig((struct sscop *)uap, SSCOP_DATA_request, m, 0);
117
118	else if (end_at_eof)
119		sscop_aasig((struct sscop *)uap, SSCOP_RELEASE_request, 0, 0);
120}
121
122static void
123onusr1(int s __unused)
124{
125	sigusr1++;
126}
127
128int
129main(int argc, char *argv[])
130{
131	int opt;
132	struct sscop *sscop;
133	struct sscop_param param;
134	struct sigaction sa;
135	int wait = 0;
136	u_int mask;
137	evEvent ev;
138
139	/*
140	 * Default is to have the USER on stdin and SSCOP on stdout
141	 */
142	sscop_fd = 0;
143	user_fd = 1;
144	user_out_fd = -1;
145
146	memset(&param, 0, sizeof(param));
147	param.maxk = MAXUSRMSG;
148	param.maxj = 0;
149	param.maxcc = 4;
150	mask = SSCOP_SET_MAXK | SSCOP_SET_MAXJ | SSCOP_SET_MAXCC;
151
152	while((opt = getopt(argc, argv, "3a:befFhil:rt:v:V:wW:x")) != -1)
153		switch(opt) {
154
155		  case '3':
156			user_out_fd = 3;
157			break;
158
159		  case 'e':
160			end_at_eof = 0;
161			break;
162
163		  case 'f':
164			useframe = 1;
165			break;
166
167		  case 'F':
168			sscopframe = 1;
169			break;
170
171		  case 'h':
172			fprintf(stderr, usgtxt);
173			exit(0);
174
175		  case 'i':
176			unidir++;
177			break;
178
179		  case 'l':
180			loose = strtoul(optarg, NULL, 0);
181			break;
182
183		  case 'r':
184			sscop_fd = 1;
185			user_fd = 0;
186			break;
187
188		  case 'v':
189			sscop_vflag = strtoul(optarg, NULL, 16);
190			break;
191
192		  case 'V':
193			verbose = strtoul(optarg, NULL, 16);
194			break;
195
196		  case 'w':
197			wait = 1;
198			break;
199
200		  case 'a':
201		  case 't':
202		  case 'b':
203		  case 'x':
204		  case 'W':
205			parse_param(&param, &mask, opt, optarg);
206			break;
207		}
208
209	if(user_out_fd < 0)
210		user_out_fd = user_fd;
211
212	if (evCreate(&evctx))
213		err(1, "evCreate");
214
215	/*
216	 * Catch USR1
217	 */
218	sa.sa_handler = onusr1;
219	sigemptyset(&sa.sa_mask);
220	sa.sa_flags = SA_RESTART;
221	if(sigaction(SIGUSR1, &sa, NULL))
222		err(1, "sigaction(SIGUSR1)");
223
224	/*
225	 * Allocate and initialize SSCOP
226	 */
227	if ((sscop = sscop_create(NULL, &sscop_funcs)) == NULL)
228		err(1, NULL);
229	sscop_setdebug(sscop, sscop_vflag);
230	if ((errno = sscop_setparam(sscop, &param, &mask)) != 0)
231		err(1, "can't set sscop parameters %#x", mask);
232
233	/*
234	 * Register sscop fd
235	 */
236	if (evSelectFD(evctx, sscop_fd, EV_READ, proto_infunc, sscop, &sscop_h))
237		err(1, "can't select on sscop fd");
238
239	/*
240	 * if we are active - send establish request
241	 */
242	if(!wait)
243		sscop_aasig(sscop, SSCOP_ESTABLISH_request, NULL, 1);
244
245	/*
246	 * Run protocol until it get's ready
247	 */
248	while (sscop_fd >= 0 && !ready) {
249		if (evGetNext(evctx, &ev, EV_WAIT) == 0) {
250			if (evDispatch(evctx, ev))
251				err(1, "dispatch event");
252		} else if (errno != EINTR)
253			err(1, "get event");
254	}
255
256	/*
257	 * If this led to a closed file - exit.
258	 */
259	if (sscop_fd < 0) {
260		VERBOSE(("SSCOP file descriptor closed - exiting"));
261		sscop_destroy(sscop);
262		return 0;
263	}
264
265	VERBOSE(("READY - starting data transfer"));
266
267	if (!unidir &&
268	    evSelectFD(evctx, user_fd, EV_READ, user_infunc, sscop, &user_h))
269		err(1, "can't select on sscop fd");
270
271	while (!sigusr1 && sscop_fd >= 0) {
272		if (evGetNext(evctx, &ev, EV_WAIT) == 0) {
273			if (evDispatch(evctx, ev))
274				err(1, "dispatch event");
275		} else if (errno != EINTR)
276			err(1, "get event");
277	}
278
279	if (sigusr1 && sscop_fd >= 0) {
280		/*
281		 * Release if we still have the connection
282		 */
283		sscop_aasig(sscop, SSCOP_RELEASE_request, NULL, 0);
284		while (!finished && sscop_fd >= 0) {
285			if (evGetNext(evctx, &ev, EV_WAIT) == 0) {
286				if (evDispatch(evctx, ev))
287					err(1, "dispatch event");
288			} else if (errno != EINTR)
289				err(1, "get event");
290		}
291	}
292
293	VERBOSE(("SSCOP file descriptor closed - exiting"));
294	sscop_destroy(sscop);
295
296	return (0);
297}
298
299
300
301/*
302 * AAL OUTPUT
303 */
304static void
305sscop_send_lower(struct sscop *sscop __unused, void *arg __unused,
306    struct SSCOP_MBUF_T *m)
307{
308	proto_msgout(m);
309}
310
311
312/*
313 * Write the message to the user and move the window
314 */
315static void
316uoutput(struct sscop *sscop, struct uni_msg *m)
317{
318	user_msgout(m);
319	sscop_window(sscop, +1);
320}
321
322/*
323 * SSCOP AA-SIGNALS
324 */
325static void
326sscop_send_upper(struct sscop *sscop, void *arg __unused, enum sscop_aasig sig,
327    struct SSCOP_MBUF_T *m, u_int p __unused)
328{
329	VERBOSE(("--> got aa %d(%s)", sig, sscop_signame(sig)));
330
331	switch (sig) {
332
333	  case SSCOP_RELEASE_indication:
334		if (end_at_eof) {
335			VERBOSE((" ... exiting"));
336			evDeselectFD(evctx, sscop_h);
337			(void)close(sscop_fd);
338			sscop_fd = -1;
339		}
340		finished++;
341		if (m)
342			uni_msg_destroy(m);
343		break;
344
345	  case SSCOP_RELEASE_confirm:
346		if (end_at_eof) {
347			VERBOSE((" ... exiting"));
348			evDeselectFD(evctx, sscop_h);
349			(void)close(sscop_fd);
350			sscop_fd = -1;
351		}
352		finished++;
353		break;
354
355	  case SSCOP_ESTABLISH_indication:
356		sscop_aasig(sscop, SSCOP_ESTABLISH_response, NULL, 1);
357		ready++;
358		if (m)
359			uni_msg_destroy(m);
360		break;
361
362	  case SSCOP_ESTABLISH_confirm:
363		ready++;
364		if (m)
365			uni_msg_destroy(m);
366		break;
367
368	  case SSCOP_DATA_indication:
369		assert(m != NULL);
370		uoutput(sscop, m);
371		break;
372
373	  case SSCOP_UDATA_indication:
374		assert(m != NULL);
375		VERBOSE(("UDATA.indication ignored"));
376		uni_msg_destroy(m);
377		break;
378
379	  case SSCOP_RECOVER_indication:
380		sscop_aasig(sscop, SSCOP_RECOVER_response, NULL, 0);
381		break;
382
383	  case SSCOP_RESYNC_indication:
384		sscop_aasig(sscop, SSCOP_RESYNC_response, NULL, 0);
385		if (m)
386			uni_msg_destroy(m);
387		break;
388
389	  case SSCOP_RESYNC_confirm:
390		break;
391
392	  case SSCOP_RETRIEVE_indication:
393	  case SSCOP_RETRIEVE_COMPL_indication:
394		warnx("Ooops. A retrieve indication");
395		abort();
396
397	  case SSCOP_ESTABLISH_request:
398	  case SSCOP_RELEASE_request:
399	  case SSCOP_ESTABLISH_response:
400	  case SSCOP_DATA_request:
401	  case SSCOP_UDATA_request:
402	  case SSCOP_RECOVER_response:
403	  case SSCOP_RESYNC_request:
404	  case SSCOP_RESYNC_response:
405	  case SSCOP_RETRIEVE_request:
406		warnx("bad signal for this direction");
407		abort();
408	}
409}
410
411/*
412 * This get's called for MAAL
413 */
414static void
415sscop_send_manage(struct sscop *sscop __unused, void *arg __unused,
416    enum sscop_maasig sig, struct uni_msg *m, u_int error, u_int cnt)
417{
418	VERBOSE(("--> got maa %d(%s)", sig, sscop_msigname(sig)));
419
420	switch (sig) {
421
422	  case SSCOP_MDATA_indication:
423		VERBOSE(("MDATA.indication ignored"));
424		uni_msg_destroy(m);
425		break;
426
427	  case SSCOP_MERROR_indication:
428		VERBOSE(("MAAL-ERROR.indication '%c' %u", error, cnt));
429		break;
430
431	  case SSCOP_MDATA_request:
432		warnx("bad signal for this direction");
433		abort();
434	}
435}
436