/* $Id: mcl.cpp,v 1.2 2003/10/14 09:27:03 chneuman Exp $ */ /* * Copyright (c) 1999-2003 INRIA - Universite Paris 6 - All rights reserved * (main author: Vincent Roca - vincent.roca@inrialpes.fr) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include "mcl_includes.h" /* private functions */ static int mcl_init_sender (mclcb_t *mclcb); static int mcl_init_receiver(mclcb_t *mclcb); /* * version # and credits * edit as appropriate! */ void mcl_moreabout(void) { /* * credits (very important :-) */ PRINT_OUT((mcl_stdout, "\n-- MultiCast Library (MCL) --\n")) PRINT_OUT((mcl_stdout, MCLv3_VERSION)) PRINT_OUT((mcl_stdout, " Copyright (c) 1999-2003 INRIA - Univ. Paris 6 - All rights reserved\n")) PRINT_OUT((mcl_stdout, " main author/contact: vincent.roca@inrialpes.fr\n")) PRINT_OUT((mcl_stdout, " web site: http://www.inrialpes.fr/planete/people/roca/mcl/\n")) PRINT_OUT((mcl_stdout, " MCL comes with ABSOLUTELY NO WARRANTY; This is free software,\n")) PRINT_OUT((mcl_stdout, " and you are welcome to redistribute it under certain conditions;\n")) PRINT_OUT((mcl_stdout, " See the GNU General Public License as published by the Free \n")) PRINT_OUT((mcl_stdout, " Software Foundation, version 2 or later, for more details.\n")) PRINT_OUT((mcl_stdout, "-- Credits:\n")) PRINT_OUT((mcl_stdout, "* Vincent Roca (INRIA R.A.)\n")) PRINT_OUT((mcl_stdout, "* Julien Laboure (since May 2000: INRIA R.A.)\n")) PRINT_OUT((mcl_stdout, "* Christoph Neumann (since April 2002: INRIA R.A.)\n")) PRINT_OUT((mcl_stdout, "* Benoit Mordelet (December 2000 - 2001: Activia Networks)\n")) #ifdef RSE_FEC PRINT_OUT((mcl_stdout, "* fec.c -- forward error corection based on Vandermonde matrices\n")) PRINT_OUT((mcl_stdout, " (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) (980624)\n")) PRINT_OUT((mcl_stdout, " Portions derived from code by Phil Karn (karn@ka9q.ampr.org),\n")) PRINT_OUT((mcl_stdout, " Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and\n")) PRINT_OUT((mcl_stdout, " Hari Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995\n")) #endif /* RSE_FEC */ #ifdef LDPC_FEC PRINT_OUT((mcl_stdout, "* The LDPC codec is\n")) PRINT_OUT((mcl_stdout, " Copyright (c) 2002,2003 INRIA - All rights reserved\n")) PRINT_OUT((mcl_stdout, " It also contains code from R. Neal:\n")) PRINT_OUT((mcl_stdout, " Copyright (c) 2000, 2001 by Radford M. Neal\n")) #endif /* LDPC_FEC */ /* * compilation options */ PRINT_OUT((mcl_stdout, "-- Compiled with:\n ")) #ifdef ALC PRINT_OUT((mcl_stdout, "ALC ")) #endif #ifdef LCT_SCHED1 PRINT_OUT((mcl_stdout, "LCT_SCHED1 ")) #endif #ifdef LCT_SCHED2 PRINT_OUT((mcl_stdout, "LCT_SCHED2 ")) #endif #ifdef LCT_SCHED3 PRINT_OUT((mcl_stdout, "LCT_SCHED3 (%d) ",DEFAULT_DU_IN_SEQ_IN_TXTAB)) #endif #ifdef RLC PRINT_OUT((mcl_stdout, "RLC ")) #endif #ifdef FLIDS PRINT_OUT((mcl_stdout, "FLID-SL ")) #endif #ifdef RSE_FEC PRINT_OUT((mcl_stdout, "RSE_FEC ")) #endif #ifdef LDPC_FEC PRINT_OUT((mcl_stdout, "LDPC_FEC ")) #endif #ifdef POSTPONE_FEC_DECODING PRINT_OUT((mcl_stdout, "POSTPONE_FEC_DECODING ")) #endif #ifdef ANTICIPATED_TX_FOR_PUSH PRINT_OUT((mcl_stdout, "ANTICIPATED_TX_FOR_PUSH ")) #endif #ifdef MCL_SELECT PRINT_OUT((mcl_stdout, "MCL_SELECT ")) #endif #ifdef VIRTUAL_TX_MEM PRINT_OUT((mcl_stdout, "VIRTUAL_TX_MEM (%d) ",VIRTUAL_TX_MAX_PHY_MEM_SIZE)) #endif #ifdef VIRTUAL_RX_MEM PRINT_OUT((mcl_stdout, "VIRTUAL_RX_MEM (%d) ",VIRTUAL_RX_MAX_PHY_MEM_SIZE)) #endif #ifdef DEBUG PRINT_OUT((mcl_stdout, "DEBUG ")) #endif #ifdef GET_SYSINFO PRINT_OUT((mcl_stdout, "GET_SYSINFO ")) #endif #ifdef SIMUL_LOSSES PRINT_OUT((mcl_stdout, "!!!SIMUL_LOSSES!!! ")) #endif } /* * called only once after mcl_open() and parameter parsing with mcl_ctl(). * Initialize everything (context, sockets, mcast, thread, etc.). */ void #ifdef STREAM mcl_end_init_mclcb (mclcb_t *mclcb, int nb_level) #else mcl_end_init_mclcb (mclcb_t *mclcb) #endif { /* NB: mode considers SIG, mclcb->sender/receiver considers appl data */ int mode = 0; /* init mode of sockets for each layer */ mcl_init_random(); ASSERT(mclcb); TRACELVL(5, (mcl_stdout, "-> mcl_end_init_mclcb: id=%d\n", mclcb->id)) mclcb->initialized = 1; /* mark as done first! */ /* moved here from init_receiver which is called to late! */ memset((void *)&mclcb->rxlvl, 0, sizeof(mclcb->rxlvl)); /* * set the init mode first... */ if (mclcb->sender == 1) { if (mclcb->addr.is_multicast_addr()) mode |= MODE_MCAST_TX; else mode |= MODE_UNI_TX; } else if (mclcb->sender == 2) { /* this is above all a receiver */ mode |= MODE_UNI_TX; } if (mclcb->receiver == 1) { if (mclcb->addr.is_multicast_addr()) mode |= MODE_MCAST_RX; else mode |= MODE_UNI_RX; } else if (mclcb->receiver == 2) { /* this is above all a sender */ mode |= MODE_UNI_RX; } mclcb->mode = mode; /* remember the mode, used later... */ #ifdef STREAM if (mcl_init_layer_nb(mclcb,nb_level) < 0) { #else if (mcl_init_layer_nb(mclcb) < 0) { #endif PRINT_ERR((mcl_stderr, "mcl_end_init_mclcb: ERROR: mcl_init_layer_nb failed")) mcl_exit(1); } /* * ... then create the socket endpoints, */ if (mcl_init_sockets(mclcb) < 0) { mcl_exit(1); } /* * ... then create/init everything else */ if (mclcb->sender == 1 && mclcb->receiver == 2) { mcl_init_sender(mclcb); mcl_init_receiver(mclcb); } else if (mclcb->receiver == 1 && mclcb->sender == 2) { mcl_init_receiver(mclcb); mcl_init_sender(mclcb); } else if (mclcb->sender) { mcl_init_sender(mclcb); if (mode & MODE_SIG_UNI_RX) mcl_init_receiver(mclcb); } else if (mclcb->receiver) { mcl_init_receiver(mclcb); if (mode & MODE_SIG_UNI_TX) mcl_init_sender(mclcb); } /* mcl_init_timer(mclcb); */ /* * ... initialize the congestion control protocol */ #ifdef NEVERDEF /* moved to mcl_open() */ #ifdef RLC rlc_init_session(mclcb); #endif /* RLC */ #ifdef FLIDS FLIDs_InitSession(mclcb); #endif /* FLIDS */ #endif /* NEVERDEF */ TRACELVL(5, (mcl_stdout, "<- mcl_end_init_mclcb: OK\n")) } /* * initialize the sending context... */ static int mcl_init_sender (mclcb_t *mclcb) /* session cb */ { int i; txlvl_t *tl; int sent_on_lower_lvl = 0; /* nb of packets per tick */ /* already sent on lower tx lvls */ TRACELVL(5, (mcl_stdout, "-> mcl_init_sender: id=%d\n", mclcb->id)) /* required below but... */ ASSERT((mclcb->mcl_max_group == MAX_TX_LEVEL)) /* * Init the txlvl array first... */ memset((void *)mclcb->txlvl_tab, 0, sizeof(mclcb->txlvl_tab)); /* * The rate scale depends on the type of scheduling. * If FEC is used, then the redundancy levels also have a * different rate scale. */ for (i = 0, tl = mclcb->txlvl_tab; i < MAX_TX_LEVEL; i++, tl++) { tl->level = i; if (mclcb->addr.is_multicast_addr()) { /* one to one for the present */ tl->mcgroup = &(mclcb->mcgroup_tab[i]); } else tl->mcgroup = &(mclcb->mcgroup_tab[0]); #if defined(ALC) /* take advantage of data sent on lower levels */ tl->du_per_tick = mclcb->du_per_tick_scale[i]; /* rates are preinit'd in a tab */ tl->rate = sent_on_lower_lvl + tl->du_per_tick; sent_on_lower_lvl = tl->rate; #ifdef RLC /* Julien's HACK */ if (i > 0) { tl->wait_sp = 1; tl->wait_after_sp_count = MCL_WAIT_AFTER_SP_COUNT; } #endif /* RLC */ #elif defined(DSS_SCHED) /* here transmission rate and du/tick are the same */ tl->du_per_tick = mclcb->du_per_tick_scale[i]; /* rates are preinit'd in a tab */ tl->rate = tl->du_per_tick; #endif } if (mclcb->verbose >= 1) mcl_print_tx_profile (mclcb); TRACELVL(5, (mcl_stdout, "<- mcl_init_sender: OK\n")) return 0; } /* * initialize the receiving context... */ static int mcl_init_receiver (mclcb_t *mclcb) /* session cb */ { TRACELVL(5, (mcl_stdout, "-> mcl_init_receiver: id=%d\n", mclcb->id)) mclcb->rxlvl.mcgroup_head = mclcb->mcgroup_tab; mclcb->rxlvl.next_adu2give = NULL; /* not yet known */ mclcb->rxlvl.next_adu2give_seq = mcl_iss; /* * ... and create the reception thread and lock. */ #ifdef WIN32 if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mcl_rx_thread, (void*)mclcb, 0, (LPDWORD)&mclcb->rx_thread) == NULL) { perror("mcl_init_receiver: CreateThread"); mcl_exit(1); } #else if ((pthread_create((pthread_t*)&mclcb->rx_thread, NULL, mcl_rx_thread, (void*)mclcb)) != 0) { perror("mcl_init_receiver: pthread_create"); mcl_exit(1); } #endif TRACELVL(5, (mcl_stdout, "<- mcl_init_receiver: OK\n")) return 0; } /* * emergency exit function. * do as little as possible as we are in an unknown state... */ void mcl_exit (int n) { int id; mclcb_t *mclcb = NULL; PRINT_ERR((mcl_stderr, "mcl_exit: Fatal error, exit everything...\n")) /* find the first valid mclcb first */ for (id = 0; id < MCLCB_MAX_ID; id++) { if (mclcbs[id] != NULL) { mclcb = mclcbs[id]; break; } } /* close the vtm/vrm services to destroy the temp files */ #ifdef VIRTUAL_TX_MEM if (mclcb) mcl_vtm_close (mclcb); #endif #ifdef VIRTUAL_RX_MEM if (mclcb) mcl_vrm_close (mclcb); #endif exit(n); }