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