+ ssize_t data_read;
+ do
+ {
+ data_read= ::recv(instance->fd, instance->read_buffer, MEMCACHED_MAX_BUFFER, MSG_NOSIGNAL);
+ if (data_read == SOCKET_ERROR)
+ {
+ switch (get_socket_errno())
+ {
+ case EINTR: // We just retry
+ continue;
+
+ case ETIMEDOUT: // OSX
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+#ifdef __linux
+ case ERESTART:
+#endif
+ {
+ memcached_return_t io_wait_ret;
+ if (memcached_success(io_wait_ret= io_wait(instance, MEM_READ)))
+ {
+ continue;
+ }
+
+ return io_wait_ret;
+ }
+
+ /* fall through */
+
+ case ENOTCONN: // Programmer Error
+ WATCHPOINT_ASSERT(0);
+ case ENOTSOCK:
+ WATCHPOINT_ASSERT(0);
+ case EBADF:
+ assert_msg(instance->fd != INVALID_SOCKET, "Programmer error, invalid socket");
+ case EINVAL:
+ case EFAULT:
+ case ECONNREFUSED:
+ default:
+ memcached_quit_server(instance, true);
+ memcached_set_errno(*instance, get_socket_errno(), MEMCACHED_AT);
+ break;
+ }
+
+ return memcached_instance_error_return(instance);
+ }
+ else if (data_read == 0)
+ {
+ /*
+ EOF. Any data received so far is incomplete
+ so discard it. This always reads by byte in case of TCP
+ and protocol enforcement happens at memcached_response()
+ looking for '\n'. We do not care for UDB which requests 8 bytes
+ at once. Generally, this means that connection went away. Since
+ for blocking I/O we do not return 0 and for non-blocking case
+ it will return EGAIN if data is not immediatly available.
+ */
+ memcached_quit_server(instance, true);
+ return memcached_set_error(*instance, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("::rec() returned zero, server has disconnected"));
+ }
+ instance->io_wait_count._bytes_read+= data_read;
+ } while (data_read <= 0);
+
+ instance->io_bytes_sent= 0;
+ instance->read_data_length= (size_t) data_read;
+ instance->read_buffer_length= (size_t) data_read;
+ instance->read_ptr= instance->read_buffer;
+
+ return MEMCACHED_SUCCESS;