/**
 * Simple data fetcher.
 * @param url path or url of data to fetch.
 * @return data fetched, or NULL on error. Must be freed with g_free.
 */
static char *
lastfm_get(const char *url, GMutex *mutex, GCond *cond)
{
	struct input_stream *input_stream;
	GError *error = NULL;
	char buffer[4096];
	size_t length = 0, nbytes;

	input_stream = input_stream_open(url, mutex, cond, &error);
	if (input_stream == NULL) {
		if (error != NULL) {
			g_warning("%s", error->message);
			g_error_free(error);
		}

		return NULL;
	}

	g_mutex_lock(mutex);

	input_stream_wait_ready(input_stream);

	do {
		nbytes = input_stream_read(input_stream, buffer + length,
					   sizeof(buffer) - length, &error);
		if (nbytes == 0) {
			if (error != NULL) {
				g_warning("%s", error->message);
				g_error_free(error);
			}

			if (input_stream_eof(input_stream))
				break;

			/* I/O error */
			g_mutex_unlock(mutex);
			input_stream_close(input_stream);
			return NULL;
		}

		length += nbytes;
	} while (length < sizeof(buffer));

	g_mutex_unlock(mutex);

	input_stream_close(input_stream);
	return g_strndup(buffer, length);
}
Beispiel #2
0
/**
 * Opens the input stream with input_stream_open(), and waits until
 * the stream gets ready.  If a decoder STOP command is received
 * during that, it cancels the operation (but does not close the
 * stream).
 *
 * Unlock the decoder before calling this function.
 *
 * @return an input_stream on success or if #DECODE_COMMAND_STOP is
 * received, NULL on error
 */
static struct input_stream *
decoder_input_stream_open(struct decoder_control *dc, const char *uri)
{
	GError *error = NULL;
	struct input_stream *is;

	is = input_stream_open(uri, &error);
	if (is == NULL) {
		if (error != NULL) {
			g_warning("%s", error->message);
			g_error_free(error);
		}

		return NULL;
	}

	/* wait for the input stream to become ready; its metadata
	   will be available then */

	while (!is->ready &&
	       decoder_lock_get_command(dc) != DECODE_COMMAND_STOP) {
		int ret;

		ret = input_stream_buffer(is, &error);
		if (ret < 0) {
			input_stream_close(is);
			g_warning("%s", error->message);
			g_error_free(error);
			return NULL;
		}
	}

	return is;
}
Beispiel #3
0
enum playlist_result
playlist_open_into_queue(const char *uri,
                         unsigned start_index, unsigned end_index,
                         struct playlist *dest, struct player_control *pc,
                         bool secure)
{
    GMutex *mutex = g_mutex_new();
    GCond *cond = g_cond_new();

    struct input_stream *is;
    struct playlist_provider *playlist =
    playlist_open_any(uri, mutex, cond, &is);
    if (playlist == NULL) {
        g_cond_free(cond);
        g_mutex_free(mutex);
        return PLAYLIST_RESULT_NO_SUCH_LIST;
    }

    enum playlist_result result =
        playlist_load_into_queue(uri, playlist, start_index, end_index,
                                 dest, pc, secure);
    playlist_plugin_close(playlist);

    if (is != NULL)
        input_stream_close(is);

    g_cond_free(cond);
    g_mutex_free(mutex);

    return result;
}
Beispiel #4
0
static struct playlist_provider *
playlist_open_remote(const char *uri, GMutex *mutex, GCond *cond,
		     struct input_stream **is_r)
{
	assert(uri_has_scheme(uri));

	struct playlist_provider *playlist =
		playlist_list_open_uri(uri, mutex, cond);
	if (playlist != NULL) {
		*is_r = NULL;
		return playlist;
	}

	GError *error = NULL;
	struct input_stream *is = input_stream_open(uri, mutex, cond, &error);
	if (is == NULL) {
		if (error != NULL) {
			g_warning("Failed to open %s: %s",
				  uri, error->message);
			g_error_free(error);
		}

		return NULL;
	}

	playlist = playlist_list_open_stream(is, uri);
	if (playlist == NULL) {
		input_stream_close(is);
		return NULL;
	}

