Logo Search packages:      
Sourcecode: icecast-server version File versions  Download package

main.c

/* main.c
 * - Main Program *
 * Copyright (c) 1999 Jack Moffitt, Barath Raghavan, and Alexander Havšng
 *
 * 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.
 *
 */

/* Last overhauled: 000302 <eel@musiknet.se> */

#ifdef HAVE_CONFIG_H
#ifdef _WIN32
#include <win32config.h>
#else
#include <config.h>
#endif
#endif

#include "definitions.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "definitions.h"

#include <string.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>

#ifndef _WIN32
#include <sys/socket.h> 
#include <sys/wait.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
# ifdef TIME_WITH_SYS_TIME
#  include <sys/time.h>
# endif
#else
#include <winsock.h>
#endif

#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif

#include "avl.h"
#include "threads.h"
#include "icecast.h"
#include "icetypes.h"
#include "avl_functions.h"
#include "ice_resolv.h"
#include "sock.h"
#include "globals.h"
#include "directory.h"
#include "log.h"
#include "commands.h"
#include "logtime.h"
#include "main.h"
#include "utility.h"
#include "ice_string.h"
#include "commandline.h"
#include "admin.h"
#include "source.h"
#include "client.h"
#include "connection.h"
#include "threads.h"
#include "timer.h"
#include "memory.h"
#include "relay.h"
#include "authenticate/basic.h"
#include "pool.h"
#include "interpreter.h"

#ifndef _WIN32
#include <signal.h>
#endif

/* We need this for perror and for various sanity checks */
extern int errno;

/* Importing a tree and mutex from sock.c */
extern avl_tree *sock_sockets;
extern mutex_t sock_mutex;

/* This is global, doh! */
server_info_t info;
struct in_addr localaddr;

/* 
 * The world starts here.
 * - First initialize the run path and 
 *   some structures and mutex locks needed for
 *   debugging output and other nifty features. 
 * - Then set the default values for the info struct, which is basicly
 *   just a pot to keep all the server global variables in. The default
 *   values are taken from icecast.h
 * - Then trap some system signals so they don't interfere with the server
 *   and allocate some extra resources.
 * - Run sanity_check() to make sure everything is ok.
 * - Parse the configuration file (icecast.conf by default). This overrides
 *   any of the settings from icecast.h
 * - Parse the command line options, which in turn overrides the configuration
 *   file options.
 * - Initialize some network stuff
 * - Leave the rest to startup_mode()
 *
 * Assert Class: 1
 */

int 
main (int argc, char **argv)
{
      /* If defined, start the memory checker */
      initialize_memory_checker ();

      /* Setup run path and initialize memory debugging (if set) */
      set_run_path (argv);

      /* Initialize the system library mutex */
      thread_lib_init ();

      /* Need to create a new thread entry */
      init_thread_tree (__LINE__, __FILE__);
      
      /* Set all server variables to a default value */
      setup_defaults ();

      /* Trap some signals */
      setup_signal_traps ();

      /* Allocate client slots, admin slots, source slots, etc */
      allocate_resources ();

      /* Check for -d arguments, which will make us read the config file in another directory */
      parse_directory_args_only (argc, argv);

      /* Override the default values with the ones defined in this configfile */
      parse_default_config_file ();

      /* Override them again, with the values from the command line */
      parse_args (argc, argv);

      /* Initialize some platform dependant network stuff */
      initialize_network ();
      
      /* Initialize the interpreter (if configured) */
      interpreter_init ();

      /* Parse all authentication files */
      init_authentication_scheme (); 

      /* Make sure we can write to current directory, and other sanity checks */
      sanity_check ();

      /* Print header, select console mode, start the main loop */
      startup_mode (); /* Never returns */

      /* And we're done.. this will never happen */
      return 0;
}

/* A process can only open a certain number of filedescriptors (files/sockets),
   usually something like 64. We call setrlimit() and request a larger limit.
   If the kernel allows it it will increase the number of open file descriptors
   for this process. The kernel has a limit too, often set when you compile
   the kernel, or in /proc/sys/fs/file-max or something similar */
