Exemplo n.º 1
0
static void	*get_chunk_empty_freelist(unsigned long total_needed_size,
					  t_chunk **flist, t_chunk **alist)
{
  t_chunk	*new_elem;
  unsigned long	allocated_size;

  if (!(new_elem = extend_heap(allocated_size
			       = A_PAGE(total_needed_size + PAD_MUL + 1,
					get_power(getpagesize())))))
    return (NULL);
  new_elem->size = total_needed_size - HEADER_SIZE;
  new_elem->magic = M_ALLOC;
  put_in_list(&alist[INDEX(new_elem->size)], new_elem);
  if (total_needed_size == allocated_size)
    return (new_elem + 1);
  add_remaining(&flist[0], new_elem, total_needed_size);
  return (new_elem + 1);
}
Exemplo n.º 2
0
static gboolean try_read_data(liMemcachedCon *con, gsize datalen) {
	liBuffer *data;
	ssize_t r;

	datalen += 2; /* \r\n */

	/* if we have remaining data use it for a new line */
	if ((!con->data || con->data->used == 0) && con->remaining && con->remaining->used > 0) {
		liBuffer *tmp = con->remaining; con->remaining = con->data; con->data = tmp;
	}

	if (!con->data) con->data = li_buffer_new_slice(MAX(BUFFER_CHUNK_SIZE, datalen));

	if (con->data->alloc_size < datalen) {
		data = li_buffer_new_slice(MAX(BUFFER_CHUNK_SIZE, datalen));
		memcpy(data->addr, con->data->addr, (data->used = con->data->used));
		li_buffer_release(con->data);
		con->data = data;
	}

	g_assert(NULL == con->remaining || 0 == con->remaining->used); /* there shouldn't be any data in remaining while we fill con->data */

	data = con->data;

	if (data->used < datalen) {
		/* read more data */
		r = net_read(con->fd, data->addr + data->used, data->alloc_size - data->used);
		if (r == 0) {
			/* EOF */
			g_clear_error(&con->err);
			g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Connection closed by peer");
			close_con(con);
			return FALSE;
		} else if (r < 0) {
			switch (errno) {
			case EAGAIN:
#if EWOULDBLOCK != EAGAIN
			case EWOULDBLOCK:
#endif
				break;
			default:
				g_clear_error(&con->err);
				g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Connection closed: %s", g_strerror(errno));
				close_con(con);
				break;
			}
			return FALSE;
		}

		data->used += r;
	}

	if (data->used >= datalen) {
		if (data->addr[datalen-2] != '\r' || data->addr[datalen-1] != '\n') {
			/* Protocol error: data block not terminated with \r\n */
			g_clear_error(&con->err);
			g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Protocol error: data block not terminated with \\r\\n");
			close_con(con);
			return FALSE;
		}
		add_remaining(con, data->addr + datalen, data->used - datalen);
		data->used = datalen - 2;
		data->addr[datalen-2] = '\0';
		return TRUE;
	}

	return FALSE;
}
Exemplo n.º 3
0
static gboolean try_read_line(liMemcachedCon *con) {
	liBuffer *line;
	ssize_t r;

	if (!con->line) con->line = li_buffer_new_slice(BUFFER_CHUNK_SIZE);
	if (!con->remaining) con->remaining = li_buffer_new_slice(BUFFER_CHUNK_SIZE);

	/* if we have remaining data use it for a new line */
	if (con->line->used == 0 && con->remaining->used > 0) {
		liBuffer *tmp = con->remaining; con->remaining = con->line; con->line = tmp;
	}

	g_assert(NULL == con->remaining || 0 == con->remaining->used); /* there shouldn't be any data in remaining while we fill con->line */

	line = con->line;

	if (line->used > 0) {
		/* search for \r\n */
		gchar *addr = line->addr;
		gsize i, len = line->used;
		for (i = 0; i < len; i++) {
			if (addr[i] == '\r') {
				i++;
				if (i < len && addr[i] == '\n') {
					add_remaining(con, addr + i+1, len - (i+1));
					line->used = i-1;
					line->addr[i-1] = '\0';
					return TRUE;
				}
			}
		}
	}

	if (line->used > 1024) {
		/* Protocol error: we don't parse line longer than 1024 */
		g_clear_error(&con->err);
		g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Protocol error: line too long");
		close_con(con);
		return FALSE;
	}

	/* need more data */
	r = net_read(con->fd, line->addr + line->used, line->alloc_size - line->used);
	if (r == 0) {
		/* EOF */
		g_clear_error(&con->err);
		g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Connection closed by peer");
		close_con(con);
		return FALSE;
	} else if (r < 0) {
		switch (errno) {
		case EAGAIN:
#if EWOULDBLOCK != EAGAIN
		case EWOULDBLOCK:
#endif
			break;
		default:
			g_clear_error(&con->err);
			g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Connection closed: %s", g_strerror(errno));
			close_con(con);
			break;
		}
		return FALSE;
	}

	line->used += r;

	if (line->used > 0) {
		/* search for \r\n */
		gchar *addr = line->addr;
		gsize i, len = line->used;
		for (i = 0; i < len; i++) {
			if (addr[i] == '\r') {
				i++;
				if (i < len && addr[i] == '\n') {
					add_remaining(con, addr + i+1, len - (i+1));
					line->used = i-1;
					line->addr[i-1] = '\0';
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}