	*is_r = is;
	return playlist;
}
int main(int argc, char **argv)
{
	GError *error = NULL;
	struct input_stream *is;
	int ret;

	if (argc != 2) {
		g_printerr("Usage: run_input URI\n");
		return 1;
	}

	/* initialize GLib */

	g_thread_init(NULL);
	g_log_set_default_handler(my_log_func, NULL);

	/* initialize MPD */

	tag_pool_init();
	config_global_init();

#ifdef ENABLE_ARCHIVE
	archive_plugin_init_all();
#endif

	if (!input_stream_global_init(&error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return 2;
	}

	/* open the stream and dump it */

	is = input_stream_open(argv[1], &error);
	if (is != NULL) {
		ret = dump_input_stream(is);
		input_stream_close(is);
	} else {
		if (error != NULL) {
			g_warning("%s", error->message);
			g_error_free(error);
		} else
			g_printerr("input_stream_open() failed\n");
		ret = 2;
	}

	/* deinitialize everything */

	input_stream_global_finish();

#ifdef ENABLE_ARCHIVE
	archive_plugin_deinit_all();
#endif

	config_global_finish();
	tag_pool_deinit();

	return ret;
}
static void
lastfm_close(struct playlist_provider *_playlist)
{
	struct lastfm_playlist *playlist = (struct lastfm_playlist *)_playlist;

	playlist_plugin_close(playlist->xspf);
	input_stream_close(playlist->is);
	g_free(playlist);
}
Beispiel #7
0
void
zonefile_close(zone_file* in_file)
{
    zassert(in_file != NULL);

    /* The filter closes the filtered */

    input_stream_close(&in_file->bis);
}
Beispiel #8
0
static void
buffer_input_stream_close(input_stream* stream)
{
    buffer_input_stream_data* data = (buffer_input_stream_data*)stream->data;
    input_stream_close(&data->filtered);
    free(data);

    input_stream_set_void(stream);
}
Beispiel #9
0
static void
zdb_zone_axfr_input_stream_close(input_stream* is)
{
    zdb_zone_axfr_input_stream_data* data = (zdb_zone_axfr_input_stream_data*)is->data;
    
    input_stream_close(&data->filtered);
    
    free(data);
    
    input_stream_set_void(is);
}
struct playlist_provider *
playlist_list_open_path(const char *path_fs)
{
	GError *error = NULL;
	const char *suffix;
	struct input_stream *is;
	struct playlist_provider *playlist;

	assert(path_fs != NULL);

	suffix = uri_get_suffix(path_fs);
	if (suffix == NULL || !playlist_suffix_supported(suffix))
		return NULL;

	is = input_stream_open(path_fs, &error);
	if (is == NULL) {
		if (error != NULL) {
			g_warning("%s", error->message);
			g_error_free(error);
		}

		return NULL;
	}

	while (!is->ready) {
		int ret = input_stream_buffer(is, &error);
		if (ret < 0) {
			input_stream_close(is);
			g_warning("%s", error->message);
			g_error_free(error);
			return NULL;
		}
	}

	playlist = playlist_list_open_stream_suffix(is, suffix);
	if (playlist == NULL)
		input_stream_close(is);

	return playlist;
}
Beispiel #11
0
static void
bz2_close(struct archive_file *file)
{
	struct bz2_archive_file *context = (struct bz2_archive_file *) file;

	if (!refcount_dec(&context->ref))
		return;

	g_free(context->name);

	input_stream_close(context->istream);
	g_free(context);
}
static enum playlist_result
playlist_open_remote_into_queue(const char *uri, struct playlist *dest)
{
	GError *error = NULL;
	struct playlist_provider *playlist;
	struct input_stream *is = NULL;
	enum playlist_result result;

	assert(uri_has_scheme(uri));

	playlist = playlist_list_open_uri(uri);
	if (playlist == NULL) {
		is = input_stream_open(uri, &error);
		if (is == NULL) {
			if (error != NULL) {
				g_warning("Failed to open %s: %s",
					  uri, error->message);
				g_error_free(error);
			}

			return PLAYLIST_RESULT_NO_SUCH_LIST;
		}

		playlist = playlist_list_open_stream(is, uri);
		if (playlist == NULL) {
			input_stream_close(is);
			return PLAYLIST_RESULT_NO_SUCH_LIST;
		}
	}

	result = playlist_load_into_queue(uri, playlist, dest);
	playlist_plugin_close(playlist);

	if (is != NULL)
		input_stream_close(is);

	return result;
}
Beispiel #13
0
/**
 * Try decoding a file.
 */
static bool
decoder_run_file(struct decoder *decoder, const char *path_fs)
{
	struct decoder_control *dc = decoder->dc;
	const char *suffix = uri_get_suffix(path_fs);
	const struct decoder_plugin *plugin = NULL;

	if (suffix == NULL)
		return false;

	decoder_unlock(dc);

	decoder_load_replay_gain(decoder, path_fs);

	while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) {
		if (plugin->file_decode != NULL) {
			decoder_lock(dc);

			if (decoder_file_decode(plugin, decoder, path_fs))
				return true;

			decoder_unlock(dc);
		} else if (plugin->stream_decode != NULL) {
			struct input_stream *input_stream;
			bool success;

			input_stream = decoder_input_stream_open(dc, path_fs);
			if (input_stream == NULL)
				continue;

			decoder_lock(dc);

			success = decoder_stream_decode(plugin, decoder,
							input_stream);

			decoder_unlock(dc);

			input_stream_close(input_stream);

			if (success) {
				decoder_lock(dc);
				return true;
			}
		}
	}

	decoder_lock(dc);
	return false;
}
Beispiel #14
0
static bool
wavpack_open_wvc(struct decoder *decoder, struct input_stream *is_wvc,
		 struct wavpack_input *wpi)
{
	char *utf8url;
	char *wvc_url = NULL;
	bool ret;
	char first_byte;
	size_t nbytes;

	/*
	 * As we use dc->utf8url, this function will be bad for
	 * single files. utf8url is not absolute file path :/
	 */
	utf8url = decoder_get_uri(decoder);
	if (utf8url == NULL) {
		return false;
	}

	wvc_url = g_strconcat(utf8url, "c", NULL);
	g_free(utf8url);

	ret = input_stream_open(is_wvc, wvc_url);
	g_free(wvc_url);

	if (!ret) {
		return false;
	}

	/*
	 * And we try to buffer in order to get know
	 * about a possible 404 error.
	 */
	nbytes = decoder_read(
		decoder, is_wvc, &first_byte, sizeof(first_byte)
	);
	if (nbytes == 0) {
		input_stream_close(is_wvc);
		return false;
	}

	/* push it back */
	wavpack_input_init(wpi, decoder, is_wvc);
	wpi->last_byte = first_byte;
	return true;
}
Beispiel #15
0
/* this is primarily used for getting total time for tags */
static int mp3_total_file_time(const char *file)
{
	struct input_stream input_stream;
	struct mp3_data data;
	int ret;

	if (!input_stream_open(&input_stream, file))
		return -1;
	mp3_data_init(&data, NULL, &input_stream);
	if (!mp3_decode_first_frame(&data, NULL, NULL))
		ret = -1;
	else
		ret = data.total_time + 0.5;
	mp3_data_finish(&data);
	input_stream_close(&input_stream);

	return ret;
}
Beispiel #16
0
enum playlist_result
playlist_open_into_queue(const char *uri,
			 struct playlist *dest, struct player_control *pc,
			 bool secure)
{
	struct input_stream *is;
	struct playlist_provider *playlist = playlist_open_any(uri, &is);
	if (playlist == NULL)
		return PLAYLIST_RESULT_NO_SUCH_LIST;

	enum playlist_result result =
		playlist_load_into_queue(uri, playlist, dest, pc, secure);
	playlist_plugin_close(playlist);

	if (is != NULL)
		input_stream_close(is);

	return result;
}
static struct input_stream *
wavpack_open_wvc(struct decoder *decoder, const char *uri,
		 struct wavpack_input *wpi)
{
	struct input_stream *is_wvc;
	char *wvc_url = NULL;
	char first_byte;
	size_t nbytes;

