Esempio n. 1
0
/**
 * Create new message queue capable of holding `maxsize' bytes, and
 * owned by the supplied node.
 *
 * @param maxsize		the overall sum of message size that can be held
 * @param n				the network node to which the message queue is attached
 * @oaram nd			the top of the TX stack to use to send out messages
 * @param uops			user-defined operations
 */
mqueue_t *
mq_udp_make(int maxsize,
	gnutella_node_t *n, struct txdriver *nd, const struct mq_uops *uops)
{
	mqueue_t *q;

	node_check(n);
	tx_check(nd);
	g_assert(uops != NULL);
	g_assert(maxsize > 0);

	WALLOC0(q);

	q->magic = MQ_MAGIC;
	q->node = n;
	q->tx_drv = nd;
	q->maxsize = maxsize;
	q->lowat = maxsize >> 2;		/* 25% of max size */
	q->hiwat = maxsize >> 1;		/* 50% of max size */
	q->qwait = slist_new();
	q->ops = &mq_udp_ops;
	q->cops = mq_get_cops();
	q->uops = uops;
	q->debug = GNET_PROPERTY_PTR(mq_udp_debug);

	tx_srv_register(nd, mq_udp_service, q);

	return q;
}
Esempio n. 2
0
/**
 * Creates a new THEX upload context. The context must be freed with
 * thex_upload_close().
 *
 * @param owner			the owner of the TX stack (the upload)
 * @param host			the host to which we're talking to
 * @param writable		no document
 * @param link_cb		callbacks for the link layer
 * @param wio			no document
 * @param flags			opening flags
 *
 * @return An initialized THEX upload context.
 */
struct special_upload *
thex_upload_open(
	void *owner,
	const struct gnutella_host *host,
	const shared_file_t *sf,
	special_upload_writable_t writable,
	const struct tx_link_cb *link_cb,
	struct wrap_io *wio,
	int flags)
{
	struct thex_upload *ctx;

	WALLOC(ctx);
	ctx->special_upload.read =  thex_upload_read;
	ctx->special_upload.write = thex_upload_write;
	ctx->special_upload.flush = thex_upload_flush;
	ctx->special_upload.close = thex_upload_close;

	ctx->tth = atom_tth_get(shared_file_tth(sf));
	ctx->filesize = shared_file_size(sf);
	ctx->data = NULL;
	ctx->size = 0;
	ctx->offset = 0;
	ctx->state = THEX_STATE_INITIAL;

	/*
	 * Instantiate the TX stack.
	 */

	{
		struct tx_link_args args;

		args.cb = link_cb;
		args.wio = wio;
		args.bws = bsched_out_select_by_addr(gnet_host_get_addr(host));

		ctx->tx = tx_make(owner, host, tx_link_get_ops(), &args);
	}

	if (flags & THEX_UPLOAD_F_CHUNKED) {
		ctx->tx = tx_make_above(ctx->tx, tx_chunk_get_ops(), 0);
	}

	/*
	 * Put stack in "eager" mode: we want to be notified whenever
	 * we can write something.
	 */

	tx_srv_register(ctx->tx, writable, owner);
	tx_eager_mode(ctx->tx, TRUE);

	/*
	 * Update statistics.
	 */

	gnet_prop_incr_guint32(PROP_THEX_FILES_REQUESTED);
	return &ctx->special_upload;
}
Esempio n. 3
0
/**
 * Create new message queue capable of holding `maxsize' bytes, and
 * owned by the supplied node.
 */
mqueue_t *
mq_udp_make(int maxsize, struct gnutella_node *n, struct txdriver *nd)
{
	mqueue_t *q;

	WALLOC0(q);

	q->magic = MQ_MAGIC;
	q->node = n;
	q->tx_drv = nd;
	q->maxsize = maxsize;
	q->lowat = maxsize >> 2;		/* 25% of max size */
	q->hiwat = maxsize >> 1;		/* 50% of max size */
	q->qwait = slist_new();
	q->ops = &mq_udp_ops;
	q->cops = mq_get_cops();
	q->debug = GNET_PROPERTY_PTR(mq_udp_debug);

	tx_srv_register(nd, mq_udp_service, q);

	return q;
}
Esempio n. 4
0
/**
 * Creates a new browse host context. The context must be freed with
 * browse_host_close().
 *
 * @param owner			the owner of the TX stack (the upload)
 * @param host			the host to which we're talking to
 * @param writable		no document
 * @param deflate_cb	callbacks for the deflate layer
 * @param link_cb		callbacks for the link layer
 * @param wio			no document
 * @param flags			opening flags
 *
 * @return An initialized browse host context.
 */