#ifndef _WIN32
void 
increase_maximum_number_of_open_files()
{
#if defined(HAVE_SETRLIMIT) && defined (HAVE_GETRLIMIT)
      struct rlimit before, after;
      
      if (getrlimit (RLIMIT_NOFILE, &before) == 0) {
            xa_debug (1, "DEBUG: Max number of open files: soft: %d hard: %d",
                    (int)before.rlim_cur, (int)before.rlim_max);
      } else {
            xa_debug (1, "WARNING: getrlimit() failed.");
            return;
      }

      after.rlim_cur = info.max_clients + info.max_sources + info.max_admins + 20;
      after.rlim_max = before.rlim_max > after.rlim_cur ? before.rlim_max : after.rlim_cur;
      
      if (setrlimit (RLIMIT_NOFILE, &after) == 0) 
      {
            xa_debug (1, "DEBUG: Max number of open files raised from: soft %d hard: %d, to soft: %d hard: %d", before.rlim_cur, before.rlim_max, after.rlim_cur, after.rlim_max);
      } else {
            write_log (LOG_DEFAULT, "ERROR: Increasing maximum number of open files from %d:%d to: %d:%d failed, try lowering the maximum values for listeners, admins, and sources.", before.rlim_cur, before.rlim_max, after.rlim_cur, after.rlim_max);
            write_log (LOG_DEFAULT, "WARNING: The server will run out of file descriptors before the reaching specified limits!");
      }
#endif
}
#endif

void 
initialize_network()
{
#ifdef _WIN32
      WSADATA wsad;
      
      /* Initialize Winsock*/
      WSAStartup(0x0101, &wsad);
#else
      /* On some systems, we need to increase the max number of open files. */
      increase_maximum_number_of_open_files();

      /* Create a tcp socket for DNS queries that stays open */
      sethostent(1);
#endif
}

/* Print header, select the console mode, and start the main server loop. */
void
startup_mode()
{
      /* Try to open the icecast log files */
      open_log_files();

      /* Write startup information in the log file, and print a nice header on stdout */
      write_icecast_header();
  
      /* Print some information available only in runtime */
      show_runtime_configuration();

      /* Set the running flag */
      running = SERVER_RUNNING;

      /* Select how the server should be started, i.e how we should use the console */
#ifdef _WIN32
      if ((info.console_mode == CONSOLE_ADMIN) || (info.console_mode == CONSOLE_ADMIN_TAIL)) 
      {
            add_icecast_console();
      } else {
            write_log(LOG_DEFAULT, "Using stdout as icecast logging window [%i]", info.console_mode);
      }
#else
      if (info.console_mode == CONSOLE_BACKGROUND) 
      {
            server_detach();
            info.detach = 1;
      } else if ((info.console_mode == CONSOLE_ADMIN) || (info.console_mode == CONSOLE_ADMIN_TAIL)) {
            add_icecast_console();
      } else {
            write_log(LOG_DEFAULT, "Using stdout as icecast logging window");
      }
#endif

      threaded_server_proc(&info); /* Never returns */
}

/* We need to trap some signals. 
   SIGCHLD to avoid zombies
   SIGHUP to close/open logfiles
   SIGINT, SIGTERM to close down cleanly.
*/
void 
setup_signal_traps()
{
      xa_debug (1, "DEBUG: Activating signal handler");

#ifdef _WIN32
      if (!SetConsoleCtrlHandler( win_sig_die, 1 ))
            write_log(LOG_DEFAULT, "FAILED setting up win32 signal handler");
#else
      
# if (defined(SYSV) && !defined(hpux)) || defined(SVR4)
#  define signal sigset
# endif
      
      signal(SIGHUP, (sighandler_t)sig_hup);
      signal(SIGINT, (sighandler_t)sig_die);
      signal(SIGTERM, (sighandler_t)sig_die);
      signal(SIGCHLD, (sighandler_t)sig_child);
      signal(SIGPIPE, SIG_IGN);
#endif
}

