diff options
Diffstat (limited to 'contrib/ngatm/sscop/sscop_main.c')
-rw-r--r-- | contrib/ngatm/sscop/sscop_main.c | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/contrib/ngatm/sscop/sscop_main.c b/contrib/ngatm/sscop/sscop_main.c new file mode 100644 index 0000000..c426535 --- /dev/null +++ b/contrib/ngatm/sscop/sscop_main.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Harti Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/sscop/sscop_main.c,v 1.3 2003/09/19 13:10:35 hbb Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <signal.h> +#include <assert.h> +#include <err.h> +#include <isc/eventlib.h> + +#include <netnatm/unimsg.h> +#include <netnatm/saal/sscop.h> +#include "common.h" + +static int sigusr1; /* got SIGUSR1 */ +static int unidir; /* write only user */ +static int end_at_eof = 1; /* send RELEASE_request at user EOF */ + +static volatile int ready; /* flag if connection is established */ +static volatile int finished; /* got release confirm or indication */ + +static const char usgtxt[] = "\ +SSCOP transport protocol\n\ +Usage: sscop [-h] [-Fbefirwx3] [-ap=v] [-lN] [-tt=m] [-v X] [-V X] [-W N]\n\ +Options:\n\ + -F use framing for sscop also\n\ + -V X set verbose flags to hex X\n\ + -W N set initial window to N\n\ + -a p=v set parameter 'p' to 'v'\n\ + -b enable robustness enhancement\n\ + -e don't RELEASE_request on user EOF\n\ + -f use begemot frame functions for user fd\n\ + -h print this info\n\ + -i use user fd only for output\n\ + -lN loose every nth message\n\ + -r reverse user and sscop file descriptors\n\ + -t t=m set timer 't' to 'm' milliseconds\n\ + -v X set sscop verbose flags to hex X\n\ + -w don't start conversation\n\ + -x enable POLL after retransmission\n\ + -3 redirect output to fd 3\n\ +Timers are cc, poll, ka, nr or idle; parameters are j, k, cc, pd or stat.\n"; + +static void sscop_send_manage(struct sscop *, void *, + enum sscop_maasig, struct uni_msg *, u_int, u_int); +static void sscop_send_upper(struct sscop *, void *, enum sscop_aasig, + struct SSCOP_MBUF_T *, u_int); +static void sscop_send_lower(struct sscop *, void *, struct SSCOP_MBUF_T *); + +static const struct sscop_funcs sscop_funcs = { + sscop_send_manage, + sscop_send_upper, + sscop_send_lower, + sscop_verbose, + sscop_start_timer, + sscop_stop_timer +}; + +/* + * SSCOP file descriptor is ready. Allocate and read one message + * and dispatch a signal. + */ +static void +proto_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) +{ + struct uni_msg *m; + + if ((m = proto_msgin(fd)) != NULL) + sscop_input((struct sscop *)uap, m); +} + +/* + * User input. Allocate and read message and dispatch signal. + */ +static void +user_infunc(evContext ctx __unused, void *uap, int fd, int mask __unused) +{ + struct uni_msg *m; + + if ((m = user_msgin(fd)) != NULL) + sscop_aasig((struct sscop *)uap, SSCOP_DATA_request, m, 0); + + else if (end_at_eof) + sscop_aasig((struct sscop *)uap, SSCOP_RELEASE_request, 0, 0); +} + +static void +onusr1(int s __unused) +{ + sigusr1++; +} + +int +main(int argc, char *argv[]) +{ + int opt; + struct sscop *sscop; + struct sscop_param param; + struct sigaction sa; + int wait = 0; + u_int mask; + evEvent ev; + + /* + * Default is to have the USER on stdin and SSCOP on stdout + */ + sscop_fd = 0; + user_fd = 1; + user_out_fd = -1; + + memset(¶m, 0, sizeof(param)); + param.maxk = MAXUSRMSG; + param.maxj = 0; + param.maxcc = 4; + mask = SSCOP_SET_MAXK | SSCOP_SET_MAXJ | SSCOP_SET_MAXCC; + + while((opt = getopt(argc, argv, "3a:befFhil:rt:v:V:wW:x")) != -1) + switch(opt) { + + case '3': + user_out_fd = 3; + break; + + case 'e': + end_at_eof = 0; + break; + + case 'f': + useframe = 1; + break; + + case 'F': + sscopframe = 1; + break; + + case 'h': + fprintf(stderr, usgtxt); + exit(0); + + case 'i': + unidir++; + break; + + case 'l': + loose = strtoul(optarg, NULL, 0); + break; + + case 'r': + sscop_fd = 1; + user_fd = 0; + break; + + case 'v': + sscop_vflag = strtoul(optarg, NULL, 16); + break; + + case 'V': + verbose = strtoul(optarg, NULL, 16); + break; + + case 'w': + wait = 1; + break; + + case 'a': + case 't': + case 'b': + case 'x': + case 'W': + parse_param(¶m, &mask, opt, optarg); + break; + } + + if(user_out_fd < 0) + user_out_fd = user_fd; + + if (evCreate(&evctx)) + err(1, "evCreate"); + + /* + * Catch USR1 + */ + sa.sa_handler = onusr1; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + if(sigaction(SIGUSR1, &sa, NULL)) + err(1, "sigaction(SIGUSR1)"); + + /* + * Allocate and initialize SSCOP + */ + if ((sscop = sscop_create(NULL, &sscop_funcs)) == NULL) + err(1, NULL); + sscop_setdebug(sscop, sscop_vflag); + if ((errno = sscop_setparam(sscop, ¶m, &mask)) != 0) + err(1, "can't set sscop parameters %#x", mask); + + /* + * Register sscop fd + */ + if (evSelectFD(evctx, sscop_fd, EV_READ, proto_infunc, sscop, &sscop_h)) + err(1, "can't select on sscop fd"); + + /* + * if we are active - send establish request + */ + if(!wait) + sscop_aasig(sscop, SSCOP_ESTABLISH_request, NULL, 1); + + /* + * Run protocol until it get's ready + */ + while (sscop_fd >= 0 && !ready) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + + /* + * If this led to a closed file - exit. + */ + if (sscop_fd < 0) { + VERBOSE(("SSCOP file descriptor closed - exiting")); + sscop_destroy(sscop); + return 0; + } + + VERBOSE(("READY - starting data transfer")); + + if (!unidir && + evSelectFD(evctx, user_fd, EV_READ, user_infunc, sscop, &user_h)) + err(1, "can't select on sscop fd"); + + while (!sigusr1 && sscop_fd >= 0) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + + if (sigusr1 && sscop_fd >= 0) { + /* + * Release if we still have the connection + */ + sscop_aasig(sscop, SSCOP_RELEASE_request, NULL, 0); + while (!finished && sscop_fd >= 0) { + if (evGetNext(evctx, &ev, EV_WAIT) == 0) { + if (evDispatch(evctx, ev)) + err(1, "dispatch event"); + } else if (errno != EINTR) + err(1, "get event"); + } + } + + VERBOSE(("SSCOP file descriptor closed - exiting")); + sscop_destroy(sscop); + + return (0); +} + + + +/* + * AAL OUTPUT + */ +static void +sscop_send_lower(struct sscop *sscop __unused, void *arg __unused, + struct SSCOP_MBUF_T *m) +{ + proto_msgout(m); +} + + +/* + * Write the message to the user and move the window + */ +static void +uoutput(struct sscop *sscop, struct uni_msg *m) +{ + user_msgout(m); + sscop_window(sscop, +1); +} + +/* + * SSCOP AA-SIGNALS + */ +static void +sscop_send_upper(struct sscop *sscop, void *arg __unused, enum sscop_aasig sig, + struct SSCOP_MBUF_T *m, u_int p __unused) +{ + VERBOSE(("--> got aa %d(%s)", sig, sscop_signame(sig))); + + switch (sig) { + + case SSCOP_RELEASE_indication: + if (end_at_eof) { + VERBOSE((" ... exiting")); + evDeselectFD(evctx, sscop_h); + (void)close(sscop_fd); + sscop_fd = -1; + } + finished++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_RELEASE_confirm: + if (end_at_eof) { + VERBOSE((" ... exiting")); + evDeselectFD(evctx, sscop_h); + (void)close(sscop_fd); + sscop_fd = -1; + } + finished++; + break; + + case SSCOP_ESTABLISH_indication: + sscop_aasig(sscop, SSCOP_ESTABLISH_response, NULL, 1); + ready++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_ESTABLISH_confirm: + ready++; + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_DATA_indication: + assert(m != NULL); + uoutput(sscop, m); + break; + + case SSCOP_UDATA_indication: + assert(m != NULL); + VERBOSE(("UDATA.indication ignored")); + uni_msg_destroy(m); + break; + + case SSCOP_RECOVER_indication: + sscop_aasig(sscop, SSCOP_RECOVER_response, NULL, 0); + break; + + case SSCOP_RESYNC_indication: + sscop_aasig(sscop, SSCOP_RESYNC_response, NULL, 0); + if (m) + uni_msg_destroy(m); + break; + + case SSCOP_RESYNC_confirm: + break; + + case SSCOP_RETRIEVE_indication: + case SSCOP_RETRIEVE_COMPL_indication: + warnx("Ooops. A retrieve indication"); + abort(); + + case SSCOP_ESTABLISH_request: + case SSCOP_RELEASE_request: + case SSCOP_ESTABLISH_response: + case SSCOP_DATA_request: + case SSCOP_UDATA_request: + case SSCOP_RECOVER_response: + case SSCOP_RESYNC_request: + case SSCOP_RESYNC_response: + case SSCOP_RETRIEVE_request: + warnx("bad signal for this direction"); + abort(); + } +} + +/* + * This get's called for MAAL + */ +static void +sscop_send_manage(struct sscop *sscop __unused, void *arg __unused, + enum sscop_maasig sig, struct uni_msg *m, u_int error, u_int cnt) +{ + VERBOSE(("--> got maa %d(%s)", sig, sscop_msigname(sig))); + + switch (sig) { + + case SSCOP_MDATA_indication: + VERBOSE(("MDATA.indication ignored")); + uni_msg_destroy(m); + break; + + case SSCOP_MERROR_indication: + VERBOSE(("MAAL-ERROR.indication '%c' %u", error, cnt)); + break; + + case SSCOP_MDATA_request: + warnx("bad signal for this direction"); + abort(); + } +} |