	/*
	 * As we use dc->utf8url, this function will be bad for
	 * single files. utf8url is not absolute file path :/
	 */
	if (uri == NULL)
		return false;

	wvc_url = g_strconcat(uri, "c", NULL);
	is_wvc = input_stream_open(wvc_url, NULL);
	g_free(wvc_url);

	if (is_wvc == NULL)
		return NULL;

	/*
	 * And we try to buffer in order to get know
	 * about a possible 404 error.
	 */
	nbytes = decoder_read(
		decoder, is_wvc, &first_byte, sizeof(first_byte)
	);
	if (nbytes == 0) {
		input_stream_close(is_wvc);
		return NULL;
	}

	/* push it back */
	wavpack_input_init(wpi, decoder, is_wvc);
	wpi->last_byte = first_byte;
	return is_wvc;
}
/*
 * Decodes a stream.
 */
static void
wavpack_streamdecode(struct decoder * decoder, struct input_stream *is)
{
	char error[ERRORLEN];
	WavpackContext *wpc;
	struct input_stream *is_wvc;
	int open_flags = OPEN_NORMALIZE;
	struct wavpack_input isp, isp_wvc;
	bool can_seek = is->seekable;

	is_wvc = wavpack_open_wvc(decoder, is->uri, &isp_wvc);
	if (is_wvc != NULL) {
		open_flags |= OPEN_WVC;
		can_seek &= is_wvc->seekable;
	}

	if (!can_seek) {
		open_flags |= OPEN_STREAMING;
	}

	wavpack_input_init(&isp, decoder, is);
	wpc = WavpackOpenFileInputEx(
		&mpd_is_reader, &isp,
		open_flags & OPEN_WVC ? &isp_wvc : NULL,
		error, open_flags, 23
	);

	if (wpc == NULL) {
		g_warning("failed to open WavPack stream: %s\n", error);
		return;
	}

	wavpack_decode(decoder, wpc, can_seek);

	WavpackCloseFile(wpc);
	if (open_flags & OPEN_WVC) {
		input_stream_close(is_wvc);
	}
}
Beispiel #19
0
/**
 * Try decoding a stream.
 */