/* Set all global variables to their default values */
void 
setup_defaults()
{
      int i;

      xa_debug (1, "DEBUG: Setting up default values");

      info.consoledebuglevel = 0;
      info.logfiledebuglevel = 0;

#ifdef HAVE_UMASK
      {
        mode_t before, after = 022;
        before = umask(after);
        xa_debug(1, "DEBUG: Changed umask from %d to %d", before, after);
      }
#endif

      /* Create the data locking mutexes */
      thread_create_mutex(&info.double_mutex);
      thread_create_mutex(&info.source_mutex);
      thread_create_mutex(&info.admin_mutex);
      thread_create_mutex(&info.directory_mutex);
      thread_create_mutex(&info.misc_mutex);
      thread_create_mutex(&info.alias_mutex);
      thread_create_mutex(&info.mount_mutex);
      thread_create_mutex(&info.hostname_mutex);
      thread_create_mutex(&info.resolvmutex);
      thread_create_mutex(&info.relay_mutex);
      thread_create_mutex(&info.acl_mutex);

#ifdef DEBUG_SOCKETS
      thread_create_mutex(&sock_mutex);
#endif
      info.resolv_type = DEFAULT_RESOLV_TYPE;

      memset((void *)&localaddr, 0, sizeof (localaddr));

      /* Setup main thread */
      info.main_thread = thread_self();

      /* We're not detached */
      info.detach = 0;

      /* Default value for hostname reverse lookups */
      info.reverse_lookups = DEFAULT_LOOKUPS;

      /* Statistics */
      zero_stats(&info.daily_stats);
      zero_stats(&info.hourly_stats);
      zero_stats(&info.total_stats);

      /* Time settings to zero */
      info.directorylasttime = 0;
      info.udpupdatelasttime = 0;
      info.statslasttime = 0;
      info.server_start_time = get_time();
      info.statuslasttime = 0;

      info.mount_fallback = DEFAULT_MOUNT_FALLBACK;
      info.force_servername = DEFAULT_FORCE_SERVERNAME;

      info.throttle = (double)DEFAULT_THROTTLE;
      info.sleep_ratio = (double)DEFAULT_SLEEP_RATIO;
      info.throttle_on = 0;
      info.bandwidth_usage = 0;

      info.id = 0;

      info.policy = DEFAULT_ACL_POLICY;
      info.allow_http_admin = DEFAULT_ALLOW_HTTP_ADMIN;

      info.port[0] = DEFAULT_PORT;
      for (i = 1; i < MAXLISTEN; i++) {
            info.port[i] = 0;
      }

      info.streamtitle = nstrdup(DEFAULT_STREAM_TITLE);
      info.streamurl = nstrdup(DEFAULT_STREAM_URL);
      info.streamurllock = 0;
      info.streamtitletemplate = nstrdup (DEFAULT_STREAMTITLE_TEMPLATE);
      info.nametemplate = nstrdup (DEFAULT_NAME_TEMPLATE);
      info.descriptiontemplate = nstrdup (DEFAULT_DESC_TEMPLATE);

      info.metainterval = DEFAULT_METADATA_INTERVAL;
      info.use_meta_data = DEFAULT_USE_META_DATA;

      /* Variables that affect clients */
      info.num_clients = 0;
      info.max_clients = DEFAULT_MAX_CLIENTS;
      info.max_clients_per_source = DEFAULT_MAX_CLIENTS_PER_SOURCE;
      info.client_timeout = DEFAULT_CLIENT_TIMEOUT; /* How long to wait after lost encoder to kick clients */
      info.client_pass = nstrdup(DEFAULT_CLIENT_PASSWORD);

      /* Variables that affect sources */
      info.num_sources = 0;
      info.max_sources = DEFAULT_MAX_SOURCES;
      info.encoder_pass = nstrdup(DEFAULT_ENCODER_PASSWORD);
      info.default_sourceopts = nstrdup (DEFAULT_SOURCE_OPTS);

      /* Variables that affect admins */
      info.num_admins = 0;
      info.max_admins = DEFAULT_MAX_ADMINS;
      info.remote_admin_pass = nstrdup(DEFAULT_REMOTE_ADMIN_PASSWORD);

      /* Variables that affect directories */
      info.max_directories = DEFAULT_MAX_DIRECTORIES;
      info.touch_freq = DEFAULT_TOUCH_FREQ;
      info.udpupdatetime = DEFAULT_UDP_UPDATE_TIME;

      /* Variables that affect stats dumping */
      info.statsfilename = nstrdup(DEFAULT_STATSFILE);
      info.statshtmlfilename = nstrdup(DEFAULT_STATSHTMLFILE);
      info.statsfile = -1;
      info.statstime = DEFAULT_STATSTIME;
      info.statustime = DEFAULT_STATUSTIME;

      /* Other variables */
      info.console_mode = CONSOLE_ADMIN_TAIL;

      info.myhostname = NULL;
      info.server_name = nstrdup("localhost");
      info.prompt = nstrdup ("-> ");

      info.oper_pass = nstrdup(DEFAULT_OPER_PASSWORD);

      info.staticdir = nstrdup(DEFAULT_STATIC_DIR);

      if (!info.runpath) 
            fprintf (stderr, "WARNING: info.runpath == NULL!!\n");

      if (info.staticdir[0] != DIR_DELIMITER) {
            nfree(info.staticdir);
            info.staticdir = nmalloc(strlen(info.runpath) + strlen(DEFAULT_STATIC_DIR) + 1);
            strcpy(info.staticdir, info.runpath);
            strcat(info.staticdir, DEFAULT_STATIC_DIR);
      }
      info.logdir = nstrdup(DEFAULT_LOG_DIR);
      if (info.logdir[0] != DIR_DELIMITER) {
            nfree(info.logdir);
            info.logdir = nmalloc(strlen(info.runpath) + strlen(DEFAULT_LOG_DIR) + 1);
            strcpy(info.logdir, info.runpath);
            strcat(info.logdir, DEFAULT_LOG_DIR);
      }
      info.etcdir = nstrdup(DEFAULT_ETC_DIR);
      if (info.etcdir[0] != DIR_DELIMITER) {
            nfree(info.etcdir);
            info.etcdir = nmalloc(strlen(info.runpath) + strlen(DEFAULT_ETC_DIR) + 1);
            strcpy(info.etcdir, info.runpath);
            strcat(info.etcdir, DEFAULT_ETC_DIR);
      }
      info.templatedir = nstrdup(DEFAULT_TEMPLATE_DIR);
      if (info.templatedir[0] != DIR_DELIMITER) {
            nfree(info.templatedir);
            info.templatedir = nmalloc(strlen(info.runpath) + strlen(DEFAULT_TEMPLATE_DIR) + 1);
            strcpy(info.templatedir, info.runpath);
            strcat(info.templatedir, DEFAULT_TEMPLATE_DIR);
      }

      info.configfile = nstrdup(DEFAULT_CONFIG_FILE);
      info.userfile = nstrdup(DEFAULT_USER_FILE);
      info.mountfile = nstrdup(DEFAULT_MOUNT_FILE);
      info.groupfile = nstrdup(DEFAULT_GROUP_FILE);

      info.accessfilename = nstrdup(DEFAULT_ACCESS_FILE);
      info.accessfile = -1;
      
      info.usagefilename = nstrdup(DEFAULT_USAGE_FILE);
      info.usagefile = -1;

      info.logfilename = nstrdup(DEFAULT_LOGFILE);
      info.logfile = -1;
  
      /* Transparent proxy support? */
      info.transparent_proxy = DEFAULT_TRANSPARENT_PROXY;

      info.kick_relays = DEFAULT_KICK_RELAYS;
      info.relay_reconnect_time = DEFAULT_RELAY_RECONNECT_TIME;
      info.relay_reconnect_tries = DEFAULT_RELAY_RECONNECT_TRIES;
      info.kick_clients = DEFAULT_KICK_CLIENTS;

      /* Server meta info */
      info.location = nstrdup(DEFAULT_LOCATION);
      info.rp_email = nstrdup(DEFAULT_RP_EMAIL);
      info.server_url = nstrdup(DEFAULT_SERVER_URL);

      /* Point variables, bit of a mess */
      setup_config_file_settings(); 
      setup_admin_settings();
}

