+ memcached_quit_server(ptr, 1);
+}
+
+/**
+ * Read a given number of bytes from the server and place it into a specific
+ * buffer. Reset the IO channel on this server if an error occurs.
+ */
+memcached_return memcached_safe_read(memcached_server_st *ptr,
+ void *dta,
+ size_t size)
+{
+ size_t offset= 0;
+ char *data= dta;
+
+ while (offset < size)
+ {
+ ssize_t nread;
+ memcached_return rc= memcached_io_read(ptr, data + offset, size - offset,
+ &nread);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ offset+= nread;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+memcached_return memcached_io_readline(memcached_server_st *ptr,
+ char *buffer_ptr,
+ size_t size)
+{
+ bool line_complete= false;
+ size_t total_nr= 0;
+
+ while (!line_complete)
+ {
+ if (ptr->read_buffer_length == 0)
+ {
+ /*
+ * We don't have any data in the buffer, so let's fill the read
+ * buffer. Call the standard read function to avoid duplicating
+ * the logic.
+ */
+ ssize_t nread;
+ memcached_return rc= memcached_io_read(ptr, buffer_ptr, 1, &nread);
+ if (rc != MEMCACHED_SUCCESS)
+ return rc;
+
+ if (*buffer_ptr == '\n')
+ line_complete= true;
+
+ ++buffer_ptr;
+ ++total_nr;
+ }
+
+ /* Now let's look in the buffer and copy as we go! */
+ while (ptr->read_buffer_length && total_nr < size && !line_complete)
+ {
+ *buffer_ptr = *ptr->read_ptr;
+ if (*buffer_ptr == '\n')
+ line_complete = true;
+ --ptr->read_buffer_length;
+ ++ptr->read_ptr;
+ ++total_nr;
+ ++buffer_ptr;
+ }
+
+ if (total_nr == size)
+ return MEMCACHED_PROTOCOL_ERROR;
+ }
+
+ return MEMCACHED_SUCCESS;
+}
+
+/*
+ * The udp request id consists of two seperate sections
+ * 1) The thread id
+ * 2) The message number
+ * The thread id should only be set when the memcached_st struct is created
+ * and should not be changed.
+ *
+ * The message num is incremented for each new message we send, this function
+ * extracts the message number from message_id, increments it and then
+ * writes the new value back into the header
+ */
+static void increment_udp_message_id(memcached_server_st *ptr)
+{
+ struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+ uint16_t cur_req= get_udp_datagram_request_id(header);
+ uint16_t msg_num= get_msg_num_from_request_id(cur_req);
+ uint16_t thread_id= get_thread_id_from_request_id(cur_req);
+
+ if (((++msg_num) & UDP_REQUEST_ID_THREAD_MASK) != 0)
+ msg_num= 0;
+
+ header->request_id= htons(thread_id | msg_num);
+}
+
+memcached_return memcached_io_init_udp_header(memcached_server_st *ptr, uint16_t thread_id)
+{
+ if (thread_id > UDP_REQUEST_ID_MAX_THREAD_ID)
+ return MEMCACHED_FAILURE;
+
+ struct udp_datagram_header_st *header= (struct udp_datagram_header_st *)ptr->write_buffer;
+ header->request_id= htons(generate_udp_request_thread_id(thread_id));
+ header->num_datagrams= htons(1);
+ header->sequence_number= htons(0);
+
+ return MEMCACHED_SUCCESS;