+ return (-1);
+ }
+
+ return (0);
+} /* }}} int nc_connection_init */
+
+static char *nc_connection_gets (nc_connection_t *conn, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ ssize_t status;
+ char *orig_buffer = buffer;
+
+ if (conn == NULL)
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (!conn->have_tls_session)
+ return (fgets (buffer, (int) buffer_size, conn->fh_in));
+
+ if ((buffer == NULL) || (buffer_size < 2))
+ {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* ensure null termination */
+ memset (buffer, 0, buffer_size);
+ buffer_size--;
+
+ while (42)
+ {
+ size_t max_copy_bytes;
+ size_t newline_pos;
+ _Bool found_newline;
+ size_t i;
+
+ /* If there's no more data in the read buffer, read another chunk from the
+ * socket. */
+ if (conn->read_buffer_fill < 1)
+ {
+ status = gnutls_record_recv (conn->tls_session,
+ conn->read_buffer, NC_READ_BUFFER_SIZE);
+ if (status < 0) /* error */
+ {
+ ERROR ("netcmd plugin: Error while reading from TLS stream.");
+ return (NULL);
+ }
+ else if (status == 0) /* we reached end of file */
+ {
+ if (orig_buffer == buffer) /* nothing has been written to the buffer yet */
+ return (NULL); /* end of file */
+ else
+ return (orig_buffer);
+ }
+ else
+ {
+ conn->read_buffer_fill = (size_t) status;
+ }
+ }
+ assert (conn->read_buffer_fill > 0);
+
+ /* Determine where the first newline character is in the buffer. We're not
+ * using strcspn(3) here, becaus the buffer is possibly not
+ * null-terminated. */
+ newline_pos = conn->read_buffer_fill;
+ found_newline = 0;
+ for (i = 0; i < conn->read_buffer_fill; i++)
+ {
+ if (conn->read_buffer[i] == '\n')
+ {
+ newline_pos = i;
+ found_newline = 1;
+ break;
+ }
+ }
+
+ /* Determine how many bytes to copy at most. This is MIN(buffer available,
+ * read buffer size, characters to newline). */
+ max_copy_bytes = buffer_size;
+ if (max_copy_bytes > conn->read_buffer_fill)
+ max_copy_bytes = conn->read_buffer_fill;
+ if (max_copy_bytes > (newline_pos + 1))
+ max_copy_bytes = newline_pos + 1;
+ assert (max_copy_bytes > 0);
+
+ /* Copy bytes to the output buffer. */
+ memcpy (buffer, conn->read_buffer, max_copy_bytes);
+ buffer += max_copy_bytes;
+ assert (buffer_size >= max_copy_bytes);
+ buffer_size -= max_copy_bytes;
+
+ /* If there is data left in the read buffer, move it to the front of the
+ * buffer. */
+ if (max_copy_bytes < conn->read_buffer_fill)
+ {
+ size_t data_left_size = conn->read_buffer_fill - max_copy_bytes;
+ memmove (conn->read_buffer, conn->read_buffer + max_copy_bytes,
+ data_left_size);
+ conn->read_buffer_fill -= max_copy_bytes;
+ }
+ else
+ {
+ assert (max_copy_bytes == conn->read_buffer_fill);
+ conn->read_buffer_fill = 0;
+ }
+
+ if (found_newline)
+ break;
+
+ if (buffer_size == 0) /* no more space in the output buffer */
+ break;
+ }
+
+ return (orig_buffer);
+} /* }}} char *nc_connection_gets */
+
+static void *nc_handle_client (void *arg) /* {{{ */
+{
+ nc_connection_t *conn;
+ char errbuf[1024];
+ int status;
+
+ conn = arg;
+
+ DEBUG ("netcmd plugin: nc_handle_client: Reading from fd #%i", conn->fd);
+
+ status = nc_connection_init (conn);
+ if (status != 0)
+ {
+ nc_connection_close (conn);