rlc/rlc.c010064400373640000764000000227740657027043100140170ustar00ucaclxvcsstaff00002440000013/* * rlc.c -- sender/receiver setup routines * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #include /* for stat: without this doesn't compile in FreeBSD 2.1 */ #include #include #include #include /* for stat */ #include /* for sleep */ #if (defined(Linux)) #include #endif #if (!defined(Linux)) #if (defined(FreeBSD) || (defined(SunOS) && (OSMVER < 5))) #include #include #endif #endif #include "rlc.h" #include "rlcif.h" #include "agent.h" #include "ui.h" #include "sender.h" #include "receiver.h" #include "layers.h" #include "utils.h" #include "compat.h" #include "init.h" #include "event.h" #include "error.h" rlc_app_chanhandle_t client_chanhandle = NULL; /*++++ Creates a new protocol instance assigning a local protocol instance identifier. Returns: - the protocol instance id, on success. - a negative value on failure: */ int rlc_new(int isreceiver) { int ret, retvalue, i; sxs_t *se; /* library initialization ? */ if ((ret = rlc_internal_init()) != 0) { if (ret > 0) retvalue = ret; else return (rlc_return_error_ (-1, ret, "Error in rlc_internal_init()")); } _rlc_rx_init(); _rlc_tx_init(); /** ** allocate session descriptor **/ if (NULL == (se = calloc(1, sizeof(sxs_t)))) { return (rlc_return_error_ (-1, ALLOC_ERROR, "* Cannot allocate session descriptor")); } if (NULL == (se->cong = calloc(1, sizeof(cong_t)))) { free (se); return (rlc_return_error_ (-1, ALLOC_ERROR, NULL)); } if (_rlc_insert_instance ((instance_des_t *) se, rlc_inst_mngr) < 0) { free(se); return (rlc_return_error_(-1, TOO_MANY_INSTANCES, NULL)); } se->is_on = 0; /* start will set to true */ se->port = 0; se->cpi = 0; se->have_gui = 0; #ifdef HAVE_UI se->error_gui = NULL; se->warning_gui = NULL; #endif se->geometry = NULL; se->starttime = 0; /* will be set by start */ se->isreceiver = isreceiver; /* Sender Specific */ se->ch = 0; se->ttl = TTL; se->rate = L0_PERIOD; se->mpkts = DATA_SIZE; se->Mpkts = DATA_SIZE; se->pkts_left = INFINITE; /* this is not used ! */ se->tx_packet = NULL; se->flags = 0; se->l.nc = NLAY; /* Receiver Specific */ se->termdelayed = 0; se->src = 0; se->lkypays = MAX_PAYLOAD_SIZE; se->lkypaysv = 0; se->rx_packet = NULL; assert(congestion_setup(se->ides, se->cong) >= 0); for (i=0; isocks[i] = NO_SOCK; se->addrss[0] = -1; /* this to detect if addresses * has ben set */ se->have_addr_ass = 0; /* se->addrss ? */ se->watch_t = 0; se->watch_last = 0; se->watch_f = NULL; /* XXX the wornings get lost !!! */ return (se->ides); } /*++++ Provides the multicast address(es), port and ttl. ttl is ingnored in the receiver. Returns: - 0 on success. - a negative value on failure: - > 0 in caso of warning: */ int rlc_set_addr(int pi, addr_list_t *rlcaddr) { int consecutive; sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (sxs->is_on) return (rlc_return_error_ (pi, CANT_CHANGE_ADDR, NULL)); /** ** start checking parameters **/ /* port */ sxs->port = htons(rlcaddr->port); if (ntohs(sxs->port)%2) { sxs->port = htons(ntohs(sxs->port)-1); NDEB(fprintf(stderr, "Warning: rlc_tx_setup called with odd port #," " now port # = %u\n", ntohs(sxs->port));) } rlcaddr->port = ntohs(sxs->port); /* ttl */ sxs->ttl = max (rlcaddr->ttl, 0); sxs->ttl = min (sxs->ttl, 255); rlcaddr->ttl = sxs->ttl; NDEB(fprintf(stderr, "rlc_tx_setup: have ttl %d\n", sxs->ttl);) /* addrs */ hton_addlist(rlcaddr); if ((consecutive = set_addresses(rlcaddr, MAX_LAYERS, sxs->addrss)) < 0) { return (rlc_return_error_ (pi, consecutive, NULL)); } if (consecutive) { sxs->have_addr_ass = 0; sxs->flags |= ADDR_CONS; } else { sxs->have_addr_ass = 1; sxs->flags &= (~ADDR_CONS); } return (0); } /*++++ Provides a reference to the client (cpi) and a pointer to a callback function used to get/provide the packets being transmitted/received. Returns: - 0 on success. - a negative value on failure: - > 0 in caso of warning: */ int rlc_attach(int pi, int cpi, void *f) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); sxs->cpi = cpi; /* check tx_packet */ if (f == NULL) return (rlc_return_error_(pi, BAD_CALLBACK_FUNCTION, NULL)); sxs->tx_packet = (rlc_tx_packet_t)f; sxs->rx_packet = (rlc_rx_packet_t)f; return(0); } int rlc_gui_enable(int pi) { int retvalue = 0; sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); #ifdef HAVE_UI if (!client_chanhandle) { if (rlc_gui_init(pi, 0, "rlc", sxs->geometry) < 0) { retvalue = NOUI_WARNING; } else { if (sxs->isreceiver && rlc_gui_rx_init (pi) < 0) retvalue = NOUI_WARNING; if (!sxs->isreceiver && rlc_gui_tx_init (pi) < 0) retvalue = NOUI_WARNING; if (_rlc_error_gui_init (pi) < 0) retvalue = NOUI_WARNING; } } #else /* HAVE_UI */ retvalue = NOUI_WARNING; #endif /* HAVE_UI */ if (!retvalue) sxs->have_gui = 1; return retvalue; } int rlc_gui_geometry(int pi, char *geometry) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); #ifdef HAVE_UI if (geometry) { sxs->geometry = malloc (strlen(geometry)+1); strcpy (sxs->geometry, geometry); } #else return NOUI_WARNING; #endif return 0; } /*++++ This registers a function that gets called when an IO descriptor must be added/deleted from the list of descriptor to be polled (select). This function is intended only for use in the client driven mode (the one where the client controls the event loop), and must be called before any other call to the library. */ int rlc_registerchanhandle(rlc_app_chanhandle_t f) { if (f && !rlc_events) { client_chanhandle = f; return(0); } return(-1); } /*++++ Starts the reception/transmission. In the reciever starts the reception by subscribing the first layer. Each time a packet is available rx_packet gets called to consume the packet. The reception is terminate by explicitly calling `rlc_abort' for this protocol instance. Returns: - 0 on success. - a negative value on failure: - > 0 in caso of warning: */ int rlc_start(int pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); /* XXX add all the checkes ... now seems OK */ if (sxs->addrss[0] == -1) return (rlc_return_error_ (pi, BAD_ADDRESS, NULL)); /* XXX check the client_chanhandle stuff */ if (client_chanhandle == NULL && sxs->tx_packet == NULL && sxs->rx_packet == NULL) return (rlc_return_error_ (pi, BAD_CALLBACK_FUNCTION, NULL)); sxs->starttime = timestamp_u(); sxs->is_on = 1; if (sxs->isreceiver) return (_rlc_rx_start(pi)); else return (_rlc_tx_start(pi)); } /*++++ Stops the reception/transmission. Returns: - 0 on success. - a negative value on failure: */ int rlc_abort(int pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (sxs->isreceiver) return (_rlc_rx_abort(pi)); else sxs->is_on = 0; return 0; } rlc/sender.c010064400373640000764000000365450657124506400145250ustar00ucaclxvcsstaff00002440000013/* * rlc.c -- sender/receiver setup routines * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #include /* for stat: without this doesn't compile in FreeBSD 2.1 */ #include #include #include #include /* for stat */ #include /* for sleep */ #if (defined(Linux)) #include #endif #if (!defined(Linux)) #if (defined(FreeBSD) || (defined(SunOS) && (OSMVER < 5))) #include #include #endif #endif #include "rlc.h" #include "rlcif.h" #include "sender.h" #include "agent.h" #include "layers.h" #include "utils.h" #include "compat.h" #include "init.h" #include "event.h" static int sender_init = 0; static ui32 source_id = 0; #define C(x) ((x!=NULL)?(*x):0) static void se_delete(sxs_t *s); static int se_send(sxs_t *s); static int warm_up(sxs_t *s); int rlc_tx_setup(int pi, rlc_tx_params_t *params) { sxs_t *sxs; NDEB(fprintf(stderr, "rlc_tx_setup: called with %x(%s) %x(%d) %x(%d) %x(%d) %x(%d) %x(%lu)\n", (ui32)addr, (addr!=NULL)?addr:"", (ui32)ttl, C(ttl), (ui32)nlay, C(nlay), (ui32)mpkts, C(mpkts), (ui32)Mpkts, C(Mpkts), (ui32)t, C(p));) sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); /* check nlay */ if (params->nlay != 0) { if (params->nlay < 0 || params->nlay > MAX_LAYERS) return (rlc_return_error_(pi, BAD_NUMBER_OF_LAYS, NULL)); } else { params->nlay = NLAY; } NDEB(fprintf(stderr, "rlc_tx_setup: have %d layers\n", tnlay);) /* check mpkts */ if (params->mpkts != 0) { if (params->mpkts < MIN_PAYLOAD_SIZE || params->mpkts > MAX_PAYLOAD_SIZE) return (rlc_return_error_(pi, BAD_MIN_PAYLOAD, NULL)); } else { params->mpkts = DATA_SIZE; } NDEB(fprintf(stderr, "rlc_tx_setup: have %d mpkts\n", tmpkts);) /* check Mpkts */ if (params->Mpkts != 0) { if (params->Mpkts < MIN_PAYLOAD_SIZE || params->Mpkts > MAX_PAYLOAD_SIZE || params->Mpkts < params->mpkts) return (rlc_return_error_(pi, BAD_MAX_PAYLOAD, NULL)); } else { params->Mpkts = DATA_SIZE; } NDEB(fprintf(stderr, "rlc_tx_setup: have %d Mpkts\n", tMpkts);) /* check t */ if (params->t != 0) { if ((long)(params->t) < 0 || params->t > (double)MAX_L0_PERIOD/(1<<(params->nlay-1))) return (rlc_return_error_(pi, BAD_PERIOD, NULL)); } else { params->t = (double)MAX_L0_PERIOD/(1<<(params->nlay-1)); } NDEB(fprintf(stderr, "rlc_tx_setup: have %lu t\n", tp);) /* add check on throughput and deb. summary */ NDEB(fprintf(stderr, "+++ running at (%.2f, %.2f) pkts/s, (%d, %d) Kbit/s m(m, M), " "(%d, %d) Kbit/s M(m, M)\n", 1.0e6/(params->t*(1<<(params->nlay-1))), 1.0e6/params->t, (int)(8 * params->mpkts * 1.0e6 / (params->t * 1024 * (1<<(params->nlay-1)))), (int)(8 * params->mpkts * 1.0e6 / (params->t * 1024)), (int)(8 * params->Mpkts * 1.0e6 / (params->t * 1024 * (1<<(params->nlay-1)))), (int)(8 * params->Mpkts * 1.0e6 / (params->t * 1024)));) sxs->rate = (double)params->t*(1<<(params->nlay-1)); sxs->mpkts = params->mpkts; sxs->Mpkts = params->Mpkts; sxs->l.nc = params->nlay; return(0); } /*++++ Adjusts the transmission rate at run time. The change will take effect from the next packet transmission. The same constraint for the interpacket time holds, as in rlc_tx_setup(). Warning: this facility must be used carefully, as the congestion control algorithm doesn't take into account the intertime modification. Params: pi : protocol instance ID. newr : the new period (in usec) between 2 consecutive packet transmissions at the higher rate; see ``tx_setup'' `p' parameter for more details. Returns: the new value on success, 0 on failure. */ unsigned long rlc_change_rate(int pi, unsigned long newr) { sxs_t *se = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); ui32 lr; if (!se) return(0); DEB(fprintf(stderr, "ooo+++ rlc_change_rate with new = %lu\n", newr);) DEB(fprintf(stderr, "ooo+++ was running at (%.2f, %.2f) pkts/s, (%d, %d) Kbit/s m(m, M)," " (%d, %d) Kbit/s M(m, M)\n", 1.0e6/se->rate, 1.0e6*(1<<(se->l.nc-1))/se->rate, (int)(8 * se->mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)));) lr = newr*(1<<(se->l.nc-1)); if (lr > MAX_L0_PERIOD) { lr = MAX_L0_PERIOD; newr = (double)lr/(1<<(se->l.nc-1)); } se->rate = lr; l_change_rate(newr, &se->l); DEB(fprintf(stderr, "ooo+++ now running at (%.2f, %.2f) pkts/s, (%d, %d) Kbit/s m(m, M)," " (%d, %d) Kbit/s M(m, M)\n", 1.0e6/se->rate, 1.0e6*(1<<(se->l.nc-1))/se->rate, (int)(8 * se->mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)));) return(newr); } /*++++ Adjusts the transmission rate by a scale factor. The change will take effect from the next packet transmission. The same constraint for the interpacket time holds, as in rlc_tx_setup(). Warning: this facility must be used carefully, as the congestion control algorithm doesn't take into account the intertime modification. Params: pi : protocol instance ID. scale : the scale factor. Returns: the new value on success, 0 on failure. */ unsigned long rlc_adj_rate(int pi, double scale) { unsigned long newr; sxs_t *se = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!se) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (se->rate / scale <= MAX_L0_PERIOD) se->rate = se->rate / scale; else se->rate = MAX_L0_PERIOD; newr = (ui32)((double)se->rate/(1<<(se->l.nc-1))); l_change_rate(newr, &se->l); NDEB(fprintf(stderr, "+++ running at (%.2f, %.2f) pkts/s, (%d, %d) Kbit/s m(m, M), (%d, %d) Kbit/s M(m, M)\n", 1.0e6/se->rate, 1.0e6*(1<<(se->l.nc-1))/se->rate, (int)(8 * se->mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 / (se->rate * 1024)), (int)(8 * se->Mpkts * 1.0e6 * (1<<(se->l.nc-1)) / (se->rate * 1024)));) return (newr); } /*++++ Starts the transmission. It first transmits 3 warm-up packets on all the multicast channels to allow the pruning of the multicast tree; then it schedules the first data packet transmission. The client-provided function `tx_packet' is called each time a packet must be transmitted. The transmissions ends when tx_packet returns a zero value. Params: pi : protocol instance ID. Returns: 0 on success, < 0 on failure, > 0 if a warning is generated, use rlc_error_info() to get error or warning description. Possible error/warning causes are: - CANT_START_SENDER (cannot start this sender). */ int _rlc_tx_start(int pi) { int ret; sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); addr_list_t addrlist; if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); /* addrss has been initialized by attach */ addrlist.nadd = sxs->l.nc; addrlist.addrs = (unsigned long *)sxs->addrss; if ((ret = setup_l_sock(&sxs->l, &addrlist, sxs->port, sxs->ttl)) < 0) { return (rlc_return_error_ (pi, NET_CALL_ERROR, NULL)); } #ifdef ONE_SEND_SOCK sxs->ch = sxs->l.chan; #else sxs->ch = sxs->l.chs[0]; #endif NDEB(fprintf(stderr, "rlc_tx_setup: setup_l_sock done\n")); setup_layers((ui32)((double)sxs->rate/(1<<(sxs->l.nc-1))), &sxs->l, THE_W, THE_Y, THE_P); sxs->isreceiver = 0; warm_up(sxs); sxs->pkts_left = INFINITE; NDEB(fprintf(stderr, "rlc_tx_start: pkts_left %d (%d * %d pkt/s)\n", sxs->pkts_left, duration_glob, (int)(1e6 * (1<<(sxs->l.nc-1)) / sxs->rate));) if (rlc_settimer(TX_RUN, sxs->rate, (CALLBACK)se_send, (void *)sxs, 1) < 0) return (rlc_return_error_(pi, CANT_START_SENDER, NULL)); return(0); } void _rlc_tx_init() { /* sender specific initialization ? */ if (!sender_init) { source_id = compute_id(); sender_init = 1; } } static char dummyp[MAX_PKT_LEN]; int rlc_tx_send_appl_pkt (int pi, char *buff, int paylen) { rlc_h *packet = (rlc_h *)dummyp; struct msghdr msg; struct iovec iov[2]; sxs_t *s = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!s) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (!(s->is_on)) return -1; if (paylen > s->Mpkts || paylen < 0) { return (rlc_return_error_(pi, TOO_LARGE_PACKET, "attmp to transmit a too large packet (%d)", paylen)); } /* only fill transport header */ FILL_D_H(*packet, htons(0), htons(0), htonl(source_id), 0, (ui8)s->l.nc, BT_EXP_1, 1); packet->type = RLC_APPL_T; bzero((char *)&msg, sizeof(msg)); msg.msg_iovlen = 2; msg.msg_iov = iov; iov[0].iov_base = (caddr_t)packet; iov[0].iov_len = DATA_H_SIZE; iov[1].iov_base = (caddr_t)buff; iov[1].iov_len = paylen; NDEB(fprintf(stderr, "+=+= now %d (%x) next in %lu\n", paylen, buff, next_delta);) #ifdef ONE_SEND_SOCK msg.msg_name = (caddr_t)&(s->l.saddrs[0]); msg.msg_namelen = sizeof(s->l.saddrs[0]); if (sendmsg(s->l.chan, &msg, 0) == -1) #else if (sendmsg(s->l.chs[0], &msg, 0) == -1) #endif return (rlc_return_error_(pi, SND_ERROR, NULL)); return (0); } /* ** se_delete gets called 2 times: the 1st (asynch) mark the session deleted, ** the second (synch) actually delete the session. */ static void se_delete(sxs_t *s) { int pi = s->ides; sxs_t *ss = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!ss) return; if (ss != s) return; NDEB(fprintf(stderr, "--- se_delete: sess (%x) is_on = %d\n", ss->ides, ss->is_on);) if (ss->is_on) { ss->is_on = 0; return; } #ifdef ONE_SEND_SOCK close(ss->l.chan); #else { int i; for (i=0; i<(ss->l.nc); i++) close(ss->l.chs[i]); } #endif _rlc_return_instance((instance_des_t *) ss, rlc_inst_mngr); free(ss); NDEB(fprintf(stderr, "--- se_delete: sess (%x) freed\n", s->ides);) return; } #define WARM_UP_PKTS 3 static int warm_up(sxs_t *s) { int i, l; ui8 this_flags = 0; rlc_h *dummyh = (rlc_h *)dummyp; NDEB(fprintf(stderr, "starting warm-up\n")); for (i=0; il.nc; l++) { FILL_D_H(*dummyh, 0, 0, htonl(source_id), this_flags, (ui8)s->l.nc, BT_EXP_1, 0); dummyh->type = RLC_WRMP_T; #ifdef ONE_SEND_SOCK if (sendto(s->l.chan, dummyp, DATA_H_SIZE, 0, (struct sockaddr *)&(s->l.saddrs[l]), sizeof(s->l.saddrs[l])) == -1) { rlc_have_error_ (s->ides, SND_ERROR, NULL); } #else if (send(s->l.chs[l], dummyp, DATA_H_SIZE, 0) == -1) { rlc_have_error_ (s->ides, SND_ERROR, NULL); } #endif } sleep(1); } NDEB(fprintf(stderr, "warm-up finished\n")); return 0; } static int se_send(sxs_t *s) { rlc_h *packet = (rlc_h *)dummyp; char *buff; int paylen, givenlen; static int do_err = 1; int this_layer; ui16 this_pn; ui16 this_lidx; ui32 next_delta; ui8 this_flags = '\0'; struct msghdr msg; struct iovec iov[2]; if (!(s->is_on)) { s->tx_packet(s->cpi, -1, 0, &buff); /* notify the termination */ se_delete(s); return 0; } /* only consec. addr. supported for the time being ! */ if (s->flags & ADDR_CONS) this_flags |= RLC_F_CONS_ADDR; else this_flags &= (~RLC_F_CONS_ADDR); /* in this implementation RLC_F_EDGE_TRIG is stucked at 0 */ next_delta = send_layers(s, &buff, &givenlen, &this_layer, &this_pn, &this_lidx, &this_flags); if (next_delta == IS_OVER) { s->is_on = 0; se_delete(s); return 0; } if (givenlen > s->Mpkts) { rlc_have_error_(s->ides, TOO_LARGE_PACKET, "attmp to transmit a too large packet (%d)", givenlen); this_flags |= RLC_F_HART_BEAT; paylen = s->mpkts; buff = dummyp+DATA_H_SIZE; } else if (givenlen < 0) { this_flags |= RLC_F_HART_BEAT; paylen = s->mpkts; buff = dummyp+DATA_H_SIZE; } else { paylen = givenlen; } NDEB(fprintf(stderr, "--- sending %d bytes (%d) |%d|-[%d -- %d] %x\n", paylen, givenlen, this_layer, this_pn, this_lidx, this_flags)); /* only fill transport header */ FILL_D_H(*packet, htons(this_lidx), htons(this_pn), htonl(source_id), this_flags, (ui8)s->l.nc, BT_EXP_1, 1); bzero((char *)&msg, sizeof(msg)); msg.msg_iovlen = 2; msg.msg_iov = iov; iov[0].iov_base = (caddr_t)packet; iov[0].iov_len = DATA_H_SIZE; iov[1].iov_base = (caddr_t)buff; iov[1].iov_len = paylen; NDEB(fprintf(stderr, "+=+= now %d (%x) next in %lu\n", paylen, buff, next_delta);) #ifdef ONE_SEND_SOCK msg.msg_name = (caddr_t)&(s->l.saddrs[this_layer]); msg.msg_namelen = sizeof(s->l.saddrs[this_layer]); if (sendmsg(s->l.chan, &msg, 0) == -1) { #else if (sendmsg(s->l.chs[this_layer], &msg, 0) == -1) { #endif if (do_err) { rlc_have_error_ (s->ides, SND_ERROR, NULL); } do_err = 0; #if 0 perror ("send"); /* XXX */ #endif } else do_err = 1; NDEB(fprintf(stderr, "*** data send (%d)\n", do_err)); if ( (s->pkts_left % 100 == 0)) { NDEB(fprintf(stderr, "--- %4d packets left for session 0x%08x\n", s->pkts_left, s->ides) ); } if (s->pkts_left != INFINITE) s->pkts_left -- ; if (s->pkts_left) { if (rlc_settimer(s->ides, next_delta, (CALLBACK)se_send, s, 0) < 0) { se_delete(s); rlc_have_error_(s->ides, STOP_TRANSMISSION, NULL); } NDEB(fprintf(stderr, "--- next d %d\n", next_delta)); } else { s->is_on = 0; se_delete(s); } return 0; } derr, "ooo+++ was running at (%.2f, %.2f) pkts/s, (%d, %d) Kbit/s m(m, M)," " (%d, %d) Kbit/s M(m, M)\n", 1.0e6/se->rate, 1.0e6*(1<<(se->l.nc-1))/se->rarlc/receiver.c010064400373640000764000000443630657027675600150610ustar00ucaclxvcsstaff00002440000013/* * receiver.c -- receiver routines for rlc. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. */ /* * receiver main routines */ #include #include #include #include #include #include #include #include "rlc.h" #include "rlcif.h" #include "agent.h" #include "net.h" #include "congestion.h" #include "layers.h" #include "ui.h" #include "utils.h" #include "init.h" #include "event.h" #include "receiver.h" /*+ the event loop desctiptor is unique for sender and receiver, and is in init.c (rlc_events). +*/ /*+ this is the pointer to the function used to add/remove IO descriptor to the client IO list, when the library is used in client driven mode (without looping on rlc_getevent */ extern rlc_app_chanhandle_t client_chanhandle; /*+ globally associates layers to sockets +*/ static int chans[MAX_RX_SOCKS]; static int receiver_init = 0; static int get_data(void *p); /** ** We have been woken up by the client, it should mean that ** we have received some data, so first check and then call ** get_data. Note that checking we also make `rlc_showselected' ** return the proper value . **/ static void ex_wakeup() { int i; void *p; if (rlc_poolchan(&i, &p) >= 0 && i == ID_GETDATA && p ) (void)get_data(p); } /** ** various auxiliary fonctions ** **/ #define NO_SOCK -1 /* * Join group, possibly creating socket. */ int do_join (int pi, int g) { ui16 tport; sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_internal_set_error_ (pi, JOIN_ERROR, NULL)); tport = htons(ntohs(sxs->port) + 2 * g); assert(g>=0 && gsocks[g] == NO_SOCK) { if ((sxs->socks[g] = openrsock(sxs->addrss[g], &tport)) < 0) return (rlc_internal_set_error_ (pi, JOIN_ERROR, NULL)); if (fcntl (sxs->socks[g], F_SETFL, O_NONBLOCK) < 0) { return (rlc_internal_set_error_ (pi, JOIN_ERROR, NULL)); } if (sxs->socks[g] < 0) { sxs->socks[g] = NO_SOCK; return (rlc_internal_set_error_ (pi, JOIN_ERROR, NULL)); } } else { struct sockaddr_in srcaddr; char buff_in[MAX_PKT_LEN]; int srcaddrlen = sizeof(srcaddr); /* discard old packets... but shouldn't thrown away! (but there shouldn't be!) XXX */ while ( recvfrom(sxs->socks[g], buff_in, sizeof(buff_in), 0, (struct sockaddr *)&srcaddr, &srcaddrlen) > 0) ; if (join_group(sxs->socks[g], sxs->addrss[g]) != 0) return (rlc_internal_set_error_ (pi, JOIN_ERROR, NULL)); } NDEB(fprintf(stderr, "group %x joined (port %d)\n", sxs->addrss[g], tport);) if (sxs->socks[g] >= MAX_RX_SOCKS) { return (rlc_internal_set_error_ (pi, TOO_MANY_SOCKET, NULL)); } chans[sxs->socks[g]] = g; if (rlc_insertchan(sxs->socks[g], ID_GETDATA, get_data, (void *)sxs) < 0) { return (rlc_internal_set_error_ (pi, NO_CHAN, NULL)); } if (client_chanhandle) (*client_chanhandle)(sxs->socks[g], &ex_wakeup); #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_current %d", g); #endif /* HAVE_UI */ return (0); } int do_leave (int pi, int g) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return(-1); assert(g>=0 && gsocks[g] == NO_SOCK) return (0); if (leave_group(sxs->socks[g], sxs->addrss[g]) != 0) return (rlc_internal_set_error_ (pi, LEAVE_ERROR, NULL)); #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_current %d", g-1); #endif /* HAVE_UI */ DEB (fprintf(stderr, "do_leave: %d left\n", g);) /* note that we don't call rlc_deletechan to allow to suck packets anyway! this call will be made when the protocol instance terminates */ return(0); } void receiver_last_stuff(int i) { int j; ui32 endtime; sxs_t *sxs; int id = GET_SESSION_START; while ((id = rlc_get_allinst(id, rlc_inst_mngr)) != GET_SESSION_END ) { sxs = (sxs_t *)_rlc_getinstance(id, rlc_inst_mngr); if (!sxs->isreceiver) continue; if (!sxs->is_on) { /* ..... XXX */ DEB(fprintf(stderr, "rlc: last_stuff for %d (%x)\n", sxs->ides, (int)sxs);) endtime = timestamp_u(); /* the following leaves all groups as well */ congestion_end(sxs->ides, sxs->cong, endtime); for (j=0; sxs->socks[j] != NO_SOCK && jsocks[j]); if (client_chanhandle) (*client_chanhandle)(sxs->socks[j], NULL); close(sxs->socks[j]); } NDEB(printf("Stats: \n" "in %d sec. ???\n", (int)((endtime-sxs->starttime)/1e6));) _rlc_return_instance((instance_des_t *) sxs, rlc_inst_mngr); free(sxs); } } if (i == SIGINT ) exit(i); } cong_t * get_cong_inst(int pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return(NULL); return(sxs->cong); } /* that's to terminate asynchronously the reception */ static int force (int pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); DEB(fprintf(stderr, "rlc force for %d (%x)\n", pi, (int)sxs);) if (!sxs) return(-1); sxs->is_on = 0; if (!sxs->termdelayed) { DEB(fprintf(stderr, "rlc force no delay: terminating\n");) if (sxs->watch_t && _rlc_howmany_instance(rlc_inst_mngr) == 1) { DEB(fprintf(stderr, "rlc force deleting RLC_WATCHDOG\n");) rlc_deletetimer(RLC_WATCHDOG); } receiver_last_stuff(0); } return(0); } #define APPL_SPEC -3 static int chk_pkt(rlc_h *header, sxs_t *sxs, int chan, int src) { int this_lay; assert(chan < MAX_RX_SOCKS); this_lay = chans[chan]; assert(sxs->socks[this_lay] == chan); if (header->magic != htons(RLC_MAGIC)) { NDEB(fprintf(stderr, "chk_pkt: incorrect magic number\n")); return(-1); } if (!sxs->src) /* not bound */ sxs->src = src; else if (sxs->src != src) /* bound!! */ return -1; if (header->vers != 1) { NDEB(fprintf(stderr, "chk_pkt: only understand version 1, this is %d\n", header->vers)); return(-1); } if (header->type != RLC_DATA_T) { if (header->type != RLC_APPL_T) return(APPL_SPEC); /* this also includes RLC_WRMP_T */ NDEB(fprintf(stderr, "chk_pkt: incorrect data packet, discarding\n")); return(-1); } if (header->bp != BT_EXP_1) { /* in this implementation we don't support this ! */ NDEB(fprintf(stderr, "chk_pkt: we only implement band. profile" " BT_EXP_1!\n")); rlc_have_error_ (sxs->ides, BAND_NOT_IMPL, NULL); return -1; } if ((header->flags & RLC_F_EDGE_TRIG) != 0) { /* in this implementation we don't support this ! */ NDEB(fprintf(stderr, "chk_pkt: RLC_F_EDGE_TRIG is not stucked at 0!\n")); rlc_have_error_ (sxs->ides, TRIG_NOT_IMPL, NULL); return -1; } if (!sxs->have_addr_ass) { if (!(header->flags & RLC_F_CONS_ADDR)) { NDEB(fprintf(stderr, "chk_pkt: waiting for address assignement" ", discarding\n")); return(-1); } } else if (header->flags & RLC_F_CONS_ADDR) { sxs->have_addr_ass = 0; /* and do something else */ } return(this_lay); } static inline void update_guess(int *lkypays, int *lkypaysv, int thispays) { if (*lkypays > thispays) { *lkypaysv = (*lkypaysv + *lkypays - thispays) >> 1; } else { *lkypaysv = (*lkypaysv + thispays - *lkypays) >> 1; } *lkypays = (*lkypays + thispays) >> 1; NDEB(fprintf(stderr, "***update_guess now %u %u\n", *lkypays, *lkypaysv);) } /* ** this is going to become pretty complex: ** `somehow' we try to guess the most likely payload size (lkypays) ** and its sort-of-variance (lkypaysv), then we read a scattered array like ** that: [[sizeof(header)] [lkypays+lkypaysv] [sizeof(safety_buff)]]. ** */ static char * read_pkt(sxs_t *sxs, int chan, rlc_h **header, int *len, ui32 *src, int *lkypays, int *lkypaysv) { char *buff; struct iovec iov[3]; struct msghdr msg; struct sockaddr_in srcaddr; char safety_buff[MAX_PAYLOAD_SIZE]; int doublev = *lkypaysv << 1; if ((*header = (rlc_h *)malloc(sizeof(rlc_h))) == NULL) { rlc_have_error_ (sxs->ides, ALLOC_PKT_ERROR, NULL); return NULL; } if ((buff = malloc(*lkypays+doublev)) == NULL) { rlc_have_error_ (sxs->ides, ALLOC_PKT_ERROR, NULL); return NULL; } iov[0].iov_base = (caddr_t)*header; iov[0].iov_len = sizeof(rlc_h); /* XXX what about if we have header extensions ??? */ iov[1].iov_base = (caddr_t)buff; iov[1].iov_len = *lkypays+doublev; iov[2].iov_base = (caddr_t)safety_buff; iov[2].iov_len = sizeof(safety_buff); bzero((char *) &msg, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = 3; msg.msg_name = (caddr_t)&srcaddr; msg.msg_namelen = sizeof(srcaddr); if ((*len = recvmsg(chan, &msg, 0)) <=0) { rlc_have_error_(sxs->ides, RCV_ERROR, NULL); free(buff); return(NULL); } /* have we failed our guess ? */ if (*len > sizeof(rlc_h)+*lkypays+doublev) { void *pt; if ((pt = realloc(buff, *len-sizeof(rlc_h))) == NULL) { rlc_have_error_ (sxs->ides, ALLOC_PKT_ERROR, NULL); return NULL; } buff = pt; bcopy(safety_buff, buff+*lkypays+doublev, *len-(sizeof(rlc_h)+*lkypays+doublev)); NDEB(fprintf(stderr, "read_pkt: Guess wrong (read %d)!!\n", *len-sizeof(rlc_h));) } update_guess(lkypays, lkypaysv, *len-sizeof(rlc_h)); NDEB(fprintf(stderr, "--- read_pkt: pkt %u sess %ld from: %lx, siz %d\n", ntohs((*header)->lsn), ntohl((*header)->suid), (unsigned long)srcaddr.sin_addr.s_addr, *len)); *src = (unsigned long)srcaddr.sin_addr.s_addr; return(buff); } static pkt_lis_d *pkt_lis_h; /*+ this is a pointer to a temporary queue of received packets: all the received packet gets read from the sockets and reordered before delivering them to the application and running the congestion control algorithm +*/ static int get_data(void *p) { sxs_t *sxs; int len, chan, this_lay; char *buff_in; ui32 this_time; int paylen; rlc_h *header; pkt_lis_d **plp, *lp; int i; ui32 tidx; ui32 src; do { sxs = (sxs_t *)p; chan = rlc_showselected(); if (NULL == (buff_in = read_pkt(sxs, chan, &header, &len, &src, &(sxs->lkypays), &(sxs->lkypaysv)))) { continue; } assert((long)len - (long)sizeof(*header) >= 0 && len - sizeof(*header) < MAX_PAYLOAD_SIZE); if ((this_lay = chk_pkt(header, sxs, chan, src)) < 0) { if (sxs->rx_packet != NULL && this_lay == APPL_SPEC) sxs->rx_packet(sxs->cpi, 0, '\1' /* XXX */, buff_in, len - sizeof(*header)); else free(buff_in); continue; } /* this is for the watchdog */ sxs->watch_last = timestamp_u(); /* and insert in queue... have to save: p, buff_in, header, len, chan? */ tidx = global_index (ntohs(header->lsn), ntohs(header->pn), this_lay, (int)header->layer_n - 1, is_in_burst(header->flags)); lp = NULL; if (!pkt_lis_h) plp = &pkt_lis_h; else for (plp = &(pkt_lis_h->next); *plp != NULL; plp = &((*plp)->next)) if (ui32diff(tidx, (*plp)->gindex) < 0) { lp = *plp; break; } if ( (*plp = malloc(sizeof(pkt_lis_d))) == NULL) { rlc_have_error_ (sxs->ides, ALLOC_TMP_ERROR, NULL); return 0; } (*plp)->p = p; (*plp)->buff_in = buff_in; (*plp)->header = header; (*plp)->len = len; (*plp)->next = lp; (*plp)->gindex = tidx; (*plp)->this_lay = this_lay; } while ( rlc_poolchan(&i, &p) >= 0 && i == ID_GETDATA && p ); sxs->termdelayed = 1; for (i = 0; pkt_lis_h != NULL && sxs->is_on; lp = pkt_lis_h, pkt_lis_h = pkt_lis_h->next, free(lp), i++) { p = pkt_lis_h->p; buff_in = pkt_lis_h->buff_in; header = pkt_lis_h->header; len = pkt_lis_h->len; this_lay = pkt_lis_h->this_lay; tidx = pkt_lis_h->gindex; sxs = (sxs_t *)p; paylen = len - sizeof(*header); /* XXX this should be saved before... */ this_time = timestamp_u(); /* perform congestion control */ congestion_control(sxs->ides, sxs->cong, header, paylen, this_lay, tidx, this_time); /* this must be the last .... */ if (sxs->rx_packet != NULL && !(header->flags & RLC_F_HART_BEAT)) sxs->rx_packet(sxs->cpi, this_lay, '\0' /* XXX */, buff_in, paylen); } sxs->termdelayed = 0; if (!sxs->is_on) force (sxs->ides); return(0); } void _rlc_rx_init() { if (!receiver_init) { pkt_lis_h = NULL; receiver_init = 1; } } /*++++ This registers a function that gets called when an IO descriptor must be added/deleted from the list of descriptor to be polled (select). This function is intended only for use in the client driven mode (the one where the client controls the event loop), and must be called before any other call to the library. Params: - f : pointer to the function to be called by the library. The argument function is prototyped as : typedef void (*rlc_app_chanhandle_t) (int iodes, void (f)()); where iodes is the IO descriptor to be observed, and f is the function to be called whe the descriptor is ready for reading. If f = NULL the descriptor must be removed. This function is implemented by the client. Returns: 0 on succes, < 0 on failure. */ int rlc_rx_registerchanhandle(rlc_app_chanhandle_t f) { if (f && !rlc_events) { client_chanhandle = f; return(0); } return(-1); } /*++++ This sets up a watchdog timer to detect reception stall. It should be used in rlc driven mode only. If a stall is detected, rlc either call the provided callback function or rise an asynhronous error (RECEPTION_TIMEOUT_WAR). Params: pi : protocol instance ID. f : pointer to the function to be called by rlc. If a NULL argument is given, the timeout procedure will rise an error condition. The argument function is prototyped in `rlcif.h' as : typedef void (*rx_watchdog_t) (int pi); pi is the rlc protocol instance descriptor. time : the max idle time, if = 0 the default of 30s is used. Returns: 0 on success, < 0 on failure. */ int rlc_rx_set_watchdog(int pi, rx_watchdog_t f, int time) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, CANT_SET_WATCHDOG, NULL)); sxs->watch_f = f; if (time > 0) sxs->watch_t = time; else sxs->watch_t = 30e6; /* default 30s */ return(0); } int rlc_watchdog_(void *pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance((int)pi, rlc_inst_mngr); ui32 now=timestamp_u(); if (!sxs) return 0; NDEB(fprintf(stderr, "rlc_watchdog_ now %d, last %d, t %d\n", now, sxs->watch_last, sxs->watch_t);) if ((int)(now - sxs->watch_last - sxs->watch_t) >= 0) { /** hops, we have been too much idle! */ if (sxs->watch_f) (*sxs->watch_f)((int)pi); else rlc_have_error_ ((int)pi, RECEPTION_TIMEOUT_WAR, NULL); } if (sxs->is_on && sxs->watch_t && rlc_settimer(RLC_WATCHDOG, sxs->watch_t, (CALLBACK)rlc_watchdog_, (void *)pi, 0) < 0) { rlc_have_error_ ((int)pi, CANT_SET_WATCHDOG, NULL); } return 0; } /*++++ Starts the reception by subscribing the first layer. Each time a packet is available rx_packet gets called to consume the packet. The reception is terminate by explicitly calling `rlc_abort' for this protocol instance. Params: pi : protocol instance ID. Returns: 0 on success, < 0 on failure, > 0 if a warning is generated, use rlc_error_info() to get error or warning description. Possible error/warning causes are: - CANT_START_RECEIVER (cannot start this receiver). */ int _rlc_rx_start(int pi) { int res; sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); /* XXX specific receiver checks ... there should be none */ if ((res = do_join(pi, 0)) < 0) return (rlc_return_error_ (pi, res, NULL)); if (sxs->watch_t && !client_chanhandle && (res = rlc_settimer(RLC_WATCHDOG, sxs->watch_t, (CALLBACK)rlc_watchdog_, (void *)pi, 0)) < 0) { return (rlc_return_error_ (pi, res, "rlc_settimer error")); } sxs->watch_last = timestamp_u(); sxs->src = 0; /* not bounded */ return(0); } /*++++ Terminates the reception unsubscribing all the currently joined layers. It also frees the instance descriptor. Params: pi : protocol instance ID. Returns: 0 on success, < 0 on failure. */ int _rlc_rx_abort(int pi) { return(force(pi)); } /*++++ Retrieves the source address. Params: pi : protocol instance ID. Returns: the source address on success, -1 on failure. */ unsigned long rlc_rx_get_src (int pi) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) { rlc_internal_set_error_ (pi, NO_SUCH_INSTANCE, NULL); return (-1); } if (sxs->src == 0) return (rlc_return_error_ (pi, -1, "No source address available")); return (sxs->src); } ntation we don't support this ! */ NDEB(fprintf(stderr, "chk_pkt: RLC_F_EDGE_TRIG is not stucked at 0!\n")); rlc_have_error_ (sxs->ides, TRIG_NOT_IMPL, NULL); return -1; } if (!sxs->have_addr_ass) { if (!(header->flags & RLC_F_CONS_ADDR)) { NDEB(fprintf(stdrlc/congestion.c010064400373640000764000000512360657031771000154040ustar00ucaclxvcsstaff00002440000013/* * congestion.c -- RLC congestion control routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #include #if __STDC__ #include #else #include #endif #include "rlcif.h" #include "agent.h" #include "congestion.h" #include "receiver.h" #include "layers.h" #include "utils.h" #include "error.h" /* todo: * - possibly all the time values can be converted from double to * ui32 */ /*++++ Enables logging facilities in this receiver. Params: pi : protocol instance descriptor. ev_fn : pathname for the event-log file po_fn : pathname for the poll-log file Returns: 0 on success, < 0 on failure. */ int rlc_rx_log(int pi, char *ev_fn, char *po_fn) { FILE *tev_fd, *tpo_fd; cong_t *inst; inst = get_cong_inst(pi); if (!inst) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); /* check event file name */ tev_fd = NULL; if (ev_fn != NULL) { tev_fd = fopen(ev_fn, "w"); if (!tev_fd) return (-1); } /* check poll file name */ tpo_fd = NULL; if (po_fn != NULL) { tpo_fd = fopen(po_fn, "w"); if (!tpo_fd) return (-1); } inst->pollf = tpo_fd; inst->eventf = tev_fd; return (0); } /*++++ Retrieves some status information for this receiver. The information are in the form defined by the structure rx_info_t (defined in rlcif.h). In the current implementation rx_info_t is defined as: typedef struct rx_info_s { int nlay; / number of layers provided by the sender / int clay; / number of layers currently joined / unsigned long t0; / packet intertime extimation on l0 (us) / int received; / total number of packets received / int lost; / total number of packets lost / int cong_ev; / congestion events seen so far / } rx_info_t; Params: pi : protocol instance descriptor. buf : buffer to store the retrieved information. len : must be initialized to the buffer size and will be set to the size of the portion of the buffer used to store the retrieved data. If the buffer is smaller than the available data size, data will be truncated. Returns: 0 on success, < 0 on failure. */ int rlc_rx_info(int pi, void *buf, int *len) { rx_info_t str; cong_t *inst; NDEB(fprintf(stderr, "rlc_rx_info pi = %d\n", pi);) inst = get_cong_inst(pi); assert(inst != NULL); if (buf == NULL || len <= 0) return(-1); bzero(&str, sizeof(str)); str.nlay = inst->n_lays; str.clay = inst->curr_session_; str.t0 = inst->base_period_ * 1e6; str.received = inst->tot_count_; str.lost = inst->lost_; str.cong_ev = inst->cong_ev_; *len = min(*len, sizeof(str)); bcopy(&str, buf, *len); /* *len = 0; */ return(0); } int rlc_rx_set_stats_deliver_f (int pi, int gid, rx_stats_deliver_f stats_deliver, int maxsize) { cong_t *inst; inst = get_cong_inst(pi); if (!inst) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (!stats_deliver) { /* disable */ inst->stats_deliver = NULL; inst->statsbufoffset = 0; return 0; } if (maxsize > 0) inst->maxstatbufsize = min (maxsize, MAXSTATSBUFSIZE); else inst->maxstatbufsize = MAXSTATSBUFSIZE; inst->stats_deliver = stats_deliver; inst->stats_gid = gid; return 0; } /*++++ It gets called once at library initialization time. Params: pi : protocol instance descriptor. inst : congestion control data structure of this protocol instance. Returns: 0 on success, < 0 on failure. */ int congestion_setup(int pi, cong_t *inst) { if (!inst) return(-1); NDEB(fprintf(stderr, "congestion_setup pi = %d\n", pi);) inst->local_id_ = pi; fset(inst->flags, LP_UNS); inst->n_lays = UNSEEN; inst->thresh_ = inst->init_thresh_ = -1; /* thresh_ is initially set to max_bwt_/5 */ fclear(inst->flags, JN_PND); #if UNSUPP for (int i=0; i<= inst->start_session_; i++) GO_UP(pi); #endif inst->max_bwt_ = 0; inst->clean_count_ = inst->tot_count_ = 0; inst->lost_ = 0; inst->cong_ev_ = 0; inst->lost_in_burst = 0; fclear(inst->flags, SEEN_UPS); fclear(inst->flags, SEEN_BST); fclear(inst->flags, LV_PND); inst->leave_deaf_ = 0.; inst->del_in = inst->del_c = 0; inst->del_l = 4; inst->lay_limit = UNSEEN; inst->pollf = NULL; inst->eventf = NULL; inst->base_period_ = L0_PERIOD / 1e6; /* initial estimation */ inst->last_0_time = 0; inst->last_0_idx = 0; inst->stats_deliver = NULL; inst->statsbufoffset = 0; return(0); } /* ** should conform to ns format: ** event time src dst pktType size flags class src.sport dst.dport seqno uid ** The following event are defined here: ** +j start joining layer `l' ** -j layer `l' joined ** +l start leaving layer `l' ** -l layer `l' left */ char trace_buffer[512]; static void trace_dump(FILE *fil) { if (fil) fprintf(fil, "%s\n", trace_buffer); } #if __STDC__ static void mytrace (FILE *fil, char const *fmt, ...) #else static void mytrace (fmt, va_alist) char *fmt; va_dcl #endif { va_list ap; if(fil) { #if __STDC__ va_start(ap, fmt); #else va_start(ap); #endif vsprintf(trace_buffer, fmt, ap); va_end(ap); trace_dump(fil); } } /*++++ Sets a limit to the maximum subscription level in this receiver. Params: pi : protocol instance descriptor. limit : the maximum subscription level. Returns: 0 on success, < 0 on failure. */ int rlc_rx_limit(int pi, int limit) { cong_t *inst; #ifdef HAVE_UI sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); #endif DEB(fprintf(stderr, "rlc_rx_limit pi = %d\n", pi);) inst = get_cong_inst(pi); assert(inst != NULL); if (limit < 0) return(-1); if (inst->n_lays != UNSEEN && limit >= inst->n_lays) { inst->lay_limit = inst->n_lays-1; } else { if (inst->lay_limit == limit) return 0; inst->lay_limit = limit; } #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_limit %d", inst->lay_limit); #endif if (inst->curr_session_ == UNSEEN) return(0); while (inst->curr_session_ > inst->lay_limit) { do_leave(pi, inst->curr_session_); fclear(inst->flags, JN_PND); fset(inst->flags, LV_PND); inst->curr_session_--; fset(inst->flags, LP_UNS); } return(inst->lay_limit); } static void add_compact_stats(cong_t *inst, ui32 this_time, int force) { int size = sizeof (comp_stats_t); comp_stats_t *p = (comp_stats_t *)(inst->statsbuf + inst->statsbufoffset); inst->statsbufoffset += size; p->time = htonl (this_time); p->tot_count = htons ((unsigned short)(inst->tot_count_)); p->clean_count = htons ((unsigned short)(inst->clean_count_)); p->lost = htons ((unsigned short)(inst->lost_)); p->cong_ev = htons ((unsigned short)(inst->cong_ev_)); p->max_bwt = htons ((unsigned short)(inst->max_bwt_/(1024*8))); p->curr_session = (unsigned char)inst->curr_session_; p->flags = inst->flags; if (force || inst->statsbufoffset + size > inst->maxstatbufsize) { inst->stats_deliver(inst->stats_gid, inst->statsbuf, inst->statsbufoffset); inst->statsbufoffset = 0; } } /* * Leave all groups and possibly compute statistics */ void congestion_end(int pi, cong_t *inst, timest_t endtime) { while (inst->curr_session_ >= 0) do_leave(pi, inst->curr_session_--); if (inst->eventf) fflush(inst->eventf); if (inst->pollf) fflush(inst->pollf); if (inst->stats_deliver) { add_compact_stats(inst, endtime, 1); } } #define TH_RESET -2 #define DUNNO 999999 #define INSEQ 0 static void t0_guess (cong_t *inst, double time, unsigned short idx) { if (idx - inst->last_0_idx == 1 && time - inst->last_0_time < 100. * inst->base_period_ && time - inst->last_0_time > inst->base_period_ / 100. ) { inst->base_period_ = inst->base_period_ * 0.8 + (time - inst->last_0_time) * 0.2 ; } inst->last_0_time = time; inst->last_0_idx = idx; } static int outseq(ui32 idx, cong_t *inst) { #if 1 int diff = ui32diff(idx, inst->last_p_+(ui32)1); #else int diff = idx - inst->last_p_ -1; #endif if (fisset(inst->flags, LP_UNS)) { fclear(inst->flags, LP_UNS); inst->last_p_ = idx; return DUNNO; } if (diff < 0) /* dup or out of sequence!! don't update */ return diff; inst->last_p_ = idx; return diff; } void congestion_control(int pi, cong_t *inst, rlc_h *p, int paylen, int this_lay, ui32 gidx, timest_t rec_time) { double now; int in_burst, burst_starting, burst_ended, burst_ending; int inseq, update, minus; ui32 this_idx; /* compute the global index on all layers, for reordering pourpose */ this_idx = gidx; /* first packet initializations */ if (inst->n_lays == UNSEEN) { #ifdef HAVE_UI sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); #endif now = rec_time/1e6; inst->next_poll = now + POLL_INTERVAL; assert (p->layer_n <= MAX_LAYERS); inst->n_lays = p->layer_n; #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_last %d", inst->n_lays-1); #endif NDEB(fprintf(stderr, "--- *** have %d layers\n", inst->n_lays);) if (inst->lay_limit == UNSEEN || inst->lay_limit >= inst->n_lays) { inst->lay_limit = inst->n_lays-1; #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_limit %d", inst->n_lays - 1); #endif } inst->pkt_size_ = paylen; #if 0 mytrace(inst->eventf, "v %.6f rlc/br%.2f %d %u %x %d ---- %d %x.%d %x.%d %d %d", now, inst->base_rate_/1024., inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); #endif } /* ** Packet delay for resequencing */ inst->heads[inst->del_c] = p; inst->rec_times[inst->del_c] = rec_time; inst->gidx[inst->del_c] = gidx; inst->this_lay[inst->del_c] = this_lay; if (inst->del_in < inst->del_l) inst->del_in++; NDEB(fprintf(stderr, "%d pakts in buf (%d %d)\n", inst->del_in, inst->del_c, inst->del_l)); if (inst->del_in < inst->del_l) { inst->del_c++; return; } else { int i, j; for (j = i = 0; i < inst->del_l; i++) { if (ui32diff(inst->gidx[i], inst->gidx[j]) < 0) j = i; } inst->del_c = j; NDEB(fprintf(stderr, "peeking %d (%d)\n", inst->del_c, inst->del_l)); } p = inst->heads[inst->del_c]; rec_time = inst->rec_times[inst->del_c]; this_lay = inst->this_lay[inst->del_c]; gidx = inst->gidx[inst->del_c]; inst->tot_count_ ++; now = rec_time/1e6; minus = 0; if (fisset(inst->flags, JN_PND) && this_lay != inst->curr_session_) minus = 1; /* now compute the index relatively to the current subscription level */ this_idx = global_index (ntohs(p->lsn), ntohs(p->pn), this_lay, inst->curr_session_-minus, is_in_burst(p->flags)); NDEB(fprintf(stderr, "--- have packet %lu\n", this_idx);) /* `join_pending_' takes into account the delay in joining * sessions, so that we avoid seeing false losses while * waiting for the join to take effect */ if (fisset(inst->flags, JN_PND) && this_lay == inst->curr_session_) { /* join committed */ fclear(inst->flags, JN_PND); fset(inst->flags, LP_UNS); mytrace(inst->eventf, "v %.6f rlc/-j%d %d %u %x %d ---- %d %x.%d %x.%d %lu %d", now, inst->curr_session_, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); } /* `leave_pending_' takes into account the delay in leaving * sessions: packets coming from the left layer are ignored * and we will prevent cascade leaves */ if (this_lay > inst->curr_session_) { /* packet from left layers : ignore ... */ if (fisset(inst->flags, LV_PND)) { /* extend timeout */ /* don't see why I don't use the same as the first... */ int temp = max(0, inst->curr_session_-1); inst->leave_timeout = now + 3. * inst->base_period_ / (1<flags, LV_PND) && inst->leave_timeout < now) { /* leave committed */ fclear(inst->flags, LV_PND); mytrace(inst->eventf, "v %.6f rlc/-l%d %d %u %x %d ---- %d %x.%d %x.%d %lu %d", now, inst->curr_session_+1, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); } DEB( mytrace(inst->eventf, "v %.6f rlc/R %d %u %x %d ---- %d %x.%d %x.%d %lu %d - %d %d", now, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_, ntohs(p->pn), ntohs(p->lsn)); ) /* this extracts pattern information from the (unique) ** packet sequence # . Extracts a per-session seq. # ** (this_idx) and the following: */ in_burst = 0; /* are we in burst? */ burst_starting = 0; /* first burst packet? */ burst_ended = 0; /* first non-burst packet? */ burst_ending = 0; /* last burst packet? */ burst_ended = is_first_non_burst ( this_lay, inst->curr_session_-minus, p->flags); if ((in_burst = is_in_burst(p->flags)) == 1) { burst_starting = is_first_burst ( this_lay, inst->curr_session_-minus, p->flags); burst_ending = is_burst_ending (p->flags); if (up_synch_burst (this_lay, inst->curr_session_-minus, p->flags)) { fset(inst->flags, SEEN_UPS); NDEB(fprintf(stderr, "=== UP_SYN on lay %d at %.6f (%x)\n", inst->curr_session_, now, gidx);) } } NDEB(fprintf(stderr, "%d(%d) %d %d %d %d %d - %x - %.6f\n", this_lay, inst->curr_session_, burst_starting, burst_ending, burst_ended, in_burst, fisset(inst->flags, SEEN_UPS), gidx, now);) inst->clean_count_ ++; /* ** check the session index to detect packet loss. */ inseq = outseq(this_idx, inst); if (inseq < 0) { /* os = out of seq. (0=dup) */ mytrace(inst->eventf, "v %.6f rlc/os%d %d %u %x %d ---- %d %x.%d %x.%d %lu %d", now, inseq+1, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); inseq = INSEQ; } /* properly adj. in_burst so that: ** ** in_burst = ... 0 0 01 11 11 11 1 0 0 ... ** packets ... X X XX XX XX XX X X X ... */ if (burst_starting) { /* this packet belong to the `non burst' phase, if we don't see it, we will go down at the next received packet.... */ in_burst = 0; inst->lost_in_burst = 0; fset(inst->flags, SEEN_BST); #if 0 } else if (burst_ended) { #else } else if (!in_burst) { /* this seems more correct */ #endif fclear(inst->flags, SEEN_BST); } if (this_lay == 0 && !in_burst) t0_guess(inst, now, ntohs(p->lsn)); update = 1; if (inseq == DUNNO) { /* DUNNO, do nothing */ NDEB(fprintf(stderr, "%d DUNNO [c=%d, l=%d]\n", inst->local_id_, inst->curr_session_, this_lay);) } else if (inseq == INSEQ) { /* no nosses */ if (!in_burst) { /* do nothing ? */ NDEB(fprintf(stderr, "%d noburst, no loss [c=%d, l=%d]\n", inst->local_id_, inst->curr_session_, this_lay);) } else { NDEB(fprintf(stderr, "%d burst, no loss [c=%d, l=%d]\n", inst->local_id_, inst->curr_session_, this_lay);) if (this_idx%2) { /* just received the second packet of a burst, compute max_bwt_ */ int tmp = (int)(inst->pkt_size_ * 8 / (now-inst->last_arrival)); if (inst->max_bwt_ < tmp) { inst->max_bwt_ = tmp; mytrace(inst->eventf, "v %.6f rlc/bw%.2f %d %u %x %d ---- %d %x.%d " "%x.%d %lu %d", now, inst->max_bwt_/ 1024., inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); /* compute thresh_ */ if (inst->thresh_ != TH_RESET) { #if 0 /* what to do with this ? */ int i; inst->thresh_ = inst->n_lays; for (i=1; i< inst->n_lays; i++) if (inst->base_rate_ * (1< inst->max_bwt_/5) { inst->thresh_ = i-1; break; } mytrace(inst->eventf, "v %.6f rlc/th%d %d %u %x %d ---- " "%d %x.%d %x.%d %lu %d", now, inst->thresh_, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); #endif } } } /* if (last burst and can go up) join next */ if (burst_ending) { /* this is the sync. point, the only one when we are allowed to go up */ if ((!inst->lost_in_burst) && ( (inst->curr_session_ < inst->thresh_) || /* this is only the first rise... slow start ! */ (fisset(inst->flags, SEEN_UPS) && !fisset(inst->flags, JN_PND)) ) ) { fclear(inst->flags, SEEN_UPS); if (inst->curr_session_ < inst->lay_limit) { /* GOUP */ inst->curr_session_++; if (do_join(pi, inst->curr_session_) < 0) { rlc_have_error_ (pi, JOIN_ERROR, NULL); return; } fset(inst->flags, JN_PND); fclear(inst->flags, LV_PND); inst->leave_deaf_ = now; mytrace(inst->eventf, "v %.6f rlc/+j%d %d %u %x %d ---- " "%d %x.%d %x.%d %lu %d", now, inst->curr_session_, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); } } } } } else { /* we have had `inseq' losses */ inst->lost_ += inseq; mytrace(inst->eventf, "v %.6f rlc/ls%d %d %u %x %d ---- %d %x.%d %x.%d %lu %d", now, inseq, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); /* we must be _very_ careful to attribute the losses... */ if (in_burst && fisset(inst->flags, SEEN_BST)) { inst->lost_in_burst+= inseq; } else { /* _NEVER_ _RESTART_ */ /* XXX we must make sure that a leave, possibly issued before, takes effect */ if (!fisset(inst->flags, LV_PND) && now >= inst->leave_deaf_ && inst->curr_session_ > 0) { inst->cong_ev_ ++; inst->thresh_ = TH_RESET; fclear(inst->flags, SEEN_UPS); /* GO_DOWN */ if (do_leave(pi, inst->curr_session_) < 0) { rlc_have_error_ (pi, LEAVE_ERROR, NULL); return; } fclear(inst->flags, JN_PND); fset(inst->flags, LV_PND); inst->curr_session_--; fset(inst->flags, LP_UNS); inst->leave_timeout = now + 5. * inst->base_period_ / (1<curr_session_); inst->leave_deaf_ = now + LEAVE_DEAF; mytrace(inst->eventf, "v %.6f rlc/+l%d %d %u %x %d ---- " "%d %x.%d %x.%d %lu %d", now, inst->curr_session_+1, inst->local_id_, 0, gidx, paylen, this_lay, 0, 0, 0, 0, this_idx, inst->curr_session_); update = 0; } } } if (inst->next_poll < now) { mytrace(inst->pollf, "v %.6f rlcst %d %d %d %d %d %d %d %.4f %d %d %d %d", now, 0, inst->tot_count_, inst->lost_, inst->curr_session_, fisset(inst->flags, LV_PND), fisset(inst->flags, JN_PND), inst->pkt_size_, inst->base_period_, inst->max_bwt_, inst->thresh_, inst->clean_count_, inst->cong_ev_); if (inst->stats_deliver) { add_compact_stats(inst, rec_time, 0); } inst->next_poll += POLL_INTERVAL; } free(p); if (!update) return; inst->last_arrival = now; } inst->next_poll = now + POLL_INTERVAL; assert (p->layer_n <= MAX_LAYERS); inst->n_lays = p->layer_n; #ifdef HAVE_UI if (sxs->have_gui) rlc_gui_tcl_exec (pi, NULL, "set_last %d", inst->n_lays-1); #endif NDEB(fprintf(stderr, "--- *** have %d layers\n", inst->n_lays);) if (inst->lay_limit == UNSEEN || inst->lay_limit >= inst->n_layrlc/layers.c010064400373640000764000000236600656702222000145260ustar00ucaclxvcsstaff00002440000013/* * layers.c -- layers handling routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include "rlc.h" #include "rlcif.h" #include "layers.h" #include "agent.h" #include "net.h" #include "utils.h" /* * Setup trasmission sockets for layers, * assume addr is for layer 0 and layer * `i' has address addr+i. */ int setup_l_sock(lay_d *l, addr_list_t *addr, n16 port, int ttl) { int i, consecutive; ui32 tmpaddr[MAX_LAYERS]; if ((consecutive = set_addresses(addr, l->nc, tmpaddr)) < 0) return (rlc_internal_set_error_(-1, consecutive, NULL)); #ifdef ONE_SEND_SOCK /* if called with unbound=1 port can be 0 */ if ((l->chan = openssock(tmpaddr[0], port, ttl, 1)) < 0) return (rlc_internal_set_error_ (-1, l->chan, NULL)); NDEB(fprintf(stderr, "--LAY: have a new sock: %s %d + 2*i, ttl %d\n", inet_ntoa(*(struct in_addr *)&(tmpaddr[0])), port, ttl)) #endif for (i=0; i<(l->nc); i++) { #ifdef ONE_SEND_SOCK bzero((char *)&(l->saddrs[i]), sizeof(l->saddrs[i])); l->saddrs[i].sin_family = AF_INET; l->saddrs[i].sin_addr.s_addr = tmpaddr[i]; l->saddrs[i].sin_port = htons(ntohs(port) + 2 * i); #else if ((l->chs[i] = openssock(tmpaddr[i], htons(ntohs(port) + 2 * i), ttl, 0)) < 0) return (rlc_internal_set_error_ (-1, l->chs[i], NULL)); NDEB(fprintf(stderr, "--LAY: have a new sock: %s %d, ttl %d\n", inet_ntoa(*(struct in_addr *)&(tmpaddr[i])), htons(ntohs(port) + 2 * i), ttl)) #endif } return consecutive; } ui32 l_change_rate(ui32 rate, lay_d *l) { l->pu = rate; NDEB( for (i=(l->nc)-1; i>=0; i--) { fprintf(stderr, "*** lay %d period = %d (%d), next = %d (%d)\n", i, l->rates[i], l->rates[i]*l->pu, l->left[i], l->left[i]*l->pu); } ) return(rate); } /* * Setup data stuctures for layers. * `rate' is the inverse of the overall * packet rate. */ void setup_layers(ui32 rate, lay_d *l, int W, int Y, int P) { int i; ui32 base; int t_W = W*(1<<(l->nc-1)); int t_Y = Y*(1<<(l->nc-1)); /* compute a random pn ... multiple of W */ #if 0 /** XXX to debug.. there might be problems! **/ l->pn = (ui16) (timestamp_u()*W); #else l->pn = 0; #endif l->pu = rate; l->inc_todo = 0; l->W = W; l->Y = Y; l->P = P; l->now = 0; /* debugging only */ base = rate = 1; for (i=(l->nc)-1; i>=0; i--) { l->left[i] = rate - base; if (i != 0) { rate *= 2; t_W /= 2; t_Y /= 2; } l->rates[i] = rate; NDEB(fprintf(stderr, "*** lay %d period = %d (%d), next = %d (%d)\n", i, rate, rate*l->pu, l->left[i], l->left[i]*l->pu)) l->idxs[i] = l->pn * (1<cyc_l[i] = t_W; l->bur_l[i] = t_Y; l->gap[i] = l->rates[i] * ((l->bur_l[i] >> 1) + 1); } } /* * Establish where to send now (lay) and * return the time to next send. * We assume that at least one `left' is = 0 * * BURSTS should be arranged here !! * */ static ui32 next_to_send(lay_d *l, int *lay, ui16 *lidx, char *f) { int i; int app; ui32 minor = 0xffffffff; *lay = -1; /* search which layer to trasmit on * (precedence is given to faster layers) */ for (i=(l->nc)-1; i>=0; i--) { if (*lay == -1 && l->left[i] == 0) { *lay = i; /* * Layer `i' has been selected, now set * left to next trasm. time in this layer. * To introduce burst change below, lowering * left, when appropriate. */ app = l->idxs[i] % l->cyc_l[i]; if (app < l->bur_l[i]) { /* this is in burst */ *f |= RLC_F_IN_BURST; if (!app) *f |= RLC_F_S_F_BURST; if (app == l->bur_l[i]-1) { /* this is the last */ if (!i) *f |= RLC_F_L_BURST; l->left[i] = l->gap[i]; } else { if (!(app%2)) { /* next is attached */ l->left[i] = 0; } else { l->left[i] = l->rates[i]; } } } else { /* non in burst */ if (app == l->bur_l[i]) *f |= RLC_F_S_F_BURST; l->left[i] = l->rates[i]; } } minor = min(minor, l->left[i]); } /* adjust times */ if (minor) for (i=0; i<(l->nc); i++) l->left[i] = l->left[i] - minor; *lidx = l->idxs[*lay]; (l->idxs[*lay]) ++; return (minor*l->pu); } char *trst[] = {"normal pkt", "no data in buff.", "skip to sync", "burst", "frame over"}; /* * Establish where to send next packet * (lay, lidx) and get its ponter p and * lenght. Return the time to next send. */ ui32 send_layers(sxs_t *s, char **p, ui32 *len, int *lay, ui16 *pn, ui16 *lidx, char *f) { int res; ui32 delta; char flags = '\0'; lay_d *l = &(s->l); delta = next_to_send(&(s->l), lay, lidx, f); /* adjust the indexes like that: ** ** 0,1 2,3 4,5 6,7 8 9 10 11 12 ** 0,0 0,0 0,0 0,0 2 2 2 2 3 ** XX XX XX XX X X X X X ** 0,1 2,3 4 5 6 ** 0,0 0,0 2 2 3 ** XX XX X X X ** 0,1 3 ** 0,0 2 ** XX X ** 0,1 2 ** 0,0 2 ** XX X */ *pn = l->pn; if ( !(*lay) ) if ( !(l->pn%l->W) ) { /* not increment at the first on the burst */ if (!(l->inc_todo)) l->inc_todo = 1; else { l->inc_todo = 0; l->pn += 2; } } else l->pn ++; /* mark up sync. point */ if (*f & RLC_F_IN_BURST && ( (*pn/l->W )%((1<<*lay)*l->P) == 0 )) *f |= RLC_F_P_BURST; res = s->tx_packet(s->cpi, *lay, /* *lidx,*/ flags, p); if (res > 0) { *len = res; res = 0; } else if (res < 0) { *len = res; res = -res; } else { *len = 0; return(IS_OVER); } NDEB(fprintf(stderr, "send_layers: %d bytes for %s (%d, %d)\n", *len, trst[res], *lay, *lidx)); NDEB(fprintf(stderr, "+++ L: we had lay %d lidx %d\n", *lay, *lidx)) return (delta); } /* * Compute a global index on 32 bits (wrapping) on the basis of * the current joined layer (curr_lay). Used in the receiver to detect * gaps and to reorder packets. */ ui32 global_index (ui16 lsn, ui16 pn, int lay, int curr_lay, int inbu) { if (inbu) { /* IN_BURST */ #if 0 ui32 a = ((lsn/2) % (1<>= 1; } else { off = gidx % (1< 0; i--) { if (!(off % 2)) break; off >>= 1; } *lay = i; *lsn = *pn * (1<<(max(*lay-1, 0)+inbu)) + inbu * gidx%2; if (inbu) *pn -= *pn % 2; } int is_in_burst (char f) { if (f&RLC_F_IN_BURST) return (1); return (0); } int is_first_burst (int lay, int curr_lay, char f) { if (lay == curr_lay && is_in_burst(f) && (f&RLC_F_S_F_BURST)) return (1); return (0); } int is_first_non_burst (int lay, int curr_lay, char f) { if (lay == curr_lay && !is_in_burst(f) && (f&RLC_F_S_F_BURST)) return (1); return (0); } int is_burst_ending (char f) { if (f&RLC_F_L_BURST) return (1); return (0); } int up_synch_burst (int lay, int curr_lay, char f) { if (lay == curr_lay && f&RLC_F_P_BURST) return (1); return (0); } rlc/net.c010064400373640000764000000216760656725423200140340ustar00ucaclxvcsstaff00002440000013/* * net.c -- socket I/O -- This is a stripped down version of the * net.cc module from vic, with the following (original) copyright: * * Copyright (c) 1993-1994 The Regents of the University of California. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #include #include #include #include "net.h" #include "utils.h" #include "compat.h" #include "rlcif.h" /*** *** We need the following routines: - open a multicast/unicast socket for send. (receiver: send request; sender: send data) openssock() does that; - open a multicast/unicast socket for receive (receiver: get request; sender: get data) openrsock() does that, it also join the m-cast group (if a multicast address is provided). - join a m-cast group join_group(). - leave a m-cast group leave_group(). *** ***/ static int nonblock(int fd) #ifdef DUMMYNET {} #else /* DUMMYNET */ { #ifdef WIN32 u_long flag = 1; if (ioctlsocket(fd, FIONBIO, &flag) == -1) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* ioctlsocket: FIONBIO ERROR")); } #else int flags = fcntl(fd, F_GETFL, 0); #if defined(hpux) || defined(__hpux) flags |= O_NONBLOCK; #else flags |= O_NONBLOCK|O_NDELAY; #endif if (fcntl(fd, F_SETFL, flags) == -1) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* fcntl: F_SETFL ERROR")); } #endif return 0; } #endif /* DUMMYNET */ int openssock(n32 addr, n16 port, int ttl, int unbound) #ifdef DUMMYNET {return(0);} #else /* DUMMYNET */ { int fd; struct sockaddr_in sin; NDEB(fprintf(stderr,"--- openssock addr %s port %d\n", inet_ntoa(*(struct in_addr *)&addr), ntohs(port) )); fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* socket call ERROR")); if (nonblock(fd) < 0) return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* nonblock ERROR")); if (IN_CLASSD(ntohl(addr))) { #ifdef IP_ADD_MEMBERSHIP #ifdef WIN32 u_int t; #else u_char t; #endif /*** set the multicast TTL ***/ t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&t, sizeof(t)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* setsockopt: IP_MULTICAST_TTL ERROR")); } #else return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* no multicast support ERROR")); #endif } if (unbound) return fd; #ifdef WIN32 memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = 0; sin.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* bind call ERROR")); } #endif memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = addr; if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* connect call ERROR")); } return fd ; } #endif /* DUMMYNET */ int join_group(int fd, n32 addr) #ifdef DUMMYNET {return(0);} #else /* DUMMYNET */ { struct ip_mreq mr; /* if not m-cast addr. do nothing */ if (!IN_CLASSD(ntohl(addr))) return(0); /*** XXX now we shuold check whether fd is a valif socket */ mr.imr_multiaddr.s_addr = addr; mr.imr_interface.s_addr = INADDR_ANY; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* setsockopt: IP_ADD_MEMBERSHIP ERROR")); } return (0); } #endif /* DUMMYNET */ int leave_group(int fd, n32 addr) #ifdef DUMMYNET {return(0);} #else /* DUMMYNET */ { struct ip_mreq mr; /* if not m-cast addr. do nothing */ if (!IN_CLASSD(ntohl(addr))) return(0); /*** XXX now we shuold check whether fd is a valif socket */ mr.imr_multiaddr.s_addr = addr; mr.imr_interface.s_addr = INADDR_ANY; if (setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* setsockopt: IP_DROP_MEMBERSHIP ERROR")); } return (0); } #endif /* DUMMYNET */ int openrsock(n32 addr, n16 *port) #ifdef DUMMYNET {static n16 i=0; port = &i; return(0);} #else /* DUMMYNET */ { int fd; struct sockaddr_in sin; int on = 1; NDEB(fprintf(stderr,"--- openrsock addr %s port %d\n", inet_ntoa(*(struct in_addr *)&addr), ntohs(*port) );) fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* socket call ERROR")); } if (nonblock(fd) < 0) return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* nonblock ERROR")); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,(char *)&on, sizeof(on)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* setsockopt: SO_REUSEADDR ERROR")); } #ifdef SO_REUSEPORT on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* setsockopt: SO_REUSEPORT ERROR")); } #endif memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = *port; #ifdef IP_ADD_MEMBERSHIP if (IN_CLASSD(ntohl(addr))) { /* * Try to bind the multicast address as the socket * dest address. On many systems this won't work * so fall back to a destination of INADDR_ANY if * the first bind fails. */ sin.sin_addr.s_addr = addr; if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { rlc_have_error_ (-1, MULTI_BIND_ERROR, NULL); sin.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* bind call ERROR")); } } if (join_group(fd, addr)!=0) return (fd); } else #endif { /* * bind the local port to this socket. If that * fails, another app probably has the addresses bound so * just exit. */ sin.sin_addr.s_addr = addr ; if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { return (rlc_internal_set_error_ (-1, NET_CALL_ERROR, "* bind call ERROR")); } } if (*port == 0) { memset((char *)&sin, 0, sizeof(sin)); on = sizeof(sin); getsockname(fd, (struct sockaddr *)&sin, &on) ; *port = sin.sin_port ; } NDEB(fprintf(stderr, "--- port bound to %s : %d\n", inet_ntoa(sin.sin_addr), ntohs(*port) );) return fd ; } #endif /* DUMMYNET */ unsigned long localaddr(int ssock_) #ifdef DUMMYNET {return 0;} #else /* DUMMYNET */ { struct sockaddr_in ad; struct sockaddr_in *p = &ad; int len = sizeof(*p); memset((char *)p, 0, sizeof(*p)); p->sin_family = AF_INET; if (getsockname(ssock_, (struct sockaddr *)p, &len) < 0) { /* perror("getsockname"); */ memset((char *)p, 0, sizeof(*p)); } if (p->sin_addr.s_addr == 0) { char hostname[80]; struct hostent *hp; if (gethostname(hostname, sizeof(hostname)) >= 0) { if ((hp = gethostbyname(hostname)) >= 0) { p->sin_addr.s_addr = ((struct in_addr *)hp->h_addr)->s_addr; } } } NDEB(fprintf(stderr, "localname addr is %s\n", inet_ntoa(p->sin_addr) );) if (p->sin_addr.s_addr != 0) return (p->sin_addr.s_addr); else return -1; } #endif /* DUMMYNET */ rlc/event.c010064400373640000764000000346440656707126100143650ustar00ucaclxvcsstaff00002440000013/* * event.c -- scheduler for rlc * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ /*** *** These routines implement an event loop. First, the event list must be created using rlc_createevlist(). Timeouts can be registered with rlc_settimer(). They eventually expire, unless removed using rlc_deletetimer(). rlc_deletetimer() removes all the pending timeouts with a given id. i/o descriptors can be inserted/deleted using rlc_insertchan() and rlc_deletechan(). One function per timeout, and one function per channel, can be called. *** ***/ #include "event.h" #include "utils.h" #include "error.h" #undef TEST #undef ONE_GO /* define to make rlc_getevent return after each event */ /* not sure whether it still works ... */ static timit_t *timit_free_list = NULL; static int timit_free_count = 0 ; static void free_timit(timit_t *p) { p->next = timit_free_list ; timit_free_list = p; bzero(p, sizeof (timit_t) ); timit_free_count++ ; } static timit_t * new_timit() { timit_t *p; if (timit_free_list) { p = timit_free_list ; timit_free_list = p->next ; timit_free_count-- ; } else { p = (timit_t *)calloc(1, sizeof(timit_t)) ; if (p == NULL) { (void) rlc_internal_set_error_(-1, ALLOC_ERROR, NULL); return NULL; } } return p ; } void * rlc_createevlist_() { int i; evlist_t *e; if (NULL==(e=(evlist_t *)calloc(1, sizeof(evlist_t)))) { rlc_internal_set_error_ (-1, NO_EVLIST, NULL); return NULL; } for (i=0; iio_chan[i]= -1; } e->io_ch_num = 0; e->timevent = NULL; FD_ZERO(&(e->in_s)); FD_ZERO(&(e->out_s)); FD_ZERO(&(e->err_s)); timestamp_t(&(e->lasttime)); e->late = 0; e->selected = -1; e->def_f = NULL; return((void *)e); } /* * |<--------------- past ----------->| * |<--------- delta --------->| * |---------------------------#-----------> virtual time * ^ ^ * VT start first event * * |<- late ->| * ----|----------*-----------------------*----> actual time * ^ ^ * lasttime thistime */ /*++++ Selects the next event to be executed or an IO descriptor ready for reading, and executes the associate function. If there are no events ready, it generally blocks, unless there are no timers pending and blocking = 0, in this case it just polls the IO descriptor and returns if none is ready for reading. Params: vp : event manager reference. blocking : if = 0 doesn't blok in the select if there are no timers, it just polls. Returns: The id of the last event found or, if none, one of the following values (< 0): - EV_DEFTIMEOUT got the default timeout; - EV_GOTSIGNAL got a signal in select(); - EV_TERMINATE no event selected because there are no timer pending and the IO descriptor list is empty, typically we must terminate the event loop; - EV_NO_PENDING no event selected because there are no timer pending and no IO descriptor was ready (only if blocking = 0). */ int rlc_getevent_(void *vp, int blocking) { #define e ((evlist_t *)vp) struct timeval thistime, interval, *timp; ui32 past; timit_t *tim; int id, max_chan, i, j, ret; again: NDEB(fprintf(stderr, "# %u usec past\n", past)); tim = e->timevent; id = EV_NO_PENDING ; NDEB( { timit_t *ti = e->timevent; fprintf(stderr, "X"); for ( ; ti != NULL ; ti = ti->next ) fprintf(stderr, "--->[%u] (%u)|", ti->delta, ti->id); fprintf(stderr, "\n"); } ); while (tim != NULL) { id = EV_NO_PENDING ; /* see how much time has past since last update */ timestamp_t(&thistime); past = diff_t(thistime, e->lasttime) + e->late ; if (tim->delta <= past) { e->late = past - tim->delta; /* how late was this event ? */ if (e->late > 1000) { /* more than 1ms late... */ NDEB(fprintf(stderr, "--- we are %u usec late with ev. %d\n", e->late, tim->id)); } e->timevent = tim->next; /* first adj the event list (which could be acceded) */ e->lasttime = thistime ; if (tim->t_f) tim->t_f(tim->t_p); /* execute the action */ past -= tim->delta; /* update virtual time */ #ifdef NODEF /* we don't free the arguments */ free(tim->t_p); #endif id = tim->id; free_timit(tim); tim = e->timevent; #ifdef ONE_GO return(id); #endif } else /* e->late = past ; */ break ; } /* before sleeping adjust e->late to compensate the time spent in the last event */ NDEB(fprintf(stderr, " Before adj late = %d\n", e->late)); timestamp_t(&thistime); e->late += diff_t(thistime, e->lasttime); e->lasttime = thistime ; NDEB(fprintf(stderr, " After adj late = %d\n", e->late)); /* set timeout to next event */ timp = &interval; if (e->timevent != NULL) { ui32 next; if (e->late > e->timevent->delta) goto again; /* no need to sleep */ next = e->timevent->delta - e->late; interval.tv_sec = next/1000000; interval.tv_usec = next%1000000; NDEB(fprintf(stderr, "# timeout in %u usec\n", next)); } else { interval = e->default_timeout ; if (blocking && e->default_timeout.tv_sec==0 && e->default_timeout.tv_usec==0) timp = NULL; NDEB(if(timp) fprintf(stderr, "# def timeout in %lu usec\n", e->default_timeout.tv_usec+1000000*e->default_timeout.tv_sec)); } FD_ZERO(&(e->in_s)); max_chan = -1 ; for (j=0; j< e->io_ch_num; j++) if ( (i = e->io_chan[j]) >=0 ) { if (i > max_chan) max_chan = i ; FD_SET( i, &(e->in_s)); NDEB(fprintf(stderr, "selecting with %d\n", i )); } if (e->io_ch_num || e->timevent != NULL) { ret=select(1+max_chan, &(e->in_s), &(e->out_s), &(e->err_s), timp); NDEB(fprintf(stderr, "select returning...\n")) if (ret<0) { /* signal... */ fprintf(stderr, "rlc_getevent SIGNAL during poll, shouldn't happen...\n"); id = EV_GOTSIGNAL ; } else if (ret==0) { /* timeout */ NDEB(fprintf(stderr,"timeout, ev %x blocking %d\n", e->timevent, blocking)); if (e->timevent != NULL) { if (e->def_f) e->def_f(e->def_p); goto again; } else id = EV_DEFTIMEOUT ; } else { /* descriptor ready */ for (i=0; !(e->io_chan[i]>=0 && FD_ISSET(e->io_chan[i], &(e->in_s))) && iselected = e->io_chan[i]; if (e->io_f[i]) e->io_f[i](e->io_p[i]); id = e->io_id[i]; } } else if (id == EV_NO_PENDING) id = EV_TERMINATE; if (e->def_f) e->def_f(e->def_p); return(id); } int rlc_poolchan_(void *vp, int *rid, void **rp) { #define e ((evlist_t *)vp) int i, j, ret; int max_chan = 0; struct timeval tim; bzero(&tim, sizeof(tim)); if (e->io_ch_num) { for (j=0; j< e->io_ch_num; j++) if ( (i = e->io_chan[j]) >=0 ) { if (i > max_chan) max_chan = i ; FD_SET( i, &(e->in_s)); NDEB(fprintf(stderr, "selecting with %d\n", i )); } ret=select(1+max_chan, &(e->in_s), NULL, NULL, &tim); NDEB(fprintf(stderr, "select returning...\n")) if (ret>0) { /* descriptor ready... */ for (i=0; !(e->io_chan[i]>=0 && FD_ISSET(e->io_chan[i], &(e->in_s))) && iselected = e->io_chan[i]; *rid = e->io_id[i]; *rp = e->io_p[i]; return (e->selected); } } return (-1); } void rlc_set_default_timeout_(void *vp, unsigned long delta) { #define e ((evlist_t *)vp) e->default_timeout.tv_sec = delta/1000000; e->default_timeout.tv_usec = delta%1000000; } /*++++ Add an IO descriptor to the internal list of `observed' descriptors. The given function will be called when the descriptor is ready for reading. Params: vp : event manager reference. chan : IO descriptor being inserted. f : function to be called. p : function arguments. Returns: 0 on success, < 0 on failure, > 0 if a warning is generated, use rlc_error_info() to get error or warning description. Possible error/warning causes are: - TOO_MANY_IOS (too many IO descriptors, Check the compile time defined constant MAX_CHAN). */ int rlc_insertchan_(void *vp, int chan, int id, int (*f)(void *), void *p) { #define e ((evlist_t *)vp) int i, j, found; NDEB(fprintf(stderr, "rlc_insertchan: inserting chan %d\n", chan)) /*** *** check this... *** 17/10/97 lv fixed to handle holes... ***/ #if 1 for (i=0, j=0, found = -1; jio_ch_num; j++) { if (e->io_chan[j] < 0) { /* get the first hole */ if (found < 0) found = j; } else { i++; if (e->io_chan[j]==chan) { /* found the same channel */ found = j; break; } } } if (found < 0) { return (rlc_internal_set_error_(-1, TOO_MANY_IOS, NULL)); } i = found; #else for (i=0; e->io_chan[i]!=chan && e->io_chan[i]>=0 && iio_chan[i] != chan) (e->io_ch_num)++; e->io_chan[i]=chan; e->io_id[i]=id; e->io_f[i] = f; e->io_p[i] = p; return 0; } /*++++ Removes an IO descriptor from the internal list. Params: vp : event manager reference. chan : IO descriptor. */ void rlc_deletechan_(void *vp, int chan) { #define e ((evlist_t *)vp) int i; NDEB(fprintf(stderr, "rlc_deletechan: deleting chan %d\n", chan)) if (chan < 0) return; for (i=0; e->io_chan[i]!=chan && iio_chan[i]==chan) { e->io_chan[i]=-1; (e->io_ch_num)--; } } /*++++ Returns the IO descriptor last found ready by rlc_getevent. Params: vp : event manager reference. Returns: the IO descriptor last found ready. */ int rlc_showselected_ (void *vp) { #define e ((evlist_t *)vp) return(e->selected); } /*++++ Arranges for a timer event to happen after delta usec. Params: vp : event manager reference. id : id of the event to be added, will be returned by rlc_getevent after the event execution. It must be $> 0$ to avoid confusion with predefined return values. delta : relative time of event execution (in usec). f : function to be called. p : function arguments. real : if set, the event will occurr delta usec after the actual calling time. Otherwise, it is assumed that the function has been called by the scheduler, and the event is scheduled exactly delta usec after the scheduling function had to be executed. This allows not to accumulate errors. Returns: 0 on success, < 0 on failure. Possible error causes are: - ALLOC_TIMIT_ERROR (Error allocating a timer descriptor) */ int rlc_settimer_(void *vp, int id, unsigned long delta, CALLBACK f, void *p, int real) { #define e ((evlist_t *)vp) timit_t *a, *pr = NULL, *t = e->timevent; struct timeval thistime; if ((a = new_timit()) == NULL) { return (rlc_internal_set_error_(-1, ALLOC_TIMIT_ERROR, NULL)); } a->t_f = f; a->t_p = p; a->next = NULL; a->id = id; NDEB(fprintf(stderr, "<> scheduling event %d at %d\n", id, delta);) if (delta < e->late) { NDEB(fprintf(stderr, "ARGH we are scheduling event" " %d %u usec in the past!!!\n", id, e->late-delta)); } if (real) { timestamp_t(&thistime); delta += diff_t( thistime, e->lasttime) ; } if (e->timevent == NULL) { a->delta = delta; e->timevent = a; return 0; } while(t!= NULL && delta > t->delta) { delta -= t->delta; pr = t; t = t->next; } a->delta = delta; a->next = t; if (t != NULL) (t->delta) -= delta; if (t == e->timevent) { e->timevent = a; } else { pr->next = a; } return 0; } /*++++ Removes all the pending events with the given id, returns the number of events removed. Params: vp : event manager reference. id : id of event(s) to be removed. Returns: the number of events removed. */ int rlc_deletetimer_(void *vp, int id) { #define e ((evlist_t *)vp) timit_t *pr = NULL, *t = e->timevent; ui32 delay = 0; int how=0; /* if dummy event do nothing */ if (id <= 0) return (0); while(t!= NULL) { if (t->id == id) { timit_t *a = t->next; if (pr==NULL) e->timevent = t->next; else pr->next = t->next; delay += t->delta; free_timit(t); /* XXX we still don't free argument (t->t_p) */ t = a; how++; } else { t->delta += delay; pr = t; t = t->next; } } return (how); } #ifdef TEST int my_f(void *p) { struct timeval time; timestamp_t(&time); printf("%d at %u\n", *(int *)p, time.tv_usec+(time.tv_sec%1000)*1000000); *(int *)p = *(int *)p +1; if (*(int *)p < 1000) rlc_settimer_(e, (*(int *)p)+1, 10000, my_f, p, 0); } /** ** arrange for a timer event to happen every delta msec **/ int main() { int cont =0; void *e = rlc_createevlist_(); rlc_settimer_(e, 1, 10000, my_f, (void *)&cont, 1); while (rlc_getevent_(e, 0)!=EV_NO_PENDING) ; } #endif /* TEST */ imers, it just polls. Returns: The id of the last event found or, if none, one of the frlc/utils.c010064400373640000764000000175270657031465500144060ustar00ucaclxvcsstaff00002440000013/* * utils.c -- some utility functions. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #if (!defined(Linux)) #if ( defined(SunOS) && (OSMVER < 5)) #include /* looks like that netinet/in.h need it */ #endif #endif #include #include "compat.h" #include "utils.h" #include "rlcif.h" #include "event.h" /** ** compute hopefully unique id **/ ui32 compute_id() { short seed[3]; struct timeval getime; gettimeofday(&getime, NULL); seed[0] = (short)getime.tv_usec; seed[1] = (short)(getime.tv_usec*0xffff); seed[2] = (short)getime.tv_sec; return(nrand48(seed)); } /*** parameter parsing ***/ int set_link_addr(char *s, char *a, int addrlen, n16 *p, char *msg) { char *s1, *q = a ; strncpy(q, s, addrlen); s1=strchr(q,'/'); if (s1) { *p=htons(atoi(s1+1)); *s1='\0'; NDEB(printf("%s session [%s] [%d]\n", msg, q, ntohs(*p));) } else return -1; return 0; } /* ** return values: < 0 on failure, >= 0 on success. If == 1 address are ** consecutive. ** Assume addresses are in net order. */ int set_addresses(addr_list_t *list, int lays, ui32 *dstaddr) { int consecutive, i; ui32 prev; if (list->nadd < 1) return (rlc_internal_set_error_(-1, BAD_ADDRESS, NULL)); /* first check if consecutive */ consecutive = 1; prev = list->addrs[0]; if (list->nadd > 1) for (i=1; i < list->nadd; i++) if (ntohl(list->addrs[i]) != ntohl(prev)+1) { consecutive = 0; break; } else prev = list->addrs[i]; for (i=0; i < lays; i++) { if (i < list->nadd) { dstaddr[i] = list->addrs[i]; } else { dstaddr[i] = htonl(ntohl(dstaddr[i-1]) + 1); } if (!IN_CLASSD(ntohl(dstaddr[i]))) return (rlc_internal_set_error_(-1, ADDR_NOT_IN_CLASSD, NULL)); NDEB (fprintf(stderr, "* have addr %lx\n", ntohl(dstaddr[i]))); } return consecutive; } void hton_addlist(addr_list_t *list) { int i; for (i=0; inadd; i++) list->addrs[i] = htonl(list->addrs[i]); } int ui32diff(ui32 a, ui32 b) { return((a-b)); } long diff_t(struct timeval b, struct timeval a) { return (ui32)( 1000000*(b.tv_sec - a.tv_sec) + b.tv_usec - a.tv_usec) ; } long timestamp_u() { struct timeval t; (void)gettimeofday(&t, NULL); return((ui32)(t.tv_sec*1000000+t.tv_usec)); } long timestamp_m() { struct timeval t; (void)gettimeofday(&t, NULL); return((ui32)(t.tv_sec*1000+t.tv_usec/1000)); } long timestamp_s() { struct timeval t; (void)gettimeofday(&t, NULL); return((ui32)(t.tv_sec)); } void timestamp_t(struct timeval *t) { (void)gettimeofday(t, NULL); } /** ** those are the stubs for events functions **/ /*++++ Selects the next event to be executed or an IO descriptor ready for reading, and executes the associate function. If there are no events ready, it generally blocks, unless there are no timers pending and blocking = 0, in this case it just polls the IO descriptor and returns if none is ready for reading. Params: blocking : if = 0 doesn't blok in the select if there are no timers, it just polls. Returns: The id of the last event found or, if none, one of the following values ($< 0$): - EV_DEFTIMEOUT got the default timeout; - EV_GOTSIGNAL got a signal in select(); - EV_TERMINATE no event selected because there are no timer pending and the IO descriptor list is empty, typically we must terminate the event loop; - EV_NO_PENDING no event selected because there are no timer pending and no IO descriptor was ready (only if blocking = 0). */ int rlc_getevent(int blocking) { return (rlc_getevent_(rlc_events, blocking)); } int rlc_poolchan(int *rid, void **rp) { return (rlc_poolchan_(rlc_events, rid, rp)); } void rlc_set_default_timeout(unsigned long delta) { return (rlc_set_default_timeout_(rlc_events, delta)); } /*++++ Adds an IO descriptor to the internal list of `observed' descriptors. The given function will be called when the descriptor is ready for reading. Params: chan : IO descriptor being inserted. f : function to be called. p : function arguments. Returns: 0 on success, < 0 on failure, > 0 if a warning is generated, use rlc_error_info() to get error or warning description. Possible error/warning causes are: - TOO_MANY_IOS (too many IO descriptors, Check the compile time defined constant MAX_CHAN). */ int rlc_insertchan(int chan, int id, int (*f)(void *), void *p) { return (rlc_insertchan_(rlc_events, chan, id, f, p)); } /*++++ Removes an IO descriptor from the internal list. Params: chan : IO descriptor. */ void rlc_deletechan(int chan) { return (rlc_deletechan_(rlc_events, chan)); } /*++++ Returns the IO descriptor last found ready by rlc_getevent. Returns: the IO descriptor last found ready. */ int rlc_showselected () { return (rlc_showselected_(rlc_events)); } /*++++ Arranges for a timer event to happen after delta usec. Params: id : id of the event to be added, will be returned by rlc_getevent after the event execution. It must be > 0 to avoid confusion with predefined return values. delta : relative time of event execution (in usec). f : function to be called. p : function arguments. real : if set, the event will occurr delta usec after the actual calling time. Otherwise, it is assumed that the function has been called by the scheduler, and the event is scheduled exactly delta usec after the scheduling function had to be executed. This allows not to accumulate errors. Returns: 0 on success, $<$ 0 on failure. Possible error causes are: - ALLOC_TIMIT_ERROR (Error allocating a timer descriptor) */ int rlc_settimer(int id, unsigned long delta, CALLBACK f, void *p, int real) { return (rlc_settimer_(rlc_events, id, delta, f, p, real)); } /*++++ Removes all the pending events with the given id, returns the number of events removed. Params: id : id of event(s) to be removed. Returns: the number of events removed. */ int rlc_deletetimer(int id) { return (rlc_deletetimer_(rlc_events, id)); } rlc/ui.c010064400373640000764000000246110657027620200136460ustar00ucaclxvcsstaff00002440000013/* * ui.c -- UI routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1997, 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Lorenzo Vicisano and * other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifdef HAVE_UI #include #include #include #include #if __STDC__ #include #else #include #endif #include "receiver.h" #include "agent.h" #include "event.h" #include "rlcif.h" #include "ui.h" #include "bitmaps.h" #define MAX_EVENTS_WIN 10 /***** * We expect that the following are defined in the tcl script: * * "set_instance_id %d" * "have_an_error %d \"%s\"" * "have_an_warning %d \"%s\"" * * for the receiver: * "set_current %d" * "set_last %d" * "set_limit %d" *****/ /***** * We register the following commands: * * "quit %d" (pi) * * for the receiver: * "limit_notify %d %d" (limit, pi) *****/ char *ui_result; typedef struct _gui_sessd_t { Tcl_Interp *interp; } ui_sessd_t; static ui_sessd_t ui_sess[MAX_RLC_INSTANCES]; extern char RLC_TLC_SCRPT[]; extern char RLC_RX_TLC_SCRPT[]; extern char RLC_TX_TLC_SCRPT[]; int APPCallBack (ClientData data, Tcl_Interp *interp, int argc, char **argv); typedef struct { char *name; /* Name of command */ Tcl_CmdProc *proc; /* Pointer to procedure */ ClientData data; /* Client data */ } TKCallbacks, *TKCallPtr; /* Definitions of Tcl callbacks */ static TKCallbacks ApplCallbacks[] = { {"appcall", APPCallBack, NULL}, {NULL, NULL, NULL} /**** LIST TERMINATOR ****/ }; static int _rlc_gui_upcall (int pi, char *cmd); /*++++ Executes a tcl command in the gui context... */ int #if __STDC__ rlc_gui_tcl_exec (int pi, char **ret, char const *fmt, ...) #else rlc_gui_tcl_exec (pi, ret, fmt, va_alist) int pi; char **ret; char *fmt; va_dcl #endif { va_list ap; char cmd[4096]; int res; #if __STDC__ va_start(ap, fmt); #else va_start(ap); #endif vsprintf(cmd, fmt, ap); if ((res = _rlc_gui_upcall(pi, cmd)) != TCL_OK) rlc_internal_set_error_(pi, TCL_UI_ERROR, NULL); if (ret != NULL) { if (res == TCL_OK && ui_result != NULL) { if ((*ret = (char *)malloc(strlen(ui_result)+1)) == NULL) rlc_internal_set_error_(pi, TCL_UI_ERROR, NULL); else strcpy (*ret, ui_result); } else { *ret = NULL; } } NDEB(fprintf(stderr, "rlc_gui_tcl_exec : ");) NDEB(vfprintf(stderr, fmt, ap);) NDEB(fprintf(stderr, "\n res is : %d\n", res);) NDEB(if (ret) fprintf(stderr, "\n ret is : %s\n", *ret);) va_end(ap); return (res); } inline void ui_place (Tcl_Interp *interp, char *geom) { char cmd[512]; sprintf (cmd, "wm geometry . %s", geom); Tcl_Eval (interp, cmd); } static int _rlc_gui_upcall (int pi, char *cmd) { Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return (-1); ui_result = theInterpreter->result; return(Tcl_Eval (theInterpreter, cmd)); } #if 0 /* this is currently unused */ int rlc_gui_loadcallback (int pi, char *name, void *proc, void *data, void *delproc) { Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return (-1); if (Tcl_CreateCommand ( theInterpreter, name, (Tcl_CmdProc *)proc, (ClientData)data, (Tcl_CmdDeleteProc *)delproc) != TCL_OK) return(-1);; return (0); } #endif int rlc_gui_loadtcl (int pi, char *code) { Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return (-1); if (Tcl_VarEval (theInterpreter, code, NULL) != TCL_OK) return (-1); return (0); } void rlc_gui_delete (int pi) { /* to implement XXX */ } int rlc_gui_init (int pi, int upper_lay, char *appname, char *geometry) { Tk_Window mainWindow; char *windowName, *class; TKCallPtr cbPtr = ApplCallbacks; Tcl_Interp *theInterpreter; windowName = class = appname; /* shouldnt do it only once XXX */ theInterpreter = Tcl_CreateInterp(); Tcl_Init(theInterpreter); Tk_Init(theInterpreter); if ((mainWindow = Tk_MainWindow(theInterpreter) ) == NULL) { return (rlc_internal_set_error_(pi, TCL_UI_ERROR, NULL)); } Tk_SetAppName(mainWindow, windowName); Tk_SetClass (mainWindow, class); if (geometry != NULL) ui_place (theInterpreter, geometry); if (cbPtr) { while (cbPtr->name != NULL) { if (cbPtr->data == NULL) { Tcl_CreateCommand ( theInterpreter, cbPtr->name, cbPtr->proc, mainWindow, NULL); } else { Tcl_CreateCommand ( theInterpreter, cbPtr->name, cbPtr->proc, cbPtr->data, NULL); } cbPtr++; } } #if 0 Tk_DoWhenIdle ((Tcl_IdleProc *)MapWindow, mainWindow); #endif assert(pi>=0 && pi< MAX_RLC_INSTANCES); ui_sess[pi].interp = theInterpreter; rlc_gui_tcl_exec (pi, NULL, "set ProtoInstance %d", pi); if (rlc_settimer(UI_RUN, 100000, (CALLBACK)ui_run, NULL, 1) < 0) { rlc_gui_delete (pi); return (-1); } if (Tcl_VarEval (theInterpreter, RLC_TLC_SCRPT, NULL) < 0) { rlc_gui_delete (pi); return (-1); } return pi; } int rlc_gui_rx_init (int pi) { int result; Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return (-1); Tk_DefineBitmap(theInterpreter, Tk_GetUid("upto"), upto_bits, upto_width, upto_height); result = Tcl_VarEval (theInterpreter, RLC_RX_TLC_SCRPT, NULL); if (result != TCL_OK) { NDEB(fprintf (stderr, "%s\n", theInterpreter->result);) return (-1); } return (0); } int rlc_gui_tx_init (int pi) { int result; Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return (-1); result = Tcl_VarEval (theInterpreter, RLC_TX_TLC_SCRPT, NULL); if (result != TCL_OK) { NDEB(fprintf (stderr, "%s\n", theInterpreter->result);) return (-1); } return (0); } void rlc_gui_error_handle (int pi, char *e) { Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return; rlc_gui_tcl_exec (pi, NULL, "have_an_error %d \"%s\"", pi, e); } void rlc_gui_warning_handle (int pi, char *e) { Tcl_Interp *theInterpreter; assert(pi>=0 && pi< MAX_RLC_INSTANCES); if((theInterpreter = ui_sess[pi].interp) == NULL) return; DEB(fprintf (stderr, "have_an_warning %d \"%s\"", pi, e);) rlc_gui_tcl_exec (pi, NULL, "have_an_warning %d \"%s\"", pi, e); } #if 0 static void MapWindow (Tk_Window theWindow) { while (Tk_DoOneEvent (TK_IDLE_EVENTS) != 0) { ; } Tk_MapWindow (theWindow); } #endif /* * TCL command procedure that does everything * * Called after initial parameter are set up and the window * has been mapped * */ int ui_run (void *dummy) { int i, ret=1; int id; int terminated = 1; for (id=GET_SESSION_START, id=rlc_get_allinst(id, rlc_inst_mngr); id != GET_SESSION_END; id=rlc_get_allinst(id, rlc_inst_mngr)) { sxs_t *sxs = (sxs_t *)_rlc_getinstance(id, rlc_inst_mngr); if (!sxs->have_gui) continue; terminated = 0; if (sxs->isreceiver) { #if 0 rlc_rx_info(id, (void *)&info, &ilen); if (info.nlay-1 != ui_sess[id].nlay) { ui_last(ui_sess[id].interp, info.nlay-1); ui_limit(ui_sess[id].interp, info.nlay-1); ui_sess[id].nlay = info.nlay-1; } if (info.clay != ui_sess[id].clay) { ui_current(ui_sess[id].interp, info.clay); ui_sess[id].clay = info.clay; } #endif } } for(i=0; ret && i 0); i++) ret = Tcl_DoOneEvent(TCL_DONT_WAIT); if (!terminated && rlc_settimer(UI_RUN, 100000, (CALLBACK)ui_run, NULL, 0) < 0 ) { rlc_have_error_ (-1, STOP_UI, NULL); } return(0); } int APPCallBack (ClientData data, Tcl_Interp *interp, int argc, char **argv) { int newlimit; int pi; if (strcmp (argv [1], "limit_notify") == 0) { if (argc == 4) { Tcl_GetInt (interp, argv [2], &newlimit); Tcl_GetInt (interp, argv [3], &pi); /* **** call here **** */ NDEB(fprintf(stderr, "*** have new limit %d\n", newlimit);) if (pi < 0) return TCL_OK; rlc_rx_limit(pi, newlimit); } else { Tcl_AppendResult (interp, "Wrong number of args \"", argv [1], "\"", NULL); return TCL_ERROR; } } else if (strcmp (argv [1], "quit") == 0) { Tcl_GetInt (interp, argv [2], &pi); if (pi < 0) return TCL_OK; return (rlc_abort(pi)); } else { /* eat and do nothing ! */ return TCL_ERROR; #if 0 Tcl_AppendResult (interp, "Bad option \"", argv [1], "\": must be dc, mode or source", NULL); return TCL_ERROR; #endif } return TCL_OK; } #endif /* HAVE_UI */ r contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse rlc/error.c010064400373640000764000000262120657252245700143710ustar00ucaclxvcsstaff00002440000013/* * error.c -- error handling routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #include #include #if __STDC__ #include #else #include #endif #if 0 #include #endif #include "error.h" #include "ui.h" #include "agent.h" #include "rlcif.h" static void default_error(int pi, int errcode); static error_handle_t error_handle = default_error; static char msgbuf[512]; static int code = 0; static int msg_append = 0; static int this_pi = -1; static char *error_msgs[] = { "* Memory allocation ERROR", /*ALLOC_ERROR*/ "* Timer allocation ERROR", /*ALLOC_TIMIT_ERROR*/ "* Malformed address ERROR", /*BAD_ADDRESS*/ "* Not in class D address ERROR", /*ADDR_NOT_IN_CLASSD*/ "* Bad Callback function ERROR", /*BAD_CALLBACK_FUNCTION*/ "* Too many protocol instances ERROR", /*TOO_MANY_INSTANCES*/ "* Cannot start sender ERROR", /*CANT_START_SENDER*/ "* Cannot keep transmitting ERROR", /*STOP_TRANSMISSION*/ "* Cannot allocate event list ERROR", /*NO_EVLIST*/ "* Bad TTL ERROR", /*BAD_TTL*/ "* Bad number of layers ERROR", /*BAD_NUMBER_OF_LAYS*/ "* Bad minimum payload size ERROR", /*BAD_MIN_PAYLOAD*/ "* Bad maximum payload size ERROR", /*BAD_MAX_PAYLOAD*/ "* Bad interpacket transmission period ERROR", /*BAD_PERIOD*/ "* This address is already in use in this sender host ERROR",/*ADDR_IN_USE*/ "* Too many IO descriptor ERROR", /*TOO_MANY_IOS*/ "* No input channel available ERROR", /*NO_CHAN*/ "* Cannot start receiver ERROR", /*CANT_START_RECEIVER*/ "* join layer ERROR", /*JOIN_ERROR*/ "* Too many sockets (check MAX_RX_SOCKS) ERROR", /*TOO_MANY_SOCKET*/ "* Error in a network routine ERROR", /*NET_CALL_ERROR*/ "* leave layer ERROR", /*LEAVE_ERROR*/ "* attmp to transmit a too large packet ERROR", /*TOO_LARGE_PACKET*/ "* init TCL UI ERROR", /*TCL_UI_ERROR*/ "* bandwidth distribution option not implemented ERROR", /*BAND_NOT_IMPL*/ "* option edge trigger not implemented ERROR", /*TRIG_NOT_IMPL*/ "* Cannot allocate storage for incoming packet ERROR", /*ALLOC_PKT_ERROR*/ "* Cannot allocate temporary storage ERROR", /*ALLOC_TMP_ERROR*/ "* Timeout in reception ERROR", /*ALLOC_TMP_ERROR*/ "* Cannot set watchdog ERROR", /*ALLOC_TMP_ERROR*/ "* Non existent protocol instance ERROR", /*ALLOC_TMP_ERROR*/ "* Can't change address when the protocol has started ERROR", /*CANT_CHANGE_ADDR*/ "* Don't hace GUI stuff ERROR" }; static char *warn_msgs[] = { "* Warning: no user interface", /*NOUI_WARNING*/ "* Warning: Cannot keep running UI", /*STOP_UI*/ "* Warning: reception error", /*RCV_ERROR*/ "* Warning: sending error", /*SND_ERROR*/ "* Warning: binding to M-cast source address failed, trying INADDRANY", /*MULTI_BIND_ERROR*/ "* Warning: invalid odd port number, using the preceeding even value", /*ODD_PORT*/ "* Warning: no default error handler", /*NODEFERR_WARNING*/ "* Warning: no handler for SIGINT", /*NOSIGINT_WARNING*/ "* Warning: reception timeout" /*RECEPTION_TIMEOUT_WAR*/ }; static err_inf_t *err_ta = NULL; static err_inf_t *warn_ta = NULL; static int err_disp (int code, err_inf_t *e) { if (code > 0) { if (code >= e->base && code < e->base + e->length) return (code - e->base); return (-1); } else { if (code <= e->base && code > e->base - e->length) return (e->base - code); return (-1); } } static char *err_msg (int code) { err_inf_t **pt; if (IS_RLC_ERR(code)) return (error_msgs[ERR_MSG_IDX(code)]); if (IS_RLC_WARN(code)) return (warn_msgs[ERR_MSG_IDX(code)]); if (code < 0) pt = &err_ta; else pt = &warn_ta; while (*pt != NULL && err_disp(code, *pt) < 0) pt = &((*pt)->next); if (err_disp(code, *pt) < 0) return (NULL); return ((*pt)->table[err_disp(code, *pt)]); } int rlc_register_error_table (char **table, int base, int length) { err_inf_t *t, **pt; if ( (t = (err_inf_t *)malloc(sizeof(err_inf_t))) == NULL) return (rlc_internal_set_error_ (-1, ALLOC_ERROR, NULL)); if (base < 0) pt = &err_ta; else pt = &warn_ta; while (*pt != NULL) pt = &((*pt)->next); *pt = t; t->next = NULL; t->base = base; t->length = length; t->table = table; return (0); } /*++++ Returns the code and description of the last generated error. Params: msg : pointer to a char * that will be set to point to the error description string. Returns: the error code */ int rlc_error_info(char **msg) { if (msg) *msg = msgbuf; return (code); } /*++++ Registers the error handler client function. This function will be called when an internal exception occurs: error/warning that verifies in a function called by the event manager (typically reception/transmission routines). The rlc client can retrieve the event code using rlc_error_info(), which returns a value > 0 for warning and < 0 for errors. Errors must be handled by the client, while warnings can be ingnored. If the client has not register the error handler, a SIGUSR1 signal is raised on error; warnings are ignored. A default signal handler is installed for SIGUSR1, that prints the error stack and terminates the program. A complete list of error/warming codes definition is in rlcif.h . Params: f : the client provided error-handling function. the type error_handle_t is defined as: typedef void (*error_handle_t) (int pi); */ void rlc_set_error_h(error_handle_t f) { error_handle = f; } /* ** The actual storing function. Gets called by the function below or ** by the library to store intermediate error messages. */ int rlc_internal_set_error_ (int pi, int errcode, char const *fmt, ...) { va_list ap; char *p; if (fmt) { va_start(ap, fmt); if (msg_append) { #if 0 strncat (msgbuf, msg, sizeof(msgbuf)-1-strlen(msgbuf)); #else p = msgbuf + strlen(msgbuf); vsprintf(p, fmt, ap); #endif } else #if 0 strncpy (msgbuf, msg, sizeof(msgbuf)-1); #else vsprintf(msgbuf, fmt, ap); #endif } else /* XXX shell we check ? if (HAVE_ERR_MSG(errcode)) */ { if (msg_append) strncat (msgbuf, err_msg(errcode), sizeof(msgbuf)-1-strlen(msgbuf)); else strncpy (msgbuf, err_msg(errcode), sizeof(msgbuf)-1); } code = errcode; msg_append = 1; this_pi = pi; return code; } /* ** Stores the error message and error code in temporary variables, ** so that can be retrieved by the client using rlc_error_info(). */ int rlc_return_error_ (int pi, int errcode, char const *fmt, ...) { va_list ap; va_start(ap, fmt); rlc_internal_set_error_(pi, errcode, fmt, ap); msg_append = 0; return errcode; } /* ** Propagetes an error to the client calling the user-provided error ** handling function (of type *error_handle_t). If the error handling ** function is not defined, it rises a SIGUSR1 signal. The user ** can install its error handler using rlc_set_error_h(), and get the ** error cause using rlc_error_info(). */ void rlc_have_error_ (int pi, int errcode, char const *fmt, ...) { va_list ap; va_start(ap, fmt); NDEB(fprintf(stderr, "*** rlc_have_error_ for %d with (%d)\n", pi, errcode);) NDEB(if (msg) fprintf(stderr, "\t%s\n", msg);) (void) rlc_return_error_ (pi, errcode, fmt, ap); if (error_handle) error_handle (pi, errcode); else if (RLC_IS_ERR(errcode)) #if (!defined(Linux)) #if ( defined(SunOS) && (OSMVER < 5)) kill (getpid(), SIGUSR1); #else raise (SIGUSR1); #endif #else raise (SIGUSR1); #endif } /* ** Just print the error message stack and exit */ static void default_error(int pi, int errcode) { char *c; (void)rlc_error_info(&c); DEB(fprintf(stderr, "*** default_error with %s\n", c);) if (pi >= 0 || this_pi >= 0) { #ifdef HAVE_UI sxs_t *sxs; #endif int tpi; if (pi >= 0) tpi = pi; else tpi = this_pi; #ifdef HAVE_UI sxs = (sxs_t *)_rlc_getinstance(tpi, rlc_inst_mngr); DEB(fprintf(stderr, "*** default_error pi = %d\n", tpi);) if (sxs->error_gui && RLC_IS_ERR(errcode)) { DEB(fprintf(stderr, "*** default_error going " "error gui\n");) sxs->error_gui (tpi, c); return; } else if (sxs->warning_gui && !RLC_IS_ERR(errcode)) { DEB(fprintf(stderr, "*** default_error going " "warning gui\n");) sxs->warning_gui (tpi, c); return; } #endif if (RLC_IS_ERR(errcode)) { fprintf (stderr, "+++rlc (pi %d) fatal error:\n\t%s\n", tpi, c); exit (1); } else { fprintf (stderr, "+++rlc (pi %d) warning:\n\t%s\n", tpi, c); } } else { if (RLC_IS_ERR(errcode)) { fprintf (stderr, "+++rlc fatal error:\n\t%s\n", c); exit(1); } else { fprintf (stderr, "+++rlc warning:\n\t%s\n", c); } } } int _rlc_error_gui_init (int pi) { #ifdef HAVE_UI sxs_t *sxs = (sxs_t *)_rlc_getinstance(pi, rlc_inst_mngr); if (!sxs) return (rlc_return_error_ (pi, NO_SUCH_INSTANCE, NULL)); if (sxs->have_gui) return (rlc_return_error_ (pi, NO_GUI_ERROR, NULL)); sxs->error_gui = rlc_gui_error_handle; sxs->warning_gui = rlc_gui_warning_handle; return (0); #else return (rlc_return_error_ (pi, NO_GUI_ERROR, NULL)); #endif } /* ** Install the default error-signal handler. */ int set_default_error_h () { rlc_set_error_h (default_error); #if 0 if (signal(SIGUSR1, default_error) < 0) { return (rlc_internal_set_error_ (-1, NODEFERR_WARNING, strerror (errno))); } #endif return (0); } many protocol instances ERROR", /*TOO_MANY_INSTANCES*/ "* Cannot start sender ERROR", /*CANT_START_SENDER*/ "* Cannot keep transmitting ERROR", /*STOP_TRANSMISSION*/ "* Cannot allocate event list ERROR", /*NO_EVLIST*/ "* Bad TTL ERROR", /*BAD_TTL*/ "* Bad number of layers ERROR", /*BAD_NUMBER_OF_LAYS*/ "* Bad minimum payload size ERROR", /*rlc/init.c010064400373640000764000000056260656702212500142000ustar00ucaclxvcsstaff00002440000013/* * init.c -- library initialization routines * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include #include #include #include "rlcif.h" #include "sender.h" #include "receiver.h" #include "error.h" #include "event.h" void *rlc_inst_mngr = NULL; static int rlc_init_done = 0; void *rlc_events = NULL; static void rlc_last_stuff (int i) { receiver_last_stuff (i); /* if needed we could add something for the sender */ } int rlc_internal_init() { int ret, retvalue = 0; if (rlc_init_done) return retvalue; rlc_init_done = 1; if ((ret = _rlc_init_instance (MAX_RLC_INSTANCES, &rlc_inst_mngr)) < 0) { rlc_internal_set_error_ (-1, ret, NULL); return ret; } if ((rlc_events = rlc_createevlist_()) == NULL) { return (rlc_internal_set_error_ (-1, NO_EVLIST, NULL)); } if ((ret = set_default_error_h ()) != 0) { rlc_internal_set_error_ (-1, NODEFERR_WARNING, NULL); retvalue = NODEFERR_WARNING; } if (signal(SIGINT, rlc_last_stuff) < 0){ rlc_internal_set_error_ (-1, NOSIGINT_WARNING, strerror (errno)); retvalue = NOSIGINT_WARNING; } return retvalue; } rlc/instance.c010064400373640000764000000050620656704011100150260ustar00ucaclxvcsstaff00002440000013#include #include #include #include "rlcif.h" #include "utils.h" typedef struct _instance_manager_t { instance_des_t * _local_all_instances; instance_des_t ** _local_inst_vect; int instancenum; int maxinstances; } instance_manager_t; #define m ((instance_manager_t *)ptr) int _rlc_insert_instance (instance_des_t * inst, void *ptr) { int i; for (i=0; imaxinstances && m->_local_inst_vect[i] != NULL; i++); if (i != m->maxinstances) { m->_local_inst_vect[i] = inst; inst->ides = i; } else { rlc_return_error_(inst->ides, TOO_MANY_INSTANCES, NULL); } inst->next = m->_local_all_instances; m->_local_all_instances = inst; m->instancenum ++; return i; } int _rlc_howmany_instance (void **ptr) { return (m->instancenum); } void _rlc_return_instance (instance_des_t * inst, void *ptr) { instance_des_t * app; if (inst == m->_local_all_instances) m->_local_all_instances = m->_local_all_instances->next; else { for (app = m->_local_all_instances; app->next == inst || !app->next; app = app->next); if (app->next == inst) app->next = inst->next; } m->_local_inst_vect[inst->ides] = NULL; m->instancenum --; } instance_des_t * _rlc_getinstance(int pi, void *ptr) { if (pi < m->maxinstances && m->_local_inst_vect[pi] && m->_local_inst_vect[pi]->ides == pi) return (m->_local_inst_vect[pi]); rlc_internal_set_error_ (pi, NO_SUCH_INSTANCE, NULL); return (NULL); } int _rlc_init_instance (int maxinstances, void **ptr) { int i; #define mm ((instance_manager_t **)ptr) if (((*ptr) = malloc(sizeof(instance_manager_t))) == NULL) return (rlc_return_error_ (-1, ALLOC_ERROR, NULL)); if (((*mm)->_local_inst_vect = malloc(sizeof(instance_des_t *) * maxinstances)) == NULL) { free(*ptr); return (rlc_return_error_ (-1, ALLOC_ERROR, NULL)); } (*mm)->instancenum = 0; (*mm)->maxinstances = maxinstances; (*mm)->_local_all_instances = NULL; for (i=0; i<(*mm)->maxinstances; i++) { (*mm)->_local_inst_vect[i] = NULL; } return (0); } int rlc_get_allinst(int pi, void *ptr) { instance_des_t *ip = NULL; assert(ptr != NULL); if (pi == GET_SESSION_START) { ip = m->_local_all_instances; NDEB(fprintf(stderr, "rlc_get_allinst GET_SESSION_START\n");) } else if (pi < m->maxinstances && pi >= 0 && m->_local_inst_vect[pi]) ip = m->_local_inst_vect[pi]->next; if (!ip) { return(GET_SESSION_END); } NDEB(fprintf(stderr, "rlc_get_allinst returns %d\n", ip->ides);) return(ip->ides); } rlc/rlcif.h010064400373640000764000000247770657124713500143560ustar00ucaclxvcsstaff00002440000013/* * library header file for rlc * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLCIF_H #define RLCIF_H #if __STDC__ #include #else #include #endif #define MAX_RLC_INSTANCES 256 /* ** Error codes, Error infos in error.c. */ #define ALLOC_ERROR -100 #define ALLOC_TIMIT_ERROR -101 #define BAD_ADDRESS -102 #define ADDR_NOT_IN_CLASSD -103 #define BAD_CALLBACK_FUNCTION -104 #define TOO_MANY_INSTANCES -105 #define CANT_START_SENDER -106 #define STOP_TRANSMISSION -107 #define NO_EVLIST -108 #define BAD_TTL -109 #define BAD_NUMBER_OF_LAYS -110 #define BAD_MIN_PAYLOAD -111 #define BAD_MAX_PAYLOAD -112 #define BAD_PERIOD -113 #define ADDR_IN_USE -114 #define TOO_MANY_IOS -115 #define NO_CHAN -116 #define CANT_START_RECEIVER -117 #define JOIN_ERROR -118 #define TOO_MANY_SOCKET -119 #define NET_CALL_ERROR -120 #define LEAVE_ERROR -121 #define TOO_LARGE_PACKET -122 #define TCL_UI_ERROR -123 #define BAND_NOT_IMPL -124 #define TRIG_NOT_IMPL -125 #define ALLOC_PKT_ERROR -126 #define ALLOC_TMP_ERROR -127 #define RECEPTION_TIMEOUT -128 #define CANT_SET_WATCHDOG -129 #define NO_SUCH_INSTANCE -130 #define CANT_CHANGE_ADDR -131 #define NO_GUI_ERROR -132 /* ** Warning codes, Warning infos in error.c. */ #define NOUI_WARNING 1000 #define STOP_UI 1001 #define RCV_ERROR 1002 #define SND_ERROR 1003 #define MULTI_BIND_ERROR 1004 #define ODD_PORT 1005 #define NODEFERR_WARNING 1006 #define NOSIGINT_WARNING 1007 #define RECEPTION_TIMEOUT_WAR 1008 #define ERR_BASE 100 #define WARN_BASE 1000 #define ERR_SIZE 33 #define WARN_SIZE 9 #define RLC_IS_ERR(code) ((code) < 0 ? 1:0) #define IS_RLC_ERR(code) ( (code) <= -100 && (code) > -100 - ERR_SIZE ?\ 1 : 0 ) #define IS_RLC_WARN(code) ( (code) >= 1000 && (code) < 1000 + WARN_SIZE?\ 1 : 0 ) #define ERR_MSG_IDX(code) (RLC_IS_ERR(code) ? (-(code)-100) : ((code)-1000)) /* ** Structs used as function parameters ... */ typedef struct rx_info_s { int nlay; /* number of layers provided by the sender */ int clay; /* number of layers currently joined */ unsigned long t0; /* packet intertime extimation on l0 (us) */ int received; /* total number of packets received */ int lost; /* total number of packets lost */ int cong_ev; /* congestion events seen so far */ /* anything else to add ? */ } rx_info_t; typedef struct _addr_list_t { int nadd; /* number od addresses provided */ unsigned long *addrs; /* array of addresses */ short port; /* port number */ int ttl; /* ttl */ } addr_list_t; typedef struct _rlc_tx_params_t { int nlay; /* number of layers to use */ int mpkts; /* minimum packet size ... deprecated */ int Mpkts; /* Maximum packet size */ unsigned long t; /* interpacket period at the fastest rate */ } rlc_tx_params_t; #define GET_SESSION_START -1 #define GET_SESSION_END -2 /* ** Functions used as function parameters ... */ /* this must be implemented by the client */ /*++++ This function should be implemeted by the client. The function will be called by rlc to notify the client of the occurence of an unrecoverable error. The client can get the error code and textual info using rlc_error_info() . pi is the procol instance descriptor or -1 if a general error occurred. */ typedef void (*error_handle_t) (int pi, int errcode); /* watchdog callback ... */ typedef void (*rx_watchdog_t)(int pi); /* stats deliverer ... */ typedef void (*rx_stats_deliver_f)(int gid, void *buff, int size); /* sender ... */ /*++++ This function must be implemeted by the sender client, and a reference to it must be passed to rlc at the initialization. The function will be called by rlc each time a new packet must be transmitted. Params: pi: client protocol instance ID. lay: the layer in which the packet will be transmitted. flags: TBD p: the payload of the packet being transmitted. Returns: the payload size, or 0 indicating that the transmission must be terminated, and the current session deleted. A negative value can be returned as well, in which case a dummy packet od size mpkts will be transmitted. */ typedef int (*rlc_tx_packet_t) (int pi, int lay, char flags, char **p); /* receiver ... */ /*++++ This function must be implemeted by the receiver client, and a reference to it must be passed to rlc at the initialization. The function will be called by rlc each time a new packet has been received. Params: pi: client protocol instance ID. lay: the layer in which the packet has been received. flags: TBD p: the payload of the packet received. size: the size of the packet received. */ typedef void (*rlc_rx_packet_t) (int pi, int lay, char flags, char *p, int size); /*++++ This function is only used when the client controls directly the event loop (without using `rlc_getevent'). It should be implemented by the client application, and is called by rlc to add/remove an IO descriptor that will be handled by the client. If the argument `f' is non NULL, the descriptor (`iodes') must be added to the client list, and the function f must be called when the descriptor is ready for reading. If `f' is a null pointer, the descriptor has to be removed from the client list. All the calls to this function provide a pointer to the same function (if f is non NULL), hence a single instance of its value can be stored by the client. */ typedef void (*rlc_app_chanhandle_t) (int iodes, void (f)()); /** ** Exported functions prototypes. **/ /* * Main functions */ int rlc_new(int isreceiver); int rlc_set_addr(int pi, addr_list_t *rlcaddr); int rlc_attach(int pi, int cpi, void *f); int rlc_start(int pi); int rlc_abort(int pi); int rlc_gui_enable(int pi); int rlc_gui_geometry(int pi, char *geometry); /* call before enable ! */ int rlc_registerchanhandle(rlc_app_chanhandle_t f); /* sender specific ... */ int rlc_tx_setup(int pi, rlc_tx_params_t *params); unsigned long rlc_change_rate(int pi, unsigned long newr); unsigned long rlc_adj_rate(int pi, double scale); /* receiver specific ... */ int rlc_rx_info(int pi, void *buf, int *len); int rlc_rx_limit(int pi, int upper_lay); int rlc_rx_set_watchdog(int pi, rx_watchdog_t f, int time); int rlc_rx_log(int pi, char *ev_fn, char *po_fn); int rlc_rx_set_stats_deliver_f (int pi, int gid, rx_stats_deliver_f stats_deliver, int maxsize); unsigned long rlc_rx_get_src (int pi); /* * UI functions ... */ int rlc_gui_loadcallback (int pi, char *name, void *proc, void *data, void *delproc); int rlc_gui_loadtcl (int pi, char *code); #if __STDC__ int rlc_gui_tcl_exec (int pi, char **ret, char const *fmt, ...); #else rlcint _gui_tcl_exec (pi, ret, fmt, va_alist) int pi; char **ret; char *fmt; va_dcl; #endif /* * error handling ... */ int rlc_error_info(char **msg); void rlc_set_error_h(error_handle_t f); /* these are undocumented !!! */ int rlc_register_error_table (char **table, int base, int length); int rlc_internal_set_error_ (int pi, int errcode, char const *fmt, ...); int rlc_return_error_ (int pi, int errcode, char const *fmt, ...); void rlc_have_error_ (int pi, int errcode, char const *fmt, ...); /* * these are for protocol instance management ... */ #define INSTANCE_DES_MEMB \ struct _instance_des_t *next; \ int ides; \ typedef struct _instance_des_t { INSTANCE_DES_MEMB } instance_des_t; int _rlc_insert_instance (instance_des_t * inst, void *ptr); void _rlc_return_instance (instance_des_t * inst, void *ptr); instance_des_t * _rlc_getinstance(int pi, void *ptr); int _rlc_init_instance (int maxinstances, void **ptr); int rlc_get_allinst(int pi, void *ptr); int _rlc_howmany_instance (void **ptr); /** ** scheduler stuff .... **/ typedef int (*CALLBACK)(void *); #define EV_DEFTIMEOUT -4 /* got default timeout */ #define EV_GOTSIGNAL -3 /* got a signal in select() */ #define EV_TERMINATE -2 /* exit event loop with no timer pending and no channel to listen to */ #define EV_NO_PENDING -1 /* exit event loop with no timer pending but 1 or more channels to listen to (only if blocking == 0) */ #define EV_NULL 0 /* exit event loop with no event occurred but some timer pending */ int rlc_getevent(int blocking); int rlc_insertchan(int chan, int id, CALLBACK f, void *p); void rlc_deletechan(int chan); int rlc_settimer(int id, unsigned long delta, CALLBACK f, void *p, int real); void rlc_set_default_timeout(unsigned long delta); int rlc_showselected (); int rlc_deletetimer(int id); int rlc_poolchan(int *rid, void **rp); /* * Misc ... */ /* return time in usec */ long timestamp_u(); /* return time in msec */ long timestamp_m(); /* return time in sec */ long timestamp_s(); #endif /* RLCIF_H */ trlc/sender.h010064400373640000764000000042070656432616400145230ustar00ucaclxvcsstaff00002440000013/* * sender.h -- header file for sender routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__SENDER_H #define RLC__SENDER_H #include "rlc.h" #include "rlcif.h" #include "layers.h" #define TX_RUN 1025 /* timer fumction id */ void _rlc_tx_init(); int _rlc_tx_start(int pi); #endif /* RLC__SENDER_H */ rlc/receiver.h010064400373640000764000000047130656432706200150470ustar00ucaclxvcsstaff00002440000013/* * receiver.h -- receiver routines for rlc. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. */ #ifndef RLC__RECEIVER_H #define RLC__RECEIVER_H #include "rlc.h" #include "congestion.h" #include "utils.h" #define ID_GETDATA 104 #define RLC_WATCHDOG 1032 /* timer id */ typedef struct pkt_lis_d_t { struct pkt_lis_d_t *next; void *p; char *buff_in; rlc_h *header; int len; int this_lay; ui32 gindex; } pkt_lis_d; void _rlc_rx_init(); int _rlc_rx_start(int pi); int _rlc_rx_abort(int pi); int do_join (int pi, int g); int do_leave (int pi, int g); void receiver_last_stuff(int i); cong_t * get_cong_inst(int pi); #endif /* RLC__RECEIVER_H */ rlc/congestion.h010064400373640000764000000116030657031757700154160ustar00ucaclxvcsstaff00002440000013/* * congestion.h -- headers for receiver-side congestion control. * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__CONGESTION_H #define RLC__CONGESTION_H #include #include "rlcif.h" #include "rlc.h" #define LEAVE_DEAF 2.1 /* XXX */ #define POLL_INTERVAL 0.1 /* XXX */ #define UNSEEN -1 typedef struct _comp_stats_t { unsigned int time; /* us */ unsigned short tot_count; unsigned short clean_count; unsigned short lost; unsigned short cong_ev; unsigned short max_bwt; /* kBytes/s */ unsigned char curr_session; unsigned char flags; } comp_stats_t; /* todo: * - possibly all the time values can be converted from double to * ui32 */ typedef struct _cong_t { int pkt_size_; /* is used for the paket-pair... */ int n_lays; /* number of layers */ double base_period_; /* used in the leave_timeout */ double last_0_time; /* time of the last base layer packet */ unsigned short last_0_idx; /* last index in the base layer */ ui32 local_id_; /* this agent id, */ /* added to allow application to bound the number of layers */ int lay_limit; int init_thresh_; /* initial thershold, defaults = -1, that means set to the layers with max_bwt_/5 (only for the 1st rise) */ #if UNSUPP int start_session_; #endif ui32 last_p_; /* last packet in the current session */ int curr_session_; /* upper layer currently joined */ double leave_timeout; /* this is for committing a leave */ double leave_deaf_; /* this is the time that needs to past before two subsequnt leaves */ int lost_in_burst; double last_arrival; /* last packet arrival time */ double next_poll; /* for poll logging */ int max_bwt_; /* max bandwidth in the bottleneck */ /* congestion control ... */ int thresh_; /* exp/linear thershold (in layers), only for the 1st rise */ char flags; /* status flags... */ #define SEEN_UPS 1 /* seen up synchr. point */ #define SEEN_BST 2 /* seen burst start */ #define LV_PND 4 /* leave pending */ #define JN_PND 8 /* join pending */ #define LP_UNS 16 /* last packet sn undetermined */ #define fset(f, w) (f)|=(w) #define fclear(f, w) (f)&=(~(w)) #define fisset(f, w) ((f)&(w)) /* some statistics ... */ int tot_count_; /* total numb. of data pkts received */ int clean_count_; /* total numb. of data pkts received without those rec. in left sessions */ int lost_; /* total numb. of pkts lost */ int cong_ev_; /* introduced here */ FILE *eventf, *pollf; /* this is for conpat form stats. collecting * and delivery... */ #define MAXSTATSBUFSIZE 1024 char statsbuf[MAXSTATSBUFSIZE]; int maxstatbufsize; int statsbufoffset; rx_stats_deliver_f stats_deliver; int stats_gid; /* ** Delay buffer... ** */ #define MAX_DELAY 5 rlc_h *heads[MAX_DELAY]; timest_t rec_times[MAX_DELAY]; ui32 gidx[MAX_DELAY]; int this_lay[MAX_DELAY]; int del_l, del_c, del_in; } cong_t; int congestion_setup(int pi, cong_t *inst); void congestion_end(int pi, cong_t *inst, timest_t endtime); void congestion_control(int pi, cong_t *inst, rlc_h *p, int paylen, int this_lay, ui32 gidx, timest_t r_time); #endif /* RLC__CONGESTION_H */ possibly all the time values can be converted from double to * ui32 */ typedef struct _cong_t { int pkt_size_; /* is rlc/layers.h010064400373640000764000000075650647031125400145420ustar00ucaclxvcsstaff00002440000013/* * layers.h -- headers for layers routines. * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__LAYERS_H #define RLC__LAYERS_H #include #include #include "rlc.h" #include "rlcif.h" #define TX_INPROBE '\1' /* this relates to application API */ #define IS_OVER 0xffffffff typedef struct _lay_d { ui16 pn; int nc; /* number of layers */ #ifdef ONE_SEND_SOCK int chan; struct sockaddr_in saddrs[MAX_LAYERS]; #else int chs[MAX_LAYERS]; /* sockets */ #endif ui32 pu; /* period unit: 1/f_max, in usec */ ui16 idxs[MAX_LAYERS]; /* next index in this layer */ ui32 rates[MAX_LAYERS]; /* tx rate, actually period in pu_s */ ui32 left[MAX_LAYERS]; /* time left to next send */ ui32 gap[MAX_LAYERS]; /* gap period after a burst */ int cyc_l[MAX_LAYERS]; /* cycle length in pkts */ int bur_l[MAX_LAYERS]; /* burst length in pkts */ int W, Y, P; int inc_todo; ui32 now; /* debugging only */ } lay_d; ui32 l_change_rate(ui32 rate, lay_d *l); void setup_layers(ui32 rate, lay_d *l, int W, int Y, int P); int setup_l_sock(lay_d *l, addr_list_t *addr, n16 port, int ttl); ui32 send_layers(); #if 1 ui32 global_index (ui16 lsn, ui16 pn, int lay, int curr_lay, int inbu); void from_global_index (ui32 gidx, ui16 *lsn, ui16 *pn, int *lay, int curr_lay, int inbu); int is_first_burst (int lay, int curr_lay, char f); int is_first_non_burst (int lay, int curr_lay, char f); int is_burst_ending (char f); int is_in_burst (char f); int up_synch_burst (int lay, int curr_lay, char f); #else int is_first_burst (ui16 lsn, ui16 pn, int lay, int curr_lay, int W, int Y); int is_first_non_burst (ui16 lsn, ui16 pn, int lay, int curr_lay, int W, int Y); int is_burst_ending (ui16 lsn, ui16 pn, int lay, int curr_lay, int W, int Y); int is_in_burst (ui16 pn, int W, int Y); ui16 howmany_burst (ui16 pn, int W); ui32 global_index (ui16 lsn, ui16 pn, int lay, int curr_lay, int W, int Y); void from_global_index (ui32 gidx, ui16 *lsn, ui16 *pn, int *lay, int curr_lay, int W, int Y); #endif #endif /* RLC__LAYERS_H */ rlc/net.h010064400373640000764000000046510656725425300140360ustar00ucaclxvcsstaff00002440000013/* * net.h -- header for net routines. * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__NET_H #define RLC__NET_H #include #include #include #include #include #include #include #include #include #include #include "rlc.h" extern char *inet_ntoa(); #define NAME_LEN 128 int openssock(n32 addr, n16 port, int ttl, int unbound); int openrsock(n32 addr, n16 *port); int join_group(int fd, n32 addr); int leave_group(int fd, n32 addr); unsigned long localaddr(int ssock_); #endif /* RLC__NET_H */ rlc/event.h010064400373640000764000000072350650575021700143630ustar00ucaclxvcsstaff00002440000013/* * event.h -- header file for event handling routines * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__EVENT_H #define RLC__EVENT_H #include #include #include #include #include #include #include #include #include "rlcif.h" #include "compat.h" #define MAX_CHAN 32 typedef struct _timit_t { struct _timit_t *next; int id; /* event id. */ int flags; /* flags */ int (*t_f)(void *); /* function to call */ void *t_p; /* function parameter list */ ui32 delta; /* delta t (usec) */ } timit_t; typedef struct _evlist_t { int io_chan[MAX_CHAN]; /* fd, -1 if empty */ int io_id[MAX_CHAN]; /* channel id. */ ui16 io_ch_num; /* number of active channels */ int (*io_f[MAX_CHAN])(void *); /* function to call */ void *io_p[MAX_CHAN]; /* function parameter list */ int (*def_f)(void *); /* default function */ void *def_p; /* default parameters */ fd_set in_s; fd_set out_s; fd_set err_s; timit_t *timevent; /* timevent list */ struct timeval lasttime; struct timeval default_timeout; ui32 late; /* we are scheduling the current event late usec late! */ int selected; /* the last selected fd */ } evlist_t; extern void *rlc_events; void *rlc_createevlist_(); int rlc_getevent_(void *e, int blocking); int rlc_insertchan_(void *e, int chan, int id, CALLBACK f, void *p); void rlc_deletechan_(void *e, int chan); int rlc_settimer_(void *e, int id, unsigned long delta, CALLBACK f, void *p, int real); void rlc_set_default_timeout_(void *e, unsigned long delta); int rlc_showselected_ (void *e); int rlc_deletetimer_(void *e, int id); int rlc_poolchan_(void *vp, int *rid, void **rp); /** ** event tags and some function prototype are defined in rlcif.h **/ #endif /* RLC__EVENT_H */ rlc/utils.h010064400373640000764000000047620656732073200144070ustar00ucaclxvcsstaff00002440000013/* * utils.h -- utils.c functions prototypes. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__UTILS_H #define RLC__UTILS_H #include "compat.h" #include "rlcif.h" ui32 compute_id(); int set_link_addr(char *s, char *a, int addrlen, n16 *p, char *msg); int set_addresses(addr_list_t *list, int lays, ui32 *dstaddr); void hton_addlist(addr_list_t *list); int ui32diff(ui32 a, ui32 b); long diff_t(struct timeval b, struct timeval a); long timestamp_u(); long timestamp_m(); void timestamp_t(struct timeval *t); #ifdef DEBUGE #define DEB(x) {x; fflush(stderr);} #else #define DEB(x) #endif #define NDEB(x) #define INFINITE -1 #define NO_SOCK -1 #endif /* RLC__UTILS_H */ rlc/rlc.h010064400373640000764000000117700652670136700140260ustar00ucaclxvcsstaff00002440000013/* * header file for rlc * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC_H #define RLC_H #include "compat.h" /* this is for the endianness */ /* default values */ #define TTL 255 /*+ default ttl of transmitted packets +*/ #define NLAY 5 /*+ default number of layers +*/ #define DATA_SIZE 256 /*+ default payload size +*/ #define THE_W 8 #define THE_Y 2 #define THE_P 1 #define DEFAULT_DPORT "224.5.5.6/5657" #define L0_PERIOD 125000 /*+ default base period +*/ /* limit values */ #define MAX_LAYERS 10 #define MAX_RX_SOCKS 512 #define MIN_PAYLOAD_SIZE 128 #define MAX_PAYLOAD_SIZE (1500-DATA_H_SIZE) #if 1 /* XXX check this */ #define MAX_L0_PERIOD 12500000 #else #define MAX_L0_PERIOD 125000 #endif #define MAX_LAYERS 10 /* that should disappare */ #define ADDRLEN 32 /*++++ * data packet * 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | V=0 | T |x| flags | MAGIC # | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | source id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | LSN | PN | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | num. layers | band. prof. | band. profile parameters | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | | .... | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * ++++*/ #define RLC_VERSION 1 #define RLC_MAGIC 0x5afe /* packet types */ #define RLC_DATA_T 0 /* data packet (down-link) */ #define RLC_WRMP_T 1 /* warmup paket */ #define RLC_INFO_T 2 /* info paket */ #define RLC_APPL_T 3 /* application specific info */ typedef struct _rlc_h { #ifdef _LITTLE_ENDIAN ui8 pad:1, type:3, /* packet type */ vers:4; /* version */ #endif #ifdef _BIG_ENDIAN ui8 vers:4, /* version */ type:3, /* packet type */ pad:1; #endif #define RLC_F_IN_BURST 0x1 #define RLC_F_S_F_BURST 0x2 #define RLC_F_L_BURST 0x4 #define RLC_F_P_BURST 0x8 #define RLC_F_HART_BEAT 0x10 #define RLC_F_CONS_ADDR 0x20 #define RLC_F_EDGE_TRIG 0x40 ui8 flags; /* various flags */ ui16 magic; /* magic number */ ui32 suid; /* source ID */ ui16 lsn; /* sequence number within the layer */ ui16 pn; /* inter layer pattern sequence number */ #define BT_EXP_1 0 ui8 layer_n; /* number of layers */ ui8 bp; ui16 bpp; } rlc_h; #define FILL_D_H(p,t_lsn,t_pn,t_suid,f, \ l_n, b_p,valid_data) { \ (p).vers=RLC_VERSION; \ (p).magic=htons(RLC_MAGIC); \ if (valid_data) (p).type=RLC_DATA_T; \ else (p).type=RLC_WRMP_T; \ (p).lsn=(t_lsn); \ (p).pn=(t_pn); \ (p).suid=(t_suid); \ (p).flags=(f); \ (p).layer_n=(l_n); \ (p).bp=(b_p); \ (p).bpp=0; \ } #define DATA_H_SIZE sizeof(rlc_h) #define MAX_PKT_LEN (DATA_H_SIZE+MAX_PAYLOAD_SIZE) #endif /* RLC_H */ rlc/compat.h010064400373640000764000000071460647037227300145310ustar00ucaclxvcsstaff00002440000013/* * compat.h -- compatibility headers for rlc. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__COMPAT_H #define RLC__COMPAT_H #include #ifdef IRIX #include #endif #ifdef HPUX #include #endif #ifdef FreeBSD #include #endif #ifdef Linux #include #endif #ifdef SunOS #include #endif #define min(x,y) (((x)>(y))?(y):(x)) #define max(x,y) (((x)<(y))?(y):(x)) #ifdef FreeBSD #include #else #define bcopy(s, d, siz) memcpy((d), (s), (siz)) #define bzero(d, siz) memset((d), '\0', (siz)) #endif #if (defined SunOS) int gethostname (char *, int); #endif #if (!(defined Linux)) #if ((defined SunOS) && (OSMVER < 5)) void perror(char *); #endif #endif /* endianess... */ #ifdef BYTE_ORDER #if (BYTE_ORDER == LITTLE_ENDIAN) #define _LITTLE_ENDIAN #elif BYTE_ORDER == BIG_ENDIAN #define _BIG_ENDIAN #endif #else /* BYTE_ORDER */ #if ( !defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) ) #ifdef SunOS #define _BIG_ENDIAN /* #error We have SunOS assuming BIG_ENDIAN */ #else #error endianness not defined! check compat.h #endif #endif #endif /* BYTE_ORDER */ /* integer types */ typedef char i8; /* 8 bit signed int */ typedef short i16; /* 16 bit signed int */ typedef int i32; /* 32 bit signed int */ #if defined(__alpha) typedef long i64; /* 64 bit signed int */ #endif typedef unsigned char ui8; /* 8 bit unsigned int */ typedef unsigned short ui16; /* 16 bit unsigned int */ typedef unsigned short n16; /* 16 bit net format */ typedef unsigned int ui32; /* 32 bit unsigned int */ typedef unsigned int n32; /* 32 bit net format */ #if defined(__alpha) typedef unsigned long ui64; /* 64 bit unsigned int */ #endif typedef ui32 timest_t; /* used for timestamp in usec */ #endif /* RLC__COMPAT_H */ rlc/ui.h010064400373640000764000000046170657027061100136550ustar00ucaclxvcsstaff00002440000013/* * ui.h -- header file for UI routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1997, 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Lorenzo Vicisano and * other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__UI_H #define RLC__UI_H #ifdef HAVE_UI typedef void (*rlc_gui_error_handle_t)(int pi, char *e); extern char *ui_result; int rlc_gui_init (int pi, int upper_lay, char *appname, char *geometry); void rlc_gui_error_handle (int pi, char *e); void rlc_gui_warning_handle (int pi, char *e); int rlc_gui_rx_init (int pi); int rlc_gui_tx_init (int pi); void rlc_rx_gui_current (void *interp, int current); int ui_run (void *dummy); void rlc_rx_gui_delete (int pi); #define UI_RUN 3452 #endif /* HAVE_UI */ #endif /* RLC__UI_H */ retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributirlc/bitmaps.h010064400373640000764000000004340647031124700146700ustar00ucaclxvcsstaff00002440000013#define upto_width 16 #define upto_height 16 static unsigned char upto_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x18, 0x18, 0xfc, 0x3f, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}; rlc/error.h010064400373640000764000000041230656702026300143630ustar00ucaclxvcsstaff00002440000013/* * error.h -- error handling routines. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Lorenzo Vicisano and * other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__ERROR_H #define RLC__ERROR_H int set_default_error_h (); int _rlc_error_gui_init (int pi); typedef struct err_inf_t_{ struct err_inf_t_ *next; int base; int length; char **table; } err_inf_t; #endif /* RLC__ERROR_H */ rlc/init.h010064400373640000764000000036720647036442300142070ustar00ucaclxvcsstaff00002440000013/* * init.h -- library initialization routines * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1998 Lorenzo Vicisano * (vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__INIT_H #define RLC__INIT_H int rlc_internal_init(); #endif RLC__INIT_H rlc/agent.h010064400373640000764000000064620657027016500143420ustar00ucaclxvcsstaff00002440000013/* * agent.h -- receiver/sender descriptor data struct. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #ifndef RLC__AGENT_H #define RLC__AGENT_H #include "rlc.h" #include "ui.h" #include "rlcif.h" #include "layers.h" #include "receiver.h" typedef struct _sxs_t { INSTANCE_DES_MEMB int is_on; /* is the session on ? */ ui16 port; /* port # (net order) */ ui32 addrss[MAX_LAYERS]; int cpi; /* client prtocol instance descriptor */ int have_gui; #ifdef HAVE_UI rlc_gui_error_handle_t error_gui; rlc_gui_error_handle_t warning_gui; #endif char *geometry; ui32 starttime; int isreceiver; /* Sender Specific */ int ch; /* transmitting socket */ int ttl; ui32 rate; /* tx rate in l_0, actually period in usec. */ int mpkts, Mpkts; /* min and Max pktsize (bytes) */ ui32 pkts_left; /* packets left to transmit */ rlc_tx_packet_t tx_packet; /* client function that provides data */ ui8 flags; /* various flags */ #define ADDR_CONS 0x01 lay_d l; /* Receiver Specific */ int termdelayed; ui32 src; /* src IP address, it bounds to * the first sender it finds */ int lkypays; /* our guess on pkt size */ int lkypaysv; /* its sort-of-variance */ rlc_rx_packet_t rx_packet; cong_t *cong; int socks[MAX_LAYERS]; int have_addr_ass; ui32 watch_t, watch_last; rx_watchdog_t watch_f; }sxs_t; int _rlc_start(int pi); extern void *rlc_inst_mngr; #endif /* RLC__AGENT_H */ res or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neitrlc/ui.tcl010064400373640000764000000041670657027772200142220ustar00ucaclxvcsstaff00002440000013 #### # Upcalls ## # proc set_instance_id {id} # have_an_error {pi errmsg} #### #### # Callback ## # quit {ProtoInstance} #### ### ### global vars ### if {![info exists ProtoInstance]} { set ProtoInstance -1 } if {![info exists RLCINFOS]} { set RLCINFOS "Not present ... sorry!" } ### # appearence parameters ### set globFonts 6x10 frame .expl frame .expr frame .expt frame .expb frame .fmenu -relief groove -bd 2 menubutton .fmenu.file -text "File" menu .fmenu.file.quit -title "quit" .fmenu.file.quit add command -label "quit" -command \ "appcall quit $ProtoInstance" .fmenu.file configure -menu .fmenu.file.quit menubutton .fmenu.help -text "Help" set HelpButt [menu .fmenu.help.rlc -title "Help"] $HelpButt add command -label "About RLC" -command \ "show_infos {$RLCINFOS} \"About RLC\"" .fmenu.help configure -menu $HelpButt # let's give a default name to the main window wm title . "rlc" pack .fmenu -side top -fill x pack .fmenu.file -side left pack .fmenu.help -side right pack .expl -side left pack .expr -side right pack .expt -side top pack .expb -side bottom proc have_an_error {pi errmsg} { tk_messageBox -icon error -title "Error" -type ok -message \ "Error in $pi :\n$errmsg" appcall quit $pi } proc have_an_warning {pi errmsg} { set ret [tk_messageBox -icon warning -title "Warning" \ -type okcancel -message \ "Warning in $pi :\n$errmsg \nAbort ?" ] case $ret { ok "appcall quit $pi" cancel {} } } proc set_instance_id {id} { global ProtoInstance set ProtoInstance $id puts "protinst set to $id" } proc show_infos {text title} { set w .text catch {destroy $w} toplevel $w wm title $w "$title" wm iconname $w "text" frame $w.buttons pack $w.buttons -side top -fill x -pady 2m button $w.buttons.dismiss -text Dismiss -command "destroy $w" pack $w.buttons.dismiss -side left -expand 1 text $w.text -relief sunken -bd 2 -yscrollcommand "$w.scroll set" \ -setgrid 1 -height 30 -width 60 scrollbar $w.scroll -command "$w.text yview" pack $w.scroll -side right -fill y pack $w.text -expand yes -fill both $w.text insert 0.0 \ $text $w.text mark set insert 0.0 } rlc/uirx.tcl010064400373640000764000000101350656704357400145660ustar00ucaclxvcsstaff00002440000013 #### # Upcalls ## # proc set_instance_id {id} (shared with the sender) # have_an_error {pi errmsg} (shared with the sender) # proc set_limit {lim} # proc set_current {curr} # proc set_last {last} #### #### # Callback ## # proc limit_notify {lim} #### ### ### global vars ### set LastLay -1 set LimitLay 0 set LastCurrent 0 # it's Kb/s set BaseRate 16 ### # appearence parameters ### set indxSize 10 set indySize 15 set indActCol green set indInactColNull lightgrey set indInactCol grey set indInactColOver darkgrey set indActColOver red proc createSetLimit {w varName custproc args} { global BaseRate LimitLay $w delete 0 end foreach i $args { set app [expr $BaseRate * (1 << $i)] set app "$app Kb/s" $w add radiobutton -label $app -variable $varName -value $i -command \ "$custproc $i" } return $w } menubutton .fmenu.conf -text "Set" menu .fmenu.conf.conf -title "set" menu .fmenu.conf.conf.limit -title "rate limit" .fmenu.conf.conf add cascade -label "rate limit" -menu .fmenu.conf.conf.limit createSetLimit .fmenu.conf.conf.limit LimitLay set_limit_int 0 .fmenu.conf configure -menu .fmenu.conf.conf frame .left -bd 2 -relief groove frame .left.l frame .left.r #.left.r.sel configure -bitmap upto frame .left.r.up -relief groove frame .left.r.down -relief sunken label .left.l.lcurrv -text "data rate\n$BaseRate Kb/s" -font $globFonts set app [expr $BaseRate * (1 << $LimitLay)] label .left.l.llimv -text "Max\n$app Kb/s" -font $globFonts canvas .left.l.ca proc pack_all {} { pack .fmenu.conf -side left pack .left -fill both -expand 1 pack .left.l -side left pack .left.r -side left -fill y pack .left.r.up -side top pack .left.r.down -side top pack .left.l.ca -side top pack .left.l.lcurrv -side top pack .left.l.llimv -side top } proc set_limit {lim} { global LimitLay if {$lim >= 0} {set LimitLay $lim} limit_set $LimitLay } proc set_limit_int {lim} { global LimitLay ProtoInstance set_limit $lim # puts "set_limit_int with $lim" ### callback... appcall limit_notify $lim $ProtoInstance } proc limit_set {limit} { global LimitLay LastCurrent BaseRate ProtoInstance set app [expr $BaseRate * (1 << $LimitLay)] .left.l.llimv configure -text "Max\n$app Kb/s" set_current $LastCurrent } proc set_last {last} { global LastLay indxSize indySize LastCurrent LimitLay \ indInactColOver indInactColNull indicat dummyoval if {$last != $LastLay} { .left.l.ca configure -height [expr ($last + 1) * $indySize] \ -width [expr ($last + 1) * $indxSize] for {set i 0} {$i <= $LastLay} {incr i} { .left.l.ca delete $indicat($i) } for {set i 0} {$i <= $last} {incr i} { set indicat($i) [ \ .left.l.ca create rectangle 0 \ [expr ($last + 1 - $i) * $indySize] \ [expr ($last + 1) * $indxSize] \ [expr ($last - $i) * $indySize] -outline "" ] } if [info exists dummyoval] { .left.l.ca delete $dummyoval } set dummyoval [ \ .left.l.ca create oval \ [expr -4 + (- $last - 1) * $indxSize] \ 4 [expr -4 + ($last + 1) * $indxSize] \ [expr 4 + 2 * ($last + 1) * $indySize] -fill \ $indInactColNull -outline "" ] } set LastLay $last set arg "createSetLimit .fmenu.conf.conf.limit LimitLay set_limit_int" for {set i $LastLay} {$i >= 0} {set i [expr $i - 1]} {set arg "$arg $i"} eval $arg set_current $LastCurrent pack_all } proc set_current {curr} { global LastLay LimitLay LastCurrent BaseRate indicat global indInactCol indActCol indInactColOver indActColOver if {$curr > $LastLay || $curr < 0} { return } set LastCurrent $curr for {set i 0} {$i <= $LastLay} {incr i} { if {$i <= $curr} { if {$i <= $LimitLay} { .left.l.ca itemconfigure $indicat($i) -fill \ $indActCol } else { .left.l.ca itemconfigure $indicat($i) -fill \ $indActColOver } } else { if {$i <= $LimitLay} { .left.l.ca itemconfigure $indicat($i) -fill \ $indInactCol } else { .left.l.ca itemconfigure $indicat($i) -fill \ $indInactColOver } } } set app [expr $BaseRate * (1 << $curr)] .left.l.lcurrv configure -text "data rate\n$app Kb/s" } #set_last 2 #set_last 9 #set_limit 5 #set_last 7 set_current 0 set_last 0 set_limit 0 rlc/uitx.tcl010064400373640000764000000000000656432456500145550ustar00ucaclxvcsstaff00002440000013rlc/Makefile.in010064400373640000764000000072470657056214700151460ustar00ucaclxvcsstaff00002440000013DEFINES=-D$(OSTYPE) -DOSMVER=$(OSMVER) -DONE_SEND_SOCK -DHAVE_UI #-DDEBUGE # -DHAVE_UI define this to have UI support # -DDUMMYNET this is for faking the net... # -DONE_SEND_SOCK for using a single socket in transmission. CFLAGS=-g -Wall -O2 $(DEFINES) # -pg CC=gcc OBJDIR = obj/$(OSTYPE) LIBS= $(TK_LIB) $(TCL_LIB) $(OTHER_LIBS) LIB_C_SRCS= rlc.c sender.c receiver.c congestion.c layers.c \ net.c event.c utils.c ui.c error.c init.c instance.c LIB_H_SRCS= rlcif.h sender.h receiver.h congestion.h layers.h \ net.h event.h utils.h rlc.h compat.h ui.h bitmaps.h error.h \ init.h agent.h OTHER_SRCS= ui.tcl uirx.tcl uitx.tcl OTHER_C_STUFF= re.c se.c rec-sample.c sen-sample.c OTHER_STUFF= Makefile.in Makefile.genarch makescript README INSTALL TODO \ Makefile.SunOS Makefile.FreeBSD Makefile.Linux Makefile.IRIX ALLSTUFF= $(LIB_C_SRCS) $(LIB_H_SRCS) $(OTHER_SRCS) $(OTHER_STUFF) \ $(OTHER_C_STUFF) UPALLSTUFF=$(ALLSTUFF:%=rlc/%) #LIB_O=$(LIB_C_SRCS:.c=.o) LIB_O=$(LIB_C_SRCS:%.c=$(OBJDIR)/%.o) I_H_DOCS=$(LIB_H_SRCS:%.h=doc/%.h.tex) I_C_DOCS=$(LIB_C_SRCS:%.c=doc/%.c.tex) DOCS= $(I_H_DOCS) $(I_C_DOCS) SUFFIXES+= .c.tex .SUFFIXES: $(SUFFIXES) all: sh makescript x-all xref: sh makescript x-xref depend: sh makescript x-depend sample: sh makescript x-sample x-all: $(OBJDIR)/librlc.a $(OBJDIR)/librlc.a: obj-dir $(LIB_O) $(OBJDIR)/ui-tcl.o - rm $(OBJDIR)/librlc.a ar r $(OBJDIR)/librlc.a $(LIB_O) $(OBJDIR)/ui-tcl.o - ranlib $(OBJDIR)/librlc.a $(OBJDIR)/ui-tcl.o: ui-tcl.c $(CC) $(CFLAGS) -c ui-tcl.c -o $(OBJDIR)/ui-tcl.o $(X11_INCLUDE) \ $(TK_INCLUDE) $(TCL_INCLUDE) ui-tcl.c: uirx.tcl uitx.tcl ui.tcl README (echo "char RLC_TLC_SCRPT[] = \"\\" ; \ ( (echo "set RLCINFOS {\\"; \ cat README | sed 's/\([^$$]\)$$/\1\\/'; \ echo "}"); \ cat ui.tcl) | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") > ui-tcl.c (echo "char RLC_RX_TLC_SCRPT[] = \"\\" ; \ cat uirx.tcl | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") >> ui-tcl.c (echo "char RLC_TX_TLC_SCRPT[] = \"\\" ; \ cat uitx.tcl | sed 's/\\/\\\\/g'| sed 's/$$/\\n\\/g' | \ sed 's/\"/\\\"/g'; \ echo "\";") >> ui-tcl.c $(OBJDIR)/ui.o: ui.c ui.h $(CC) $(CFLAGS) -c ui.c -o $(OBJDIR)/ui.o $(X11_INCLUDE) $(TK_INCLUDE) \ $(TCL_INCLUDE) #x-sample: rec-sample.c $(OBJDIR)/librlc.a # $(CC) $(CFLAGS) rec-sample.c -o $(OBJDIR)/rec-sample -L$(OBJDIR)/ \ # -lrlc $(TK_LIB) $(TCL_LIB) $(OTHER_LIBS) $(X11_LIB) x-sample: rec-sample.c sen-sample.c $(OBJDIR)/librlc.a $(CC) $(CFLAGS) sen-sample.c -o $(OBJDIR)/sen-sample -L$(OBJDIR)/ \ -lrlc $(TK_LIB) $(TCL_LIB) $(OTHER_LIBS) $(X11_LIB) $(CC) $(CFLAGS) rec-sample.c -o $(OBJDIR)/rec-sample -L$(OBJDIR)/ \ -lrlc $(TK_LIB) $(TCL_LIB) $(OTHER_LIBS) $(X11_LIB) clean: sh makescript x-clean x-clean: rm -f $(LIB_O) $(OBJDIR)/ui-tcl.o ui-tcl.c tgz: (cd ..; tar cvf - $(UPALLSTUFF) ) | gzip > rlc.tgz x-xref: doc-dir $(DOCS) -(cd doc; latex cxref; exit 0) obj-dir: if [ -d $(OBJDIR) ] ;\ then \ echo "$(OBJDIR) exists";\ else \ mkdir -p $(OBJDIR) ;\ fi doc-dir: if [ -d ./doc ] ;\ then \ echo "./doc exists"; \ else \ mkdir doc ;\ fi $(OBJDIR)/%.o: %.c $(CC) $(CFLAGS) $(DEFINES) $(TK_INCLUDE) $(TCL_INCLUDE) $(X11_INCLUDE) \ $< -c -o $@ doc/%.c.tex: %.c cxref $(DEFINES) $(TK_INCLUDE) $(TCL_INCLUDE) $(X11_INCLUDE) \ $< -Odoc -latex2e doc/%.h.tex: %.h cxref $(DEFINES) $(TK_INCLUDE) $(TCL_INCLUDE) $(X11_INCLUDE) \ $< -Odoc -latex2e se: $(SE_O) $(CC) -o se $(SE_O) $(LIBS) re: $(RE_O) $(CC) -o re $(RE_O) $(LIBS) x-depend: makedepend -s"# DO NOT DELETE BELOW! (custom makedepend delim.) :-)"\ $(DEFINES) $(X11_INCLUDE) \ $(TCL_INCLUDE) $(TK_INCLUDE) $(LIB_C_SRCS) # DO NOT DELETE BELOW! (custom makedepend delim.) :-) rlc/Makefile.genarch010064400373640000764000000007420647033150300161250ustar00ucaclxvcsstaff00002440000013## # Personalize according to your environment. ## # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### # in solaris : -I/usr/openwin/include/ X11_INCLUDE= -I/usr/X11R6/include/ TCL_INCLUDE= -I/usr/local/include/ TK_INCLUDE= -I/usr/local/include/ ### ## The following only if you compile the samples with -DHAVE_UI ### TCL_LIB= -L/usr/local/lib -ltcl TK_LIB= -L/usr/local/lib -ltk X11_LIB= -lX11 include Makefile rlc/makescript010064400373640000764000000072130651566472500151630ustar00ucaclxvcsstaff00002440000013#!/bin/sh # # Build script for rat. This script determines the type of machine it's # running on, and calls "make" with the appropriate macro definitions # to set up the machine specific includes etc. # # NOTE: If the environment variable MAKE is set, it's value will be # used instead of the default "make". Use this to give a path # to gnu make, for example. # # $Revision: 1.1 $ # $Date: 1997/10/10 12:29:57 $ # # Copyright (c) 1996 University College London # 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. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the Computer Science # Department at University College London # 4. Neither the name of the University nor of the Department may be used # to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESSED 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 AUTHORS 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. # # Find out the type of system we're running on. The nasty stuff is needed for $OSMVER # since some systems (HP-UX) give the OS version in a weird format. At the end of this # we should have the following variables set: # # OSTYPE : Base operating system type # OSMVER : The major version number of the system # OSVERS : The full version number of the system # echo "Determining system type..." OSTYPE=`uname -s` OSVERS=`uname -r` case $OSTYPE in Linux ) OSMVER=`echo $OSVERS | awk -F. '{printf("%d_%d", $1, $2)}'` ;; SunOS | IRIX ) OSMVER=`echo $OSVERS | awk -F. '{print $1}'` OSLIBS="-lsocket -lnsl" ;; HP-UX ) OSTYPE=HPUX OSMVER=`echo $OSVERS | awk -F. '{print $2}'` ;; FreeBSD ) OSMVER=`echo $OSVERS | awk -F. '{print $1}'` OSLIBS="" ;; * ) echo "$OSTYPE $OSVERS is not supported!" exit ;; esac echo "OSTYPE=$OSTYPE" echo "OSVERS=$OSVERS" echo "OSMVER=$OSMVER" TARGET=${@:-all} MM=`which gmake | sed -n "/\/gmake/p"` #if which gmake 2> /dev/null > /dev/null if test -f "/$MM" && test -x "/$MM" then echo "using gmake"; MM=gmake else echo "gmake not found, hopefully make works..."; MM=make fi MAKEFILE=Makefile.$OSTYPE if [ -f $MAKEFILE ] then echo "using $MAKEFILE" else echo "can't find $MAKEFILE"; exit 1 fi export OSLIBS cmd="${MAKE:=$MM} -f $MAKEFILE $TARGET OSTYPE=$OSTYPE OSMVER=$OSMVER OSVERS=$OSVERS" exec $cmd rlc/README010064400373640000764000000026470656713452000137540ustar00ucaclxvcsstaff00002440000013rlc-1.0a1 20/04/98 l.vicisano@cs.ucl.ac.uk http://www.cs.ucl.ac.uk/staff/l.vicisano/rlc/ RLC is based on a receiver driven congestion control algorithm which is TCP-friendly and suitable for use in the Mbone. It supports variable transmission rate by using a layered organisation of data, transmitting each layer in a separate multicast group, and letting receivers adapt to the available bandwidth by joining to one or more multicast groups. Each receiver makes decisions autonomously, but techniques are used to synchronise receivers behind the same bottleneck (and belonging to the same protocol instance), so that they can cooperate in controlling the congestion at the shared bottleneck. No feedback to the sender is needed and no explicit form of group membership is used. RLC sender is very simple, it just transmits data packets simultaneously on a number of levels associated to different multicast groups. Levels are ordered and packets are properly arranged on them, in a way that a receiver joining levels from 0 up to n sees an almost homogeneous rate of incoming packets, the actual rate depending on $n$. In the current implementation, the data rate is doubled each time the next layer is added to the current subscription set. This is a C implementation of RLC. It is an alpha release: it might (almost certainly) contain bugs. Please send me any feedback you have to the following e-mail address: l.vicisano@cs.ucl.ac.uk . rlc/INSTALL010064400373640000764000000031400656710501600141100ustar00ucaclxvcsstaff00002440000013rlc-1.0a1 20/04/98 l.vicisano@cs.ucl.ac.uk http://www.cs.ucl.ac.uk/staff/l.vicisano/rlc/ RLC library compiles on Solaris, FreeBSD, Linux, SunOS, IRIX and (maybe) most of the others Unix flavours. To have it working properly, you have to run it in a configuration where the PRUNING capability of multicast routing WORKS. Moreover you have to have IGMPv2 or greater running in your local NET. The documentation concerning the API of this library can be found in the included file rlc-api.ps (Postscript format). Information concerning the protocol itself can be found in 2 papers available on-line at my web page ( http://www.cs.ucl.ac.uk/staff/l.vicisano ). For further information either send me an e-mail or look at the source code. To build: - must have gmake or compatible, if you want to use the UI stuff, you must also have tk/tcl (It compiles with version 4.2/7.6 ... and maybe with some other versions - copy Makefile.in to Makefile - possibly edit Makefile to change DEFINES (shouldn't be needed), the only thing that's optional is HAVE_UI ! - copy Makefile.genarch to Makefile., if you are not sure about the name, run `make` : it will complain searching your makefile. - edit Makefile. according to your environment. - make clean - make depend - make It all produces librlc.a . Then you have to install it by hand, copying librlc.a and rlcif.h where you want to keep them. You can also try to compile the (naive) samples, using: - make sample Please send me any feedback you have to the following e-mail address: l.vicisano@cs.ucl.ac.uk . Lorenzo Vicisano rlc/TODO010064400373640000764000000001540650574427600135620ustar00ucaclxvcsstaff00002440000013 *** proper handling of `suid', currently is random generated at the source and ignored by the receiver. rlc/Makefile.SunOS010064400373640000764000000005570656263245700155470ustar00ucaclxvcsstaff00002440000013X11_INCLUDE= -I/usr/openwin/include/ TCL_INCLUDE= -I/cs/research/mice/starship/common/solaris/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/solaris/include/ TCL_LIB= -L/cs/research/mice/starship/common/solaris/lib -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/solaris/lib -ltk8.0 X11_LIB= -lX11 OTHER_LIBS= -lm -lsocket -lnsl -ldl include Makefile rlc/Makefile.FreeBSD010064400373640000764000000003710657056203600157360ustar00ucaclxvcsstaff00002440000013# FreeBSD X11_INCLUDE= -I/usr/X11R6/include/ TCL_INCLUDE= -I/usr/local/include/tcl8.0 TK_INCLUDE= -I/usr/local/include/tk8.0 TCL_LIB= -L/usr/local/lib -ltcl80 TK_LIB= -L/usr/local/lib -ltk80 OTHER_LIBS= -lm -L/usr/X11R6/lib/ -lX11 include Makefile rlc/Makefile.Linux010064400373640000764000000011050656436131100156130ustar00ucaclxvcsstaff00002440000013#### # Linux ## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### X11_INCLUDE= -I/usr/X11R6/include/ X11_LIB= -L/usr/X11R6/lib/ -lX11 TCL_INCLUDE= -I/cs/research/mice/starship/common/linux/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/linux/include/ TCL_LIB= -L/cs/research/mice/starship/common/linux/lib/ -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/linux/lib/ -ltk8.0 include Makefile rlc/Makefile.IRIX010064400373640000764000000011000656436420100152630ustar00ucaclxvcsstaff00002440000013#### # IRIX ## # Personalize according to your environment. ## RLC_INCLUDE= -I../rlc RLC_LIB= -L../rlc/$(OBJDIR) -lrlc # sloaris need also: -lsocket -lnsl -ldl OTHER_LIBS= -lm ### ## The following only if you compile with -DHAVE_UI ### X11_INCLUDE= -I/usr/X11R6/include/ X11_LIB= -L/usr/X11R6/lib/ -lX11 TCL_INCLUDE= -I/cs/research/mice/starship/common/irix/include/ TK_INCLUDE= -I/cs/research/mice/starship/common/irix/include/ TCL_LIB= -L/cs/research/mice/starship/common/irix/lib/ -ltcl8.0 TK_LIB= -L/cs/research/mice/starship/common/irix/lib/ -ltk8.0 include Makefile rlc/re.c010064400373640000764000000074100647031125600136330ustar00ucaclxvcsstaff00002440000013/* * re.c --- this is a dummy packet multicast receiver. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include "rlc.h" int data_pkt_len = 1024; void *events; /* callback attach. and timers */ char data[MAX_PAYLOAD_SIZE]; int datas; ui32 period = 1; ui32 daddr; void badcmdline(char *arg) { fprintf(stderr, "Bad argument %s\nCommand line:\n\t rlcd [options]\n" "options:\n" "\t-d \n", arg); exit(1); } int get_data(void *p) { int chan = rlc_showselected(events); int len, srcaddrlen; struct sockaddr_in srcaddr; if ((len = recvfrom(chan, data, sizeof(data), 0, (struct sockaddr *)&srcaddr, &srcaddrlen))<=0) perror("receiver: recvfrom"); DEB(fprintf(stderr, "got %d bytes...\n", len)) return 0; } int deal_term(void *p) { char buf[128]; int re; if((re = read(0, buf, sizeof(buf))) <= 0) { if (re < 0) perror("read"); return -1; } if (*buf == 'j') { join_group(datas, daddr); DEB(fprintf(stderr, " Join!!\n")) } else if (*buf == 'l') { leave_group(datas, daddr); DEB(fprintf(stderr, " Leave!!\n")) } return 0; } int main(int argc, char *argv[]) { int i; char dataaddr[ADDRLEN]; n16 dport = 0; ui8 ttl=TTL; extern char *optarg; extern int optind; /* parse command line... */ while ((i = getopt(argc,argv,":d:")) != EOF) { switch(i) { case 'd': /* data addr/port */ if(set_link_addr(optarg, dataaddr, ADDRLEN, &dport, "data")<0) badcmdline(optarg); break; } } if (dport == 0) set_link_addr(DEFAULT_DPORT, dataaddr, ADDRLEN, &dport, "data"); fprintf(stderr, "using ttl %d \n", ttl); argc -= optind; argv += optind; daddr = inet_addr(dataaddr) ; datas = openrsock(daddr, &dport); events = rlc_createevlist(); rlc_insertchan(events, datas, 145, get_data, NULL); rlc_insertchan(events, 0, 45, deal_term, NULL); while (rlc_getevent(events, 1)!=EV_NO_PENDING); exit(0); } rlc/se.c010064400373640000764000000101270647031126300136310ustar00ucaclxvcsstaff00002440000013/* * se.c -- dummy packet multicast sender. * * This file is part of * * rlc -- Reliable Multicast data Distribution Protocol * * (C) 1996, 1997, 1998 Luigi Rizzo and Lorenzo Vicisano * (luigi@iet.unipi.it, vicisano@cs.ucl.ac.uk) * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Luigi Rizzo, * Lorenzo Vicisano and other contributors. * 4. Neither the name of the Authors nor the names of other contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. * */ #include #include "rlc.h" int data_pkt_len = 1024; void *events; /* callback attach. and timers */ char data[MAX_PAYLOAD_SIZE]; int datas; ui32 period = 1; int se_send(int *datas) { #if 0 int i, j; double a; printf("%u\n", timestamp_u()); fflush(stdout); j = drand48() * 10000; for (i=0; i\n" "\t-d \n" "\t-l \n" "\t-t \n", arg); exit(1); } int main(int argc, char *argv[]) { int i; char dataaddr[ADDRLEN]; n16 dport = 0; ui8 ttl=TTL; ui32 daddr; extern char *optarg; extern int optind; /* parse command line... */ while ((i = getopt(argc,argv,"t:d:l:")) != EOF) { switch(i) { case 'd': /* data addr/port */ if(set_link_addr(optarg, dataaddr, ADDRLEN, &dport, "data")<0) badcmdline(optarg); break; case 't': /* TTL */ ttl = atoi(optarg); if (ttl <= 0 || ttl > 255) badcmdline(optarg); break; case 'l': /* data packet size */ data_pkt_len = atoi(optarg); if (data_pkt_len < 16 /* XXX */ || data_pkt_len > MAX_PAYLOAD_SIZE) badcmdline(optarg); case 'r': /* data rate pkts/s */ period = atoi(optarg); break; } } if (dport == 0) set_link_addr(DEFAULT_DPORT, dataaddr, ADDRLEN, &dport, "data"); fprintf(stderr, "using ttl %d \n", ttl); if (period > 0) { fprintf(stderr, "rate %d pkts/s (%.3f kbit/s)\n", period, period*data_pkt_len*8/1024.); period = 1e6/period; } else { fprintf(stderr, "Wrong data rate\n"); exit (1); } argc -= optind; argv += optind; events = rlc_createevlist(); daddr = inet_addr(dataaddr) ; datas = openssock(daddr, dport, ttl /* TTL */, 0); rlc_settimer(events, 13, period, (CALLBACK)se_send, &datas, 1); while (rlc_getevent(events, 1)!=EV_NO_PENDING); exit(0); } rlc/rec-sample.c010064400373640000764000000047600656434762600153000ustar00ucaclxvcsstaff00002440000013#include #include #include "rlcif.h" /* include the rlc include file */ #ifdef HAVE_UI char tcl_script[] = "proc have_pkts {n} {}"; /* custom UI script */ #endif static int rx_packet (int ides, int lay, char flags, char *pkt, int size); int have_gui; /* have we got a user interface ? */ int rlc_inst; int main (int argc, char *argv[]) { unsigned long addr; /* base address (host byte order) */ short port; /* base layer port # */ char *ev_f = NULL , *po_f = NULL ; /* possibly log file names */ addr_list_t addrl; /* address list ... */ char *geometry = NULL; have_gui = 0; #ifdef HAVE_UI have_gui = 1; #endif /* ** now initialize parameters ** (addr, port, have_gui, ev_f ?, po_f ? ... ) */ addr = 0xe0111213; port = 9000; if (argc > 1 && !strcmp(argv[1], "-g")) { geometry = malloc (strlen(argv[2])+1); strcpy (geometry, argv[2]); } /* ** use consecutive addresses, so ** provide only the base address. */ addrl.addrs = &addr; addrl.nadd = 1; addrl.port = port; /* ** rlc receiver initialization ... ** and possibly library initialization */ if ( (rlc_inst = rlc_new (1)) < 0 || rlc_set_addr (rlc_inst, &addrl) < 0 || rlc_attach (rlc_inst, 0, (void *)&rx_packet) < 0) { fprintf (stderr, "had error in rlc initialization\n"); exit (1); } /* ** possibly we have logging */ if (ev_f || po_f) (void)rlc_rx_log(rlc_inst, ev_f, po_f); #ifdef HAVE_UI if ( have_gui ) { if (geometry) rlc_gui_geometry(rlc_inst, geometry); if (rlc_gui_enable(rlc_inst) < 0) have_gui = 0; /* ** customize user interface */ if (rlc_gui_loadtcl(rlc_inst, tcl_script) < 0) have_gui = 0; } #endif /* ** start receiving .... */ rlc_start(rlc_inst); /* ** makes thing go ... */ while (EV_TERMINATE != rlc_getevent(1)); exit(0); } /* ** reveived paket handling */ static int rx_packet (int ides, int lay, char flags, char *pkt, int size) { static int received; received ++; free (pkt); #ifdef HAVE_UI /* ** display reception progress ? */ if (have_gui) rlc_gui_tcl_exec (rlc_inst, NULL, "have_pkts %d", received); #endif /* ** use the packet received.... */ #if 0 fprintf(stderr, "---rec-sampe: have pkt from lay %d, size %d\n", lay, size); #endif /* ** if we have done, delete the protocol instance */ if (0) { rlc_abort (rlc_inst); } return(0); } rlc/sen-sample.c010064400373640000764000000050570656435077300153110ustar00ucaclxvcsstaff00002440000013#include #include #include "rlcif.h" /* include the rlc include file */ static int tx_packet (int ides, int lay, char flags, char **pkt); int main (int argc, char *argv[]) { int ides; unsigned long addr; /* base address (host byte order) */ short port; /* base layer port # */ addr_list_t addrl; /* address list ... */ rlc_tx_params_t parml; /* tx parameter list ... */ int nlayers; /* number of layers */ unsigned long period; /* interpacket time at maximum rate */ int ttl; /* transmitting ttl */ int pktsize; /* our payload size */ int have_gui = 1; char *geometry = NULL; int ret; /* ** now perform parameter initialization ... ** (addr, port, nlayers, period, ttl, pktsize) */ /* hoops... we have harwired values! */ addr = 0xe0111213; /* 224.1.2.3 */ port = 9000; nlayers = 5; period = 7812; /* ~ 125ms on the base layer */ ttl = 127; pktsize = 256; /* ** use consecutive addresses, so ** provide only the base address. */ addrl.addrs = &addr; addrl.nadd = 1; addrl.port = port; addrl.ttl = ttl; parml.nlay = nlayers; parml.mpkts = pktsize; parml.Mpkts = pktsize; parml.t = period; /* ** rlc receiver initialization ... ** and possibly library initialization */ if ( (ret = ides = rlc_new(0)) < 0 || (ret = rlc_set_addr (ides, &addrl)) < 0 || (ret = rlc_attach (ides, 0, (void *)&tx_packet)) < 0 || (ret = rlc_tx_setup(ides, &parml)) < 0 ) { char *c; ret = rlc_error_info(&c); fprintf (stderr, "Error %d in protocol initialization (%s)\n", ret, c); exit (1); } #ifdef HAVE_UI if ( have_gui ) { if (geometry) rlc_gui_geometry(ides, geometry); if (rlc_gui_enable(ides) < 0) have_gui = 0; #if 0 /* ** customize user interface */ if (rlc_gui_loadtcl(ides, tcl_script) < 0) have_gui = 0; #endif } #endif /* ** Try to start ... */ if ((ret = rlc_start(ides)) < 0) { char *c; ret = rlc_error_info(&c); fprintf (stderr, "Error %d in start (%s)\n", ret, c); exit (1); } /* ** makes thing go ... */ while (EV_TERMINATE != rlc_getevent(1)); exit(0); } char p[256]; /* ** packet transmission routine ... */ static int tx_packet (int ides, int lay, char flags, char **pkt) { static int count; if (count < 100) { /* ** chose the packet .... (p) */ *pkt = p; return (sizeof(p)); } else return (-1); /* this stops the transmission * and deletes this rlc instance */ count ++; }