Exemplo n.º 1
0
/* Request slave thread to check the relay list for changes and to
 * update the stats for the current streams.
 */
void slave_rebuild_mounts (void)
{
    thread_mutex_lock(&_slave_mutex);
    update_settings = 1;
    thread_mutex_unlock(&_slave_mutex);
}
Exemplo n.º 2
0
static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden) {
    avl_node *avlnode;
    xmlNodePtr ret = NULL;
    ice_config_t *config;

    thread_mutex_lock(&_stats_mutex);
    /* general stats first */
    avlnode = avl_get_first(_stats.global_tree);

    while (avlnode) {
        stats_node_t *stat = avlnode->key;
        if (stat->hidden <=  hidden)
            xmlNewTextChild (root, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
        avlnode = avl_get_next (avlnode);
    }
    /* now per mount stats */
    avlnode = avl_get_first(_stats.source_tree);
    config = config_get_config();
    __add_authstack(config->authstack, root);
    config_release_config();

    while (avlnode) {
        stats_source_t *source = (stats_source_t *)avlnode->key;

        if (source->hidden <= hidden &&
                (show_mount == NULL || strcmp (show_mount, source->source) == 0))
        {
            xmlNodePtr metadata, history;
            source_t *source_real;
            mount_proxy *mountproxy;
            int i;

            avl_node *avlnode2 = avl_get_first (source->stats_tree);
            xmlNodePtr xmlnode = xmlNewTextChild (root, NULL, XMLSTR("source"), NULL);

            xmlSetProp (xmlnode, XMLSTR("mount"), XMLSTR(source->source));
            if (ret == NULL)
                ret = xmlnode;
            while (avlnode2)
            {
                stats_node_t *stat = avlnode2->key;
                xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
                avlnode2 = avl_get_next (avlnode2);
            }


            avl_tree_rlock(global.source_tree);
            source_real = source_find_mount_raw(source->source);
            history = playlist_render_xspf(source_real->history);
            if (history)
                xmlAddChild(xmlnode, history);
            metadata = xmlNewTextChild(xmlnode, NULL, XMLSTR("metadata"), NULL);
            if (source_real->format) {
                for (i = 0; i < source_real->format->vc.comments; i++)
                    __add_metadata(metadata, source_real->format->vc.user_comments[i]);
            }
            avl_tree_unlock(global.source_tree);

            config = config_get_config();
            mountproxy = config_find_mount(config, source->source, MOUNT_TYPE_NORMAL);
            __add_authstack(mountproxy->authstack, xmlnode);
            config_release_config();
        }
        avlnode = avl_get_next (avlnode);
    }
    thread_mutex_unlock(&_stats_mutex);
    return ret;
}
Exemplo n.º 3
0
/* build an XML doc containing information about currently running sources.
 * If a mountpoint is passed then that source will not be added to the XML
 * doc even if the source is running */
xmlDocPtr admin_build_sourcelist (const char *mount)
{
    avl_node *node;
    source_t *source;
    xmlNodePtr xmlnode, srcnode;
    xmlDocPtr doc;
    char buf[22];
    time_t now = time(NULL);

    doc = xmlNewDoc(XMLSTR("1.0"));
    xmlnode = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
    xmlDocSetRootElement(doc, xmlnode);

    if (mount) {
        xmlNewChild(xmlnode, NULL, XMLSTR("current_source"), XMLSTR(mount));
    }

    node = avl_get_first(global.source_tree);
    while(node) {
        source = (source_t *)node->key;
        if (mount && strcmp (mount, source->mount) == 0)
        {
            node = avl_get_next (node);
            continue;
        }

        thread_mutex_lock (&source->lock);
        if (source_available (source))
        {
            ice_config_t *config;
            mount_proxy *mountinfo;

            srcnode = xmlNewChild (xmlnode, NULL, XMLSTR("source"), NULL);
            xmlSetProp (srcnode, XMLSTR("mount"), XMLSTR(source->mount));

            snprintf (buf, sizeof(buf), "%lu", source->listeners);
            xmlNewChild (srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));

            config = config_get_config();
            mountinfo = config_find_mount (config, source->mount);
            if (mountinfo)
            {
                if (mountinfo->auth)
                {
                    xmlNewChild (srcnode, NULL, XMLSTR("authenticator"), 
                            XMLSTR(mountinfo->auth->type));
                }
                if (mountinfo->fallback_mount)
                    xmlNewChild (srcnode, NULL, XMLSTR("fallback"), 
                            XMLSTR(mountinfo->fallback_mount));
            }
            config_release_config();

            if (source_running (source))
            {
                if (source->client)
                {
                    snprintf (buf, sizeof(buf), "%lu",
                            (unsigned long)(now - source->client->connection.con_time));
                    xmlNewChild (srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
                }
                xmlNewChild (srcnode, NULL, XMLSTR("content-type"), 
                        XMLSTR(source->format->contenttype));
            }
        }
        thread_mutex_unlock (&source->lock);
        node = avl_get_next(node);
    }
    return(doc);
}
Exemplo n.º 4
0
void global_unlock(void)
{
    thread_mutex_unlock(&_global_mutex);
}
Exemplo n.º 5
0
static void queue_global_event (stats_event_t *event)
{
    thread_mutex_lock(&_global_event_mutex);
    _add_event_to_queue (event, &_global_event_queue);
    thread_mutex_unlock(&_global_event_mutex);
}
Exemplo n.º 6
0
/* find/create handle and return it with the structure in a locked state */
static fh_node *open_fh (fbinfo *finfo)
{
    fh_node *fh, *result;

    if (finfo->mount == NULL)
        finfo->mount = "";
    fh = calloc (1, sizeof (fh_node));
    memcpy (&fh->finfo, finfo, sizeof (fbinfo));
    if (avl_get_by_key (fh_cache, fh, (void**)&result) == 0)
    {
        free (fh);
        thread_mutex_lock (&result->lock);
        avl_tree_unlock (fh_cache);
        if (finfo->flags & FS_FALLBACK)
        {
            if (result->finfo.type != finfo->type && finfo->type != FORMAT_TYPE_UNDEFINED)
            {
                WARN1 ("format mismatched for %s", finfo->mount);
                thread_mutex_unlock (&result->lock);
                return NULL;
            }
            result->expire = (time_t)-1;
        }
        return result;
    }

    // insert new one
    if (fh->finfo.mount[0])
    {
        char *fullpath= util_get_path_from_normalised_uri (fh->finfo.mount, fh->finfo.flags&FS_USE_ADMIN);
        char *contenttype = fserve_content_type (fullpath);
        format_type_t type = format_get_type (contenttype);

        if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
            fh->finfo.type = type;
        if (finfo->flags & FS_FALLBACK)
        {
            if (fh->finfo.type != type && type != FORMAT_TYPE_UNDEFINED && fh->finfo.type != FORMAT_TYPE_UNDEFINED)
            {
                avl_tree_unlock (fh_cache);
                free (contenttype);
                free (fullpath);
                free (fh);
                WARN1 ("format mismatched for %s", finfo->mount);
                return NULL;
            }
            fh->expire = (time_t)-1;
            INFO2 ("lookup of fallback file \"%s\" (%d)", finfo->mount, finfo->limit);
        }
        else
            INFO1 ("lookup of \"%s\"", finfo->mount);
        if (file_open (&fh->f, fullpath) < 0)
        {
            INFO1 ("Failed to open \"%s\"", fullpath);
            avl_tree_unlock (fh_cache);
            free (contenttype);
            free (fullpath);
            free (fh);
            return NULL;
        }
        free (fullpath);
        fh->format = calloc (1, sizeof (format_plugin_t));
        fh->format->type = fh->finfo.type;
        fh->format->contenttype = strdup (contenttype);
        free (contenttype);
        if (fh->finfo.type != FORMAT_TYPE_UNDEFINED)
        {
            fh->format->mount = strdup (fh->finfo.mount);
            if (format_get_plugin (fh->format, NULL) < 0)
            {
                avl_tree_unlock (fh_cache);
                free (fh->format);
                free (fh);
                return NULL;
            }
        }
        if (fh->finfo.limit)
            fh->out_bitrate = rate_setup (10000, 1000);
    }
    fh->clients = avl_tree_new (client_compare, NULL);
    thread_mutex_create (&fh->lock);
    thread_mutex_lock (&fh->lock);
    avl_insert (fh_cache, fh);
    avl_tree_unlock (fh_cache);

    fh->refcount = 0;
    fh->peak = 0;
    fh->finfo.mount = strdup (finfo->mount);
    fh->finfo.fallback = NULL;

    return fh;
}
Exemplo n.º 7
0
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
{
    xmlDocPtr    res;
    xsltStylesheetPtr cur;
    xmlChar *string;
    int len, problem = 0;
    const char *mediatype = NULL;
    const char *charset = NULL;

    xmlSetGenericErrorFunc ("", log_parse_failure);
    xsltSetGenericErrorFunc ("", log_parse_failure);

    thread_mutex_lock(&xsltlock);
    cur = xslt_get_stylesheet(xslfilename);

    if (cur == NULL)
    {
        thread_mutex_unlock(&xsltlock);
        ICECAST_LOG_ERROR("problem reading stylesheet \"%s\"", xslfilename);
        client_send_404 (client, "Could not parse XSLT file");
        return;
    }

    res = xsltApplyStylesheet(cur, doc, NULL);

    if (xsltSaveResultToString (&string, &len, res, cur) < 0)
        problem = 1;

    /* lets find out the content type and character encoding to use */
    if (cur->encoding)
       charset = (char *)cur->encoding;

    if (cur->mediaType)
        mediatype = (char *)cur->mediaType;
    else
    {
        /* check method for the default, a missing method assumes xml */
        if (cur->method && xmlStrcmp (cur->method, XMLSTR("html")) == 0)
            mediatype = "text/html";
        else
            if (cur->method && xmlStrcmp (cur->method, XMLSTR("text")) == 0)
                mediatype = "text/plain";
            else
                mediatype = "text/xml";
    }
    if (problem == 0)
    {
        ssize_t ret;
        int failed = 0;
        refbuf_t *refbuf;
        size_t full_len = strlen (mediatype) + len + 1024;
        if (full_len < 4096)
            full_len = 4096;
        refbuf = refbuf_new (full_len);

        if (string == NULL)
            string = xmlCharStrdup ("");
        ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL);
        if (ret == -1) {
            ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
            client_send_500(client, "Header generation failed.");
        } else {
            if ( full_len < (ret + len + 64) ) {
                void *new_data;
                full_len = ret + len + 64;
                new_data = realloc(refbuf->data, full_len);
                if (new_data) {
                    ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
                    refbuf->data = new_data;
                    refbuf->len = full_len;
                    ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL);
                    if (ret == -1) {
                        ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
                        client_send_500(client, "Header generation failed.");
                        failed = 1;
                    }
                } else {
                    ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client.");
                    client_send_500(client, "Buffer reallocation failed.");
                    failed = 1;
                }
            }

            if (!failed) {
                  snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);

                client->respcode = 200;
                client_set_queue (client, NULL);
                client->refbuf = refbuf;
                refbuf->len = strlen (refbuf->data);
                fserve_add_client (client, NULL);
            }
        }
        xmlFree (string);
    }
    else
    {
        ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename);
        client_send_404 (client, "XSLT problem");
    }
    thread_mutex_unlock (&xsltlock);
    xmlFreeDoc(res);
}
Exemplo n.º 8
0
/* Returns the number of bytes actually read					 			  */
unsigned long thread_pipe_peek( pipe_handle_t ph, unsigned long bytes, char *buffer )
{
	tl_pipedata_t *pipedata = (tl_pipedata_t *) ph;
	unsigned long old_buffer_size = pipedata->peek_buffer_size;
	unsigned long bytes_to_read;
	unsigned long bytes_read;
	unsigned long chunksize;

	thread_mutex_lock(pipedata->mutex);

	if( pipedata->peek_buffer ) {

		/* peek buffer not empty, see if we have enough bytes in it already */
		unsigned long available_bytes = pipedata->peek_buffer_size - pipedata->peek_next_read;
		if( available_bytes < bytes ) {
			/* Need to do some shuffling around to make room for more bytes
			 * to be read into the peek buffer */

			/* Close the whole left by bytes already read */
			if( pipedata->peek_next_read && available_bytes ) {
				memmove( pipedata->peek_buffer, &(pipedata->peek_buffer[pipedata->peek_next_read]), available_bytes );
			}
			pipedata->peek_next_read = 0;

			/* See if we need to realloc the memory */
			if( bytes > pipedata->peek_buffer_size ) {
				pipedata->peek_buffer_size += bytes;
				pipedata->peek_buffer = realloc( pipedata->peek_buffer, pipedata->peek_buffer_size );
				if( !(pipedata->peek_buffer) ) {
					/* REALLY bad news! */
					pipedata->peek_buffer_size = 0;
					thread_mutex_unlock(pipedata->mutex);
					return 0;
				}
			}

		}
	} else {
		/* Peek buffer is empty, fill it up with bytes requested */

		pipedata->peek_buffer_size = bytes;
		pipedata->peek_next_read = 0;

		if( pipedata->peek_buffer_size < MIN_PEEK_BUFFERSIZE ) {
			/* If you're gonaa peek, you might as well have a good look */
			pipedata->peek_buffer_size = MIN_PEEK_BUFFERSIZE;
		}

		pipedata->peek_buffer = malloc( pipedata->peek_buffer_size );
		if( !(pipedata->peek_buffer) ) {
			/* REALLY bad news! */
			pipedata->peek_buffer_size = 0;
			thread_mutex_unlock(pipedata->mutex);
			return 0;
		}
	}


	/* Read bytes from the stream to fill up the peek buffer */
	if( old_buffer_size < pipedata->peek_buffer_size ) {
		long result = 0;
		int eof;
		char *readpos = &(pipedata->peek_buffer[ old_buffer_size ]);
		bytes_to_read = pipedata->peek_buffer_size - old_buffer_size;
		eof = pipedata->eof;
		bytes_read = 0;

		while( !eof && bytes_to_read ) {

			result = 0;

			/* Number of bytes to read in each chunk */
			if( pipedata->pipe_size ) {
				chunksize = min( bytes_to_read, pipedata->pipe_size );
			} else {
				chunksize = bytes_to_read;
			}

			thread_mutex_unlock(pipedata->mutex);
			/* Read chunksize bytes */
			if( pipedata->phandles[0] ) {
				/* Using low level I/O */
				result = read( pipedata->phandles[0], &(readpos[bytes_read]), chunksize );
				if( result != (long)chunksize ) {
					/* End of file reached */
					if( result == - 1 ) {
						result = 0;
					}
					eof = 1;
				}
			} else if ( pipedata->fileh ) {
				/* Using streamed file I/O */
				result = fread( &(readpos[bytes_read]), sizeof( char), chunksize, pipedata->fileh );
				if( result != (long) chunksize && feof(pipedata->fileh) ) {
					/* End of file reached */
					eof = 1;
				}
			}
			else {
				eof = 1;
			}
			thread_mutex_lock(pipedata->mutex);

			if( result > 0 ) {
				if( pipedata->limit_pipesize ) {
					pipedata->bytes_in_pipe -= result;
				}
				bytes_read += result;
				bytes_to_read -= result;
				pipedata->bytesread += result;
			}
		}

		/* If we didn't read enough, reduce the amount returned */
		bytes = bytes_read;
	}

	/* We should now have enough bytes in the peek buffer to satisfy the request */
	memcpy( buffer, &(pipedata->peek_buffer[pipedata->peek_next_read]), bytes );
	
	thread_mutex_unlock(pipedata->mutex);

	return bytes;
}
Exemplo n.º 9
0
void config_clear(ice_config_t *c)
{
    ice_config_dir_t *dirnode, *nextdirnode;
    relay_server *relay, *nextrelay;
    mount_proxy *mount, *nextmount;
    aliases *alias, *nextalias;
    int i;

    if (c->config_filename)
        free(c->config_filename);

    if (c->location && c->location != CONFIG_DEFAULT_LOCATION) 
        xmlFree(c->location);
    if (c->admin && c->admin != CONFIG_DEFAULT_ADMIN) 
        xmlFree(c->admin);
    if (c->source_password && c->source_password != CONFIG_DEFAULT_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 && c->hostname != CONFIG_DEFAULT_HOSTNAME) 
        xmlFree(c->hostname);
    if (c->base_dir && c->base_dir != CONFIG_DEFAULT_BASE_DIR) 
        xmlFree(c->base_dir);
    if (c->log_dir && c->log_dir != CONFIG_DEFAULT_LOG_DIR) 
        xmlFree(c->log_dir);
    if (c->webroot_dir && c->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR)
        xmlFree(c->webroot_dir);
    if (c->adminroot_dir && c->adminroot_dir != CONFIG_DEFAULT_ADMINROOT_DIR)
        xmlFree(c->adminroot_dir);
    if (c->pidfile)
        xmlFree(c->pidfile);
    if (c->playlist_log && c->playlist_log != CONFIG_DEFAULT_PLAYLIST_LOG) 
        xmlFree(c->playlist_log);
    if (c->access_log && c->access_log != CONFIG_DEFAULT_ACCESS_LOG) 
        xmlFree(c->access_log);
    if (c->error_log && c->error_log != CONFIG_DEFAULT_ERROR_LOG) 
        xmlFree(c->error_log);
    if (c->shoutcast_mount && c->shoutcast_mount != CONFIG_DEFAULT_SHOUTCAST_MOUNT)
        xmlFree(c->shoutcast_mount);
    for(i=0; i < MAX_LISTEN_SOCKETS; i++) {
        if (c->listeners[i].bind_address) xmlFree(c->listeners[i].bind_address);
    }
    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->user) xmlFree(c->user);
    if (c->group) xmlFree(c->group);

    thread_mutex_lock(&(_locks.relay_lock));
    relay = c->relay;
    while(relay) {
        nextrelay = relay->next;
        xmlFree(relay->server);
        xmlFree(relay->mount);
        xmlFree(relay->localmount);
        free(relay);
        relay = nextrelay;
    }
    thread_mutex_unlock(&(_locks.relay_lock));

    mount = c->mounts;
    while(mount) {
        nextmount = mount->next;
        config_clear_mount (mount);
        mount = nextmount;
    }

    alias = c->aliases;
    while(alias) {
        nextalias = alias->next;
        xmlFree(alias->source);
        xmlFree(alias->destination);
        xmlFree(alias->bind_address);
        free(alias);
        alias = nextalias;
    }

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

    memset(c, 0, sizeof(ice_config_t));
}
Exemplo n.º 10
0
/* Returns the number of bytes actually written					 			  */
unsigned long thread_pipe_write( pipe_handle_t ph, unsigned long bytes, const char *buffer )
{
	long result = 0;
	unsigned long byteswritten = 0;

	tl_pipedata_t *pipedata = (tl_pipedata_t *) ph;

	if( pipedata ) {
		unsigned long chunksize;
		unsigned long bytes_to_write = bytes;
		int error = 0;

		thread_mutex_lock(pipedata->mutex);

		pipedata->in_write = 1;

		while( bytes_to_write && !error ) {

			/* Number of bytes to write in each chunk */
			if( pipedata->limit_pipesize ) {
				chunksize = min( bytes_to_write, (pipedata->pipe_size) / 2 );
			} else {
				chunksize = bytes_to_write;
			}

			thread_mutex_unlock(pipedata->mutex);

			/* If the write pipe is active, put this buffer in there instead */
			if( pipedata->limit_pipesize ) {
				result = add_to_write_buffer( pipedata, chunksize, &(buffer[byteswritten]) );
				if( result == -1 ) {
					error = 1;
				}
			}
			else if( pipedata->phandles[1] ) {
				/* Using low level I/O */
				result = write( pipedata->phandles[1], &(buffer[byteswritten]), chunksize );
				if( result == -1 ) {
					error = 1;
				}
			} else if ( pipedata->fileh ) {
				/* Using streamed file I/O */
				result = fwrite( &(buffer[byteswritten]), sizeof(char), chunksize, pipedata->fileh );
				if( result != (long)chunksize ) {
					error = 1;
				}
			}
			thread_mutex_lock(pipedata->mutex);

			if( result > 0 ) {
				byteswritten += result;
				pipedata->byteswritten += result;
				bytes_to_write -= result;
			}
		}

		pipedata->in_write = 0;

		thread_mutex_unlock(pipedata->mutex);
	}

	return ( byteswritten );
}
Exemplo n.º 11
0
/* Returns the number of bytes actually read					 			  */
unsigned long thread_pipe_read( pipe_handle_t ph, unsigned long bytes, char *buffer )
{
	long result = 0;
	unsigned long bytes_to_read;
	unsigned long bytes_read;
	unsigned long chunksize;

	tl_pipedata_t *pipedata = (tl_pipedata_t *) ph;
	bytes_to_read = bytes;
	bytes_read = 0;

	if( pipedata ) {
		thread_mutex_lock(pipedata->mutex);

		/* Check for bytes in the peek buffer - return these first */
		if( pipedata->peek_buffer ) {
			unsigned long bytes_transfered;

			/* Transfer smallest of bytes requested and bytes available */
			bytes_transfered = pipedata->peek_buffer_size - pipedata->peek_next_read;
			if( bytes_transfered > bytes ) {
				bytes_transfered = bytes;
			}

			memcpy( buffer, &(pipedata->peek_buffer[pipedata->peek_next_read]), bytes_transfered );
			bytes_read += bytes_transfered;
			pipedata->peek_next_read += bytes_transfered;
			bytes_to_read -= bytes_transfered;

			/* See if the peek buffer is now empty */
			if( pipedata->peek_buffer_size - pipedata->peek_next_read <= 0 ) {
				/* Free the peek buffer */
				free( pipedata->peek_buffer );
				pipedata->peek_buffer = 0;
				pipedata->peek_buffer_size = 0;
				pipedata->peek_next_read = 0;
			}

		}

		while( !pipedata->eof && bytes_to_read ) {
			int eof = 0;
			result = 0;

			/* Number of bytes to read in each chunk */
			if( pipedata->limit_pipesize ) {
				chunksize = min( bytes_to_read, pipedata->pipe_size / 4);
			} else {
				chunksize = bytes_to_read;
			}

			thread_mutex_unlock(pipedata->mutex);
			/* Read chunksize bytes */
			if( pipedata->phandles[0] ) {
				/* Using low level I/O */
				result = read( pipedata->phandles[0], &(buffer[bytes_read]), chunksize );
				if( result <= 0 ) {
					/* End of file reached */
					eof = 1;
				}
			} else if ( pipedata->fileh ) {
				/* Using streamed file I/O */
				result = fread( &(buffer[bytes_read]), sizeof( char), chunksize, pipedata->fileh );
				if( result != (long)chunksize && feof(pipedata->fileh) ) {
					/* End of file reached */
					eof = 1;
				}
			}
#ifdef WIN32
			else if( pipedata->handle_in ) {
				DWORD read_count;
				result = 0;
				thread_mutex_lock(pipedata->mutex);
				if( ReadFile( pipedata->handle_in, &(buffer[bytes_read]), chunksize, &read_count, NULL ) ) {
					result = (long) read_count;
				} else {
					eof = 1;
				}
			}
#endif
			else {
				eof = 1;
			}
			thread_mutex_lock(pipedata->mutex);

			pipedata->eof = eof;

			if( result > 0 ) {
				if( pipedata->limit_pipesize ) {
					pipedata->bytes_in_pipe -= result;
				}
				bytes_read += result;
				bytes_to_read -= result;
				pipedata->bytesread += result;
			}

			/* refill the write pipe */
			if( !pipedata->in_write && !pipedata->bytes_in_pipe ) {
 				thread_mutex_unlock(pipedata->mutex);
				refill_write_pipe( pipedata, 0 );
 				thread_mutex_lock(pipedata->mutex);
			}
		}
		thread_mutex_unlock(pipedata->mutex);
	}

	return ( bytes_read );
}
Exemplo n.º 12
0
/* Add this data to the write buffer */
static unsigned long add_to_write_buffer(tl_pipedata_t *pipedata, unsigned long bytes, const char *buffer )
{
	tl_write_buffer_t *pbuffer;
	int block = 0;

	thread_mutex_lock(pipedata->mutex);

	/* Make room in the buffer list */
	if( !(pipedata->write_buffers) ) {
		/* Allocate 64 buffers at a time */
		pipedata->write_buffers = malloc( sizeof( tl_write_buffer_t * ) * 64 );
		if( !pipedata->write_buffers  ) {
			thread_mutex_unlock(pipedata->mutex);
			return -1;
		}
		memset( pipedata->write_buffers, 0 , sizeof( tl_write_buffer_t *) * 64 );
		pipedata->write_buffers_count = 64;
	} else {
		int free_buffers = 1;

		if( pipedata->last_write_buffer == (pipedata->first_write_buffer-1)  ) {
			free_buffers = 0;
		} else if( pipedata->first_write_buffer == 0 &&
				   (pipedata->last_write_buffer == (pipedata->write_buffers_count-1) ) ) {
			free_buffers = 0;
		}

		if(!free_buffers) {

			/* Re-organise to make more room */
			int newnumber;
			int n, i;
			tl_write_buffer_t **newbuffer;
			newnumber = (((pipedata->write_buffers_count)/64)+1) * 64;

			newbuffer = malloc( sizeof( tl_write_buffer_t *) * newnumber );
			if( !newbuffer ) {
				thread_mutex_unlock(pipedata->mutex);
				return -1;
			}
			memset( newbuffer, 0, sizeof( tl_write_buffer_t *) * newnumber );

			/* Move the buffer pointers to the new array */
			i = 0;
			n = pipedata->first_write_buffer;
			while( n != pipedata->last_write_buffer ) {

				newbuffer[i++] = pipedata->write_buffers[n++];

				if( n >= pipedata->write_buffers_count ) {
					n = 0;
				}
			}

			/* switch over to the new array and free the old one */
			free( pipedata->write_buffers );
			pipedata->write_buffers = newbuffer;
			pipedata->first_write_buffer = 0;
			pipedata->last_write_buffer = pipedata->write_buffers_count -1;
			pipedata->write_buffers_count = newnumber;
		}
	}

	/* guaranteed to have room so now add the buffer to the list */
	pbuffer = malloc( sizeof(tl_write_buffer_t) );
	if( !pbuffer ) {
		thread_mutex_unlock(pipedata->mutex);
		return -1;
	}
	pbuffer->buffer = malloc( bytes );
	if( !pbuffer->buffer ) {
		free( pbuffer );
		thread_mutex_unlock(pipedata->mutex);
		return -1;
	}
	memcpy( pbuffer->buffer, buffer, bytes );
	pbuffer->size = bytes;
	pipedata->write_buffers[ pipedata->last_write_buffer ] = pbuffer;
	pipedata->bytes_buffered += pbuffer->size;

	if(++(pipedata->last_write_buffer) >= pipedata->write_buffers_count) {
		pipedata->last_write_buffer = 0;
	}
	assert( pipedata->last_write_buffer != pipedata->first_write_buffer );

	/* If we have exceeded the orginal pipe size requested by the user, block when refilling the write pipe */
	/* Otherwise just write if there is room and then return without blocking */
	if( (pipedata->limit_pipesize==0) || (pipedata->bytes_buffered >= pipedata->buffer_limit ) ) {
		block = 2;
	}

	thread_mutex_unlock(pipedata->mutex);

	/* refill the write pipe */
	refill_write_pipe( pipedata, block );

	return( bytes );
}
Exemplo n.º 13
0
/* block = 0, no blocking, 1 = must block, 2 = block until room in buffer */
static void refill_write_pipe(tl_pipedata_t *pipedata, int block )
{
	if( !block ) {
		/* As we may not release processing time during a write call */
		/* We should be nice to other threads and offer them some processor time */
		/* This is in our interests too as they may clear out some buffer space */
		sleep(0);
	}

	thread_mutex_lock(pipedata->mutex);
	if( pipedata->limit_pipesize ) {

		if( pipedata->write_buffers && pipedata->first_write_buffer != pipedata->last_write_buffer) {
			long result;
			int writeit;
			tl_write_buffer_t *pbuffer;

			do {
				result = 0;
				writeit = 0;

				pbuffer = pipedata->write_buffers[pipedata->first_write_buffer];
				assert( pbuffer );
				assert( pbuffer->buffer );
				assert( pbuffer->size );

				if( (block == 2) && (pipedata->bytes_buffered < pipedata->buffer_limit ) ) {
					/* We were blocking because the buffer is full */
					/* there is now room so we don't need to do that any more */
					block = 0;
				}

				/* Is there room in the pipe for the next buffer? */
				if( block > 0 || ((pipedata->bytes_in_pipe + pbuffer->size + 256) <= pipedata->pipe_size) ) {
					writeit = 1;

					/* move on */
					pipedata->write_buffers[pipedata->first_write_buffer] = NULL;
					if( ++(pipedata->first_write_buffer) >= pipedata->write_buffers_count ) {
						pipedata->first_write_buffer = 0;
					}
					pipedata->bytes_in_pipe += pbuffer->size;
					pipedata->bytes_buffered -= pbuffer->size;
				}

				if( writeit ) {

					/* Add this buffer to the write pipe */
					thread_mutex_unlock(pipedata->mutex);

					if( pipedata->phandles[1] ) {
						result = write( pipedata->phandles[1], pbuffer->buffer, pbuffer->size );
					}
#ifdef WIN32
					else if( pipedata->handle_out ) {
						DWORD written;
						if( WriteFile( pipedata->handle_out, pbuffer->buffer, pbuffer->size, &written, NULL ) ) {
							result = (long) written;
						}
					}
#endif
					thread_mutex_lock(pipedata->mutex);

					assert( result == (long)(pbuffer->size) );

					/* Free the buffer */
					free( pbuffer->buffer );
					free( pbuffer );
				}
			} while( writeit && result && pipedata->first_write_buffer != pipedata->last_write_buffer );
		}
	}
	thread_mutex_unlock(pipedata->mutex);
}
Exemplo n.º 14
0
/* This does the actual connection for a relay. A thread is
 * started off if a connection can be acquired
 */
