Exemplo n.º 1
0
void *source_client_thread (void *arg)
{
    source_t *source = arg;
    const char ok_msg[] = "HTTP/1.0 200 OK\r\n\r\n";
    int bytes;

    source->client->respcode = 200;
    bytes = sock_write_bytes (source->client->con->sock, ok_msg, sizeof (ok_msg)-1);
    if (bytes < sizeof (ok_msg)-1)
    {
        global_lock();
        global.sources--;
        global_unlock();
        WARN0 ("Error writing 200 OK message to source client");
    }
    else
    {
        source->client->con->sent_bytes += bytes;

        stats_event_inc(NULL, "source_client_connections");
        source_main (source);
    }
    source_free_source (source);
    return NULL;
}
Exemplo n.º 2
0
static int connection_client_setup (connection_queue_t *node) {
    int err;

    err = -ENOENT;
    if (node->con->con_timeout <= time(NULL))
        return err;

    global_lock();
    err = client_create (&node->client, node->con, node->parser);
    if (err < 0)
        goto out_fail;

    if (sock_set_blocking (node->con->sock, 0) || sock_set_nodelay (node->con->sock)) {
        if (! sock_recoverable(sock_error())) {
            node->con->error = 1;
            err = -EINVAL;
            goto out_fail;
        }
        err = -EINPROGRESS;
        client_send_403 (node->client, "failed to set tcp options on client connection, dropping");
        goto out_fail;
    }
    global_unlock();

    return 0;

out_fail:
    global_unlock();
    return err;
}
Exemplo n.º 3
0
void source_client_callback (client_t *client, void *arg)
{
    const char *agent;
    source_t *source = arg;
    refbuf_t *old_data = client->refbuf;

    if (client->con->error)
    {
        global_lock();
        global.sources--;
        global_unlock();
        source_clear_source (source);
        source_free_source (source);
        return;
    }
    client->refbuf = old_data->associated;
    old_data->associated = NULL;
    refbuf_release (old_data);
    stats_event (source->mount, "source_ip", source->client->con->ip);
    agent = httpp_getvar (source->client->parser, "user-agent");
    if (agent)
        stats_event (source->mount, "user_agent", agent);

    thread_create ("Source Thread", source_client_thread,
            source, THREAD_DETACHED);
}
Exemplo n.º 4
0
/**
 * Returns a process-specific fmutex used to guard OS/2 TCP/IP DLL calls.
 * This mutex must be used to provide thread safety where it (or reentrancy)
 * is guaranteed by the respective API. Note that we assume that TCP/IP DLL
 * calls are process safe and process-reentrant and thus only guarantee thread
 * safety within a single process.
 */
_fmutex *global_tcpip_sem()
{
  _fmutex *fsem = NULL;

  global_lock();

  ProcDesc *proc = find_proc_desc(getpid());

  ASSERT(proc);

  if (proc->tcpip_fsem.hev == NULLHANDLE)
  {
    /*
     * Lazily create the mutex. Note that we never destroy it as
     * process-specific ones will be freed automatically on process termination
     */
    int rc = _fmutex_create(&proc->tcpip_fsem, 0);
    ASSERT(!rc);
  }

  fsem = &proc->tcpip_fsem;

  global_unlock();

  return fsem;
}
Exemplo n.º 5
0
  void stat_finish_thread() {
    assert(THREAD_STATS.initialized);
    assert(GLOBAL_STATS.initialized);

    std::unique_lock<std::mutex> global_lock(GLOBAL_STATS_MUTEX);
    for(uint32_t i = 0; i < _COUNTER_END; ++i) {
      GLOBAL_STATS.counters.at(i) += THREAD_STATS.counters.at(i);
    }
    for(uint32_t i = 0; i < _DISTRIB_INT_END; ++i) {
      auto& glob = GLOBAL_STATS.distrib_ints.at(i);
      auto& thrd = THREAD_STATS.distrib_ints.at(i);
      glob.count += thrd.count;
      glob.sum += thrd.sum;
      glob.sum_squares += thrd.sum_squares;
      glob.min = std::min(glob.min, thrd.min);
      glob.max = std::max(glob.max, thrd.max);
    }
    for(uint32_t i = 0; i < _TIMER_END; ++i) {
      auto& glob = GLOBAL_STATS.distrib_times.at(i);
      auto& thrd = THREAD_STATS.distrib_times.at(i);
      glob.total_count += thrd.total_count;
      glob.sampled_count += thrd.sampled_count;
      glob.sum_ns += thrd.sum_ns;
      glob.sum_squares_ns += thrd.sum_squares_ns;
      glob.sum_overhead_ns += thrd.sum_overhead_ns;
      glob.min_ns = std::min(glob.min_ns, thrd.min_ns);
      glob.max_ns = std::max(glob.max_ns, thrd.max_ns);
    }

    THREAD_STATS.initialized = false;
  }