struct special_upload *
browse_host_open(
	void *owner,
	struct gnutella_host *host,
	special_upload_writable_t writable,
	const struct tx_deflate_cb *deflate_cb,
	const struct tx_link_cb *link_cb,
	struct wrap_io *wio,
	int flags)
{
	struct browse_host_upload *bh;

	/* BH_HTML xor BH_QHITS set */
	g_assert(flags & (BH_F_HTML|BH_F_QHITS));
	g_assert((flags & (BH_F_HTML|BH_F_QHITS)) != (BH_F_HTML|BH_F_QHITS));

	WALLOC(bh);
	bh->special.read = (flags & BH_F_HTML)
						? browse_host_read_html
						: browse_host_read_qhits;
	bh->special.write = browse_host_write;
	bh->special.flush = browse_host_flush;
	bh->special.close = browse_host_close;

	browse_host_next_state(bh, BH_STATE_HEADER);
	bh->hits = NULL;
	bh->file_index = 0;
	bh->flags = flags;

	/*
	 * Instantiate the TX stack.
	 */

	{
		struct tx_link_args args;

		args.cb = link_cb;
		args.wio = wio;
		args.bws = bsched_out_select_by_addr(gnet_host_get_addr(host));

		bh->tx = tx_make(owner, host, tx_link_get_ops(), &args);
	}

	if (flags & BH_F_CHUNKED) {
		bh->tx = tx_make_above(bh->tx, tx_chunk_get_ops(), 0);
	}
	if (flags & (BH_F_DEFLATE | BH_F_GZIP)) {
		struct tx_deflate_args args;
		txdrv_t *tx;

		args.cq = cq_main();
		args.cb = deflate_cb;
		args.nagle = FALSE;
		args.reduced = FALSE;
		args.gzip = 0 != (flags & BH_F_GZIP);
		args.buffer_flush = INT_MAX;		/* Flush only at the end */
		args.buffer_size = BH_BUFSIZ;

		tx = tx_make_above(bh->tx, tx_deflate_get_ops(), &args);
		if (tx == NULL) {
			tx_free(bh->tx);
			link_cb->eof_remove(owner, "Cannot setup compressing TX stack");
			WFREE(bh);
			return NULL;
		}

		bh->tx = tx;
	}

	/*
	 * Put stack in "eager" mode: we want to be notified whenever
	 * we can write something.
	 */

	tx_srv_register(bh->tx, writable, owner);
	tx_eager_mode(bh->tx, TRUE);

	/*
	 * Update statistics.
	 */

	if (flags & BH_F_HTML) {
		gnet_prop_incr_guint32(PROP_HTML_BROWSE_COUNT);
	} else if (flags & BH_F_QHITS) {
		gnet_prop_incr_guint32(PROP_QHITS_BROWSE_COUNT);
	}
	return &bh->special;
}
Esempio n. 5
0
/**
 * Initialize the driver.
 *
 * @return NULL if there is an initialization problem.
 */