static void *start_relay_stream (void *arg)
{
    relay_server *relay = arg;
    source_t *src = relay->source;
    client_t *client;

    ICECAST_LOG_INFO("Starting relayed source at mountpoint \"%s\"", relay->localmount);
    do
    {
        client = open_relay_connection (relay);

        if (client == NULL)
            continue;

        src->client = client;
        src->parser = client->parser;
        src->con = client->con;

        if (connection_complete_source (src, 0) < 0)
        {
            ICECAST_LOG_INFO("Failed to complete source initialisation");
            client_destroy (client);
            src->client = NULL;
            continue;
        }
        stats_event_inc(NULL, "source_relay_connections");
        stats_event (relay->localmount, "source_ip", client->con->ip);

        source_main (relay->source);

        if (relay->on_demand == 0)
        {
            /* only keep refreshing YP entries for inactive on-demand relays */
            yp_remove (relay->localmount);
            relay->source->yp_public = -1;
            relay->start = time(NULL) + 10; /* prevent busy looping if failing */
            slave_update_all_mounts();
        }

        /* we've finished, now get cleaned up */
        relay->cleanup = 1;
        slave_rebuild_mounts();

        return NULL;
    } while (0);  /* TODO allow looping through multiple servers */

    if (relay->source->fallback_mount)
    {
        source_t *fallback_source;

        ICECAST_LOG_DEBUG("failed relay, fallback to %s", relay->source->fallback_mount);
        avl_tree_rlock(global.source_tree);
        fallback_source = source_find_mount (relay->source->fallback_mount);

        if (fallback_source != NULL)
            source_move_clients (relay->source, fallback_source);

        avl_tree_unlock (global.source_tree);
    }

    source_clear_source (relay->source);

    /* cleanup relay, but prevent this relay from starting up again too soon */
    thread_mutex_lock(&_slave_mutex);
    thread_mutex_lock(&(config_locks()->relay_lock));
    relay->source->on_demand = 0;
    relay->start = time(NULL) + max_interval;
    relay->cleanup = 1;
    thread_mutex_unlock(&(config_locks()->relay_lock));
    thread_mutex_unlock(&_slave_mutex);

    return NULL;
}
Exemplo n.º 15
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)
{
    unsigned long count = 0;
    if (strcmp (source->mount, dest->mount) == 0)
    {
        WARN1 ("src and dst are the same \"%s\", skipping", source->mount);
        return;
    }
    /* 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 */

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

    do
    {
        client_t *client;

        /* we need to move the client and pending trees - we must take the
         * locks in this order to avoid deadlocks */
        avl_tree_wlock (source->pending_tree);
        avl_tree_wlock (source->client_tree);

        if (source->on_demand == 0 && source->format == NULL)
        {
            INFO1 ("source mount %s is not available", source->mount);
            break;
        }
        if (source->format && dest->format)
        {
            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);

            /* when switching a client to a different queue, be wary of the 
             * refbuf it's referring to, if it's http headers then we need
             * to write them so don't release it.
             */
            if (client->check_buffer != format_check_http_buffer)
            {
                client_set_queue (client, NULL);
                client->check_buffer = format_check_file_buffer;
                if (source->con == NULL)
                    client->intro_offset = -1;
            }

            avl_insert (dest->pending_tree, (void *)client);
            count++;
        }

        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);

            /* when switching a client to a different queue, be wary of the 
             * refbuf it's referring to, if it's http headers then we need
             * to write them so don't release it.
             */
            if (client->check_buffer != format_check_http_buffer)
            {
                client_set_queue (client, NULL);
                client->check_buffer = format_check_file_buffer;
                if (source->con == NULL)
                    client->intro_offset = -1;
            }
            avl_insert (dest->pending_tree, (void *)client);
            count++;
        }
        INFO2 ("passing %lu listeners to \"%s\"", count, dest->mount);

        source->listeners = 0;
        stats_event (source->mount, "listeners", "0");

    } while (0);

    avl_tree_unlock (source->pending_tree);
    avl_tree_unlock (source->client_tree);

    /* see if we need to wake up an on-demand relay */
    if (dest->running == 0 && dest->on_demand && count)
        dest->on_demand_req = 1;

    avl_tree_unlock (dest->pending_tree);
    thread_mutex_unlock (&move_clients_mutex);
}
Exemplo n.º 16
0
static int command_metadata (client_t *client, source_t *source, int response)
{
    const char *song, *title, *artist, *artwork, *charset, *url;
    format_plugin_t *plugin;
    xmlDocPtr doc;
    xmlNodePtr node;
    int same_ip = 1;

    doc = xmlNewDoc(XMLSTR("1.0"));
    node = xmlNewDocNode(doc, NULL, XMLSTR("iceresponse"), NULL);
    xmlDocSetRootElement(doc, node);

    DEBUG0("Got metadata update request");

    COMMAND_OPTIONAL(client, "song", song);
    COMMAND_OPTIONAL(client, "title", title);
    COMMAND_OPTIONAL(client, "artist", artist);
    COMMAND_OPTIONAL(client, "url", url);
    COMMAND_OPTIONAL(client, "artwork", artwork);
    COMMAND_OPTIONAL(client, "charset", charset);

    plugin = source->format;
    if (source_running (source))
        if (strcmp (client->connection.ip, source->client->connection.ip) != 0)
            if (response == RAW && connection_check_admin_pass (client->parser) == 0)
                same_ip = 0;

	/* Update stream metadata if needed */
	if (same_ip) {
		static const struct {
			const char		*param;
			const char		*stat_name;
			const char		*hdr[3];
		} fwd[] = {
			{"xstreamname",			"server_name", 			{"ice-name",		"icy-name",			"x-audiocast-name"}},
			{"xstreamdesc",			"server_description",	{"ice-description",	"icy-description",	"x-audiocast-description"}},
			{"xstreamurl",			"server_url",			{"ice-url",			"icy-url",			"x-audiocast-url"}},
			{"xstreamgenre",		"genre",				{"ice-genre",		"icy-genre",		"x-audiocast-genre"}}
		};
		unsigned i;
		for (i = 0; i < sizeof(fwd) / sizeof(*fwd); i++) {
			const char *value;
			unsigned j;
			COMMAND_OPTIONAL(client, fwd[i].param, value);
			if (value && *value) {
				value = auto_recode(value);
				if (source->format->charset)
					stats_set_conv (source->stats, fwd[i].stat_name, value, source->format->charset);
				else
					stats_set (source->stats, fwd[i].stat_name, value);
			} else if (value) {
				stats_set (source->stats, fwd[i].stat_name, NULL);
			}
			for (j = 0; j < 3; j++) {
				if (j == 0 && value && *value) {
					httpp_setvar(source->format->parser, fwd[i].hdr[j], value);
				} else if (value && !*value) {
					httpp_deletevar(source->format->parser, fwd[i].hdr[j]);
				}
			}
		}

	}

    do
    {
        if (same_ip == 0 || plugin == NULL)
            break;
		/* Charset detection (if none specified) */
		if (!charset) {
			const char *r;
			int len;
			charset = "UTF8";
#define CCONV(s) \
			if (s && (r = auto_recode(s))) { \
				len = strlen(r); \
				s = alloca(len + 1); \
				memcpy((char*)s, r, len + 1); \
			}
			CCONV(title);
			CCONV(song);
			CCONV(artist);
		}
		/* Now send prepared metadata */
        if (artwork)
            stats_event (source->mount, "artwork", artwork);
        if (plugin->set_tag)
        {
            if (url)
            {
                plugin->set_tag (plugin, "url", url, charset);
                INFO2 ("Metadata url on %s set to \"%s\"", source->mount, url);
            }
            if (song)
            {
                plugin->set_tag (plugin, "artist", NULL, NULL);
                plugin->set_tag (plugin, "title", song, charset);
                INFO2("Metadata song on %s set to \"%s\"", source->mount, song);
            }
            if (artist)
            {
                plugin->set_tag (plugin, "artist", artist, charset);
                INFO2 ("Metadata artist on %s changed to \"%s\"", source->mount, artist);
            }
            if (title)
            {
                plugin->set_tag (plugin, "title", title, charset);
                INFO2 ("Metadata title on %s changed to \"%s\"", source->mount, title);
            }
            /* updates are now done, let them be pushed into the stream */
            plugin->set_tag (plugin, NULL, NULL, NULL);
        }
        else
        {
            break;
        }
        thread_mutex_unlock (&source->lock);
        xmlNewChild(node, NULL, XMLSTR("message"), XMLSTR("Metadata update successful"));
        xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
        return admin_send_response(doc, client, response, "response.xsl");

    } while (0);
    thread_mutex_unlock (&source->lock);
    xmlNewChild(node, NULL, XMLSTR("message"), 
            XMLSTR("Mountpoint will not accept this URL update"));
    xmlNewChild(node, NULL, XMLSTR("return"), XMLSTR("1"));
    return admin_send_response(doc, client, response, "response.xsl");
}
Exemplo n.º 17
0
void fserve_scan (time_t now)
{
    avl_node *node;
    avl_tree_wlock (fh_cache);
    node = avl_get_first (fh_cache);
    while (node)
    {
        fh_node *fh = node->key;
        node = avl_get_next (node);

        thread_mutex_lock (&fh->lock);
        if (global.running != ICE_RUNNING)
            fh->expire = 0;
        if (now == (time_t)0)
        {
            fh->expire = 0;
            thread_mutex_unlock (&fh->lock);
            continue;
        }

        if (fh->finfo.limit)
        {
            fbinfo *finfo = &fh->finfo;
            if (fh->stats == 0)
            {
                int len = strlen (finfo->mount) + 10;
                char *str = alloca (len);
                char buf[20];
                snprintf (str, len, "%s-%s", (finfo->flags & FS_FALLBACK) ? "fallback" : "file", finfo->mount);
                fh->stats = stats_handle (str);
                stats_set_flags (fh->stats, "fallback", "file", STATS_COUNTERS|STATS_HIDDEN);
                stats_set_flags (fh->stats, "outgoing_kbitrate", "0", STATS_COUNTERS|STATS_HIDDEN);
                snprintf (buf, sizeof (buf), "%d", fh->refcount);
                stats_set_flags (fh->stats, "listeners", buf, STATS_GENERAL|STATS_HIDDEN);
                snprintf (buf, sizeof (buf), "%d", fh->peak);
                stats_set_flags (fh->stats, "listener_peak", buf, STATS_GENERAL|STATS_HIDDEN);
                fh->prev_count = fh->refcount;
            }
            else
            {
                stats_lock (fh->stats, NULL);
                if (fh->prev_count != fh->refcount)
                {
                    fh->prev_count = fh->refcount;
                    stats_set_args (fh->stats, "listeners", "%ld", fh->refcount);
                    stats_set_args (fh->stats, "listener_peak", "%ld", fh->peak);
                }
            }
            if (fh->stats_update <= now)
            {
                fh->stats_update = now + 5;
                stats_set_args (fh->stats, "outgoing_kbitrate", "%ld",
                        (long)((8 * rate_avg (fh->out_bitrate))/1024));
            }
            stats_release (fh->stats);
        }

        if (fh->refcount == 0 && fh->expire >= 0 && now >= fh->expire)
        {
            DEBUG1 ("timeout of %s", fh->finfo.mount);
            if (fh->stats)
            {
                stats_lock (fh->stats, NULL);
                stats_set (fh->stats, NULL, NULL);
            }
            remove_fh_from_cache (fh);
            thread_mutex_unlock (&fh->lock);
            _delete_fh (fh);
            continue;
        }
        thread_mutex_unlock (&fh->lock);
    }
    avl_tree_unlock (fh_cache);
}
Exemplo n.º 18
0
Arquivo: php.c Projeto: budisfg/spine
/*! \fn char *php_cmd(const char *php_command, int php_process)
 *  \brief calls the script server and executes a script command
 *  \param php_command the formatted php script server command
 *  \param php_process the php script server process to call
 *
 *  This function is called directly by the spine poller when a script server
 *  request has been initiated for a host.  It will place the PHP Script Server
 *  command on it's output pipe and then wait the pre-defined timeout period for
 *  a response on the PHP Script Servers output pipe.
 *
 *  \return pointer to the string results.  Must be freed by the parent.
 *
 */
