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); }
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; }
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; }