Exemplo n.º 6
0
static int 
set_seq_contains(intset_t *set, val_t val) 
{
  int result;

  node_t prev, next;

#ifdef LOCKS
  global_lock();
#endif

  /* We have at least 2 elements */
  LOAD_NODE(prev, set->head);
  LOAD_NODE(next, ND(prev.next));
  while (next.val < val) 
    {
      prev.next = next.next;
      LOAD_NODE(next, ND(prev.next));
    }

  result = (next.val == val);

#ifdef LOCKS
  global_lock_release();
#endif

  return result;
}
Exemplo n.º 7
0
void connection_release_banned_ip (const char *ip)
{
    if (banned_ip.contents)
    {
        global_lock();
        avl_delete (banned_ip.contents, (void*)ip, cache_treenode_free);
        global_unlock();
    }
}
Exemplo n.º 8
0
int fserve_client_create(client_t *httpclient, char *path)
{
    fserve_t *client = calloc(1, sizeof(fserve_t));
    int bytes;
    int client_limit;
    ice_config_t *config = config_get_config();

    client_limit = config->client_limit;
    config_release_config();

    client->file = fopen(path, "rb");
    if(!client->file) {
        client_send_404(httpclient, "File not readable");
        return -1;
    }

    client->client = httpclient;
    client->offset = 0;
    client->datasize = 0;
    client->ready = 0;
    client->buf = malloc(BUFSIZE);

    global_lock();
    if(global.clients >= client_limit) {
        httpclient->respcode = 504;
        bytes = sock_write(httpclient->con->sock,
                "HTTP/1.0 504 Server Full\r\n"
                "Content-Type: text/html\r\n\r\n"
                "<b>Server is full, try again later.</b>\r\n");
        if(bytes > 0) httpclient->con->sent_bytes = bytes;
        fserve_client_destroy(client);
        global_unlock();
        return -1;
    }
    global.clients++;
    global_unlock();

    httpclient->respcode = 200;
    bytes = sock_write(httpclient->con->sock,
            "HTTP/1.0 200 OK\r\n"
            "Content-Type: %s\r\n\r\n",
            fserve_content_type(path));
    if(bytes > 0) httpclient->con->sent_bytes = bytes;

    sock_set_blocking(client->client->con->sock, SOCK_NONBLOCK);
    sock_set_nodelay(client->client->con->sock);

    thread_mutex_lock (&pending_lock);
    client->next = (fserve_t *)pending_list;
    pending_list = client;
    thread_mutex_unlock (&pending_lock);

    return 0;
}
Exemplo n.º 9
0
void client_destroy(client_t *client)
{
    if (client == NULL)
        return;

    if (client->worker)
    {
        WARN0 ("client still on worker thread");
        return;
    }
    /* release the buffer now, as the buffer could be on the source queue
     * and may of disappeared after auth completes */
    if (client->refbuf)
    {
        refbuf_release (client->refbuf);
        client->refbuf = NULL;
    }

    if (client->flags & CLIENT_AUTHENTICATED)
        DEBUG1 ("client still in auth \"%s\"", httpp_getvar (client->parser, HTTPP_VAR_URI));

    /* write log entry if ip is set (some things don't set it, like outgoing 
     * slave requests
     */
    if (client->respcode > 0 && client->parser)
        logging_access(client);

    if (client->flags & CLIENT_IP_BAN_LIFT)
    {
        INFO1 ("lifting IP ban on client at %s", client->connection.ip);
        connection_release_banned_ip (client->connection.ip);
        client->flags &= ~CLIENT_IP_BAN_LIFT;
    }

    connection_close (&client->connection);
    if (client->parser)
        httpp_destroy (client->parser);

    global_lock ();
    global.clients--;
    stats_event_args (NULL, "clients", "%d", global.clients);
    config_clear_listener (client->server_conn);
    global_unlock ();

    /* we need to free client specific format data (if any) */
    if (client->free_client_data)
        client->free_client_data (client);

    free(client->username);
    free(client->password);

    free(client);
}
Exemplo n.º 10
0
static int do_test(void)
{
  int rc;
  _HEAPSTATS hst;
  size_t hdr_size;

  global_lock();

  rc = _ustats(gpData->heap, &hst);
  if (rc)
  {
    perror("_ustats failed");
    return 1;
  }

  if (hst._provided > gpData->size)
  {
    printf("Total heap size %d is greater than committed size %d\n",
           hst._provided, gpData->size);
    return 1;
  }

  hdr_size = gpData->size - hst._provided;

  printf("hdr_size %u\n", hdr_size);

  check_mem(1, hdr_size, 65536);

  void *data = global_alloc(32000);

  check_mem(2, hdr_size, 65536);

  void *data2 = global_alloc(5000);

  check_mem(3, hdr_size, 65536);

  void *data3 = global_alloc(5000);

  check_mem(4, hdr_size, 65536);

  void *data4 = global_alloc(50000);

  check_mem(5, hdr_size, 65536 * 2);

  free(data4);
  free(data3);
  free(data2);
  free(data);

  global_unlock();

  return 0;
}
Exemplo n.º 11
0
static int _free_client(void *key)
{
    fserve_t *client = (fserve_t *)key;

    fserve_client_destroy(client);
    global_lock();
    global.clients--;
    global_unlock();
    stats_event_dec(NULL, "clients");

    
    return 1;
}
Exemplo n.º 12
0
void connection_add_banned_ip (const char *ip, int duration)
{
    time_t timeout = 0;
    if (duration > 0)
        timeout = time(NULL) + duration;

    if (banned_ip.contents)
    {
        global_lock();
        add_banned_ip (&banned_ip, ip, timeout);
        global_unlock();
    }
}
Exemplo n.º 13
0
static void source_shutdown (source_t *source)
{
    mount_proxy *mountinfo;

    source->running = 0;
    INFO1("Source \"%s\" exiting", source->mount);

    mountinfo = config_find_mount (config_get_config(), source->mount);
    if (mountinfo)
    {
        if (mountinfo->on_disconnect)
            source_run_script (mountinfo->on_disconnect, source->mount);
        auth_stream_end (mountinfo, source->mount);
    }
    config_release_config();

    /* we have de-activated the source now, so no more clients will be
     * added, now move the listeners we have to the fallback (if any)
     */
    if (source->fallback_mount)
    {
        source_t *fallback_source;

        avl_tree_rlock(global.source_tree);
        fallback_source = source_find_mount (source->fallback_mount);

        if (fallback_source != NULL)
            source_move_clients (source, fallback_source);

        avl_tree_unlock (global.source_tree);
    }

    /* delete this sources stats */
    stats_event(source->mount, NULL, NULL);

    /* we don't remove the source from the tree here, it may be a relay and
       therefore reserved */
    source_clear_source (source);

    global_lock();
    global.sources--;
    stats_event_args (NULL, "sources", "%d", global.sources);
    global_unlock();

    /* release our hold on the lock so the main thread can continue cleaning up */
    thread_rwlock_unlock(source->shutdown_rwlock);
}
Exemplo n.º 14
0
static int relay_install (relay_server *relay)
{
    client_t *client = calloc (1, sizeof (client_t));

    connection_init (&client->connection, SOCK_ERROR, NULL);
    global_lock();
    client_register (client);
    global_unlock();
    client->shared_data = relay;
    client->ops = &relay_init_ops;

    client->flags |= CLIENT_ACTIVE;
    DEBUG1 ("adding relay client for %s", relay->localmount);
    client_add_worker (client);

    return 0;
}
Exemplo n.º 15
0
static int 
set_seq_add(intset_t* set, val_t val) 
{
  int result;
  node_t prev, nnext;
#ifdef LOCKS
  global_lock();
#endif

  nxt_t to_store = OF(set->head);

  /* int seq = 0; */
  node_t* hd = set->head;
  LOAD_NODE(prev, hd);

  /* PRINT("%3d   LOAD: head: %10lu   val: %10ld   %d", seq++, to_store, prev.val, prev.next); */
  node_t* nd = ND(prev.next);
  LOAD_NODE(nnext, nd);
  /* PRINT("%3d   LOAD: addr: %10d   val: %10ld   %d", seq++, prev.next, nnext.val, nnext.next); */

  while (nnext.val < val) 
    {
      to_store = prev.next;
      prev.val = nnext.val;
      prev.next = nnext.next;
      node_t* nd = ND(prev.next);
      LOAD_NODE(nnext, nd);
      /* PRINT("%3d   LOAD: addr: %10lu   val: %10ld   %d", seq++, prev.next, nnext.val, nnext.next); */
    }
  result = (nnext.val != val);
  if (result) 
    {
      node_t *nn = new_node(val, prev.next, 0);
      prev.next = OF(nn);
      node_t* nd = ND(to_store);
      NONTX_STORE(nd, prev.to_int64, TYPE_INT);
      /* PRINT("%3d  STORE: addr: %10lu   val: %10ld   %d", seq++, to_store, prev.val, prev.next); */
    }

#ifdef LOCKS
  global_lock_release();
#endif

  return result;
}
Exemplo n.º 16
0
/* return 0 if the passed ip address is not to be handled by icecast, non-zero otherwise */
static int accept_ip_address (char *ip)
{
    cachefile_timecheck = time (NULL);
    global_lock();

    if (search_banned_ip (ip) > 0)
    {
        global_unlock();
        DEBUG1 ("%s banned", ip);
        return 0;
    }
    global_unlock();
    if (search_cached_pattern (&allowed_ip, ip) == 0)
    {
        DEBUG1 ("%s is not allowed", ip);
        return 0;
    }
    return 1;
}
Exemplo n.º 17
0
void client_destroy(client_t *client)
{
    if (client == NULL)
        return;

    /* release the buffer now, as the buffer could be on the source queue
     * and may of disappeared after auth completes */
    if (client->refbuf)
    {
        refbuf_release (client->refbuf);
        client->refbuf = NULL;
    }

    if (auth_release_listener (client))
        return;

    /* write log entry if ip is set (some things don't set it, like outgoing 
     * slave requests
     */
    if (client->respcode && client->parser)
        logging_access(client);

    if (client->con)
        connection_close(client->con);
    if (client->parser)
        httpp_destroy(client->parser);

    global_lock ();
    global.clients--;
    stats_event_args (NULL, "clients", "%d", global.clients);
    global_unlock ();

    /* we need to free client specific format data (if any) */
    if (client->free_client_data)
        client->free_client_data (client);

    free(client->username);
    free(client->password);

    free(client);
}
Exemplo n.º 18
0
/**
 * Prints LIBCx version and memory usage statistics to stdout.
 */