/* Allocate all the avl trees for admins, directory servers
   and sources, and make the admin settings point to the
   correct global values */
void 
allocate_resources()
{  
      xa_debug (1, "DEBUG: Allocating server resources");

      /* Allocate all the sources. */
      info.sources = avl_create(compare_connection, &info);

      /* Allocate all the admin slots */
      info.admins = avl_create(compare_connection, &info);
  
      /* Allocate all the directory servers */
      info.d_servers = avl_create(compare_directories, &info);

      /* And a tree of aliases */
      info.aliases = avl_create(compare_aliases, &info);

      /* And a tree of relays */
      info.relays = avl_create (compare_relays, &info);

      /* And a tree of hostnames that point to me */
      info.my_hostnames = avl_create(compare_strings, &info);

#ifdef DEBUG_SOCKETS
      sock_sockets = avl_create (compare_sockets, &info);
#endif

      info.all_acl = avl_create(compare_restricts, &info);
      info.admin_acl = avl_create(compare_restricts, &info);
      info.source_acl = avl_create(compare_restricts, &info);
      info.client_acl = avl_create(compare_restricts, &info);
      
      pool_init ();

      /* you might notice that the thread tree is not created here,
         this is on purpose :) */
      if (!info.sources || !info.relays || !info.admins || !info.d_servers || !info.threads || !info.aliases 
          || !info.my_hostnames) {
            fprintf(stderr, "Dammit, cannot allocate tree resources, exiting");
            clean_shutdown(&info);
      }

}

