Exemple #1
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();

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

        thread_mutex_lock (&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;
        stats_event_inc (NULL, "source_relay_connections");
        source_init (src);
        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)
            src->flags &= ~SOURCE_ON_DEMAND;
        else
        {
            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;
        thread_mutex_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;
}
/* factoring out code for stats loops
** this function copies all stats to queue, and registers 
*/
static void _register_listener (client_t *client)
{
    event_listener_t *listener = client->shared_data;
    avl_node *node;
    stats_event_t stats_count;
    refbuf_t *refbuf;
    size_t size = 8192;
    char buffer[20];

    build_event (&stats_count, NULL, "stats_connections", buffer);
    stats_count.action = STATS_EVENT_INC;
    process_event (&stats_count);

    /* first we fill our queue with the current stats */
    refbuf = refbuf_new (size);
    refbuf->len = 0;

    /* the global stats */
    avl_tree_rlock (_stats.global_tree);
    node = avl_get_first(_stats.global_tree);
    while (node)
    {
        stats_node_t *stat = node->key;

        if (stat->flags & listener->mask)
        {
            if (_append_to_buffer (refbuf, size, "EVENT global %s %s\n", stat->name, stat->value) < 0)
            {
                _add_node_to_stats_client (client, refbuf);
                refbuf = refbuf_new (size);
                refbuf->len = 0;
                continue;
            }
        }
        node = avl_get_next(node);
    }
    avl_tree_unlock (_stats.global_tree);
    /* now the stats for each source */
    avl_tree_rlock (_stats.source_tree);
    node = avl_get_first(_stats.source_tree);
    while (node)
    {
        avl_node *node2;
        stats_node_t *metadata_stat = NULL;
        stats_source_t *snode = (stats_source_t *)node->key;

        if (snode->flags & listener->mask)
        {
            stats_node_t *ct = _find_node (snode->stats_tree, "content-type");
            const char *type = "audio/mpeg";
            if (ct)
                type = ct->name;
            if (_append_to_buffer (refbuf, size, "NEW %s %s\n", type, snode->source) < 0)
            {
                _add_node_to_stats_client (client, refbuf);
                refbuf = refbuf_new (size);
                refbuf->len = 0;
                continue;
            }
        }
        node = avl_get_next(node);
        avl_tree_rlock (snode->stats_tree);
        node2 = avl_get_first(snode->stats_tree);
        while (node2)
        {
            stats_node_t *stat = node2->key;
            if (metadata_stat == NULL && strcmp (stat->name, "metadata_updated") == 0)
                metadata_stat = stat;
            else if (stat->flags & listener->mask)
            {
                if (_append_to_buffer (refbuf, size, "EVENT %s %s %s\n", snode->source, stat->name, stat->value) < 0)
                {
                    _add_node_to_stats_client (client, refbuf);
                    refbuf = refbuf_new (size);
                    refbuf->len = 0;
                    continue;
                }
            }
            node2 = avl_get_next (node2);
        }
        while (metadata_stat)
        {
            if (_append_to_buffer (refbuf, size, "EVENT %s %s %s\n", snode->source, metadata_stat->name, metadata_stat->value) < 0)
            {
                _add_node_to_stats_client (client, refbuf);
                refbuf = refbuf_new (size);
                refbuf->len = 0;
                continue;
            }
            break;
        }
        avl_tree_unlock (snode->stats_tree);
    }
    avl_tree_unlock (_stats.source_tree);
    _add_node_to_stats_client (client, refbuf);

    /* now we register to receive future event notices */
    thread_mutex_lock (&_stats.listeners_lock);
    listener->next = _stats.event_listeners;
    _stats.event_listeners = listener;
    thread_mutex_unlock (&_stats.listeners_lock);
}
Exemple #3
0
/* Actually open the connection and do some http parsing, handle any 302
 * responses within here.
 */