char *php_cmd(const char *php_command, int php_process) {
    char *result_string;
    char command[BUFSIZE];
    ssize_t bytes;
    int retries = 0;

    assert(php_command != 0);

    /* pad command with CR-LF */
    snprintf(command, BUFSIZE, "%s\r\n", php_command);

    /* place lock around mutex */
    switch (php_process) {
    case 0:
        thread_mutex_lock(LOCK_PHP_PROC_0);
        break;
    case 1:
        thread_mutex_lock(LOCK_PHP_PROC_1);
        break;
    case 2:
        thread_mutex_lock(LOCK_PHP_PROC_2);
        break;
    case 3:
        thread_mutex_lock(LOCK_PHP_PROC_3);
        break;
    case 4:
        thread_mutex_lock(LOCK_PHP_PROC_4);
        break;
    case 5:
        thread_mutex_lock(LOCK_PHP_PROC_5);
        break;
    case 6:
        thread_mutex_lock(LOCK_PHP_PROC_6);
        break;
    case 7:
        thread_mutex_lock(LOCK_PHP_PROC_7);
        break;
    case 8:
        thread_mutex_lock(LOCK_PHP_PROC_8);
        break;
    case 9:
        thread_mutex_lock(LOCK_PHP_PROC_9);
        break;
    }

    /* send command to the script server */
retry:
    bytes = write(php_processes[php_process].php_write_fd, command, strlen(command));

    /* if write status is <= 0 then the script server may be hung */
    if (bytes <= 0) {
        result_string = strdup("U");
        SPINE_LOG(("ERROR: SS[%i] PHP Script Server communications lost.  Restarting PHP Script Server", php_process));
        php_close(php_process);
        php_init(php_process);
        /* increment and retry a few times on the next item */
        retries++;
        if (retries < 3) {
            goto retry;
        }
    } else {
        /* read the result from the php_command */
        result_string = php_readpipe(php_process);

        /* check for a null */
        if (!strlen(result_string)) {
            SET_UNDEFINED(result_string);
        }
    }

    /* unlock around php process */
    switch (php_process) {
    case 0:
        thread_mutex_unlock(LOCK_PHP_PROC_0);
        break;
    case 1:
        thread_mutex_unlock(LOCK_PHP_PROC_1);
        break;
    case 2:
        thread_mutex_unlock(LOCK_PHP_PROC_2);
        break;
    case 3:
        thread_mutex_unlock(LOCK_PHP_PROC_3);
        break;
    case 4:
        thread_mutex_unlock(LOCK_PHP_PROC_4);
        break;
    case 5:
        thread_mutex_unlock(LOCK_PHP_PROC_5);
        break;
    case 6:
        thread_mutex_unlock(LOCK_PHP_PROC_6);
        break;
    case 7:
        thread_mutex_unlock(LOCK_PHP_PROC_7);
        break;
    case 8:
        thread_mutex_unlock(LOCK_PHP_PROC_8);
        break;
    case 9:
        thread_mutex_unlock(LOCK_PHP_PROC_9);
        break;
    }

    return result_string;
}
Exemplo n.º 19
0
int fserve_setup_client_fb (client_t *client, fbinfo *finfo)
{
    fh_node *fh = &no_file;
    int ret = 0;

    if (finfo)
    {
        mount_proxy *minfo;
        if (finfo->flags & FS_FALLBACK && finfo->limit == 0)
            return -1;
        avl_tree_wlock (fh_cache);
        fh = find_fh (finfo);
        minfo = config_find_mount (config_get_config(), finfo->mount);
        if (fh)
        {
            thread_mutex_lock (&fh->lock);
            avl_tree_unlock (fh_cache);
            client->shared_data = NULL;
            if (minfo)
            {
                if (minfo->max_listeners >= 0 && fh->refcount > minfo->max_listeners)
                {
                    thread_mutex_unlock (&fh->lock);
                    config_release_config();
                    return client_send_403redirect (client, finfo->mount, "max listeners reached");
                }
                if (check_duplicate_logins (finfo->mount, fh->clients, client, minfo->auth) == 0)
                {
                    thread_mutex_unlock (&fh->lock);
                    config_release_config();
                    return client_send_403 (client, "Account already in use");
                }
            }
            config_release_config();
        }
        else
        {
            if (minfo && minfo->max_listeners == 0)
            {
                avl_tree_unlock (fh_cache);
                config_release_config();
                client->shared_data = NULL;
                return client_send_403redirect (client, finfo->mount, "max listeners reached");
            }
            config_release_config();
            fh = open_fh (finfo);
            if (fh == NULL)
                return client_send_404 (client, NULL);
        }
        if (fh->finfo.limit)
        {
            client->timer_start = client->worker->current_time.tv_sec;
            if (client->connection.sent_bytes == 0)
                client->timer_start -= 2;
            client->counter = 0;
            client->intro_offset = 0;
            global_reduce_bitrate_sampling (global.out_bitrate);
        }
    }
    else
        thread_mutex_lock (&fh->lock);
    client->mount = fh->finfo.mount;
    if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
    {
        if (client->respcode == 0)
        {
            client->refbuf->len = 0;
            ret = format_general_headers (fh->format, client);
        }
    }
    else
    {
        if (fh->format->create_client_data && client->format_data == NULL)
            ret = fh->format->create_client_data (fh->format, client);
        if (fh->format->write_buf_to_client)
            client->check_buffer = fh->format->write_buf_to_client;
    }
    if (ret < 0)
    {
        thread_mutex_unlock (&fh->lock);
        return client_send_416 (client);
    }
    fh_add_client (fh, client);
    thread_mutex_unlock (&fh->lock);
    client->shared_data = fh;

    if (client->check_buffer == NULL)
        client->check_buffer = format_generic_write_to_client;

    client->ops = &buffer_content_ops;
    client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
    client->flags |= CLIENT_IN_FSERVE;
    if (client->flags & CLIENT_ACTIVE)
    {
        client->schedule_ms = client->worker->time_ms;
        if (finfo && finfo->flags & FS_FALLBACK)
            return 0; // prevent a recursive loop 
        return client->ops->process (client);
    }
    else
    {
        worker_t *worker = client->worker;
        client->flags |= CLIENT_ACTIVE;
        worker_wakeup (worker); /* worker may of already processed client but make sure */
    }
    return 0;
}
Exemplo n.º 20
0
MPID_Win_fence(assert, win)
{
    thread_mutex_lock(dwin->thread_mutex);
    {
	dwin->access_epoch_state = EPOCH_STATE_CLOSED;
	dwin->access_epoch_id++;

	copy(rhc[0..np-1], rhc[np..np*2-1]);
	zero(dwin->rhc_cnts[0..np-1]);
    }
    thread_mutex_unlock(dwin->thread_mutex);
    
    MPI_Alltoall(dwin->rhc_cnts + np, np, MPI_INT,
		 dwin->rhc_cnts + np * 2, np, MPI_INT, dwin->comm)
    dwin->rhc_incoming = sum(rhc[np*2..np*3-1]);
    
    while(dwin->rhc_processed < dwin->rhc_incoming &&
	  dwin->lops_completed < dwin->lops_posted)
    {
	/*
	 * We need to block until such time that all incoming RHCs have been
	 * handled and all locally posted operations have completed.
	 *
	 * NOTE: The number of locally posted operations may increase as a
	 * result of processing RHCs.
	 *
	 * Q: What is the right interface for this blocking operation?  The
	 * operation should block, but it needs to guarantee that forward
	 * progress is being made on both the incoming RHCs and locally posted
	 * operations.  Whatever the correct interface is, we either need to
	 * pass in dwin or declare/cast the counters unsed the above while
	 * statement as volatile.
	 */
	MPID_Win_wait(dwin);
    }
    
    thread_mutex_lock(dwin->thread_mutex);
    {
	if (assert & MPI_MODE_NOSUCCEED)
	{
	    dwin->exposure_epoch_state = EPOCH_STATE_CLOSED;
	}
	else
	{
	    dwin->access_epoch_state = EPOCH_STATE_ACTIVE;
	    dwin->exposure_epoch_state = EPOCH_STATE_ACTIVE;
	}
	
	dwin->exposure_epoch_id++;
	dwin->rhc_processed = 0;
	
	dwin->tag = 0;
    }
    thread_mutex_unlock(dwin->thread_mutex);
    
    /*
     * We could perform a barrier here to ensure that 
     */
    MPI_Barrier(dwin->comm);

}
Exemplo n.º 21
0
int db_connect(char *database, MYSQL *mysql) {
    char logmessage[LOGSIZE];
    MYSQL *db;
    int tries;
    int result;
    char *hostname;
    char *socket;

    if ((hostname = strdup(set.dbhost)) == NULL) {
        snprintf(logmessage, LOGSIZE-1, "ERROR: malloc(): strdup() failed\n");
        cacti_log(logmessage);
        exit_cactid();
    }

    if ((socket = strstr(hostname,":"))) {
        *socket++ = 0x0;
    }

    /* initialalize my variables */
    tries = 20;
    result = 0;

    if (set.verbose == POLLER_VERBOSITY_DEBUG) {
        snprintf(logmessage, LOGSIZE-1, "MYSQL: Connecting to MySQL database '%s' on '%s'...\n", database, set.dbhost);
        cacti_log(logmessage);
    }

    thread_mutex_lock(LOCK_MYSQL);
    db = mysql_init(mysql);
    if (db == NULL) {
        cacti_log("ERROR: MySQL unable to allocate memory and therefore can not connect\n");
        exit_cactid();
    }

    while (tries > 0) {
        tries--;
        if (!mysql_real_connect(mysql, hostname, set.dbuser, set.dbpass, database, set.dbport, socket, 0)) {
            if (set.verbose == POLLER_VERBOSITY_DEBUG) {
                snprintf(logmessage, LOGSIZE-1, "MYSQL: Connection Failed: %s\n", mysql_error(mysql));
                cacti_log(logmessage);
            }
            result = 1;
        } else {
            tries = 0;
            result = 0;
            if (set.verbose == POLLER_VERBOSITY_DEBUG) {
                snprintf(logmessage, LOGSIZE-1, "MYSQL: Connected to MySQL database '%s' on '%s'...\n", database, set.dbhost);
                cacti_log(logmessage);
            }
        }
        usleep(2000);
    }

    free(hostname);

    if (result == 1) {
        snprintf(logmessage, LOGSIZE-1, "MYSQL: Connection Failed: %s\n", mysql_error(mysql));
        cacti_log(logmessage);
        thread_mutex_unlock(LOCK_MYSQL);
        exit_cactid();
    } else {
        thread_mutex_unlock(LOCK_MYSQL);
        return 0;
    }
}
Exemplo n.º 22
0
static void *fserv_thread_function(void *arg)
{
    fserve_t *fclient, **trail;
    int sbytes, bytes;

    INFO0("file serving thread started");
    while (run_fserv) {
        wait_for_fds();

        fclient = active_list;
        trail = &active_list;

        while (fclient)
        {
            /* process this client, if it is ready */
            if (fclient->ready)
            {
                fclient->ready = 0;
                if(fclient->offset >= fclient->datasize) {
                    /* Grab a new chunk */
                    bytes = fread(fclient->buf, 1, BUFSIZE, fclient->file);
                    if (bytes == 0)
                    {
                        fserve_t *to_go = fclient;
                        fclient = fclient->next;
                        *trail = fclient;
                        _free_client (to_go);
                        fserve_clients--;
                        client_tree_changed = 1;
                        continue;
                    }
                    fclient->offset = 0;
                    fclient->datasize = bytes;
                }

                /* Now try and send current chunk. */
                sbytes = client_send_bytes (fclient->client, 
                        &fclient->buf[fclient->offset], 
                        fclient->datasize - fclient->offset);

                /* TODO: remove clients if they take too long. */
                if(sbytes > 0) {
                    fclient->offset += sbytes;
                }

                if (fclient->client->con->error)
                {
                    fserve_t *to_go = fclient;
                    fclient = fclient->next;
                    *trail = fclient;
                    fserve_clients--;
                    _free_client (to_go);
                    client_tree_changed = 1;
                    continue;
                }
            }
            trail = &fclient->next;
            fclient = fclient->next;
        }
    }

    /* Shutdown path */
    thread_mutex_lock (&pending_lock);
    while (pending_list)
    {
        fserve_t *to_go = (fserve_t *)pending_list;
        pending_list = to_go->next;
        _free_client (to_go);
    }
    thread_mutex_unlock (&pending_lock);

    while (active_list)
    {
        fserve_t *to_go = active_list;
        active_list = to_go->next;
        _free_client (to_go);
    }

    return NULL;
}
Exemplo n.º 23
0
/* The main loop for each instance. Gets data passed to it from the stream
 * manager (which gets it from the input module), and streams it to the
 * specified server
 */