/* Shutdown server, make sure sockets are closed, free up the memory */
void 
clean_shutdown (server_info_t *info)
{
      connection_t *con;
      directory_server_t *ds;
      int i;
      avl_traverser trav = {0};
      static int main_shutting_down = 0;
      
      thread_library_lock ();
            if (!main_shutting_down)
                  main_shutting_down = 1;
            else
                  thread_exit (0);
      thread_library_unlock ();
      
      
      write_log(LOG_DEFAULT, "Cleanly shutting down...");
  
      write_log(LOG_DEFAULT, "Closing all listening sockets...");

      for (i = 0; i < MAXLISTEN; i++) 
      {
            if (sock_valid (info->listen_sock[i]))
                  sock_close(info->listen_sock[i]);
      }
      
      pool_shutdown ();

      interpreter_shutdown ();

      /* Try to kill some threads off */
      kill_threads();
      
      /* Close all remaining bloody sockets */
      sock_close_all_sockets ();

      /* Wait for the last mad threads to die  */
      thread_wait_for_solitude ();

      write_log(LOG_DEFAULT, "Closing and removing directory servers...");
      
      thread_mutex_lock(&info->directory_mutex);
      while ((ds = avl_get_any_node(info->d_servers)))
            close_directory(ds, &info);
      thread_mutex_unlock(&info->directory_mutex);
      
      thread_mutex_lock(&info->source_mutex);

      write_log(LOG_DEFAULT, "Removing remaining sources...");
      while ((con = avl_traverse(info->sources, &trav)))
            kick_connection(con, "Server shutting down");

      thread_mutex_unlock(&info->source_mutex);

      zero_trav(&trav);

#ifdef _WIN32
      /* Cleanup Winsock */
      WSACleanup();
#endif

      write_log(LOG_DEFAULT, "Exiting..");
      if (info->logfile != -1)
            fd_close(info->logfile);
      
#ifdef DEBUG_MEMORY
      /* Check if any other threads left some shit behind */
      {
            meminfo_t *mi;
            avl_traverser trav = {0};
            
            while ((mi = avl_traverse(info->mem, &trav))) {
                  if (mi->thread_id != 0 && mi->thread_id != -1)
                        write_log(LOG_DEFAULT, "WARNING: %d bytes allocated by thread %d at line %d in %s not freed before thread exit", mi->size, mi->thread_id, mi->line, mi->file);
            }
      }
#endif
      
      exit(0);
}

/* Main server loop, listen to the specified socket for new
 * connections, and immediately spawn a new thread for each
 * new connection */
void *
threaded_server_proc (void *infoarg)
{
      connection_t *con;
      mythread_t *mt = thread_get_mythread ();

      write_log(LOG_DEFAULT, "Starting main connection handler...");
  
      /* Setup listeners */
      setup_listeners();

      /* Just print some runtime server info */
      print_startup_server_info();

      write_log (LOG_DEFAULT, "Starting Calender Thread...");
      /* Fork another thread that handles stats dumping, directory servers and other time based stuff */
      thread_create("Calendar Thread", startup_timer_thread, NULL);
      
      /* 
       * And one heartbeat thread that should never have to do anything, but
       * will unlock mutexes when locked for more than MAX_MUTEX_LOCKTIME seconds.
       * This is currently disabled, until we find a better way to do this :)
       *
         thread_create("Heartbeat Thread", startup_heartbeat_thread, NULL);
      */

      /* And one to update udp info on clients */
      write_log (LOG_DEFAULT, "Starting UDP handler thread...");
      thread_create("UDP Handler Thread", startup_udp_info_thread, NULL);

      /* And one to connect and reconnect relays */
      write_log (LOG_DEFAULT, "Starting relay connector thread...");

      thread_create("Relay Connector Thread", startup_relay_connector_thread, NULL);

      while (running == SERVER_RUNNING) 
      {
            /* Try to get a new connection */
            con = get_connection(info.listen_sock); 
            
            if (con) {
                  /* Ok, we got one, handle it in a new thread */
                  thread_create("Connection Handler", handle_connection, (void *)con);
            }
            
            if (mt->ping == 1)
                  mt->ping = 0;
      }
  
      /* I guess the user pressed ^C */
      clean_shutdown(&info);

      return NULL;
}