static void *
tx_deflate_init(txdrv_t *tx, void *args)
{
	struct attr *attr;
	struct tx_deflate_args *targs = args;
	z_streamp outz;
	int ret;
	int i;

	g_assert(tx);
	g_assert(NULL != targs->cb);

	WALLOC(outz);
	outz->zalloc = zlib_alloc_func;
	outz->zfree = zlib_free_func;
	outz->opaque = NULL;

	/*
	 * Reduce memory requirements for deflation when running as an ultrapeer.
	 *
	 * Memory used for deflation is:
	 *
	 *	(1 << (window_bits +2)) +  (1 << (mem_level + 9))
	 *
	 * For leaves, we use window_bits = 15 and mem_level = 9, which makes
	 * for 128 KiB + 256 KiB = 384 KiB per connection (TX side).
	 *
	 * For ultra peers, we use window_bits = 14 and mem_level = 6, so this
	 * uses 64 KiB + 32 KiB = 96 KiB only.
	 *
	 * Since ultra peers have many more connections than leaves, the memory
	 * savings are drastic, yet compression levels remain around 50% (varies
	 * depending on the nature of the traffic, of course).
	 *
	 *		--RAM, 2009-04-09
	 *
	 * For Ultra <-> Ultra connections we use window_bits = 15 and mem_level = 9
	 * and request a best compression because the amount of ultra connections
	 * is far less than the number of leaf connections and modern machines
	 * can cope with a "best" compression overhead.
	 *
	 * This is now controlled with the "reduced" argument, so this layer does
	 * not need to know whether we're an ultra node or even what an ultra
	 * node is... It just knows whether we have to setup a fully compressed
	 * connection or a reduced one (both in terms of memory usage and level
	 * of compression).
	 *
	 *		--RAM, 2011-11-29
	 */

	{
		int window_bits = MAX_WBITS;		/* Must be 8 .. MAX_WBITS */
		int mem_level = MAX_MEM_LEVEL;		/* Must be 1 .. MAX_MEM_LEVEL */
		int level = Z_BEST_COMPRESSION;

		if (targs->reduced) {
			/* Ultra -> Leaf connection */
			window_bits = 14;
			mem_level = 6;
			level = Z_DEFAULT_COMPRESSION;
		}

		g_assert(window_bits >= 8 && window_bits <= MAX_WBITS);
		g_assert(mem_level >= 1 && mem_level <= MAX_MEM_LEVEL);
		g_assert(level == Z_DEFAULT_COMPRESSION ||
			(level >= Z_BEST_SPEED && level <= Z_BEST_COMPRESSION));

		ret = deflateInit2(outz, level, Z_DEFLATED,
				targs->gzip ? (-window_bits) : window_bits, mem_level,
				Z_DEFAULT_STRATEGY);
	}

	if (Z_OK != ret) {
		g_warning("unable to initialize compressor for peer %s: %s",
			gnet_host_to_string(&tx->host), zlib_strerror(ret));
		WFREE(outz);
		return NULL;
	}

	WALLOC0(attr);
	attr->cq = targs->cq;
	attr->cb = targs->cb;
	attr->buffer_size = targs->buffer_size;
	attr->buffer_flush = targs->buffer_flush;
	attr->nagle = booleanize(targs->nagle);
	attr->gzip.enabled = targs->gzip;

	attr->outz = outz;
	attr->tm_ev = NULL;

	for (i = 0; i < BUFFER_COUNT; i++) {
		struct buffer *b = &attr->buf[i];

		b->arena = b->wptr = b->rptr = walloc(attr->buffer_size);
		b->end = &b->arena[attr->buffer_size];
	}

	attr->fill_idx = 0;
	attr->send_idx = -1;		/* Signals: none ready */

	if (attr->gzip.enabled) {
		/* See RFC 1952 - GZIP file format specification version 4.3 */
		static const unsigned char header[] = {
			0x1f, 0x8b, /* gzip magic */
			0x08,		/* compression method: deflate */
			0,			/* flags: none */
			0, 0, 0, 0, /* modification time: unavailable */
			0,			/* extra flags: none */
			0xff,		/* filesystem: unknown */
		};
		struct buffer *b;

		b = &attr->buf[attr->fill_idx];	/* Buffer we fill */
		g_assert(sizeof header <= (size_t) (b->end - b->wptr));
		b->wptr = mempcpy(b->wptr, header, sizeof header);

		attr->gzip.crc = crc32(0, NULL, 0);
		attr->gzip.size = 0;
	}

	tx->opaque = attr;

	/*
	 * Register our service routine to the lower layer.
	 */

	tx_srv_register(tx->lower, deflate_service, tx);

	return tx;		/* OK */
}