static bool
decoder_run_stream(struct decoder *decoder, const char *uri)
{
	struct decoder_control *dc = decoder->dc;
	struct input_stream *input_stream;
	bool success;

	decoder_unlock(dc);

	input_stream = decoder_input_stream_open(dc, uri);
	if (input_stream == NULL) {
		decoder_lock(dc);
		return false;
	}

	decoder_lock(dc);

	GSList *tried = NULL;

	success = dc->command == DECODE_COMMAND_STOP ||
		/* first we try mime types: */
		decoder_run_stream_mime_type(decoder, input_stream, &tried) ||
		/* if that fails, try suffix matching the URL: */
		decoder_run_stream_suffix(decoder, input_stream, uri,
					  &tried) ||
		/* fallback to mp3: this is needed for bastard streams
		   that don't have a suffix or set the mimeType */
		(tried == NULL &&
		 decoder_run_stream_fallback(decoder, input_stream));

	g_slist_free(tried);

	decoder_unlock(dc);
	input_stream_close(input_stream);
	decoder_lock(dc);

	return success;
}
Beispiel #20
0
static void
xfr_input_stream_close(input_stream *is)
{
    xfr_input_stream_data *data = (xfr_input_stream_data*)is->data;
    
    if(data->need_cleanup_tsig)
    {
        log_err("TSIG has not been cleared");
        data->need_cleanup_tsig = FALSE;
    }
    
    output_stream_close(&data->pipe_stream_output);
    input_stream_close(&data->pipe_stream_input);
    free(data->first_soa_record);
    
#ifdef DEBUG
    memset(data, 0xfe, sizeof(xfr_input_stream_data));
#endif
    
    ZFREE(data, xfr_input_stream_data); // used to be leaked ?
    
    input_stream_set_void(is);
}
Beispiel #21
0
int main(int argc, char **argv)
{
	GError *error = NULL;
	const char *decoder_name;
	struct decoder decoder;

	if (argc != 3) {
		g_printerr("Usage: run_decoder DECODER URI >OUT\n");
		return 1;
	}

	decoder_name = argv[1];
	decoder.uri = argv[2];

	g_log_set_default_handler(my_log_func, NULL);

	tag_pool_init();

	if (!input_stream_global_init(&error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return 2;
	}

	decoder_plugin_init_all();

	decoder.plugin = decoder_plugin_from_name(decoder_name);
	if (decoder.plugin == NULL) {
		g_printerr("No such decoder: %s\n", decoder_name);
		return 1;
	}

	decoder.initialized = false;

	if (decoder.plugin->file_decode != NULL) {
		decoder_plugin_file_decode(decoder.plugin, &decoder,
					   decoder.uri);
	} else if (decoder.plugin->stream_decode != NULL) {
		struct input_stream *is =
			input_stream_open(decoder.uri, &error);
		if (is == NULL) {
			if (error != NULL) {
				g_warning("%s", error->message);
				g_error_free(error);
			} else
				g_printerr("input_stream_open() failed\n");

			return 1;
		}

		decoder_plugin_stream_decode(decoder.plugin, &decoder, is);

		input_stream_close(is);
	} else {
		g_printerr("Decoder plugin is not usable\n");
		return 1;
	}

	decoder_plugin_deinit_all();
	input_stream_global_finish();

	if (!decoder.initialized) {
		g_printerr("Decoding failed\n");
		return 1;
	}

	tag_pool_deinit();

	return 0;
}
Beispiel #22
0
bool
song_file_update(struct song *song)
{
    const char *suffix;
    char *path_fs;
    const struct decoder_plugin *plugin;
    struct stat st;
    struct input_stream *is = NULL;

    assert(song_is_file(song));

    /* check if there's a suffix and a plugin */

    suffix = uri_get_suffix(song->uri);
    if (suffix == NULL)
        return false;

    plugin = decoder_plugin_from_suffix(suffix, NULL);
    if (plugin == NULL)
        return false;

    path_fs = map_song_fs(song);
    if (path_fs == NULL)
        return false;

    if (song->tag != NULL) {
        tag_free(song->tag);
        song->tag = NULL;
    }

    if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
        g_free(path_fs);
        return false;
    }

    song->mtime = st.st_mtime;

    GMutex *mutex = NULL;
    GCond *cond;
#if !GCC_CHECK_VERSION(4, 2)
    /* work around "may be used uninitialized in this function"
       false positive */
    cond = NULL;
#endif

    do {
        /* load file tag */
        song->tag = tag_new();
        if (decoder_plugin_scan_file(plugin, path_fs,
                                     &full_tag_handler, song->tag))
            break;

        tag_free(song->tag);
        song->tag = NULL;

        /* fall back to stream tag */
        if (plugin->scan_stream != NULL) {
            /* open the input_stream (if not already
               open) */
            if (is == NULL) {
                mutex = g_mutex_new();
                cond = g_cond_new();
                is = input_stream_open(path_fs, mutex, cond,
                                       NULL);
            }

            /* now try the stream_tag() method */
            if (is != NULL) {
                song->tag = tag_new();
                if (decoder_plugin_scan_stream(plugin, is,
                                               &full_tag_handler,
                                               song->tag))
                    break;

                tag_free(song->tag);
                song->tag = NULL;

                input_stream_lock_seek(is, 0, SEEK_SET, NULL);
            }
        }

        plugin = decoder_plugin_from_suffix(suffix, plugin);
    } while (plugin != NULL);

    if (is != NULL)
        input_stream_close(is);

    if (mutex != NULL) {
        g_cond_free(cond);
        g_mutex_free(mutex);
    }

    if (song->tag != NULL && tag_is_empty(song->tag))
        tag_scan_fallback(path_fs, &full_tag_handler, song->tag);

    g_free(path_fs);
    return song->tag != NULL;
}
Beispiel #23
0
int main(int argc, char **argv)
{
	GError *error = NULL;
	const char *decoder_name, *path;
	const struct decoder_plugin *plugin;
	struct tag *tag;
	bool empty;

#ifdef HAVE_LOCALE_H
	/* initialize locale */
	setlocale(LC_CTYPE,"");
#endif

	if (argc != 3) {
		g_printerr("Usage: read_tags DECODER FILE\n");
		return 1;
	}

	decoder_name = argv[1];
	path = argv[2];

	tag_pool_init();

	if (!input_stream_global_init(&error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return 2;
	}

	decoder_plugin_init_all();

	plugin = decoder_plugin_from_name(decoder_name);
	if (plugin == NULL) {
		g_printerr("No such decoder: %s\n", decoder_name);
		return 1;
	}

	tag = decoder_plugin_tag_dup(plugin, path);
	if (tag == NULL && plugin->stream_tag != NULL) {
		struct input_stream *is = input_stream_open(path, &error);

		if (is == NULL) {
			g_printerr("Failed to open %s: %s\n",
				   path, error->message);
			g_error_free(error);
			return 1;
		}

		tag = decoder_plugin_stream_tag(plugin, is);
		input_stream_close(is);
	}

	decoder_plugin_deinit_all();
	input_stream_global_finish();
	if (tag == NULL) {
		g_printerr("Failed to read tags\n");
		return 1;
	}

	print_tag(tag);

	empty = tag_is_empty(tag);
	tag_free(tag);

	if (empty) {
		tag = tag_ape_load(path);
		if (tag == NULL)
			tag = tag_id3_load(path);
		if (tag != NULL) {
			print_tag(tag);
			tag_free(tag);
		}
	}

	tag_pool_deinit();

	return 0;
}
Beispiel #24
0
static ya_result
journal_ix_get_ixfr_stream_at_serial(journal *jh, u32 serial_from, input_stream *out_input_stream, dns_resource_record *last_soa_rr)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result return_value = SUCCESS;
    
    journal_ix_readlock(jix);
    
    /*
     * check that serial_from in in the journal range
     * set the file descriptor to the position
     * create a stream that'll stop at the current end of the stream
     */
    
    if(serial_lt(serial_from, jix->first_serial) || serial_ge(serial_from, jix->last_serial) || ((jix->first_serial == 0) && (jix->last_serial == 0)))
    {
        /* out of known range */
        
        journal_ix_readunlock(jix);
        
        if(serial_from == jix->last_serial)
        {
            return SUCCESS;
        }
        else
        {        
            return ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
        }
    }
    
    /*
     * On success, dup() returns a new file descriptor that has the following in common with the original:
     * 
     *  _ Same open file (or pipe)
     *  _ Same file pointer (both file descriptors share one file pointer) <= THIS is a problem
     *  _ Same access mode (read, write, or read/write)
     * 
     * So this is wrong:
     * 
     * cloned_fd = dup(jix->fd);
     */    
    
    int cloned_fd;
    
    while((cloned_fd = open_ex(jix->journal_name, O_RDONLY)) < 0)
    {
        int err = errno;

        if(err == EINTR)
        {
            continue;
        }

        return_value = MAKE_ERRNO_ERROR(err);

#ifdef DEBUG
        log_debug("journal: ix: unable to clone the file descriptor: %r", return_value);
#endif
        journal_ix_readunlock(jix);

        return return_value;
    }
    
    /* 
     * given that I use a clone of the fd and
     * given that only appends are done in the file and
     * given that the limit of the file has already been processed (should be at this point)
     * 
     * THEN
     * 
     * there is no point keeping the lock for reading (on unix systems)
     */
    
    struct stat journal_stat;
    
    s64 last_page_offset = jix->last_page_offset;
    
    if(fstat(cloned_fd, &journal_stat) < 0)
    {
        return_value = ERRNO_ERROR;
        
        log_err("journal: ix: unable to get journal file status", return_value);
        
        close_ex(cloned_fd);

        return return_value;
    }
    
    s64 file_size = journal_stat.st_size;
    
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: the last page starts at position %lld", last_page_offset);
#endif

    journal_ix_readunlock(jix);
    jix = NULL;  
    
    input_stream fis;
    fd_input_stream_attach(&fis, cloned_fd);
    
    if(last_soa_rr != NULL)
    {
        /* seek and store the last SOA print*/
        
        last_soa_rr->tctr.qtype = 0; // clear type
        
        if(lseek(cloned_fd, last_page_offset, SEEK_SET) >= 0)
        {
            /* deleted SOA */
            if((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
            {
                if(last_soa_rr->tctr.qtype == TYPE_SOA)
                {
                    /* DEL records */
                    last_soa_rr->tctr.qtype = 0; // clear type
            
                    /* scan until added SOA found */
                    while((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
                    {
                        if(last_soa_rr->tctr.qtype == TYPE_SOA)
                        {
                            break;
                        }
                    }
                }
            }
            
            // if the SOA has not been found, it's an error (EOF has been reached is covered by this)
            
            
            if(ISOK(return_value))
            {
                if(last_soa_rr->tctr.qtype != TYPE_SOA)
                {
                    return_value = ZDB_JOURNAL_SOA_RECORD_EXPECTED;
                }
            }
        }
        else
        {
            return_value = ERRNO_ERROR;
        }
        
        if(FAIL(return_value))
        {
            input_stream_close(&fis);
            
            return return_value;
        }
    }
    
    /*
     * this format has no indexing so we scan for a page that STARTS with a DELETE of the SOA with serial = serial_from
     */
    
    if(lseek(cloned_fd, 0, SEEK_SET) != 0)  /* the resulting offset MUST be zero */
    {
        return_value = ERRNO_ERROR;
        
        if(ISOK(return_value))
        {
            return_value = ERROR;
        }
        
        input_stream_close(&fis);
            
        return return_value;
    }
    
    input_stream bis;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    buffer_input_stream_init(&fis, &bis, 512);
    
    s64 offset = 0;

    /* skip until the right serial is found */

    u32 soa_count = 0;

#ifdef DEBUG_JOURNAL
    u32 rr_count = 0;
#endif
    
    for(;;)
    {
        if( (return_value = dns_resource_record_read(&rr, &bis)) <= 0 ) // FAIL or nothing to 
        {
            return_value = ZDB_JOURNAL_ERROR_READING_JOURNAL; /* is the journal file broken ? */
            
            break;
        }

#ifdef DEBUG_JOURNAL
        rr_count++;
#endif
        
        u32 record_size = return_value;
        
        if(rr.tctr.qtype == TYPE_SOA)
        {
            // ((0+1)&1) != 0 => Y N Y N 
            
            if((++soa_count & 1) != 0) // 1 2 3 4
            {
                u8 *p = rr.rdata;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                u32 serial = ntohl(GET_U32_AT(*p));

                if(serial_ge(serial, serial_from))
                {
                    if(serial == serial_from)
                    {
                        /* setup the serial to be from 'offset' up to the current length of the stream */

                        return_value = SUCCESS;
                    }
                    else
                    {
                        /* the serial does not exist in the range */

                        return_value = ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
                    }

                    break;
                }
            }
        }
        
        offset += record_size;
    }
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: serial %08x (%d) is at offset %lld. %d records parsed", serial_from, serial_from, offset, rr_count);
#endif
    
    dns_resource_record_clear(&rr);
    
    /* 
     * detach the file descriptor from the file stream in the buffer stream
     * I do it like this because the streams are not needed anymore but the
     * file descriptor still is (if no error occurred)
     */
    
    fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
    input_stream_close(&bis);

    if(ISOK(return_value))
    {
        // offset is the start of the page we are looking for
        if(lseek(cloned_fd, offset, SEEK_SET) >= 0)
        {
            fd_input_stream_attach(&fis, cloned_fd);
            limited_input_stream_init(&fis, out_input_stream, file_size - offset);
        }
        else
        {
            return_value = ERRNO_ERROR;
            
            close_ex(cloned_fd);
        }
    }
    else
    {
        close_ex(cloned_fd);
    }
        
    return return_value;
}
Beispiel #25
0
ya_result
zdb_icmtl_replay(zdb_zone *zone)
{
    ya_result return_value;
    u32 serial;
    
    zdb_zone_double_lock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);

    return_value = zdb_zone_getserial(zone, &serial); // zone is locked
    
    if(FAIL(return_value))
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        log_err("journal: %{dnsname}: error reading serial for zone: %r", zone->origin, return_value);
        
        return return_value;
    }

    input_stream is;
    
#if ICMTL_DUMP_JOURNAL_RECORDS
    log_debug("journal: zdb_icmtl_replay(%{dnsname})", zone->origin);
    logger_flush();
#endif
    
    u32 first_serial;
    u32 last_serial;
        
    if(FAIL(return_value = zdb_zone_journal_get_serial_range(zone, &first_serial, &last_serial)))
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        if(return_value == ZDB_ERROR_ICMTL_NOTFOUND)
        {
            return_value = SUCCESS;
        }
        else
        {
            log_err("journal: %{dnsname}: error opening journal for zone: %r", zone->origin, return_value);
        }
                
        return return_value;
    }
    
    log_debug("journal: %{dnsname}: zone serial is %i, journal covers serials from %i to %i", zone->origin, serial, first_serial, last_serial);
    
    if(last_serial == serial)
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        log_debug("journal: %{dnsname}: nothing to read from the journal", zone->origin);
        return 0;
    }
    
    if(serial_lt(serial, first_serial))
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        log_warn("journal: %{dnsname}: first serial from the journal is after the zone", zone->origin);
        // should invalidate the journal
        zdb_zone_journal_delete(zone);
        return 0;
    }
    
    if(serial_gt(serial, last_serial))
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        log_warn("journal: %{dnsname}: last serial from the journal is before the zone", zone->origin);
        // should invalidate the journal
        zdb_zone_journal_delete(zone);
        return 0;
    }
    
    if(FAIL(return_value = zdb_zone_journal_get_ixfr_stream_at_serial(zone, serial, &is, NULL)))
    {
        zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
        
        log_err("journal: %{dnsname}: error reading journal from serial %d: %r",zone->origin, serial, return_value);

        return return_value;
    }
    
    log_info("journal: %{dnsname}: replaying from serial %u",zone->origin, serial);

    buffer_input_stream_init(&is, &is, ZDB_ICMTL_REPLAY_BUFFER_SIZE);    

    u16 shutdown_test_countdown = ZDB_ICMTL_REPLAY_SHUTDOWN_POLL_PERIOD;
    
    u32 current_serial = serial;
    
    /*
     * Read all records from [ SOA ... SOA ... [ SOA in memory
     */
    
    output_stream baos;
    input_stream bais;
    dns_resource_record rr;
    
    int baos_rr_count = 0;
    int baos_soa_count = 0;
    
    bool was_nsec3 = zdb_zone_is_nsec3(zone);

    bytearray_output_stream_init_ex(&baos, NULL, ZDB_ICMTL_REPLAY_BUFFER_SIZE, BYTEARRAY_DYNAMIC);
    dns_resource_record_init(&rr);    
           
    // 0: gather, 1: commit, 2: commit & stop
    
    for(int replay_state = ZDB_ICMTL_REPLAY_GATHER; replay_state != ZDB_ICMTL_REPLAY_COMMIT_AND_STOP;)
    {
        // ensure it's not supposed to shutdown (every few iterations)
        
        if(--shutdown_test_countdown <= 0)
        {
            if(dnscore_shuttingdown())
            {
                return_value = STOPPED_BY_APPLICATION_SHUTDOWN;
                break;
            }
            
            shutdown_test_countdown = ZDB_ICMTL_REPLAY_SHUTDOWN_POLL_PERIOD;
        }
        
        // read the next record
        
        if((return_value = dns_resource_record_read(&rr, &is)) <= 0)
        {
            if(ISOK(return_value))
            {
                log_info("journal: %{dnsname}: reached the end of the journal file", zone->origin);
                replay_state = ZDB_ICMTL_REPLAY_COMMIT_AND_STOP;
            }
            else
            {
                log_err("journal: broken journal: %r", return_value);
                logger_flush(); // broken journal (flush is slow, but this is bad, so : keep it)
                replay_state = ZDB_ICMTL_REPLAY_STOP;
            }
        }
        else // first record must be an SOA (or it's wrong)        
        if(baos_rr_count == 0) // first record ?
        {
            if(rr.tctr.qtype != TYPE_SOA) // must be SOA
            {
                // expected an SOA
                return_value = ERROR;
                break;
            }
            
            ++baos_soa_count; // 0 -> 1 // this is not mandatory but clearer to read
        }
        else // the page ends with an SOA or end of stream
        if(rr.tctr.qtype == TYPE_SOA)
        {
            if(baos_soa_count == 2)
            {
                // this record is the start of the next stream, keep it for the next iteration
                replay_state = ZDB_ICMTL_REPLAY_COMMIT;
            }
            
            ++baos_soa_count;
        }
        
        ++baos_rr_count;
        
        if((replay_state & ZDB_ICMTL_REPLAY_COMMIT) != 0)
        {
            log_info("journal: %{dnsname}: committing changes", zone->origin);
            u64 ts_start = timeus();
            zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
            bytearray_input_stream_init_const(&bais, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos));
            
            return_value = zdb_icmtl_replay_commit(zone, &bais, &current_serial);
            
            zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_LOAD, ZDB_ZONE_MUTEX_SIMPLEREADER);
            input_stream_close(&bais);
            u64 ts_stop = timeus();
            if(ts_stop < ts_start) // time change
            {
                ts_stop = ts_start;
            }
            
            u64 ts_delta = ts_stop - ts_start;
            
            if(ISOK(return_value))
            {
                if(ts_delta < 1000)
                {            
                    log_info("journal: %{dnsname}: committed changes (%lluus)", zone->origin, ts_delta);
                }
                else if(ts_delta < 1000000)
                {
                    double ts_delta_s = ts_delta;
                    ts_delta_s /= 1000.0;
                    log_info("journal: %{dnsname}: committed changes (%5.2fms)", zone->origin, ts_delta_s);
                }
                else
                {
                    double ts_delta_s = ts_delta;
                    ts_delta_s /= 1000000.0;
                    log_info("journal: %{dnsname}: committed changes (%5.2fs)", zone->origin, ts_delta_s);
                }
            }
            else
            {
                log_err("journal: %{dnsname}: failed to committed changes", zone->origin);
                break;
            }
                    
            // the current page has been processed
            
            if(replay_state == ZDB_ICMTL_REPLAY_COMMIT_AND_STOP)
            {
                // no more page to read
                break;
            }
            
            // reset the state for the next page
            // note: the next written record will be the last read SOA
                        
            baos_rr_count = 1;
            baos_soa_count = 1;
            replay_state = ZDB_ICMTL_REPLAY_GATHER;
            bytearray_output_stream_reset(&baos);
                       
        } // end if replay_state is ZDB_ICMTL_REPLAY_COMMIT (mask)
                
        dns_resource_record_write(&rr, &baos);
    }
   
    input_stream_close(&is);
    output_stream_close(&baos);
    dns_resource_record_clear(&rr);
    
    // cleanup destroyed nsec3 chains
    
    if(ISOK(return_value))
    {
        bool is_nsec3 = zdb_zone_is_nsec3(zone);

        if(is_nsec3 && !was_nsec3)
        {
            // the chain has just been created, but is probably missing internal links
            log_debug("journal: %{dnsname}: zone switched to NSEC3 by reading the journal: updating links", zone->origin);

            zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
            nsec3_zone_update_chain0_links(zone);
            zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_LOAD, ZDB_ZONE_MUTEX_SIMPLEREADER);

            log_debug("journal: %{dnsname}: zone switched to NSEC3 by reading the journal: links updated", zone->origin);
        }

        if(FAIL(return_value = zdb_zone_getserial(zone, &serial))) // zone is locked
        {
            zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);

            log_err("journal: %{dnsname}: error reading confirmation serial for zone: %r",zone->origin, return_value);

            return return_value;
        }

        if(serial != last_serial)
        {
            log_warn("journal: %{dnsname}: expected serial to be %i but it is %i instead",zone->origin, last_serial, serial);
        }

