/* $Id: mcl_var.cpp,v 1.5 2003/10/27 09:55:48 roca 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" /* * for the one time mcl global initialization */ static int mcl_glob_initialized = 0; static void mcl_glob_init (void); /* * global MCL variables are defined and initialized here */ const u_int mcl_iss = 1; /* initial sequence number */ mcl_thread_t mcl_timer_thread_id; /* timer thread; only one for all sessions */ u_int mcl_time_count = 0; /* this is the fine-grained timer, giving */ /* local time in usec; incremented by */ /* mcl_timer_thread, used everywhere */ #ifdef RLC u_int mcl_rlc_rx_period = MCL_RLC_RX_PERIOD; /* period in microseconds between*/ /* two calls to the RLC timer func (receiver) */ u_int mcl_rlc_rx_count = MCL_RLC_RX_PERIOD/MCL_TIMER_PERIOD; #endif mcl_mutex_t mcl_mutex_lock; /* global lock */ char mcl_tmp_dir_name[MAX_FILE_NAME_LEN]; /* default dir for temporary files */ mclcb_t *mclcbs[MCLCB_MAX_ID]; /* mclcb table */ /* MCL version of standard streams. */ FILE *mcl_stdout; /* MCL standard output stream */ FILE *mcl_stderr; /* MCL standard error output stream */ /* * used for tx rate calculations * uses an exponential scale up to "max" DUs/tick, and then a linear * scale of "max" DUs/tick. */ static void calc_tx_scale (int *tab, int start, /* initial power of two */ int max, /* max nb of DUs/tick */ int tab_len) { int val; int *stop = tab + tab_len; ASSERT(tab && start >= 0 && tab_len > 0); for (val = 1 << start; tab < stop ; *tab++ = min(val, max), val <<= 1); } /* * callled as soon as a new session is opened. * allocates the mclcb_t structure and pre-initialize it */ mclcb_t * mcl_alloc_mclcb () { int i; int prof; mclcb_t *mclcb; /* * Tx rate scale (how many DUs to send on each layer at each time tick) * Use the power of 2 scale of tx rate (default), or a custom scale. * XXX: adjust the nb of preinitialized elements according to * MAX_TX_LEVEL, otherwise it generates a warning! */ int du_per_tick_scale[MAX_TX_LEVEL]; /* predefined tx rate scale */ /* mcl global initialization; must be done first */ if (!mcl_glob_initialized) { mcl_glob_init(); } /* * allocate and reset to 0 everything * WARNING: using malloc prevents the automatic call of constructors * for the classes contained in the mcl_cb struct. */ if (!(mclcb = (mclcb_t*)calloc(1, sizeof(mclcb_t)))) { PRINT_ERR((mcl_stderr, "mcl_alloc_mclcb: ERROR: out of memory\n")) mcl_exit(-1); } mclcb->tx_state = TSTATE_NIL; mclcb->rx_state = RSTATE_NIL; mclcb->addr.reset(); /* call constructor manually */ mclcb->addr.set_port(5665); mclcb->mcast_if.reset(); /* call constructor manually */ mclcb->mcast_if.set_any_addr(); mclcb->src_addr.reset(); /* call constructor manually */ mclcb->check_src_addr = false; mclcb->ttl = TTL; mclcb->rx_sock_size = MCL_RX_SOCK_SIZE; for (i = 0; i < MAX_MC_GROUP; i++) { mclcb->mcgroup_tab[i].addr.reset(); /* call constructor */ } /* * call the FEC class constructor manually */ mclcb->fec.initialize(); /* * choose a default tx profile */ prof = DFLT_TX_PROFILE; if (mcl_set_tx_profile(mclcb, prof) < 0) { PRINT_ERR((mcl_stderr, "mcl_alloc_mclcb: ERROR: mcl_set_tx_profile failed\n")) mcl_exit(-1); } /* by default init nb_level to 1; updated later in mcl_init_layer_nb */ mclcb->nb_level = 1; /* only 1 tx level to start... */ mclcb->next_adu_seq = mcl_iss; mclcb->first_tx_for_mclcb = 1; /* no tx yet */ mclcb->nb_tx = 1; /* by default single tx for each DU */ /* * precalculate the transmission rates. * choose a progression... */ /* for a progression 1 1 2 4 8 16... */ du_per_tick_scale[0] = 1; calc_tx_scale(&du_per_tick_scale[1], 0, 20, MAX_TX_LEVEL - 1); #if 0 /* for a progression 1 2 4 8 16... */ calc_tx_scale(&du_per_tick_scale[1], 0, 20, MAX_TX_LEVEL); #endif for (i = 0; i < MAX_TX_LEVEL; i++) { mclcb->du_per_tick_scale[i] = du_per_tick_scale[i]; } /* choose LCT3 if available, otherwise LCT2, otherwise LCT1 */ #if defined(LCT_SCHED1) mclcb->scheduler = MCL_SCHED_LCT1; #endif #if defined(LCT_SCHED2) mclcb->scheduler = MCL_SCHED_LCT2; #endif #if defined(LCT_SCHED3) mclcb->scheduler = MCL_SCHED_LCT3; mclcb->desired_du_in_seq_in_txtab = DEFAULT_DU_IN_SEQ_IN_TXTAB; #endif #if !defined(LCT_SCHED1) && !defined(LCT_SCHED2) && !defined(LCT_SCHED3) Error, you must choose a scheduler! Define one of the previous schedulers in file mcl_profile.h. #endif /* by default mix everything */ mclcb->adu_scheduling = MCL_SCHED_MIXED_ORDER; #ifdef FEC mclcb->fec.set_max_fec_ratio(mclcb, MAX_FEC_RATIO); #endif mclcb->demux_label = 0; //mclcb->codepoint = 0; #if 0 mclcb->fec_encoding_id = FEC_ENCODING_ID_NO_FEC; mclcb->fec_instance_id = FEC_INSTANCE_ID_NULL; #endif #if !defined(RLC) && !defined(FLIDS) mclcb->no_congestion_control = 1; #else mclcb->no_congestion_control = 0; #endif /* RLC,FILDS */ #ifdef VIRTUAL_TX_MEM /* in VIRTUAL_TX_MEM mode, use the service by default */ mclcb->vtm_used = 1; mclcb->vtm_initialized = 0; #endif #ifdef VIRTUAL_RX_MEM /* in VIRTUAL_RX_MEM mode, use the service by default */ mclcb->vrm_used = 1; mclcb->vrm_initialized = 0; #endif #ifdef ANTICIPATED_TX_FOR_PUSH mclcb->anticipated_tx_for_push = 1; #endif #ifdef POSTPONE_FEC_DECODING /* it is dangerous to set fec_decoding to 1 by default. Prefer 0! */ mclcb->postpone_fec_decoding = 0; #endif mclcb->tx_mem_cleanup_count = TX_MEM_CLEANUP_PERIOD; mclcb->mcl_max_group = MAX_MC_GROUP; mclcb->stats_time_count = STATS_PERIOD; /* stats already zero'ed by calloc */ /*memset((void *)&mclcb->stats, 0, sizeof(mclcb->stats));*/ /* statistics */ return mclcb; } /* * callled by mcl_close/abort to free everything in the * session control block including the mclcb itself. */ void mcl_free_mclcb (mclcb_t *mclcb) { TRACELVL(5, (mcl_stdout, "-> mcl_free_mclcb:\n")) mclcbs[mclcb->id] = NULL; /* do it immediately for security */ /* * close all the remaining sockets; * especially required in case of a sender */ mcl_close_sockets(mclcb); /* * no sig service any more */ mcl_sig_close(mclcb); /* * free all remaining data/adu/tx tab... */ mcl_free_all_adu(mclcb); if (mclcb->sender) mcl_free_all_txtab (mclcb); /* * close congestion control services */ #ifdef RLC if (mclcb->receiver) rlc_end_session(mclcb); #elif defined(FLIDS) if (mclcb->receiver) FLIDs_EndSession(mclcb); #endif /* RLC,FILDS */ TRACELVL(5, (mcl_stdout, "<- mcl_free_mclcb: ok\n")) free(mclcb); /* no TRACELVL any more from now on */ } /** * new_handler function. */ static void mcl_new_handler_func () { PRINT_ERR((mcl_stderr, "mcl_new_handler_func: Fatal error, exit everything...\n")) mcl_exit(-1); } /* * global mcl initialization * done only once */ static void mcl_glob_init () { #ifdef STDOUT_TO_FILE char stdout_name[MAX_FILE_NAME_LEN]; #endif ASSERT(mcl_glob_initialized == 0); mcl_glob_initialized = 1; set_new_handler(mcl_new_handler_func); strcat(mcl_tmp_dir_name, MCL_DEFAULT_TMP_DIR_NAME); #ifdef STDOUT_TO_FILE memset(stdout_name, 0, MAX_FILE_NAME_LEN); strncat(stdout_name, mcl_tmp_dir_name, MAX_FILE_NAME_LEN); strncat(stdout_name, "/mcl_out.txt", MAX_FILE_NAME_LEN); /* create temp file now in the tmp dir specified in mcl_tmp_dir_name */ #ifdef WIN32 if ((mcl_stdout = open(vcb->f_name, _O_RDWR | O_CREAT | O_BINARY)) < 0) { perror("mcl_glob_init: ERROR, cannot open mlc_out.trc file"); mcl_exit(-1); } #else if ((mcl_stdout = fopen(stdout_name, "w")) == NULL) { printf("error: cannot open %s\n", stdout_name); perror("mcl_glob_init: ERROR, cannot open mlc_out.trc file"); mcl_exit(-1); } #endif mcl_stderr = mcl_stdout; /* err is the same then */ #else /* STDOUT_TO_FILE */ mcl_stdout = stdout; mcl_stderr = stderr; #endif /* STDOUT_TO_FILE */ /* the session control block table */ memset(mclcbs, 0, MCLCB_MAX_ID * sizeof(mclcb_t*)); /* thread vs. thread vs. application lock; only one global lock */ mcl_init_lock(&mcl_mutex_lock); #ifdef WIN32 /* Socket initialisation for WinSock */ mcl_winsock_init(); #endif /* WIN32 */ /* * create the timer thread. * it will be shared by all MCL session. */ #ifdef WIN32 if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mcl_timer_thread, NULL, 0, (LPDWORD)&mcl_timer_thread_id) == NULL) { perror("mcl_init_timer: CreateThread"); mcl_exit(1); } #else if (pthread_create((pthread_t*)&mcl_timer_thread_id, NULL, mcl_timer_thread, (void*)NULL) != 0) { perror("mcl_init_timer: pthread_create"); mcl_exit(1); } #endif ASSERT(mcl_iss > 0); /* must be > 0 (0 means non initialized) */ }