void *ices_instance_stream(void *arg)
{
	int ret, shouterr;
	ref_buffer *buffer;
	char *connip;
	stream_description *sdsc = arg;
	instance_t *stream = sdsc->stream;
	input_module_t *inmod = sdsc->input;
	int reencoding = (inmod->type == ICES_INPUT_VORBIS) && stream->encode;
	int encoding = (inmod->type == ICES_INPUT_PCM) && stream->encode;
    char *stream_name = NULL, *stream_genre = NULL, *stream_description = NULL;
    char *user = NULL;
	
	vorbis_comment_init(&sdsc->vc);

	sdsc->shout = shout_new();

	/* we only support the ice protocol and vorbis streams currently */
	shout_set_format(sdsc->shout, SHOUT_FORMAT_VORBIS);
	//shout_set_protocol(sdsc->shout, SHOUT_PROTOCOL_ICE);
	shout_set_protocol(sdsc->shout, SHOUT_PROTOCOL_HTTP);

    signal(SIGPIPE, signal_hup_handler);

	connip = malloc(16);
	if(!resolver_getip(stream->hostname, connip, 16))
	{
		LOG_ERROR1("Could not resolve hostname \"%s\"", stream->hostname);
		free(connip);
		stream->died = 1;
		return NULL;
	}

	if (!(shout_set_host(sdsc->shout, connip)) == SHOUTERR_SUCCESS) {
		LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
		free(connip);
		stream->died = 1;
		return NULL;
	}

	shout_set_port(sdsc->shout, stream->port);
	if (!(shout_set_password(sdsc->shout, stream->password)) == SHOUTERR_SUCCESS) {
		LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
		free(connip);
		stream->died = 1;
		return NULL;
	}
    if (stream->user)
        user = stream->user;
    else
        user = "******";

    if(shout_set_user(sdsc->shout, user) != SHOUTERR_SUCCESS) {
		LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
		free(connip);
		stream->died = 1;
		return NULL;
    }

	if (!(shout_set_agent(sdsc->shout, VERSIONSTRING)) == SHOUTERR_SUCCESS) {
		LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
		free(connip);
		stream->died = 1;
		return NULL;
	}

	if (!(shout_set_mount(sdsc->shout, stream->mount)) == SHOUTERR_SUCCESS) {
		LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
		free(connip);
		stream->died = 1;
		return NULL;
	}

	/* set the metadata for the stream */
    if(stream->stream_name)
        stream_name = stream->stream_name;
    else if (ices_config->stream_name)
        stream_name = ices_config->stream_name;

    if(stream->stream_description)
        stream_description = stream->stream_description;
    else if (ices_config->stream_description)
        stream_description = ices_config->stream_description;

    if(stream->stream_genre)
        stream_genre = stream->stream_genre;
    else if (ices_config->stream_genre)
        stream_genre = ices_config->stream_genre;

    if(stream_name)
		if (!(shout_set_name(sdsc->shout, stream_name)) == SHOUTERR_SUCCESS) {
			LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
			free(connip);
			stream->died = 1;
			return NULL;
		}
	if (stream_genre)
		if (!(shout_set_genre(sdsc->shout, stream_genre)) == SHOUTERR_SUCCESS) {
			LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
			free(connip);
			stream->died = 1;
			return NULL;
		}
	if (stream_description)
		if (!(shout_set_description(sdsc->shout, stream_description)) == SHOUTERR_SUCCESS) {
			LOG_ERROR1("libshout error: %s\n", shout_get_error(sdsc->shout));
			free(connip);
			stream->died = 1;
			return NULL;
		}

    if(stream->downmix && encoding && stream->channels == 1) {
        stream->channels = 1;
        sdsc->downmix = downmix_initialise();
    }

    if(stream->resampleinrate && stream->resampleoutrate && encoding) {
        stream->samplerate = stream->resampleoutrate;
        sdsc->resamp = resample_initialise(stream->channels, 
                stream->resampleinrate, stream->resampleoutrate);
    }

	if(encoding)
	{
		if(inmod->metadata_update)
			inmod->metadata_update(inmod->internal, &sdsc->vc);
		sdsc->enc = encode_initialise(stream->channels, stream->samplerate,
				stream->managed, stream->min_br, stream->nom_br, stream->max_br,
                stream->quality, stream->serial++, &sdsc->vc);
        if(!sdsc->enc) {
            LOG_ERROR0("Failed to configure encoder");
		    stream->died = 1;
            return NULL; /* FIXME: probably leaking some memory here */
        }
	}
	else if(reencoding)
		sdsc->reenc = reencode_init(stream);

    if(stream->savefilename != NULL) 
    {
        stream->savefile = fopen(stream->savefilename, "wb");
        if(!stream->savefile)
            LOG_ERROR2("Failed to open stream save file %s: %s", 
                    stream->savefilename, strerror(errno));
        else
            LOG_INFO1("Saving stream to file %s", stream->savefilename);
    }

	if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS)
	{
		LOG_INFO3("Connected to server: %s:%d%s", 
				shout_get_host(sdsc->shout), shout_get_port(sdsc->shout), shout_get_mount(sdsc->shout));

		while(1)
		{
			if(stream->buffer_failures > MAX_ERRORS)
			{
				LOG_WARN0("Too many errors, shutting down");
				break;
			}

			buffer = stream_wait_for_data(stream);

			/* buffer being NULL means that either a fatal error occured,
			 * or we've been told to shut down
			 */
			if(!buffer)
				break;

			/* If data is NULL or length is 0, we should just skip this one.
			 * Probably, we've been signalled to shut down, and that'll be
			 * caught next iteration. Add to the error count just in case,
			 * so that we eventually break out anyway 
			 */
			if(!buffer->buf || !buffer->len)
			{
				LOG_WARN0("Bad buffer dequeued!");
				stream->buffer_failures++;
				continue; 
			}

            if(stream->wait_for_critical)
            {
                LOG_INFO0("Trying restart on new substream");
                stream->wait_for_critical = 0;
            }

            ret = process_and_send_buffer(sdsc, buffer);

            /* No data produced, do nothing */
            if(ret == -1)
                ;
            /* Fatal error */
            else if(ret == -2)
            {
                LOG_ERROR0("Serious error, waiting to restart on "
                           "next substream. Stream temporarily suspended.");
                /* Set to wait until a critical buffer comes through (start of
                 * a new substream, typically), and flush existing queue.
                 */
                thread_mutex_lock(&ices_config->flush_lock);
                stream->wait_for_critical = 1;
                input_flush_queue(stream->queue, 0);
                thread_mutex_unlock(&ices_config->flush_lock);
            }
            /* Non-fatal shout error */
            else if(ret == 0)
			{
				LOG_ERROR2("Send error: %s (%s)", 
                        shout_get_error(sdsc->shout), strerror(errno));
				if(shout_get_errno(sdsc->shout) == SHOUTERR_SOCKET)
				{
					int i=0;

					/* While we're trying to reconnect, don't receive data
					 * to this instance, or we'll overflow once reconnect
					 * succeeds
					 */
					thread_mutex_lock(&ices_config->flush_lock);
					stream->skip = 1;

					/* Also, flush the current queue */
					input_flush_queue(stream->queue, 1);
					thread_mutex_unlock(&ices_config->flush_lock);
					
					while((i < stream->reconnect_attempts ||
							stream->reconnect_attempts==-1) && 
                            !ices_config->shutdown)
					{
						i++;
						LOG_WARN0("Trying reconnect after server socket error");
						shout_close(sdsc->shout);
						if((shouterr = shout_open(sdsc->shout)) == SHOUTERR_SUCCESS)
						{
							LOG_INFO3("Connected to server: %s:%d%s", 
                                    shout_get_host(sdsc->shout), shout_get_port(sdsc->shout), 
                                    shout_get_mount(sdsc->shout));
                            /* This stream can't restart until the next
                             * logical stream comes along, since the
                             * server won't have any cached headers for
                             * this source/connection. So, don't continue
                             * yet.
                             */
                            thread_mutex_lock(&ices_config->flush_lock);
                            stream->wait_for_critical = 1;
                            input_flush_queue(stream->queue, 0);
                            thread_mutex_unlock(&ices_config->flush_lock);
							break;
						}
						else
						{
							LOG_ERROR3("Failed to reconnect to %s:%d (%s)",
								shout_get_host(sdsc->shout),shout_get_port(sdsc->shout),
								shout_get_error(sdsc->shout));
							if(i==stream->reconnect_attempts)
							{
								LOG_ERROR0("Reconnect failed too many times, "
										  "giving up.");
                                /* We want to die now */
								stream->buffer_failures = MAX_ERRORS+1; 
							}
							else /* Don't try again too soon */
								sleep(stream->reconnect_delay); 
						}
					}
					stream->skip = 0;
				}
				stream->buffer_failures++;
			}
			stream_release_buffer(buffer);
		}
	}
	else
	{
		LOG_ERROR3("Failed initial connect to %s:%d (%s)", 
				shout_get_host(sdsc->shout),shout_get_port(sdsc->shout), shout_get_error(sdsc->shout));
	}
	
	shout_close(sdsc->shout);

    if(stream->savefile != NULL) 
        fclose(stream->savefile);

    shout_free(sdsc->shout);
	encode_clear(sdsc->enc);
	reencode_clear(sdsc->reenc);
    downmix_clear(sdsc->downmix);
    resample_clear(sdsc->resamp);
	vorbis_comment_clear(&sdsc->vc);

	stream->died = 1;
	return NULL;
}
Exemplo n.º 24
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();
    struct stat file_buf;
    char *range = NULL;
    int64_t new_content_len = 0;
    int64_t rangenumber = 0;
    int rangeproblem = 0;
    int ret = 0;

    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->content_length = 0;
    client->buf = malloc(BUFSIZE);
    if (stat(path, &file_buf) == 0) {
        client->content_length = (int64_t)file_buf.st_size;
    }

    global_lock();
    if(global.clients >= client_limit) {
        global_unlock();
        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);
        return -1;
    }
    global.clients++;
    global_unlock();

    range = httpp_getvar (client->client->parser, "range");

    if (range != NULL) {
        ret = sscanf(range, "bytes=" FORMAT_INT64 "-", &rangenumber);
        if (ret != 1) {
            /* format not correct, so lets just assume
               we start from the beginning */
            rangeproblem = 1;
        }
        if (rangenumber < 0) {
            rangeproblem = 1;
        }
        if (!rangeproblem) {
            ret = fseek(client->file, rangenumber, SEEK_SET);
            if (ret != -1) {
                new_content_len = client->content_length - rangenumber;
                if (new_content_len < 0) {
                    rangeproblem = 1;
                }
            }
            else {
                rangeproblem = 1;
            }
            if (!rangeproblem) {
                /* Date: is required on all HTTP1.1 responses */
                char currenttime[50];
                time_t now;
                int strflen;
                struct tm result;
                int64_t endpos = rangenumber+new_content_len-1;
                if (endpos < 0) {
                    endpos = 0;
                }
                time(&now);
                strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",
                                   gmtime_r(&now, &result));
                httpclient->respcode = 206;
                bytes = sock_write(httpclient->con->sock,
                    "HTTP/1.1 206 Partial Content\r\n"
                    "Date: %s\r\n"
                    "Content-Length: " FORMAT_INT64 "\r\n"
                    "Content-Range: bytes " FORMAT_INT64 \
                    "-" FORMAT_INT64 "/" FORMAT_INT64 "\r\n"
                    "Content-Type: %s\r\n\r\n",
                    currenttime,
                    new_content_len,
                    rangenumber,
                    endpos,
                    client->content_length,
                    fserve_content_type(path));
                if(bytes > 0) httpclient->con->sent_bytes = bytes;
            }
            else {
                httpclient->respcode = 416;
                bytes = sock_write(httpclient->con->sock,
                    "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
                if(bytes > 0) httpclient->con->sent_bytes = bytes;
                fserve_client_destroy(client);
                return -1;
            }
        }
        else {
            /* If we run into any issues with the ranges
               we fallback to a normal/non-range request */
            httpclient->respcode = 416;
            bytes = sock_write(httpclient->con->sock,
                "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
            if(bytes > 0) httpclient->con->sent_bytes = bytes;
            fserve_client_destroy(client);
            return -1;
        }
    }
    else {

        httpclient->respcode = 200;
        bytes = sock_write(httpclient->con->sock,
            "HTTP/1.0 200 OK\r\n"
            "Content-Length: " FORMAT_INT64 "\r\n"
            "Content-Type: %s\r\n\r\n",
            client->content_length,
            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.º 25
0
static void *_stats_thread(void *arg)
{
    stats_event_t *event;
    stats_event_t *copy;
    event_listener_t *listener;

    stats_event_time (NULL, "server_start");
    stats_event_time_iso8601 (NULL, "server_start_iso8601");

    /* global currently active stats */
    stats_event (NULL, "clients", "0");
    stats_event (NULL, "connections", "0");
    stats_event (NULL, "sources", "0");
    stats_event (NULL, "stats", "0");
    stats_event (NULL, "listeners", "0");

    /* global accumulating stats */
    stats_event (NULL, "client_connections", "0");
    stats_event (NULL, "source_client_connections", "0");
    stats_event (NULL, "source_relay_connections", "0");
    stats_event (NULL, "source_total_connections", "0");
    stats_event (NULL, "stats_connections", "0");
    stats_event (NULL, "listener_connections", "0");

    ICECAST_LOG_INFO("stats thread started");
    while (_stats_running) {
        thread_mutex_lock(&_global_event_mutex);
        if (_global_event_queue.head != NULL) {
            /* grab the next event from the queue */
            event = _get_event_from_queue (&_global_event_queue);
            thread_mutex_unlock(&_global_event_mutex);

            if (event == NULL)
                continue;
            event->next = NULL;

            thread_mutex_lock(&_stats_mutex);

            /* check if we are dealing with a global or source event */
            if (event->source == NULL)
                process_global_event (event);
            else
                process_source_event (event);

            /* now we have an event that's been processed into the running stats */
            /* this event should get copied to event listeners' queues */
            listener = (event_listener_t *)_event_listeners;
            while (listener) {
                copy = _copy_event(event);
                thread_mutex_lock (&listener->mutex);
                _add_event_to_queue (copy, &listener->queue);
                thread_mutex_unlock (&listener->mutex);

                listener = listener->next;
            }

            /* now we need to destroy the event */
            _free_event(event);

            thread_mutex_unlock(&_stats_mutex);
            continue;
        }
        else
        {
            thread_mutex_unlock(&_global_event_mutex);
        }

        thread_sleep(300000);
    }

    return NULL;
}
Exemplo n.º 26
0
/* run along queue checking for any data that has come in or a timeout */
static void process_request_queue (void)
{
    client_queue_t **node_ref = (client_queue_t **)&_req_queue;
    ice_config_t *config = config_get_config ();
    int timeout = config->header_timeout;
    config_release_config();

    while (*node_ref)
    {
        client_queue_t *node = *node_ref;
        client_t *client = node->client;
        int len = PER_CLIENT_REFBUF_SIZE - 1 - node->offset;
        char *buf = client->refbuf->data + node->offset;

        if (len > 0)
        {
            if (client->con->con_time + timeout <= time(NULL))
                len = 0;
            else
                len = client_read_bytes (client, buf, len);
        }

        if (len > 0)
        {
            int pass_it = 1;
            char *ptr;

            /* handle \n, \r\n and nsvcap which for some strange reason has
             * EOL as \r\r\n */
            node->offset += len;
            client->refbuf->data [node->offset] = '\000';
            do
            {
                if (node->shoutcast == 1)
                {
                    /* password line */
                    if (strstr (client->refbuf->data, "\r\r\n") != NULL)
                        break;
                    if (strstr (client->refbuf->data, "\r\n") != NULL)
                        break;
                    if (strstr (client->refbuf->data, "\n") != NULL)
                        break;
                }
                /* stream_offset refers to the start of any data sent after the
                 * http style headers, we don't want to lose those */
                ptr = strstr (client->refbuf->data, "\r\r\n\r\r\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+6) - client->refbuf->data;
                    break;
                }
                ptr = strstr (client->refbuf->data, "\r\n\r\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+4) - client->refbuf->data;
                    break;
                }
                ptr = strstr (client->refbuf->data, "\n\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+2) - client->refbuf->data;
                    break;
                }
                pass_it = 0;
            } while (0);

            if (pass_it)
            {
                thread_mutex_lock (&_req_queue_mutex);
                if ((client_queue_t **)_req_queue_tail == &(node->next))
                    _req_queue_tail = (volatile client_queue_t **)node_ref;
                *node_ref = node->next;
                node->next = NULL;
                thread_mutex_unlock (&_req_queue_mutex);
                _add_connection (node);
                continue;
            }
        }
        else
        {
            if (len == 0 || client->con->error)
            {
                thread_mutex_lock (&_req_queue_mutex);
                if ((client_queue_t **)_req_queue_tail == &node->next)
                    _req_queue_tail = (volatile client_queue_t **)node_ref;
                *node_ref = node->next;
                thread_mutex_unlock (&_req_queue_mutex);
                client_destroy (client);
                free (node);
                continue;
            }
        }
        node_ref = &node->next;
    }
}
Exemplo n.º 27
0
static int command_stats_mount (client_t *client, source_t *source, int response)
{
    thread_mutex_unlock (&source->lock);
    return command_stats (client, NULL);
}
Exemplo n.º 28
0
/*! \fn main(int argc, char *argv[])
 *  \brief The Cactid program entry point
 *  \param argc The number of arguments passed to the function plus one (+1)
 *  \param argv An array of the command line arguments
 *
 *  The Cactid entry point.  This function performs the following tasks.
 *  1) Processes command line input parameters
 *  2) Processes the Cactid configuration file to obtain database access information
 *  3) Process runtime parameters from the settings table
 *  4) Initialize the runtime threads and mutexes for the threaded environment
 *  5) Initialize Net-SNMP, MySQL, and the PHP Script Server (if required)
 *  6) Spawns X threads in order to process hosts
 *  7) Loop until either all hosts have been processed or until the poller runtime
 *     has been exceeded
 *  8) Close database and free variables
 *  9) Log poller process statistics if required
 *  10) Exit
 *
 *  Note: Command line runtime parameters override any database settings.
 *
 *  \return 0 if SUCCESS, or -1 if FAILED
 *
 */
int main(int argc, char *argv[]) {
	struct timeval now;
	char *conf_file = NULL;
	double begin_time, end_time, current_time;
	int poller_interval;
	int num_rows;
	int device_counter = 0;
	int poller_counter = 0;
	int last_active_threads = 0;
	long int EXTERNAL_THREAD_SLEEP = 100000;
	long int internal_thread_sleep;
	time_t nowbin;
	struct tm now_time;
	struct tm *now_ptr;

	pthread_t* threads = NULL;
	pthread_attr_t attr;

	int* ids = NULL;
	MYSQL mysql;
	MYSQL_RES *result = NULL;
	MYSQL_ROW mysql_row;
	int canexit = 0;
	int host_id;
	int i;
	int mutex_status = 0;
	int thread_status = 0;

	UNUSED_PARAMETER(argc);		/* we operate strictly with argv */

	/* establish php processes and initialize space */
	php_processes = (php_t*) calloc(MAX_PHP_SERVERS, sizeof(php_t));
	for (i = 0; i < MAX_PHP_SERVERS; i++) {
		php_processes[i].php_state = PHP_BUSY;
	}

	/* set start time for cacti */
	begin_time = get_time_as_double();

	/* get time for poller_output table */
	if (time(&nowbin) == (time_t) - 1) {
		die("ERROR: Could not get time of day from time()\n");
	}
	localtime_r(&nowbin,&now_time);
	now_ptr = &now_time;

	if (strftime(start_datetime, sizeof(start_datetime), "%Y-%m-%d %H:%M:%S", now_ptr) == (size_t) 0) {
		die("ERROR: Could not get string from strftime()\n");
	}

	/* set default verbosity */
	set.log_level = POLLER_VERBOSITY_LOW;

	/* get static defaults for system */
	config_defaults();

	/*! ----------------------------------------------------------------
	 * PROCESS COMMAND LINE
	 *
	 * Run through the list of ARGV words looking for parameters we
	 * know about. Most have two flavors (-C + --conf), and many
	 * themselves take a parameter.
	 *
	 * These parameters can be structured in two ways:
	 *
	 *	--conf=FILE		both parts in one argv[] string
	 *	--conf FILE		two separate argv[] strings
	 *
	 * We set "arg" to point to "--conf", and "opt" to point to FILE.
	 * The helper routine
	 *
	 * In each loop we set "arg" to next argv[] string, then look
	 * to see if it has an equal sign. If so, we split it in half
	 * and point to the option separately.
	 *
	 * NOTE: most direction to the program is given with dash-type
	 * parameters, but we also allow standalone numeric device IDs
	 * in "first last" format: this is how poller.php calls this
	 * program.
	 */

	/* initialize some global variables */
	set.start_host_id = -1;
	set.end_host_id   = -1;
	set.php_initialized = FALSE;
	set.logfile_processed = FALSE;
	set.parent_fork = CACTID_PARENT;

	for (argv++; *argv; argv++) {
		char	*arg = *argv;
		char	*opt = strchr(arg, '=');	/* pick off the =VALUE part */

		if (opt) *opt++ = '\0';

		if (STRIMATCH(arg, "-f") ||
			STRIMATCH(arg, "--first")) {
			if (HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.start_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.start_host_id)) {
				die("ERROR: '%s=%s' is invalid first-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-l") ||
				 STRIMATCH(arg, "--last")) {
			if (HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: %s can only be used once", arg);
			}

			set.end_host_id = atoi(opt = getarg(opt, &argv));

			if (!HOSTID_DEFINED(set.end_host_id)) {
				die("ERROR: '%s=%s' is invalid last-host ID", arg, opt);
			}
		}

		else if (STRIMATCH(arg, "-p") ||
				 STRIMATCH(arg, "--poller")) {
			set.poller_id = atoi(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-h") ||
				 STRIMATCH(arg, "-v") ||
				 STRIMATCH(arg, "--help") ||
				 STRIMATCH(arg, "--version")) {
			display_help();

			exit(EXIT_SUCCESS);
		}

		else if (STRIMATCH(arg, "-O") ||
				 STRIMATCH(arg, "--option")) {
			char	*setting = getarg(opt, &argv);
			char	*value   = strchr(setting, ':');

			if (*value) {
				*value++ = '\0';
			}else{
				die("ERROR: -O requires setting:value");
			}

			set_option(setting, value);
		}

		else if (STRIMATCH(arg, "-R") ||
				 STRIMATCH(arg, "--readonly") ||
				 STRIMATCH(arg, "--read-only")) {
			set.SQL_readonly = TRUE;
		}

		else if (STRIMATCH(arg, "-C") ||
				 STRIMATCH(arg, "--conf")) {
			conf_file = strdup(getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-S") ||
				 STRIMATCH(arg, "--stdout")) {
			set_option("log_destination", "STDOUT");
		}

		else if (STRIMATCH(arg, "-L") ||
				 STRIMATCH(arg, "--log")) {
			set_option("log_destination", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "-V") ||
				 STRIMATCH(arg, "--verbosity")) {
			set_option("log_verbosity", getarg(opt, &argv));
		}

		else if (STRIMATCH(arg, "--snmponly") ||
				 STRIMATCH(arg, "--snmp-only")) {
			set.snmponly = TRUE;
		}

		else if (!HOSTID_DEFINED(set.start_host_id) && all_digits(arg)) {
			set.start_host_id = atoi(arg);
		}

		else if (!HOSTID_DEFINED(set.end_host_id) && all_digits(arg)) {
			set.end_host_id = atoi(arg);
		}

		else {
			die("ERROR: %s is an unknown command-line parameter", arg);
		}
	}

	/* we require either both the first and last hosts, or niether host */
	if (HOSTID_DEFINED(set.start_host_id) != HOSTID_DEFINED(set.end_host_id)) {
		die("ERROR: must provide both -f/-l, or neither");
	}

	if (set.start_host_id > set.end_host_id) {
		die("ERROR: Invalid row spec; first host_id must be less than the second");
	}

	/* read configuration file to establish local environment */
	if (conf_file) {
		if ((read_cactid_config(conf_file)) < 0) {
			die("ERROR: Could not read config file: %s\n", conf_file);
		}
	}else{
		if (!(conf_file = calloc(1, BUFSIZE))) {
			die("ERROR: Fatal malloc error: cactid.c conf_file!\n");
		}

		for (i=0; i<CONFIG_PATHS; i++) {
			snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[i], DEFAULT_CONF_FILE);

			if (read_cactid_config(conf_file) >= 0) {
				break;
			}

			if (i == CONFIG_PATHS-1) {
				snprintf(conf_file, BUFSIZE-1, "%s%s", config_paths[0], DEFAULT_CONF_FILE);
			}
		}
	}

	/* read settings table from the database to further establish environment */
	read_config_options();

	/* set the poller interval for those who use less than 5 minute intervals */
	if (set.poller_interval == 0) {
		poller_interval = 300;
	}else {
		poller_interval = set.poller_interval;
	}

	/* calculate the external_tread_sleep value */
	internal_thread_sleep = EXTERNAL_THREAD_SLEEP * set.num_parent_processes / 2;

	if (set.log_level == POLLER_VERBOSITY_DEBUG) {
		CACTID_LOG_DEBUG(("CACTID: Version %s starting\n", VERSION));
	}else{
		printf("CACTID: Version %s starting\n", VERSION);
	}

	/* connect to database */
	db_connect(set.dbdb, &mysql);

	/* initialize SNMP */
	CACTID_LOG_DEBUG(("CACTID: Initializing Net-SNMP API\n"));
	snmp_cactid_init();

	/* initialize PHP if required */
	CACTID_LOG_DEBUG(("CACTID: Initializing PHP Script Server\n"));

	/* tell cactid that it is parent, and set the poller id */
	set.parent_fork = CACTID_PARENT;
	set.poller_id = 0;

	/* initialize the script server */
	if (set.php_required) {
		php_init(PHP_INIT);
		set.php_initialized = TRUE;
		set.php_current_server = 0;
	}

	/* obtain the list of hosts to poll */
	{
	char querybuf[256], *qp = querybuf;

	qp += sprintf(qp, "SELECT id FROM host");
	qp += sprintf(qp, " WHERE disabled=''");
	qp += append_hostrange(qp, "id");	/* AND id BETWEEN a AND b */
	qp += sprintf(qp, " ORDER BY id");

	result = db_query(&mysql, querybuf);
	}

	num_rows = mysql_num_rows(result) + 1; /* add 1 for host = 0 */

	if (!(threads = (pthread_t *)malloc(num_rows * sizeof(pthread_t)))) {
		die("ERROR: Fatal malloc error: cactid.c threads!\n");
	}

	if (!(ids = (int *)malloc(num_rows * sizeof(int)))) {
		die("ERROR: Fatal malloc error: cactid.c host id's!\n");
	}

	/* initialize threads and mutexes */
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	init_mutexes();

	CACTID_LOG_DEBUG(("DEBUG: Initial Value of Active Threads is %i\n", active_threads));

	/* tell fork processes that they are now active */
	set.parent_fork = CACTID_FORK;

	/* loop through devices until done */
	while ((device_counter < num_rows) && (canexit == 0)) {
		mutex_status = thread_mutex_trylock(LOCK_THREAD);

		switch (mutex_status) {
		case 0:
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			while ((active_threads < set.threads) && (device_counter < num_rows)) {
				if (device_counter > 0) {
					mysql_row = mysql_fetch_row(result);
					host_id = atoi(mysql_row[0]);
					ids[device_counter] = host_id;
				}else{
					ids[device_counter] = 0;
				}

				/* create child process */
				thread_status = pthread_create(&threads[device_counter], &attr, child, &ids[device_counter]);

				switch (thread_status) {
					case 0:
						CACTID_LOG_DEBUG(("DEBUG: Valid Thread to be Created\n"));

						device_counter++;
						active_threads++;

						CACTID_LOG_DEBUG(("DEBUG: The Value of Active Threads is %i\n", active_threads));

						break;
					case EAGAIN:
						CACTID_LOG(("ERROR: The System Lacked the Resources to Create a Thread\n"));
						break;
					case EFAULT:
						CACTID_LOG(("ERROR: The Thread or Attribute Was Invalid\n"));
						break;
					case EINVAL:
						CACTID_LOG(("ERROR: The Thread Attribute is Not Initialized\n"));
						break;
					default:
						CACTID_LOG(("ERROR: Unknown Thread Creation Error\n"));
						break;
				}
				usleep(internal_thread_sleep);

				/* get current time and exit program if time limit exceeded */
				if (poller_counter >= 20) {
					current_time = get_time_as_double();

					if ((current_time - begin_time + 6) > poller_interval) {
						CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
						canexit = 1;
						break;
					}

					poller_counter = 0;
				}else{
					poller_counter++;
				}
			}

			thread_mutex_unlock(LOCK_THREAD);

			break;
		case EDEADLK:
			CACTID_LOG(("ERROR: Deadlock Occured\n"));
			break;
		case EBUSY:
			break;
		case EINVAL:
			CACTID_LOG(("ERROR: Attempt to Unlock an Uninitialized Mutex\n"));
			break;
		case EFAULT:
			CACTID_LOG(("ERROR: Attempt to Unlock an Invalid Mutex\n"));
			break;
		default:
			CACTID_LOG(("ERROR: Unknown Mutex Lock Error Code Returned\n"));
			break;
		}

		usleep(internal_thread_sleep);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* wait for all threads to complete */
	while (canexit == 0) {
		if (thread_mutex_trylock(LOCK_THREAD) == 0) {
			if (last_active_threads != active_threads) {
				last_active_threads = active_threads;
			}

			if (active_threads == 0) {
				canexit = 1;
			}

			thread_mutex_unlock(LOCK_THREAD);
		}

		usleep(EXTERNAL_THREAD_SLEEP);

		/* get current time and exit program if time limit exceeded */
		if (poller_counter >= 20) {
			current_time = get_time_as_double();

			if ((current_time - begin_time + 6) > poller_interval) {
				CACTID_LOG(("ERROR: Cactid Timed Out While Processing Hosts Internal\n"));
				canexit = 1;
				break;
			}

			poller_counter = 0;
		}else{
			poller_counter++;
		}
	}

	/* tell Cactid that it is now parent */
	set.parent_fork = CACTID_PARENT;

	/* print out stats */
	gettimeofday(&now, NULL);

	/* update the db for |data_time| on graphs */
	db_insert(&mysql, "replace into settings (name,value) values ('date',NOW())");
	db_insert(&mysql, "insert into poller_time (poller_id, start_time, end_time) values (0, NOW(), NOW())");

	/* cleanup and exit program */
	pthread_attr_destroy(&attr);

	CACTID_LOG_DEBUG(("DEBUG: Thread Cleanup Complete\n"));

	/* close the php script server */
	if (set.php_required) {
		php_close(PHP_INIT);
	}

	CACTID_LOG_DEBUG(("DEBUG: PHP Script Server Pipes Closed\n"));

	/* free malloc'd variables */
	free(threads);
	free(ids);
	free(conf_file);

	CACTID_LOG_DEBUG(("DEBUG: Allocated Variable Memory Freed\n"));

	/* shutdown SNMP */
	snmp_cactid_close();

	CACTID_LOG_DEBUG(("CACTID: Net-SNMP API Shutdown Completed\n"));

	/* close mysql */
	mysql_free_result(result);
	mysql_close(&mysql);

	CACTID_LOG_DEBUG(("DEBUG: MYSQL Free & Close Completed\n"));

	/* finally add some statistics to the log and exit */
	end_time = TIMEVAL_TO_DOUBLE(now);

	CACTID_LOG_MEDIUM(("Time: %.4f s, Threads: %i, Hosts: %i\n", (end_time - begin_time), set.threads, num_rows));

	exit(EXIT_SUCCESS);
}
Exemplo n.º 29
0
static int command_manageauth (client_t *client, source_t *source, int response)
{
    xmlDocPtr doc;
    xmlNodePtr node, srcnode, msgnode;
    const char *action = NULL;
    const char *username = NULL;
    const char *message = NULL;
    int ret = AUTH_OK;
    ice_config_t *config = config_get_config ();
    mount_proxy *mountinfo = config_find_mount (config, source->mount);

    do
    { 
        if (mountinfo == NULL || mountinfo->auth == NULL)
        {
            WARN1 ("manage auth request for %s but no facility available", source->mount);
            break;
        }
        COMMAND_OPTIONAL (client, "action", action);
        COMMAND_OPTIONAL (client, "username", username);

        if (action == NULL)
            action = "list";

        if (!strcmp(action, "add"))
        {
            const char *password = NULL;
            COMMAND_OPTIONAL (client, "password", password);

            if (username == NULL || password == NULL)
            {
                WARN1 ("manage auth request add for %s but no user/pass", source->mount);
                break;
            }
            ret = mountinfo->auth->adduser(mountinfo->auth, username, password);
            if (ret == AUTH_FAILED) {
                message = "User add failed - check the icecast error log";
            }
            if (ret == AUTH_USERADDED) {
                message = "User added";
            }
            if (ret == AUTH_USEREXISTS) {
                message = "User already exists - not added";
            }
        }
        if (!strcmp(action, "delete"))
        {
            if (username == NULL)
            {
                WARN1 ("manage auth request delete for %s but no username", source->mount);
                break;
            }
            ret = mountinfo->auth->deleteuser(mountinfo->auth, username);
            if (ret == AUTH_FAILED) {
                message = "User delete failed - check the icecast error log";
            }
            if (ret == AUTH_USERDELETED) {
                message = "User deleted";
            }
        }

        doc = xmlNewDoc(XMLSTR "1.0");
        node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
        srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
        xmlSetProp(srcnode, XMLSTR "mount", XMLSTR(source->mount));
        thread_mutex_unlock (&source->lock);

        if (message) {
            msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL);
            xmlNewChild(msgnode, NULL, XMLSTR "message", XMLSTR(message));
        }

        xmlDocSetRootElement(doc, node);

        if (mountinfo && mountinfo->auth && mountinfo->auth->listuser)
            mountinfo->auth->listuser (mountinfo->auth, srcnode);

        config_release_config ();

        return admin_send_response (doc, client, response, "manageauth.xsl");
    } while (0);

    thread_mutex_unlock (&source->lock);
    config_release_config ();
    return client_send_400 (client, "missing parameter");
}
Exemplo n.º 30
0
static void *_stats_thread(void *arg)
{
    stats_event_t *event;
    stats_event_t *copy;
    event_listener_t *listener;

    if (!kitsune_is_updating()) { /**DSU control */
        stats_event (NULL, "server", ICECAST_VERSION_STRING);
        stats_event_time (NULL, "server_start");

        /* global currently active stats */
        stats_event (NULL, "clients", "0");
        stats_event (NULL, "connections", "0");
        stats_event (NULL, "sources", "0");
        stats_event (NULL, "stats", "0");
        
        /* global accumulating stats */
        stats_event (NULL, "client_connections", "0");
        stats_event (NULL, "source_client_connections", "0");
        stats_event (NULL, "source_relay_connections", "0");
        stats_event (NULL, "source_total_connections", "0");
        stats_event (NULL, "stats_connections", "0");
        stats_event (NULL, "listener_connections", "0");
        INFO0 ("stats thread started");
    }

    while (_stats_running) {
      kitsune_update("stats"); /**DSU updatepoint */
        if (_global_event_queue != NULL) {
            /* grab the next event from the queue */
            thread_mutex_lock(&_global_event_mutex);
            event = (stats_event_t *)_global_event_queue;
            _global_event_queue = event->next;
            thread_mutex_unlock(&_global_event_mutex);

            event->next = NULL;

            thread_mutex_lock(&_stats_mutex);

            /* check if we are dealing with a global or source event */
            if (event->source == NULL)
                process_global_event (event);
            else
                process_source_event (event);
            
            /* now we have an event that's been processed into the running stats */
            /* this event should get copied to event listeners' queues */
            listener = (event_listener_t *)_event_listeners;
            while (listener) {
                copy = _copy_event(event);
                thread_mutex_lock(listener->mutex);
                _add_event_to_queue(copy, listener->queue);
                thread_mutex_unlock(listener->mutex);

                listener = listener->next;
            }

            /* now we need to destroy the event */
            _free_event(event);

            thread_mutex_unlock(&_stats_mutex);
            continue;
        }

        thread_sleep(300000);
    }

    return NULL;
}