Ejemplo n.º 1
0
/**
 * Dump relayed or locally-emitted packet.
 * If ``from'' is NULL, packet was emitted locally.
 */
static void
dump_packet_from_to(struct dump *dump,
	const struct gnutella_node *from, const struct gnutella_node *to,
	const pmsg_t *mb)
{
	struct dump_header dh_to;	
	struct dump_header dh_from;	

	g_assert(to != NULL);
	g_assert(mb != NULL);
	g_assert(pmsg_read_base(mb) == pmsg_start(mb));

	if (!dump_initialize(dump))
		return;

	/*
	 * This is only for Gnutella packets, leave DHT messages out.
	 */

	if (GTA_MSG_DHT == gnutella_header_get_function(pmsg_start(mb)))
		return;

	if (!ipset_contains_addr(&dump_tx_to_addrs, to->addr, TRUE))
		return;

	if (NULL == from) {
		struct gnutella_node local;
		local.peermode = NODE_IS_UDP(to) ? NODE_P_UDP : NODE_P_NORMAL;
		local.addr = listen_addr();
		local.port = GNET_PROPERTY(listen_port);
		if (!ipset_contains_addr(&dump_tx_from_addrs, local.addr, TRUE))
			return;
		dump_header_set(&dh_from, &local);
	} else {
		if (!ipset_contains_addr(&dump_tx_from_addrs, from->addr, TRUE))
			return;
		dump_header_set(&dh_from, from);
	}

	dump_header_set(&dh_to, to);
	dh_to.data[0] |= DH_F_TO;
	if (pmsg_prio(mb) != PMSG_P_DATA)
		dh_to.data[0] |= DH_F_CTRL;
		
	dump_append(dump, dh_to.data, sizeof dh_to.data);
	dump_append(dump, dh_from.data, sizeof dh_from.data);
	dump_append(dump, pmsg_read_base(mb), pmsg_size(mb));
	dump_flush(dump);
}
Ejemplo n.º 2
0
/**
 * Creates an iovec from a singly-linked list of pmsg_t buffers.
 * It should be freed via hfree().
 *
 * NOTE: The iovec will hold no more than MAX_IOV_COUNT items. That means
 *       the iovec might not cover the whole buffered data. This limit
 *		 is applied because writev() could fail with EINVAL otherwise
 *		 which would simply add more unnecessary complexity.
 */
iovec_t *
pmsg_slist_to_iovec(slist_t *slist, int *iovcnt_ptr, size_t *size_ptr)
{
	iovec_t *iov;
	size_t held = 0;
	int n;

	g_assert(slist);

	n = slist_length(slist);

	if (n > 0) {
		slist_iter_t *iter;
		int i;

		n = MIN(n, MAX_IOV_COUNT);
		iov = halloc(n * sizeof *iov);

		iter = slist_iter_before_head(slist);
		for (i = 0; i < n; i++) {
			pmsg_t *mb;
			size_t size;

			mb = slist_iter_next(iter);
			pmsg_check_consistency(mb);

			size = pmsg_size(mb);
			g_assert(size > 0);
			held += size;

			iovec_set(&iov[i], deconstify_pointer(pmsg_read_base(mb)), size);
		}
		slist_iter_free(&iter);
	} else {
		iov = NULL;
	}
	if (iovcnt_ptr) {
		*iovcnt_ptr = MAX(0, n);
	}
	if (size_ptr) {
		*size_ptr = held;
	}
	return iov;
}
Ejemplo n.º 3
0
/**
 * Dechunk more data from the input buffer `mb'.
 * @returns dechunked data in a new buffer, or NULL if no more data.
 */
static pmsg_t *
dechunk_data(rxdrv_t *rx, pmsg_t *mb)
{
	struct attr *attr = rx->opaque;
	const char *error_str, *src;
	size_t size;

	/*
	 * Prepare call to parse_chunk().
	 */

	size = pmsg_size(mb);
	src = pmsg_read_base(mb);

	while (size > 0) {
		size_t ret;

		g_assert(CHUNK_STATE_ERROR != attr->state);

		/*
		 * Copy avoidance: if the data we got fits into the current chunk size,
		 * then we don't have to parse anything: all the data belong to the
		 * current chunk, so we can simply pass them to the upper layer.
		 */

		if (CHUNK_STATE_DATA == attr->state) {
			pmsg_t *nmb;

			nmb = pmsg_clone(mb);
			if (size < attr->data_remain) {
				/* The complete chunk data is forwarded to the upper layer */
				mb->m_rptr += size;
				attr->data_remain -= size;
			} else {
				/* Only the first ``data_remain'' bytes are forwarded */
				mb->m_rptr += attr->data_remain;
				nmb->m_wptr =
					deconstify_pointer(&nmb->m_rptr[attr->data_remain]);
				attr->data_remain = 0;
				attr->state = CHUNK_STATE_DATA_CRLF;
			}
			if (GNET_PROPERTY(rx_debug) > 9)
				g_debug("dechunk_data: returning chunk of %u bytes",
					pmsg_size(nmb));
			return nmb;
		}

		g_assert(size > 0);
		g_assert(CHUNK_STATE_DATA != attr->state);

		/*
		 * Parse chunk headers
		 */

		ret = parse_chunk(rx, src, size, &error_str);
		if (0 == ret) {
			/*
			 * We can't continue if we meet a dechunking error.  Signal
			 * our user so that the connection is terminated.
			 */

			errno = EIO;
			attr->cb->chunk_error(rx->owner,
					"dechunk() failed: %s", error_str);
			g_warning("dechunk_data(): %s", error_str);
			break;
		}
		g_assert(ret <= size);
		size -= ret;
		mb->m_rptr += ret;		/* Read that far */
	}

	return NULL;				/* No more data */
}