예제 #1
0
/**
 * Checks whether appending `len' bytes of data to the header would fit
 * within the maximum header size requirement in case a continuation
 * is emitted, and using the configured separator.
 */
bool
header_fmt_value_fits(const header_fmt_t *hf, size_t len)
{
	size_t final_len;
	size_t maxlen, n;

	header_fmt_check(hf);

	if (hf->empty)
		return FALSE;

	maxlen = size_saturate_sub(hf->max_size, sizeof("\r\n"));

	/*
	 * If it fits on the line, no continuation will have to be emitted.
	 * Otherwise, we'll need the stripped version of the separator,
	 * followed by "\r\n\t" (3 chars).
	 */

	final_len = size_saturate_add(str_len(hf->header), len);

	n = size_saturate_add(hf->current_len, size_saturate_add(len, hf->seplen));
	if (n <= hf->maxlen) {
		final_len = size_saturate_add(final_len, hf->seplen);
	} else {
		final_len = size_saturate_add(final_len, hf->stripped_seplen);
		final_len = size_saturate_add(final_len, 3);
	}

	return final_len < maxlen;	/* Could say "<=" perhaps, but let's be safe */
}
예제 #2
0
파일: concat.c 프로젝트: MrJoe/gtk-gnutella
size_t
concat_strings_v(char *dst, size_t size, const char *s, va_list ap)
{
	char *p = dst;
	size_t ret = 0;

	g_assert(0 == size || NULL != dst);

	if (size > 0) {
		if (!s)
			*p = '\0';

		while (NULL != s) {
			size_t len;

			len = g_strlcpy(p, s, size);
			ret = size_saturate_add(ret, len);
			s = va_arg(ap, const char *);
			size = size_saturate_sub(size, len);
			if (0 == size)
				break;

			p += len;
		}
	}

	while (NULL != s) {
		ret = size_saturate_add(ret, strlen(s));
		s = va_arg(ap, const char *);
	}

	g_assert(ret < SIZE_MAX);
	return ret;
}
예제 #3
0
/**
 * Drop message (eslist iterator).
 *
 * @return TRUE to force message to be removed from list.
 */
static bool
udp_tx_desc_drop(void *data, void *udata)
{
	struct udp_tx_desc *txd = data;
	udp_sched_t *us = udata;

	udp_sched_check(us);
	udp_tx_desc_check(txd);
	g_assert(1 == pmsg_refcnt(txd->mb));

	us->buffered = size_saturate_sub(us->buffered, pmsg_size(txd->mb));
	udp_tx_desc_flag_release(txd, us);
	return TRUE;
}
예제 #4
0
/**
 * Send message (eslist iterator callback).
 *
 * @return TRUE if message was sent and freed up.
 */
static bool
udp_tx_desc_send(void *data, void *udata)
{
	struct udp_tx_desc *txd = data;
	udp_sched_t *us = udata;
	unsigned prio;

	udp_sched_check(us);
	udp_tx_desc_check(txd);

	if (us->used_all)
		return FALSE;

	/*
	 * Avoid flushing consecutive queued messages to the same destination,
	 * for regular (non-prioritary) messages.
	 *
	 * This serves two purposes:
	 *
	 * 1- It makes sure one single host does not capture all the available
	 *    outgoing bandwidth.
	 *
	 * 2- It somehow delays consecutive packets to a given host thereby reducing
	 *    flooding and hopefully avoiding saturation of its RX flow.
	 */

	prio = pmsg_prio(txd->mb);

	if (PMSG_P_DATA == prio && hset_contains(us->seen, txd->to)) {
		udp_sched_log(2, "%p: skipping mb=%p (%d bytes) to %s",
			us, txd->mb, pmsg_size(txd->mb), gnet_host_to_string(txd->to));
		return FALSE;
	}

	if (udp_sched_mb_sendto(us, txd->mb, txd->to, txd->tx, txd->cb)) {
		if (PMSG_P_DATA == prio && pmsg_was_sent(txd->mb))
			hset_insert(us->seen, atom_host_get(txd->to));
	} else {
		return FALSE;		/* Unsent, leave it in the queue */
	}

	us->buffered = size_saturate_sub(us->buffered, pmsg_size(txd->mb));
	udp_tx_desc_flag_release(txd, us);
	return TRUE;
}
예제 #5
0
/**
 * Store big value in the .dat file, writing to the supplied block numbers.
 *
 * @param db		the sdbm database
 * @param bvec		start of block vector, containing block numbers
 * @param data		start of data to write
 * @param len		length of data to write
 *
 * @return -1 on error with errno set, 0 if OK.
 */