static int open_relay_connection (client_t *client, relay_server *relay, relay_server_master *master)
{
    int redirects = 0;
    http_parser_t *parser = NULL;
    connection_t *con = &client->connection;
    char *server = strdup (master->ip);
    char *mount = strdup (master->mount);
    int port = master->port, timeout = master->timeout, ask_for_metadata = relay->mp3metadata;
    char *auth_header = NULL;

    if (relay->username && relay->password)
    {
        char *esc_authorisation;
        unsigned len = strlen(relay->username) + strlen(relay->password) + 2;

        DEBUG2 ("using username %s for %s", relay->username, relay->localmount);
        auth_header = malloc (len);
        snprintf (auth_header, len, "%s:%s", relay->username, relay->password);
        esc_authorisation = util_base64_encode(auth_header);
        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);
    }

    while (redirects < 10)
    {
        sock_t streamsock;
        char *bind = NULL;

        /* policy decision, we assume a source bind even after redirect, possible option */
        if (master->bind)
            bind = strdup (master->bind);

        if (bind)
            INFO4 ("connecting to %s:%d for %s, bound to %s", server, port, relay->localmount, bind);
        else
            INFO3 ("connecting to %s:%d for %s", server, port, relay->localmount);

        con->con_time = time (NULL);
        relay->in_use = master;
        streamsock = sock_connect_wto_bind (server, port, bind, timeout);
        free (bind);
        if (connection_init (con, streamsock, server) < 0)
        {
            WARN2 ("Failed to connect to %s:%d", server, port);
            break;
        }

        parser = get_relay_response (con, mount, server, ask_for_metadata, auth_header);

        if (parser == NULL)
        {
            ERROR4 ("Problem trying to start relay on %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");
            INFO1 ("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);
            parser = NULL;
        }
        else
        {
            if (httpp_getvar (parser, HTTPP_VAR_ERROR_MESSAGE))
            {
                ERROR2("Error from relay request: %s (%s)", relay->localmount,
                        httpp_getvar(parser, HTTPP_VAR_ERROR_MESSAGE));
                client->parser = NULL;
                break;
            }
            sock_set_blocking (streamsock, 0);
            thread_mutex_lock (&relay->source->lock);
            client->parser = parser; // old parser will be free in the format clear
            thread_mutex_unlock (&relay->source->lock);
            client->connection.discon_time = 0;
            client->connection.con_time = time (NULL);
            client_set_queue (client, NULL);
            free (server);
            free (mount);
            free (auth_header);

            return 0;
        }
        redirects++;
    }
    /* failed, better clean up */
    free (server);
    free (mount);
    free (auth_header);
    if (parser)
        httpp_destroy (parser);
    connection_close (con);
    con->con_time = time (NULL);
    if (relay->in_use) relay->in_use->skip = 1;
    return -1;
}
Exemple #4
0
/* Move clients from source to dest provided dest is running
 * and that the stream format is the same.
 * The only lock that should be held when this is called is the
 * source tree lock
 */