#ifdef _WIN32

BOOL WINAPI 
win_sig_die(DWORD CtrlType)
{
      write_log(LOG_DEFAULT, "Caught signal %d, perhaps someone is at the door?", CtrlType);
      running = SERVER_DYING;
      return 1;
}

#else /* others */

RETSIGTYPE 
sig_child(int signo)
{
      pid_t pid;
      int stat;
  
      pid = wait(&stat);
#ifdef __linux__
      signal(SIGCHLD, (sighandler_t)sig_child);
#endif
      return (RETSIGTYPE)0;
}

RETSIGTYPE 
sig_hup(int signo)
{
      parse_default_config_file();
      open_log_files();
      
      write_log(LOG_DEFAULT, "Caught SIGHUP, rehashed config and reopened logfiles...");
      
/* This might not be necessary on all systems, but I doubt it will hurt anyone */
      signal(SIGHUP, (sighandler_t)sig_hup);
      return (RETSIGTYPE)0;
}

RETSIGTYPE 
sig_die(int signo)
{
      write_log(LOG_DEFAULT, "Caught signal %d, perhaps someone is at the door?", signo);
      running = SERVER_DYING;
      return (RETSIGTYPE)0;
}

RETSIGTYPE 
sig_die_hard(int signo)
{
      printf("Caught signal %d, shutting down!\n", signo);
      exit(1);
}

#endif /* sig stuff */

/* 
 * Create and listen to the specified ports, 
 * find out local ip if dynamic,
 * make sure the server name is resolvable 
 */
void 
setup_listeners()
{
      int i;

      for (i = 0; i < MAXLISTEN; i++)
            info.listen_sock[i] = INVALID_SOCKET;

      /* Create the socket, on the correct hostname or INADDR_ANY and bind it to the port. */
      for (i = 0; i < MAXLISTEN; i++) 
      {
            if (info.port[i] <= 0) {
                  info.port[i] = INVALID_SOCKET;
                  continue;
            }

            info.listen_sock[i] = sock_get_server_socket(info.port[i]);
  
            if (info.listen_sock[i] == INVALID_SOCKET) 
            {
                  write_log(LOG_DEFAULT, "ERROR: Could not listen to port %d. Perhaps another process is using it?", info.port[i]);
                  clean_shutdown(&info);
            }

            /* Set the socket to nonblocking */
            sock_set_blocking(info.listen_sock[i], SOCK_NONBLOCK);

            if (listen(info.listen_sock[i], LISTEN_QUEUE) == SOCKET_ERROR) 
            {
                  write_log(LOG_DEFAULT, "Could not listen for clients on port %d", info.port[i]);
                  clean_shutdown(&info);
            } 
      }
      
      if (ice_strcasecmp(info.server_name, "dynamic") == 0) 
      {
            info.server_name = sock_get_local_ipaddress();
            write_log(LOG_DEFAULT, "Dynamic server name, using the local ip [%s]", info.server_name);
      } else {
            char *res, *buf = (char *)nmalloc(20);
            res = forward(info.server_name, buf);
            if (!res) {
                  nfree(buf);
                  write_log(LOG_DEFAULT, "WARNING: Resolving the server name [%s] does not work!", info.server_name);
                  return;
            }
            
            thread_mutex_lock(&info.hostname_mutex);
            
            avl_insert(info.my_hostnames, info.server_name);
            avl_insert(info.my_hostnames, res);
            
            thread_mutex_unlock(&info.hostname_mutex);
      }
}




Generated by  Doxygen 1.6.0   Back to index