void print_stats()
{
  int rc;
  _HEAPSTATS hst;

  printf("LIBCx version: " VERSION_MAJ_MIN_BLD LIBCX_DEBUG_SUFFIX LIBCX_DEV_SUFFIX "\n");

  {
    char name[CCHMAXPATH] = {0};
    get_module_name(name, sizeof(name));
    printf("LIBCx module:  %s\n", name);
  }

  global_lock();

  char buf[StatsBufSize];
  format_stats(buf, sizeof(buf));
  fputs(buf, stdout);

  global_unlock();
}
Exemplo n.º 19
0
void client_destroy(client_t *client)
{
    if (client == NULL)
        return;

    if (release_client (client))
        return;

    /* write log entry if ip is set (some things don't set it, like outgoing 
     * slave requests
     */
    if (client->respcode && client->parser)
        logging_access(client);
    
    if (client->con)
        connection_close(client->con);
    if (client->parser)
        httpp_destroy(client->parser);

    global_lock ();
    global.clients--;
    stats_event_args (NULL, "clients", "%d", global.clients);
    global_unlock ();

    /* drop ref counts if need be */
    if (client->refbuf)
        refbuf_release (client->refbuf);

    /* we need to free client specific format data (if any) */
    if (client->free_client_data)
        client->free_client_data (client);

    free(client->username);
    free(client->password);

    free(client);
}
Exemplo n.º 20
0
static void source_shutdown (source_t *source)
{
    source->running = 0;
    INFO1("Source \"%s\" exiting", source->mount);

    /* we have de-activated the source now, so no more clients will be
     * added, now move the listeners we have to the fallback (if any)
     */
    if (source->fallback_mount)
    {
        source_t *fallback_source;

        avl_tree_rlock(global.source_tree);
        fallback_source = source_find_mount (source->fallback_mount);

        if (fallback_source != NULL)
            source_move_clients (source, fallback_source);

        avl_tree_unlock (global.source_tree);
    }

    /* delete this sources stats */
    stats_event_dec(NULL, "sources");
    stats_event(source->mount, NULL, NULL);

    /* we don't remove the source from the tree here, it may be a relay and
       therefore reserved */
    source_clear_source (source);

    global_lock();
    global.sources--;
    global_unlock();

    /* release our hold on the lock so the main thread can continue cleaning up */
    thread_rwlock_unlock(source->shutdown_rwlock);
}
Exemplo n.º 21
0
void client_destroy(client_t *client)
{
    if (client == NULL)
        return;

    if (client->worker)
    {
        WARN0 ("client still on worker thread");
        return;
    }
    /* release the buffer now, as the buffer could be on the source queue
     * and may of disappeared after auth completes */
    if (client->refbuf)
    {
        refbuf_release (client->refbuf);
        client->refbuf = NULL;
    }

    if (client->flags & CLIENT_AUTHENTICATED)
        DEBUG1 ("client still in auth \"%s\"", httpp_getvar (client->parser, HTTPP_VAR_URI));

    /* write log entry if ip is set (some things don't set it, like outgoing 
     * slave requests
     */
    if (client->respcode > 0 && client->parser)
        logging_access(client);

    if (client->flags & CLIENT_IP_BAN_LIFT)
    {
        INFO1 ("lifting IP ban on client at %s", client->connection.ip);
        connection_release_banned_ip (client->connection.ip);
        client->flags &= ~CLIENT_IP_BAN_LIFT;
    }

    if (client->parser)
        httpp_destroy (client->parser);

    /* we need to free client specific format data (if any) */
    if (client->free_client_data)
        client->free_client_data (client);

    free(client->username);
    free(client->password);
    client->username = NULL;
    client->password = NULL;
    client->parser = NULL;
    client->respcode = 0;
    client->free_client_data = NULL;

    global_lock ();
    if (global.running != ICE_RUNNING || client->connection.error ||
            (client->flags & CLIENT_KEEPALIVE) == 0 || client_connected (client) == 0)
    {
        global.clients--;
        stats_event_args (NULL, "clients", "%d", global.clients);
        config_clear_listener (client->server_conn);
        global_unlock ();
        connection_close (&client->connection);

        free(client);
        return;
    }
    global_unlock ();
    DEBUG0 ("keepalive detected, placing back onto worker");
    client->counter = client->schedule_ms = timing_get_time();
    client->connection.con_time = client->schedule_ms/1000;
    client->connection.discon.time = client->connection.con_time + 7;
    client->ops = &http_request_ops;
    client->flags = CLIENT_ACTIVE;
    client->shared_data = NULL;
    client->refbuf = NULL;
    client->pos = 0;
    client->intro_offset = client->connection.sent_bytes = 0;
    client_add_worker (client);
}
Exemplo n.º 22
0
static client_t *accept_client (void)
{
    client_t *client = NULL;
    sock_t sock, serversock = wait_for_serversock ();
    char addr [200];

    if (serversock == SOCK_ERROR)
        return NULL;

    sock = sock_accept (serversock, addr, 200);
    if (sock == SOCK_ERROR)
    {
        if (sock_recoverable (sock_error()))
            return NULL;
        WARN2 ("accept() failed with error %d: %s", sock_error(), strerror(sock_error()));
        thread_sleep (500000);
        return NULL;
    }
    do
    {
        int i, num;
        refbuf_t *r;

        if (sock_set_blocking (sock, 0) || sock_set_nodelay (sock))
        {
            WARN0 ("failed to set tcp options on client connection, dropping");
            break;
        }
        client = calloc (1, sizeof (client_t));
        if (client == NULL || connection_init (&client->connection, sock, addr) < 0)
            break;

        client->shared_data = r = refbuf_new (PER_CLIENT_REFBUF_SIZE);
        r->len = 0; // for building up the request coming in

        global_lock ();
        client_register (client);

        for (i=0; i < global.server_sockets; i++)
        {
            if (global.serversock[i] == serversock)
            {
                client->server_conn = global.server_conn[i];
                client->server_conn->refcount++;
                if (client->server_conn->ssl && ssl_ok)
                    connection_uses_ssl (&client->connection);
                if (client->server_conn->shoutcast_compat)
                    client->ops = &shoutcast_source_ops;
                else
                    client->ops = &http_request_ops;
                break;
            }
        }
        num = global.clients;
        global_unlock ();
        stats_event_args (NULL, "clients", "%d", num);
        client->flags |= CLIENT_ACTIVE;
        return client;
    } while (0);

    free (client);
    sock_close (sock);
    return NULL;
}
Exemplo n.º 23
0
void connection_accept_loop(void)
{
    connection_t *con;

    if (!kitsune_is_updating()) /**DSU control */
        tid = thread_create("connection thread", _handle_connection, NULL, THREAD_ATTACHED);

    while (global.running == ICE_RUNNING)
    {
      kitsune_update("connection_accept"); /**DSU updatepoint */

        con = _accept_connection();

        if (con)
        {
            client_queue_t *node;
            ice_config_t *config;
            int i;
            client_t *client = NULL;

            global_lock();
            if (client_create (&client, con, NULL) < 0)
            {
                global_unlock();
                client_send_404 (client, "Icecast connection limit reached");
                continue;
            }
            global_unlock();

            /* setup client for reading incoming http */
            client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000';

            node = calloc (1, sizeof (client_queue_t));
            if (node == NULL)
            {
                client_destroy (client);
                continue;
            }
            node->client = client;

            /* Check for special shoutcast compatability processing */
            config = config_get_config();
            for (i = 0; i < global.server_sockets; i++)
            {
                if (global.serversock[i] == con->serversock)
                {
                    if (config->listeners[i].shoutcast_compat)
                        node->shoutcast = 1;
                }
            }
            config_release_config(); 

            sock_set_blocking (client->con->sock, SOCK_NONBLOCK);
            sock_set_nodelay (client->con->sock);

            _add_request_queue (node);
            stats_event_inc (NULL, "connections");
        }
        process_request_queue ();
    }

    /* Give all the other threads notification to shut down */
    thread_cond_broadcast(&global.shutdown_cond);

    if (tid)
        thread_join (tid);

    /* wait for all the sources to shutdown */
    thread_rwlock_wlock(&_source_shutdown_rwlock);
    thread_rwlock_unlock(&_source_shutdown_rwlock);
}
Exemplo n.º 24
0
/* Actually open the connection and do some http parsing, handle any 302
 * responses within here.
 */