void source_move_clients (source_t *source, source_t *dest)
{
    /* we don't want the two write locks to deadlock in here */
    thread_mutex_lock (&move_clients_mutex);

    /* if the destination is not running then we can't move clients */

    if (dest->running == 0)
    {
        WARN1 ("destination mount %s not running, unable to move clients ", dest->mount);
        thread_mutex_unlock (&move_clients_mutex);
        return;
    }

    avl_tree_wlock (dest->pending_tree);
    do
    {
        client_t *client;

        /* we need to move the client and pending trees */
        avl_tree_wlock (source->pending_tree);

        if (source->format == NULL)
        {
            INFO1 ("source mount %s is not available", source->mount);
            break;
        }
        if (source->format->type != dest->format->type)
        {
            WARN2 ("stream %s and %s are of different types, ignored", source->mount, dest->mount);
            break;
        }

        while (1)
        {
            avl_node *node = avl_get_first (source->pending_tree);
            if (node == NULL)
                break;
            client = (client_t *)(node->key);
            avl_delete (source->pending_tree, client, NULL);

            /* switch client to different queue */
            client_set_queue (client, dest->stream_data_tail);
            avl_insert (dest->pending_tree, (void *)client);
        }

        avl_tree_wlock (source->client_tree);
        while (1)
        {
            avl_node *node = avl_get_first (source->client_tree);
            if (node == NULL)
                break;

            client = (client_t *)(node->key);
            avl_delete (source->client_tree, client, NULL);

            /* switch client to different queue */
            client_set_queue (client, dest->stream_data_tail);
            avl_insert (dest->pending_tree, (void *)client);
        }
        source->listeners = 0;
        stats_event (source->mount, "listeners", "0");
        avl_tree_unlock (source->client_tree);

    } while (0);

    avl_tree_unlock (source->pending_tree);
    avl_tree_unlock (dest->pending_tree);
    thread_mutex_unlock (&move_clients_mutex);
}
static int stats_listeners_send (client_t *client)
{
    int loop = 8, total = 0;
    int ret = 0;
    event_listener_t *listener = client->shared_data;

    if (client->connection.error || global.running != ICE_RUNNING)
        return -1;
    if (client->refbuf && client->refbuf->flags & STATS_BLOCK_CONNECTION)
        loop = 4;
    else
        /* allow for 200k lag but only after 2Meg has been sent, give connection time
         * to cacth up after the large dump at the beginning */
        if (client->connection.sent_bytes > 2000000 && listener->content_len > 200000)
        {
            WARN1 ("dropping stats client, %ld in queue", listener->content_len);
            return -1;
        }
    client->schedule_ms = client->worker->time_ms;
    thread_mutex_lock (&_stats.listeners_lock);
    while (1)
    {
        refbuf_t *refbuf = client->refbuf;

        if (refbuf == NULL)
        {
            client->schedule_ms = client->worker->time_ms + 60;
            break;
        }
        if (loop == 0 || total > 32768)
            break;
        ret = format_generic_write_to_client (client);
        if (ret > 0)
        {
            total += ret;
            listener->content_len -= ret;
        }
        if (client->pos == refbuf->len)
        {
            client->refbuf = refbuf->next;
            refbuf->next = NULL;
            refbuf_release (refbuf);
            client->pos = 0;
            if (client->refbuf == NULL)
            {
                if (listener->content_len)
                    WARN1 ("content length is %u", listener->content_len);
                listener->recent_block = NULL;
                client->schedule_ms = client->worker->time_ms + 50;
                break;
            }
            loop--;
        }
        else
        {
            client->schedule_ms = client->worker->time_ms + 200;
            break; /* short write, so stop for now */
        }
    }
    thread_mutex_unlock (&_stats.listeners_lock);
    if (client->connection.error || global.running != ICE_RUNNING)
        return -1;
    return 0;
}
Exemple #6
0
/*! \fn void *snmp_host_init(int host_id, char *hostname, int snmp_version, 
 * char *snmp_community, char *snmp_username, char *snmp_password, int snmp_port, 
 * int snmp_timeout)
 *  \brief initializes an snmp_session object for a Cactid host
 * 
 *	This function will initialize NET-SNMP or UCD-SNMP for the Cactid host
 *  in question.
 *
 */