static int
big_store(DBM *db, const void *bvec, const void *data, size_t len)
{
	DBMBIG *dbg = db->big;
	int bcnt = bigbcnt(len);
	int n;
	const void *p;
	const char *q;
	size_t remain;

	g_return_val_if_fail(NULL == dbg->bitcheck, -1);

	if (-1 == dbg->fd && -1 == big_open(dbg))
		return -1;

	/*
	 * Look at the amount of consecutive block numbers we have to be able
	 * to write into them via a single system call.
	 */

	n = bcnt;
	p = bvec;
	q = data;
	remain = len;

	while (n > 0) {
		size_t towrite = MIN(remain, BIG_BLKSIZE);
		guint32 bno = peek_be32(p);
		guint32 prev_bno = bno;

		p = const_ptr_add_offset(p, sizeof(guint32));
		n--;
		remain = size_saturate_sub(remain, towrite);

		while (n > 0) {
			guint32 next_bno = peek_be32(p);
			size_t amount;

			if (next_bno <= prev_bno)	/* Block numbers are sorted */
				goto corrupted_page;

			if (next_bno - prev_bno != 1)
				break;						/*  Not consecutive */

			prev_bno = next_bno;
			p = const_ptr_add_offset(p, sizeof(guint32));
			amount = MIN(remain, BIG_BLKSIZE);
			towrite += amount;
			n--;
			remain = size_saturate_sub(remain, amount);
		}

		dbg->bigwrite++;
		if (-1 == compat_pwrite(dbg->fd, q, towrite, OFF_DAT(bno))) {
			g_warning("sdbm: \"%s\": "
				"could not write %lu bytes starting at data block #%u: %s",
				sdbm_name(db), (unsigned long) towrite, bno, g_strerror(errno));

			ioerr(db, TRUE);
			return -1;
		}

		q += towrite;
		dbg->bigwrite_blk += bigblocks(towrite);
		g_assert(ptr_diff(q, data) <= len);
	}

	g_assert(ptr_diff(q, data) == len);

	return 0;

corrupted_page:
	g_warning("sdbm: \"%s\": corrupted page: %d big data block%s not sorted",
		sdbm_name(db), bcnt, 1 == bcnt ? "" : "s");

	ioerr(db, FALSE);
	errno = EFAULT;		/* Data corrupted somehow (.pag file) */
	return -1;
}
예제 #6
0
/**
 * Fetch data block from the .dat file, reading from the supplied block numbers.
 *
 * @param db		the sdbm database
 * @param bvec		start of block vector, containing block numbers
 * @param len		length of the data to be read
 *
 * @return -1 on error with errno set, 0 if OK.  Read data is left in the
 * scratch buffer.
 */
static int
big_fetch(DBM *db, const void *bvec, size_t len)
{
	int bcnt = bigbcnt(len);
	DBMBIG *dbg = db->big;
	int n;
	const void *p;
	char *q;
	size_t remain;
	guint32 prev_bno;

	if (-1 == dbg->fd && -1 == big_open(dbg))
		return -1;

	if (dbg->scratch_len < len)
		big_scratch_grow(dbg, len);

	/*
	 * Read consecutive blocks in one single system call.
	 */

	n = bcnt;
	p = bvec;
	q = dbg->scratch;
	remain = len;

	while (n > 0) {
		size_t toread = MIN(remain, BIG_BLKSIZE);
		guint32 bno = peek_be32(p);
		
		prev_bno = bno;
		if (!big_block_is_allocated(db, prev_bno))
			goto corrupted_database;
		p = const_ptr_add_offset(p, sizeof(guint32));
		n--;
		remain = size_saturate_sub(remain, toread);

		while (n > 0) {
			guint32 next_bno = peek_be32(p);
			size_t amount;

			if (next_bno <= prev_bno)	/* Block numbers are sorted */
				goto corrupted_page;

			if (next_bno - prev_bno != 1)
				break;						/*  Not consecutive */

			prev_bno = next_bno;
			if (!big_block_is_allocated(db, prev_bno))
				goto corrupted_database;
			p = const_ptr_add_offset(p, sizeof(guint32));
			amount = MIN(remain, BIG_BLKSIZE);
			toread += amount;
			n--;
			remain = size_saturate_sub(remain, amount);
		}

		dbg->bigread++;
		if (-1 == compat_pread(dbg->fd, q, toread, OFF_DAT(bno))) {
			g_warning("sdbm: \"%s\": "
				"could not read %lu bytes starting at data block #%u: %s",
				sdbm_name(db), (unsigned long) toread, bno, g_strerror(errno));

			ioerr(db, FALSE);
			return -1;
		}

		q += toread;
		dbg->bigread_blk += bigblocks(toread);
		g_assert(UNSIGNED(q - dbg->scratch) <= dbg->scratch_len);
	}

	g_assert(UNSIGNED(q - dbg->scratch) == len);

	return 0;

corrupted_database:
	g_warning("sdbm: \"%s\": cannot read unallocated data block #%u",
		sdbm_name(db), prev_bno);
	goto fault;

corrupted_page:
	g_warning("sdbm: \"%s\": corrupted page: %d big data block%s not sorted",
		sdbm_name(db), bcnt, 1 == bcnt ? "" : "s");

	/* FALL THROUGH */

fault:
	ioerr(db, FALSE);
	errno = EFAULT;		/* Data corrupted somehow (.pag or .dat file) */
	return -1;
}