static client_t *open_relay_connection (relay_server *relay)
{
    int redirects = 0;
    char *server_id = NULL;
    ice_config_t *config;
    http_parser_t *parser = NULL;
    connection_t *con=NULL;
    char *server = strdup (relay->server);
    char *mount = strdup (relay->mount);
    int port = relay->port;
    char *auth_header;
    char header[4096];

    config = config_get_config ();
    server_id = strdup (config->server_id);
    config_release_config ();

    /* build any authentication header before connecting */
    if (relay->username && relay->password)
    {
        char *esc_authorisation;
        unsigned len = strlen(relay->username) + strlen(relay->password) + 2;

        auth_header = malloc (len);
        snprintf (auth_header, len, "%s:%s", relay->username, relay->password);
        esc_authorisation = util_base64_encode(auth_header, len);
        free(auth_header);
        len = strlen (esc_authorisation) + 24;
        auth_header = malloc (len);
        snprintf (auth_header, len,
                "Authorization: Basic %s\r\n", esc_authorisation);
        free(esc_authorisation);
    }
    else
        auth_header = strdup ("");

    while (redirects < 10)
    {
        sock_t streamsock;

        ICECAST_LOG_INFO("connecting to %s:%d", server, port);

        streamsock = sock_connect_wto_bind (server, port, relay->bind, 10);
        if (streamsock == SOCK_ERROR)
        {
            ICECAST_LOG_WARN("Failed to connect to %s:%d", server, port);
            break;
        }
        con = connection_create (streamsock, -1, strdup (server));

        /* At this point we may not know if we are relaying an mp3 or vorbis
         * stream, but only send the icy-metadata header if the relay details
         * state so (the typical case).  It's harmless in the vorbis case. If
         * we don't send in this header then relay will not have mp3 metadata.
         */
        sock_write(streamsock, "GET %s HTTP/1.0\r\n"
                "User-Agent: %s\r\n"
                "Host: %s\r\n"
                "%s"
                "%s"
                "\r\n",
                mount,
                server_id,
                server,
                relay->mp3metadata?"Icy-MetaData: 1\r\n":"",
                auth_header);
        memset (header, 0, sizeof(header));
        if (util_read_header (con->sock, header, 4096, READ_ENTIRE_HEADER) == 0)
        {
            ICECAST_LOG_ERROR("Header read failed for %s (%s:%d%s)", relay->localmount, server, port, mount);
            break;
        }
        parser = httpp_create_parser();
        httpp_initialize (parser, NULL);
        if (! httpp_parse_response (parser, header, strlen(header), relay->localmount))
        {
            ICECAST_LOG_ERROR("Error parsing relay request for %s (%s:%d%s)", relay->localmount,
                    server, port, mount);
            break;
        }
        if (strcmp (httpp_getvar (parser, HTTPP_VAR_ERROR_CODE), "302") == 0)
        {
            /* better retry the connection again but with different details */
            const char *uri, *mountpoint;
            int len;

            uri = httpp_getvar (parser, "location");
            ICECAST_LOG_INFO("redirect received %s", uri);
            if (strncmp (uri, "http://", 7) != 0)
                break;
            uri += 7;
            mountpoint = strchr (uri, '/');
            free (mount);
            if (mountpoint)
                mount = strdup (mountpoint);
            else
                mount = strdup ("/");

            len = strcspn (uri, ":/");
            port = 80;
            if (uri [len] == ':')
                port = atoi (uri+len+1);
            free (server);
            server = calloc (1, len+1);
            strncpy (server, uri, len);
            connection_close (con);
            httpp_destroy (parser);
            con = NULL;
            parser = NULL;
        }
        else
        {
            client_t *client = NULL;

            if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE))
            {
                ICECAST_LOG_ERROR("Error from relay request: %s (%s)", relay->localmount,
                        httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
                break;
            }
            global_lock ();
            if (client_create (&client, con, parser) < 0)
            {
                global_unlock ();
                /* make sure only the client_destory frees these */
                con = NULL;
                parser = NULL;
                client_destroy (client);
                break;
            }
            global_unlock ();
            sock_set_blocking (streamsock, 0);
            client_set_queue (client, NULL);
            free (server);
            free (mount);
            free (server_id);
            free (auth_header);

            return client;
        }
        redirects++;
    }
    /* failed, better clean up */
    free (server);
    free (mount);
    free (server_id);
    free (auth_header);
    if (con)
        connection_close (con);
    if (parser)
        httpp_destroy (parser);
    return NULL;
}
Exemplo n.º 25
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config = config_get_config();

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    if (global.sources < config->source_limit)
    {
        char *contenttype;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                global_unlock();
                config_release_config();
                if (response)
                {
                    client_send_404 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_404 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount);
        if (mountinfo == NULL)
            source_update_settings (config, source, mountinfo);
        source_recheck_mounts ();
        config_release_config();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_404 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Exemplo n.º 26
0
/* called when listening thread is not checking for incoming connections */
int connection_setup_sockets (ice_config_t *config)
{
    int count = 0;
    listener_t *listener, **prev;

    free (banned_ip.filename);
    banned_ip.filename = NULL;
    free (allowed_ip.filename);
    allowed_ip.filename = NULL;

    global_lock();
    if (global.serversock)
    {
        for (; count < global.server_sockets; count++)
            sock_close (global.serversock [count]);
        free (global.serversock);
        global.serversock = NULL;
    }
    if (config == NULL)
    {
        global_unlock();
        return 0;
    }

    /* setup the banned/allowed IP filenames from the xml */
    if (config->banfile)
        banned_ip.filename = strdup (config->banfile);

    if (config->allowfile)
        allowed_ip.filename = strdup (config->allowfile);

    count = 0;
    global.serversock = calloc (config->listen_sock_count, sizeof (sock_t));

    listener = config->listen_sock; 
    prev = &config->listen_sock;
    while (listener)
    {
        int successful = 0;

        do
        {
            sock_t sock = sock_get_server_socket (listener->port, listener->bind_address);
            if (sock == SOCK_ERROR)
                break;
            if (sock_listen (sock, ICE_LISTEN_QUEUE) == SOCK_ERROR)
            {
                sock_close (sock);
                break;
            }
            /* some win32 setups do not do TCP win scaling well, so allow an override */
            if (listener->so_sndbuf)
                sock_set_send_buffer (sock, listener->so_sndbuf);
            sock_set_blocking (sock, 0);
            successful = 1;
            global.serversock [count] = sock;
            count++;
        } while(0);
        if (successful == 0)
        {
            if (listener->bind_address)
                ERROR2 ("Could not create listener socket on port %d bind %s",
                        listener->port, listener->bind_address);
            else
                ERROR1 ("Could not create listener socket on port %d", listener->port);
            /* remove failed connection */
            *prev = config_clear_listener (listener);
            listener = *prev;
            continue;
        }
        if (listener->bind_address)
            INFO2 ("listener socket on port %d address %s", listener->port, listener->bind_address);
        else
            INFO1 ("listener socket on port %d", listener->port);
        prev = &listener->next;
        listener = listener->next;
    }
    global.server_sockets = count;
    global_unlock();

    if (count == 0)
        ERROR0 ("No listening sockets established");

    return count;
}
Exemplo n.º 27
0
void connection_accept_loop (void)
{
    connection_t *con;
    ice_config_t *config;
    int duration = 300;

    config = config_get_config ();
    get_ssl_certificate (config);
    config_release_config ();

    while (global.running == ICE_RUNNING)
    {
        con = _accept_connection (duration);

        if (con)
        {
            client_queue_t *node;
            ice_config_t *config;
            client_t *client = NULL;
            listener_t *listener;

            global_lock();
            if (client_create (&client, con, NULL) < 0)
            {
                global_unlock();
                client_send_403 (client, "Icecast connection limit reached");
                /* don't be too eager as this is an imposed hard limit */
                thread_sleep (400000);
                continue;
            }

            /* setup client for reading incoming http */
            client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000';

            if (sock_set_blocking (client->con->sock, 0) || sock_set_nodelay (client->con->sock))
            {
                global_unlock();
                WARN0 ("failed to set tcp options on client connection, dropping");
                client_destroy (client);
                continue;
            }

            node = calloc (1, sizeof (client_queue_t));
            if (node == NULL)
            {
                global_unlock();
                client_destroy (client);
                continue;
            }
            node->client = client;

            config = config_get_config();
            listener = config_get_listen_sock (config, client->con);

            if (listener)
            {
                if (listener->shoutcast_compat)
                    node->shoutcast = 1;
                if (listener->ssl && ssl_ok)
                    connection_uses_ssl (client->con);
                if (listener->shoutcast_mount)
                    node->shoutcast_mount = strdup (listener->shoutcast_mount);
            }
            global_unlock();
            config_release_config();

            _add_request_queue (node);
            stats_event_inc (NULL, "connections");
            duration = 5;
        }
        else
        {
            if (_req_queue == NULL)
                duration = 300; /* use longer timeouts when nothing waiting */
        }
        process_request_queue ();
    }

    /* Give all the other threads notification to shut down */
    thread_cond_broadcast(&global.shutdown_cond);

    /* wait for all the sources to shutdown */
    thread_rwlock_wlock(&_source_shutdown_rwlock);
    thread_rwlock_unlock(&_source_shutdown_rwlock);
}
Exemplo n.º 28
0
void config_clear(ice_config_t *c)
{
    ice_config_dir_t *dirnode, *nextdirnode;
    aliases *alias, *nextalias;
    int i;

    free(c->config_filename);

    xmlFree (c->server_id);
    if (c->location) xmlFree(c->location);
    if (c->admin) xmlFree(c->admin);
    if (c->source_password) xmlFree(c->source_password);
    if (c->admin_username) xmlFree(c->admin_username);
    if (c->admin_password) xmlFree(c->admin_password);
    if (c->relay_username) xmlFree(c->relay_username);
    if (c->relay_password) xmlFree(c->relay_password);
    if (c->hostname) xmlFree(c->hostname);
    if (c->base_dir) xmlFree(c->base_dir);
    if (c->log_dir) xmlFree(c->log_dir);
    if (c->webroot_dir) xmlFree(c->webroot_dir);
    if (c->adminroot_dir) xmlFree(c->adminroot_dir);
    if (c->cert_file) xmlFree(c->cert_file);
    if (c->pidfile) xmlFree(c->pidfile);
    if (c->banfile) xmlFree(c->banfile);
    if (c->allowfile) xmlFree (c->allowfile);
    if (c->agentfile) xmlFree (c->agentfile);
    if (c->playlist_log.name) xmlFree(c->playlist_log.name);
    if (c->access_log.name) xmlFree(c->access_log.name);
    if (c->error_log.name) xmlFree(c->error_log.name);
    if (c->access_log.exclude_ext) xmlFree (c->access_log.exclude_ext);
    if (c->shoutcast_mount) xmlFree(c->shoutcast_mount);

    global_lock();
    while ((c->listen_sock = config_clear_listener (c->listen_sock)))
        ;
    global_unlock();

    if (c->master_server) xmlFree(c->master_server);
    if (c->master_username) xmlFree(c->master_username);
    if (c->master_password) xmlFree(c->master_password);
    if (c->master_bind) xmlFree(c->master_bind);
    if (c->user) xmlFree(c->user);
    if (c->group) xmlFree(c->group);
    if (c->mimetypes_fn) xmlFree (c->mimetypes_fn);

    while (c->relay)
        c->relay = config_clear_relay (c->relay);

    while (c->redirect_hosts)
        c->redirect_hosts = config_clear_redirect (c->redirect_hosts);

    while (c->mounts)
    {
        mount_proxy *to_go = c->mounts;
        c->mounts = to_go->next;
        config_clear_mount (to_go);
    }
    alias = c->aliases;
    while(alias) {
        nextalias = alias->next;
        if (alias->source) xmlFree(alias->source);
        if (alias->destination) xmlFree(alias->destination);
        if (alias->bind_address) xmlFree(alias->bind_address);
        free(alias);
        alias = nextalias;
    }

    dirnode = c->dir_list;
    while(dirnode) {
        nextdirnode = dirnode->next;
        if (dirnode->host) xmlFree(dirnode->host);
        free(dirnode);
        dirnode = nextdirnode;
    }
#ifdef USE_YP
    i = 0;
    while (i < c->num_yp_directories)
    {
        if (c->yp_url[i]) xmlFree (c->yp_url[i]);
        i++;
    }
#endif

    memset(c, 0, sizeof(ice_config_t));
}
Exemplo n.º 29
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config;

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    config = config_get_config();
    if (global.sources < config->source_limit)
    {
        const char *contenttype;
        const char *expectcontinue;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                config_release_config();
                global_unlock();
                if (response)
                {
                    client_send_403 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_403 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

	/* For PUT support we check for 100-continue and send back a 100 to stay in spec */
	expectcontinue = httpp_getvar (source->parser, "expect");
	if (expectcontinue != NULL)
	{
#ifdef HAVE_STRCASESTR
	    if (strcasestr (expectcontinue, "100-continue") != NULL)
#else
	    WARN0("OS doesn't support case insenestive substring checks...");
	    if (strstr (expectcontinue, "100-continue") != NULL)
#endif
	    {
		client_send_100 (source->client);
	    }
	}

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL);
        source_update_settings (config, source, mountinfo);
        config_release_config();
        slave_rebuild_mounts();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_403 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Exemplo n.º 30
0
static void *start_relay_stream (void *arg)
{
    client_t *client = arg;
    relay_server *relay;
    source_t *src;
    int failed = 1, sources;

    global_lock();
    sources = ++global.sources;
    stats_event_args (NULL, "sources", "%d", global.sources);
    global_unlock();
    /* set the start time, because we want to decrease the sources on all failures */
    client->connection.con_time = time (NULL);
    do
    {
        ice_config_t *config = config_get_config();
        mount_proxy *mountinfo;

        relay = client->shared_data;
        src = relay->source;

        thread_rwlock_wlock (&src->lock);
        src->flags |= SOURCE_PAUSE_LISTENERS;
        if (sources > config->source_limit)
        {
            config_release_config();
            WARN1 ("starting relayed mountpoint \"%s\" requires a higher sources limit", relay->localmount);
            break;
        }
        config_release_config();
        INFO1("Starting relayed source at mountpoint \"%s\"", relay->localmount);

        if (open_relay (relay) < 0)
            break;
        if (connection_complete_source (src) < 0)
        {
            WARN1 ("Failed to complete initialisation on %s", relay->localmount);
            break;
        }
        stats_event_inc (NULL, "source_relay_connections");
        source_init (src);
        config = config_get_config();
        mountinfo = config_find_mount (config, src->mount);
        source_update_settings (config, src, mountinfo);
        INFO1 ("source %s is ready to start", src->mount);
        config_release_config();
        failed = 0;
    } while (0);

    client->ops = &relay_client_ops;
    client->schedule_ms = timing_get_time();

    if (failed)
    {
        /* failed to start any connection, better clean up and reset */
        if (relay->on_demand == 0)
        {
            yp_remove (relay->localmount);
            src->yp_public = -1;
        }
        relay->in_use = NULL;
        INFO2 ("listener count remaining on %s is %d", src->mount, src->listeners);
        src->flags &= ~(SOURCE_PAUSE_LISTENERS|SOURCE_RUNNING);
    }
    thread_rwlock_unlock (&src->lock);

    thread_spin_lock (&relay_start_lock);
    relays_connecting--;
    thread_spin_unlock (&relay_start_lock);

    client->flags |= CLIENT_ACTIVE;
    worker_wakeup (client->worker);
    return NULL;
}