Added separate server pipe to wait on blocking server calls.
Send the complete request/reply through the request fifo instead of
just a dummy byte.
Convert error status to text in server reply tracing.

diff --git a/server/request.c b/server/request.c
index fcaea8c..c707aea 100644
--- a/server/request.c
+++ b/server/request.c
@@ -129,6 +129,20 @@
     kill_thread( thread, 1 );
 }
 
+/* complain about a protocol error and terminate the client connection */
+void fatal_protocol_perror( struct thread *thread, const char *err, ... )
+{
+    va_list args;
+
+    va_start( args, err );
+    fprintf( stderr, "Protocol error:%p: ", thread );
+    vfprintf( stderr, err, args );
+    perror( " " );
+    va_end( args );
+    thread->exit_code = 1;
+    kill_thread( thread, 1 );
+}
+
 /* die on a fatal error */
 void fatal_error( const char *err, ... )
 {
@@ -155,20 +169,24 @@
 }
 
 /* call a request handler */
-static inline void call_req_handler( struct thread *thread )
+static inline void call_req_handler( struct thread *thread, union generic_request *request )
 {
-    enum request req;
+    enum request req = request->header.req;
+
     current = thread;
     clear_error();
 
-    req = ((struct request_header *)current->buffer)->req;
+    if (debug_level) trace_request( thread, request );
 
-    if (debug_level) trace_request( req );
-
-    if (req < REQ_NB_REQUESTS)
+    if ((unsigned int)request->header.var_offset + request->header.var_size > MAX_REQUEST_LENGTH)
     {
-        req_handlers[req]( current->buffer );
-        if (current && !current->wait) send_reply( current );
+        fatal_protocol_error( current, "bad request offset/size %d/%d\n",
+                              request->header.var_offset, request->header.var_size );
+    }
+    else if (req < REQ_NB_REQUESTS)
+    {
+        req_handlers[req]( request );
+        if (current) send_reply( current, request );
         current = NULL;
         return;
     }
@@ -176,18 +194,32 @@
 }
 
 /* send a reply to a thread */
-void send_reply( struct thread *thread )
+void send_reply( struct thread *thread, union generic_request *request )
 {
-    assert( !thread->wait );
-    if (debug_level) trace_reply( thread );
-    if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
+    int ret;
+
+    assert (thread->pass_fd == -1);
+
+    if (debug_level) trace_reply( thread, request );
+
+    request->header.error = thread->error;
+
+    if ((ret = write( thread->reply_fd, request, sizeof(*request) )) != sizeof(*request))
+    {
+        if (ret >= 0)
+            fatal_protocol_error( thread, "partial write %d\n", ret );
+        else if (errno == EPIPE)
+            kill_thread( thread, 0 );  /* normal death */
+        else
+            fatal_protocol_perror( thread, "sendmsg" );
+    }
 }
 
 /* read a message from a client that has something to say */
 void read_request( struct thread *thread )
 {
+    union generic_request req;
     int ret;
-    char dummy[1];
 
 #ifdef HAVE_MSGHDR_ACCRIGHTS
     msghdr.msg_accrightslen = sizeof(int);
@@ -200,57 +232,39 @@
 
     assert( thread->pass_fd == -1 );
 
-    myiovec.iov_base = dummy;
-    myiovec.iov_len  = 1;
+    myiovec.iov_base = &req;
+    myiovec.iov_len  = sizeof(req);
 
     ret = recvmsg( thread->obj.fd, &msghdr, 0 );
 #ifndef HAVE_MSGHDR_ACCRIGHTS
     thread->pass_fd = cmsg.fd;
 #endif
 
-    if (ret > 0)
+    if (ret == sizeof(req))
     {
-        call_req_handler( thread );
+        call_req_handler( thread, &req );
         thread->pass_fd = -1;
         return;
     }
     if (!ret)  /* closed pipe */
-    {
         kill_thread( thread, 0 );
-        return;
-    }
-    perror("recvmsg");
-    thread->exit_code = 1;
-    kill_thread( thread, 1 );
+    else if (ret > 0)
+        fatal_protocol_error( thread, "partial recvmsg %d\n", ret );
+    else
+        fatal_protocol_perror( thread, "recvmsg" );
 }
 
-/* send a message to a client that is ready to receive something */
-int write_request( struct thread *thread )
+/* send the wakeup signal to a thread */
+int send_thread_wakeup( struct thread *thread, int signaled )
 {
-    int ret;
-    struct request_header *header = thread->buffer;
-
-    header->error = thread->error;
-
-    assert (thread->pass_fd == -1);
-
-    ret = write( thread->reply_fd, header, 1 );
-    if (ret > 0)
-    {
-        set_select_events( &thread->obj, POLLIN );
-        return 1;
-    }
-    if (errno == EWOULDBLOCK) return 0;  /* not a fatal error */
-    if (errno == EPIPE)
-    {
+    int ret = write( thread->wait_fd, &signaled, sizeof(signaled) );
+    if (ret == sizeof(signaled)) return 0;
+    if (ret >= 0)
+        fatal_protocol_error( thread, "partial wakeup write %d\n", ret );
+    else if (errno == EPIPE)
         kill_thread( thread, 0 );  /* normal death */
-    }
     else
-    {
-        perror("sendmsg");
-        thread->exit_code = 1;
-        kill_thread( thread, 1 );
-    }
+        fatal_protocol_perror( thread, "write" );
     return -1;
 }
 
@@ -283,9 +297,7 @@
     }
     else
     {
-        perror("sendmsg");
-        thread->exit_code = 1;
-        kill_thread( thread, 1 );
+        fatal_protocol_perror( thread, "sendmsg" );
     }
     return -1;
 }
@@ -349,23 +361,20 @@
     else if (event & POLLIN)
     {
         struct thread *thread = sock->thread;
+        union generic_request req;
         int ret;
-        char dummy[1];
 
-        ret = read( sock->obj.fd, &dummy, 1 );
-        if (ret > 0)
+        if ((ret = read( sock->obj.fd, &req, sizeof(req) )) == sizeof(req))
         {
-            call_req_handler( thread );
+            call_req_handler( thread, &req );
             return;
         }
         if (!ret)  /* closed pipe */
-        {
             kill_thread( thread, 0 );
-            return;
-        }
-        perror("read");
-        thread->exit_code = 1;
-        kill_thread( thread, 1 );
+        else if (ret > 0)
+            fatal_protocol_error( thread, "partial read %d\n", ret );
+        else
+            fatal_protocol_perror( thread, "read" );
     }
 }
 
@@ -384,6 +393,7 @@
     sock->thread = thread;
     send_client_fd( thread, fd[1], 0 );
     close( fd[1] );
+    fcntl( fd[0], F_SETFL, O_NONBLOCK );
     set_select_events( &sock->obj, POLLIN );
     return &sock->obj;
 }