void *snmp_host_init(int host_id, char *hostname, int snmp_version, char *snmp_community, 
					char *snmp_username, char *snmp_password, int snmp_port, int snmp_timeout) {
	void *sessp = NULL;
	struct snmp_session session;
	char hostnameport[BUFSIZE];   

	/* initialize SNMP */
  	snmp_sess_init(&session);

	#ifdef USE_NET_SNMP
		/* Prevent update of the snmpapp.conf file */
		#ifdef NETSNMP_DS_LIB_DONT_PERSIST_STATE
			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
		#endif

		/* Prevent update of the snmpapp.conf file */
		#ifdef NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD
			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD, 1);
		#endif

		#ifdef NETSNMP_DS_LIB_DONT_PRINT_UNITS
			netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PRINT_UNITS, 1);
		#endif

		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, 1);
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_BARE_VALUE, 1);
		netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NUMERIC_TIMETICKS, 1);
	#else
		ds_set_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT, 1);
		ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_BARE_VALUE, 1);
		ds_set_boolean(DS_LIBRARY_ID, DS_LIB_NUMERIC_TIMETICKS, 1);
	#endif

	/* verify snmp version is accurate */
	if (snmp_version == 2) {
		session.version = SNMP_VERSION_2c;
	}else if (snmp_version == 1) {
		session.version = SNMP_VERSION_1;
	}else if (snmp_version == 3) {
		session.version = SNMP_VERSION_3;
	}else {
		CACTID_LOG(("Host[%i] ERROR: SNMP Version Error for Host '%s'\n", host_id, hostname));
		return 0;
	}		

	snprintf(hostnameport, sizeof(hostnameport), "%s:%i", hostname, snmp_port);
	session.peername = hostnameport;
	session.retries = 3;
	session.remote_port = snmp_port;
	session.timeout = (snmp_timeout * 1000); /* net-snmp likes microseconds */

	if ((snmp_version == 2) || (snmp_version == 1)) {
		session.community = snmp_community;
		session.community_len = strlen(snmp_community);
	}else {
	    /* set the SNMPv3 user name */
	    session.securityName = snmp_username;
	    session.securityNameLen = strlen(session.securityName);

		session.securityAuthKeyLen = USM_AUTH_KU_LEN;

	    /* set the authentication method to MD5 */
	    session.securityAuthProto = snmp_duplicate_objid(usmHMACMD5AuthProtocol, OIDSIZE(usmHMACMD5AuthProtocol));
	    session.securityAuthProtoLen = OIDSIZE(usmHMACMD5AuthProtocol);

		/* set the privacy protocol to none */
		session.securityPrivProto = usmNoPrivProtocol;
		session.securityPrivProtoLen = OIDSIZE(usmNoPrivProtocol);
		session.securityPrivKeyLen = USM_PRIV_KU_LEN;

	    /* set the security level to authenticate, but not encrypted */
		session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;

	    /* set the authentication key to the hashed version. The password must me at least 8 char */
	    if (generate_Ku(session.securityAuthProto, 
						session.securityAuthProtoLen,
						(u_char *) snmp_password,
						strlen(snmp_password),
	                    session.securityAuthKey,
	                    &(session.securityAuthKeyLen)) != SNMPERR_SUCCESS) {
	        CACTID_LOG(("SNMP: Error generating SNMPv3 Ku from authentication pass phrase."));
		}
	}

	/* open SNMP Session */
 	thread_mutex_lock(LOCK_SNMP);
	sessp = snmp_sess_open(&session);
	thread_mutex_unlock(LOCK_SNMP);

	if (!sessp) {
		CACTID_LOG(("ERROR: Problem initializing SNMP session '%s'\n", hostname));
	}
	
	return sessp;
}
Exemple #7
0
void global_lock(void)
{
    thread_mutex_lock(&_global_mutex);
}
Exemple #8
0
static void tls_mem_free(const char *filename, int line, void *ptr)
{
	MBLOCK *real_ptr;
	size_t len;

	CHECK_IN_PTR2(ptr, real_ptr, len, filename, line);

#if 1
	if (real_ptr->mem_slice->tid != (unsigned long) acl_pthread_self()) {
#else
	if (real_ptr->mem_slice->tid != mem_slice->tid) {
#endif
		MUTEX_LOCK(real_ptr->mem_slice);
		PRIVATE_ARRAY_PUSH(real_ptr->mem_slice->list, real_ptr);
		MUTEX_UNLOCK(real_ptr->mem_slice);
	} else
		acl_slice_pool_free(filename, line, real_ptr);
}

static void *tls_mem_alloc(const char *filename, int line, size_t len)
{
	const char *myname = "tls_mem_alloc";
	ACL_MEM_SLICE *mem_slice = acl_pthread_getspecific(__mem_slice_key);
	char *ptr;
	MBLOCK *real_ptr;

	if (mem_slice == NULL) {
		/* 每个子线程获得自己的线程局部存储内存池 */
		mem_slice = mem_slice_create();
		mem_slice->slice_list = __mem_slice_list;

		/* 将子线程的线程局部存储内存池置入全局内存池句柄集合中 */
		if (__mem_slice_list_lock)
			thread_mutex_lock(__mem_slice_list_lock);
		private_array_push(__mem_slice_list, mem_slice);
		if (__mem_slice_list_lock)
			thread_mutex_unlock(__mem_slice_list_lock);
	}

	real_ptr = (MBLOCK *) acl_slice_pool_alloc(filename, line,
			mem_slice->slice_pool, SPACE_FOR(len));
	if (real_ptr == 0) {
		acl_msg_error("%s(%d): malloc: insufficient memory",
			myname, __LINE__);
		return 0;
	}

	mem_slice->nalloc++;
	if (mem_slice->nalloc == mem_slice->nalloc_gc) {
		mem_slice->nalloc = 0;
		mem_slice_gc(mem_slice);
	}
	CHECK_OUT_PTR(ptr, real_ptr, mem_slice, len);
	return ptr;
}

static void *tls_mem_calloc(const char *filename, int line, size_t nmemb, size_t size)
{
	void *ptr = tls_mem_alloc(filename, line, nmemb * size);

	memset(ptr, 0, nmemb * size);
	return ptr;
}
Exemple #9
0
static int update_from_master(ice_config_t *config)
{
    char *master = NULL, *password = NULL, *username= NULL;
    int port;
    sock_t mastersock;
    int ret = 0;
    char buf[256];
    do
    {
        char *authheader, *data;
        relay_server *new_relays = NULL, *cleanup_relays;
        int len, count = 1;

        username = strdup ("relay");
        if (config->master_password)
            password = strdup (config->master_password);

        if (config->master_server)
            master = strdup (config->master_server);

        port = config->master_server_port;

        if (password == NULL || master == NULL || port == 0)
            break;
        ret = 1;
        config_release_config();
        mastersock = sock_connect_wto (master, port, 0);

        if (mastersock == SOCK_ERROR)
        {
            WARN0("Relay slave failed to contact master server to fetch stream list");
            break;
        }

        len = strlen(username) + strlen(password) + 2;
        authheader = malloc(len);
        snprintf (authheader, len, "%s:%s", username, password);
        data = util_base64_encode(authheader);
        sock_write (mastersock,
                "GET /admin/streamlist.txt HTTP/1.0\r\n"
                "Authorization: Basic %s\r\n"
                "\r\n", data);
        free(authheader);
        free(data);

        if (sock_read_line(mastersock, buf, sizeof(buf)) == 0 ||
                strncmp (buf, "HTTP/1.0 200", 12) != 0)
        {
            sock_close (mastersock);
            WARN0 ("Master rejected streamlist request");
            break;
        }

        while (sock_read_line(mastersock, buf, sizeof(buf)))
        {
            if (!strlen(buf))
                break;
        }
        while (sock_read_line(mastersock, buf, sizeof(buf)))
        {
            relay_server *r;
            if (!strlen(buf))
                continue;
            DEBUG2 ("read %d from master \"%s\"", count++, buf);
            r = calloc (1, sizeof (relay_server));
            if (r)
            {
                r->server = xmlStrdup (master);
                r->port = port;
                r->mount = xmlStrdup (buf);
                r->localmount = xmlStrdup (buf);
                r->mp3metadata = 1;
                r->next = new_relays;
                new_relays = r;
            }
        }
        sock_close (mastersock);

        thread_mutex_lock (&(config_locks()->relay_lock));
        cleanup_relays = update_relays (&global.master_relays, new_relays);
        
        relay_check_streams (global.master_relays, cleanup_relays);
        relay_check_streams (NULL, new_relays);

        thread_mutex_unlock (&(config_locks()->relay_lock));

    } while(0);

    if (master)
        free (master);
    if (username)
        free (username);
    if (password)
        free (password);

    return ret;
}
Exemple #10
0
static void ptmutex_acquire(mr_lock_t l)
{
    thread_mutex_lock(l);
}