#if 0 // ICMTL_DUMP_JOURNAL_RECORDS
        if(is_nsec)
        {
            nsec_logdump_tree(zone);
            logger_flush();
        }
#endif
    }
    
    zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD);
    
    log_info("journal: %{dnsname}: done", zone->origin);

    return return_value;
}
static struct playlist_provider *
lastfm_open_uri(const char *uri, GMutex *mutex, GCond *cond)
{
	struct lastfm_playlist *playlist;
	GError *error = NULL;
	char *p, *q, *response, *session;

	/* handshake */

	p = g_strconcat("http://ws.audioscrobbler.com/radio/handshake.php?"
			"version=1.1.1&platform=linux&"
			"username="******"&"
			"passwordmd5=", lastfm_config.md5, "&"
			"debug=0&partner=", NULL);
	response = lastfm_get(p, mutex, cond);
	g_free(p);
	if (response == NULL)
		return NULL;

	/* extract session id from response */

	session = lastfm_find(response, "session");
	g_free(response);
	if (session == NULL) {
		g_warning("last.fm handshake failed");
		return NULL;
	}

	q = g_uri_escape_string(session, NULL, false);
	g_free(session);
	session = q;

	g_debug("session='%s'", session);

	/* "adjust" last.fm radio */

	if (strlen(uri) > 9) {
		char *escaped_uri;

		escaped_uri = g_uri_escape_string(uri, NULL, false);

		p = g_strconcat("http://ws.audioscrobbler.com/radio/adjust.php?"
				"session=", session, "&url=", escaped_uri, "&debug=0",
				NULL);
		g_free(escaped_uri);

		response = lastfm_get(p, mutex, cond);
		g_free(response);
		g_free(p);

		if (response == NULL) {
			g_free(session);
			return NULL;
		}
	}

	/* create the playlist object */

	playlist = g_new(struct lastfm_playlist, 1);
	playlist_provider_init(&playlist->base, &lastfm_playlist_plugin);

	/* open the last.fm playlist */

	p = g_strconcat("http://ws.audioscrobbler.com/radio/xspf.php?"
			"sk=", session, "&discovery=0&desktop=1.5.1.31879",
			NULL);
	g_free(session);

	playlist->is = input_stream_open(p, mutex, cond, &error);
	g_free(p);

	if (playlist->is == NULL) {
		if (error != NULL) {
			g_warning("Failed to load XSPF playlist: %s",
				  error->message);
			g_error_free(error);
		} else
			g_warning("Failed to load XSPF playlist");
		g_free(playlist);
		return NULL;
	}

	g_mutex_lock(mutex);

	input_stream_wait_ready(playlist->is);

	/* last.fm does not send a MIME type, we have to fake it here
	   :-( */
	g_free(playlist->is->mime);
	playlist->is->mime = g_strdup("application/xspf+xml");

	g_mutex_unlock(mutex);

	/* parse the XSPF playlist */

	playlist->xspf = playlist_list_open_stream(playlist->is, NULL);
	if (playlist->xspf == NULL) {
		input_stream_close(playlist->is);
		g_free(playlist);
		g_warning("Failed to parse XSPF playlist");
		return NULL;
	}

	return &playlist->base;
}
Beispiel #27
0
void input_close(struct input_desc *s)
{
  input_stream_close(s->s);
  free(s);
}
Beispiel #28
0
bool
song_file_update(struct song *song)
{
	const char *suffix;
	char *path_fs;
	const struct decoder_plugin *plugin;
	struct stat st;
	struct input_stream *is = NULL;

	assert(song_is_file(song));

	/* check if there's a suffix and a plugin */

	suffix = uri_get_suffix(song->uri);
	if (suffix == NULL)
		return false;

	plugin = decoder_plugin_from_suffix(suffix, NULL);
	if (plugin == NULL)
		return false;

	path_fs = map_song_fs(song);
	if (path_fs == NULL)
		return false;

	if (song->tag != NULL) {
		tag_free(song->tag);
		song->tag = NULL;
	}

	if (stat(path_fs, &st) < 0 || !S_ISREG(st.st_mode)) {
		g_free(path_fs);
		return false;
	}

	song->mtime = st.st_mtime;

	do {
		/* load file tag */
		song->tag = decoder_plugin_tag_dup(plugin, path_fs);
		if (song->tag != NULL)
			break;

		/* fall back to stream tag */
		if (plugin->stream_tag != NULL) {
			/* open the input_stream (if not already
			   open) */
			if (is == NULL)
				is = input_stream_open(path_fs, NULL);

			/* now try the stream_tag() method */
			if (is != NULL) {
				song->tag = decoder_plugin_stream_tag(plugin,
								      is);
				if (song->tag != NULL)
					break;

				input_stream_seek(is, 0, SEEK_SET, NULL);
			}
		}

		plugin = decoder_plugin_from_suffix(suffix, plugin);
	} while (plugin != NULL);

	if (is != NULL)
		input_stream_close(is);

	if (song->tag != NULL && tag_is_empty(song->tag))
		song->tag = tag_fallback(path_fs, song->tag);

	g_free(path_fs);
	return song->tag != NULL;
}
Beispiel #29
0
int main(int argc, char **argv)
{
	const char *uri;
	struct input_stream *is = NULL;
	bool success;
	GError *error = NULL;
	struct playlist_provider *playlist;
	struct song *song;

	if (argc != 3) {
		g_printerr("Usage: dump_playlist CONFIG URI\n");
		return 1;
	}

	uri = argv[2];

	/* initialize GLib */

	g_thread_init(NULL);
	g_log_set_default_handler(my_log_func, NULL);

	/* initialize MPD */

	config_global_init();
	success = config_read_file(argv[1], &error);
	if (!success) {
		g_printerr("%s\n", error->message);
		g_error_free(error);
		return 1;
	}

	io_thread_init();
	if (!io_thread_start(&error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return EXIT_FAILURE;
	}

	if (!input_stream_global_init(&error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return 2;
	}

	playlist_list_global_init();
	decoder_plugin_init_all();

	/* open the playlist */

	GMutex *mutex = g_mutex_new();
	GCond *cond = g_cond_new();

	playlist = playlist_list_open_uri(uri, mutex, cond);
	if (playlist == NULL) {
		/* open the stream and wait until it becomes ready */

		is = input_stream_open(uri, mutex, cond, &error);
		if (is == NULL) {
			if (error != NULL) {
				g_warning("%s", error->message);
				g_error_free(error);
			} else
				g_printerr("input_stream_open() failed\n");
			return 2;
		}

		input_stream_lock_wait_ready(is);

		/* open the playlist */

		playlist = playlist_list_open_stream(is, uri);
		if (playlist == NULL) {
			input_stream_close(is);
			g_printerr("Failed to open playlist\n");
			return 2;
		}
	}

	/* dump the playlist */

	while ((song = playlist_plugin_read(playlist)) != NULL) {
		g_print("%s\n", song->uri);

		if (song->end_ms > 0)
			g_print("range: %u:%02u..%u:%02u\n",
				song->start_ms / 60000,
				(song->start_ms / 1000) % 60,
				song->end_ms / 60000,
				(song->end_ms / 1000) % 60);
		else if (song->start_ms > 0)
			g_print("range: %u:%02u..\n",
				song->start_ms / 60000,
				(song->start_ms / 1000) % 60);

		if (song->tag != NULL)
			tag_save(stdout, song->tag);

		song_free(song);
	}

	/* deinitialize everything */

	playlist_plugin_close(playlist);
	if (is != NULL)
		input_stream_close(is);

	g_cond_free(cond);
	g_mutex_free(mutex);

	decoder_plugin_deinit_all();
	playlist_list_global_finish();
	input_stream_global_finish();
	io_thread_deinit();
	config_global_finish();

	return 0;
}
Beispiel #30
-1
/**
 * Read JSON data and parse it using the given YAJL parser.
 * @param url URL of the JSON data.
 * @param hand YAJL parser handle.
 * @return -1 on error, 0 on success.
 */
static int
soundcloud_parse_json(const char *url, yajl_handle hand, GMutex* mutex, GCond* cond)
{
	struct input_stream *input_stream;
	GError *error = NULL;
	char buffer[4096];
	unsigned char *ubuffer = (unsigned char *)buffer;
	size_t nbytes;

	input_stream = input_stream_open(url, mutex, cond, &error);
	if (input_stream == NULL) {
		if (error != NULL) {
			g_warning("%s", error->message);
			g_error_free(error);
		}
		return -1;
	}

	g_mutex_lock(mutex);
	input_stream_wait_ready(input_stream);

	yajl_status stat;
	int done = 0;

	while (!done) {
		nbytes = input_stream_read(input_stream, buffer, sizeof(buffer), &error);
		if (nbytes == 0) {
			if (error != NULL) {
				g_warning("%s", error->message);
				g_error_free(error);
			}
			if (input_stream_eof(input_stream)) {
				done = true;
			} else {
				g_mutex_unlock(mutex);
				input_stream_close(input_stream);
				return -1;
			}
		}

		if (done)
			stat = yajl_parse_complete(hand);
		else
			stat = yajl_parse(hand, ubuffer, nbytes);

		if (stat != yajl_status_ok &&
			stat != yajl_status_insufficient_data)
		{
			unsigned char *str = yajl_get_error(hand, 1, ubuffer, nbytes);
			g_warning("%s", str);
			yajl_free_error(hand, str);
			break;
		}
	}

	g_mutex_unlock(mutex);
	input_stream_close(input_stream);

	return 0;
}