Start implementing named pipes.

diff --git a/server/Makefile.in b/server/Makefile.in
index e0bb99e..bb82aa7 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -20,6 +20,7 @@
 	main.c \
 	mapping.c \
 	mutex.c \
+	named_pipe.c \
 	object.c \
 	pipe.c \
 	process.c \
diff --git a/server/named_pipe.c b/server/named_pipe.c
new file mode 100644
index 0000000..60777e7
--- /dev/null
+++ b/server/named_pipe.c
@@ -0,0 +1,299 @@
+/*
+ * Server-side pipe management
+ *
+ * Copyright (C) 1998 Alexandre Julliard
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "winbase.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "request.h"
+
+struct named_pipe;
+
+struct pipe_user
+{
+    struct object       obj;
+    int                 other_fd;
+    struct named_pipe  *pipe;
+    struct pipe_user   *next;
+    struct pipe_user   *prev;
+    struct event       *event;
+};
+
+struct named_pipe
+{
+    struct object       obj;         /* object header */
+    unsigned int        pipemode;
+    unsigned int        maxinstances;
+    unsigned int        outsize;
+    unsigned int        insize;
+    unsigned int        timeout;
+    struct pipe_user   *users;
+};
+
+static void named_pipe_dump( struct object *obj, int verbose );
+static void named_pipe_destroy( struct object *obj);
+
+static const struct object_ops named_pipe_ops =
+{
+    sizeof(struct named_pipe),    /* size */
+    named_pipe_dump,              /* dump */
+    no_add_queue,                 /* add_queue */
+    NULL,                         /* remove_queue */
+    NULL,                         /* signaled */
+    NULL,                         /* satisfied */
+    NULL,                         /* get_poll_events */
+    NULL,                         /* poll_event */
+    no_get_fd,                    /* get_fd */
+    no_flush,                     /* flush */
+    no_get_file_info,             /* get_file_info */
+    named_pipe_destroy            /* destroy */
+};
+
+static void pipe_user_dump( struct object *obj, int verbose );
+static void pipe_user_destroy( struct object *obj);
+static int pipe_user_get_fd( struct object *obj );
+
+static const struct object_ops pipe_user_ops =
+{
+    sizeof(struct pipe_user),     /* size */
+    pipe_user_dump,               /* dump */
+    default_poll_add_queue,       /* add_queue */
+    default_poll_remove_queue,    /* remove_queue */
+    default_poll_signaled,        /* signaled */
+    no_satisfied,                 /* satisfied */
+    NULL,                         /* get_poll_events */
+    default_poll_event,           /* poll_event */
+    pipe_user_get_fd,             /* get_fd */
+    no_flush,                     /* flush */
+    no_get_file_info,             /* get_file_info */
+    pipe_user_destroy             /* destroy */
+};
+
+static void named_pipe_dump( struct object *obj, int verbose )
+{
+    struct named_pipe *pipe = (struct named_pipe *)obj;
+    assert( obj->ops == &named_pipe_ops );
+    fprintf( stderr, "named pipe %p\n" ,pipe);
+}
+
+static void pipe_user_dump( struct object *obj, int verbose )
+{
+    struct pipe_user *user = (struct pipe_user *)obj;
+    assert( obj->ops == &pipe_user_ops );
+    fprintf( stderr, "named pipe user %p (%s)\n", user,
+             (user->other_fd != -1) ? "server" : "client" );
+}
+
+static void named_pipe_destroy( struct object *obj)
+{
+    struct named_pipe *pipe = (struct named_pipe *)obj;
+    assert( !pipe->users );
+}
+
+static void pipe_user_destroy( struct object *obj)
+{
+    struct pipe_user *user = (struct pipe_user *)obj;
+
+    assert( obj->ops == &pipe_user_ops );
+
+    if(user->event)
+    {
+        /* FIXME: signal waiter of failure */
+        release_object(user->event);
+        user->event = NULL;
+    }
+
+    /* remove user from pipe's user list */
+    if (user->next) user->next->prev = user->prev;
+    if (user->prev) user->prev->next = user->next;
+    else user->pipe->users = user->next;
+    release_object(user->pipe);
+}
+
+static int pipe_user_get_fd( struct object *obj )
+{
+    struct pipe_user *user = (struct pipe_user *)obj;
+    assert( obj->ops == &pipe_user_ops );
+    return user->obj.fd;
+}
+
+static struct named_pipe *create_named_pipe( const WCHAR *name, size_t len )
+{
+    struct named_pipe *pipe;
+
+    if ((pipe = create_named_object( &named_pipe_ops, name, len )))
+    {
+        if (get_error() != STATUS_OBJECT_NAME_COLLISION)
+        {
+            /* initialize it if it didn't already exist */
+            pipe->users = 0;
+        }
+    }
+    return pipe;
+}
+
+static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t handle,
+                                            unsigned int access )
+{
+    return (struct pipe_user *)get_handle_obj( process, handle, access, &pipe_user_ops );
+}
+
+static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
+{
+    struct pipe_user *user;
+    int fds[2];
+
+    if(fd == -1)
+    {
+        /* FIXME: what about messages? */
+
+        if(0>socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) goto error;
+    }
+    else
+    {
+        if ((fds[0] = dup(fd)) == -1) goto error;
+        fds[1] = -1;
+    }
+    user = alloc_object( &pipe_user_ops, fds[0] );
+    if(!user)
+    {
+        if (fds[1] != -1) close( fds[1] );
+        return NULL;
+    }
+
+    user->pipe = pipe;
+    user->other_fd = fds[1];
+    user->event = NULL;   /* thread wait on this pipe */
+
+    /* add to list of pipe users */
+    if ((user->next = pipe->users)) user->next->prev = user;
+    user->prev = NULL;
+    pipe->users = user;
+
+    grab_object(pipe);
+
+    return user;
+
+ error:
+    file_set_error();
+    return NULL;
+}
+
+static struct pipe_user *find_partner(struct named_pipe *pipe)
+{
+    struct pipe_user *x;
+
+    for(x = pipe->users; x; x=x->next)
+    {
+        /* only pair threads that are waiting */
+        if(!x->event)
+            continue;
+
+        /* only pair with pipes that haven't been connected */
+        if(x->other_fd == -1)
+            continue;
+
+        break;
+    }
+
+    return (struct pipe_user *)grab_object( x );
+}
+
+DECL_HANDLER(create_named_pipe)
+{
+    struct named_pipe *pipe;
+    struct pipe_user *user;
+
+    req->handle = 0;
+    pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
+    if(!pipe)
+        return;
+
+    user = create_pipe_user (pipe, -1);
+
+    if(user)
+    {
+        req->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
+        release_object( user );
+    }
+
+    release_object( pipe );
+}
+
+DECL_HANDLER(open_named_pipe)
+{
+    struct named_pipe *pipe;
+    struct pipe_user *user,*partner;
+
+    req->handle = 0;
+    pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
+    if(!pipe)
+        return;
+
+    if (get_error() == STATUS_OBJECT_NAME_COLLISION)
+    {
+        if ((partner = find_partner(pipe)))
+        {
+            user = create_pipe_user (pipe, partner->other_fd);
+            if(user)
+            {
+                set_event(partner->event);
+                release_object(partner->event);
+                partner->event = NULL;
+                close( partner->other_fd );
+                partner->other_fd = -1;
+                req->handle = alloc_handle( current->process, user, req->access, 0 );
+                release_object(user);
+            }
+            release_object( partner );
+        }
+        else {
+            set_error(STATUS_NO_SUCH_FILE);
+        }
+    }
+    else {
+        set_error(STATUS_NO_SUCH_FILE);
+    }
+
+    release_object(pipe);
+}
+
+DECL_HANDLER(connect_named_pipe)
+{
+    struct pipe_user *user;
+    struct event *event;
+
+    user = get_pipe_user_obj(current->process, req->handle, 0);
+    if(!user)
+        return;
+
+    if( user->event || user->other_fd == -1)
+    {
+        /* fprintf(stderr,"fd = %x  event = %p\n",user->obj.fd,user->event);*/
+        set_error(STATUS_PORT_ALREADY_SET);
+    }
+    else
+    {
+        event = get_event_obj(current->process, req->event, 0);
+        if(event)
+            user->event = event;
+    }
+
+    release_object(user);
+}
diff --git a/server/request.h b/server/request.h
index 6a5bc40..8afa8da 100644
--- a/server/request.h
+++ b/server/request.h
@@ -186,6 +186,9 @@
 DECL_HANDLER(get_serial_info);
 DECL_HANDLER(set_serial_info);
 DECL_HANDLER(create_async);
+DECL_HANDLER(create_named_pipe);
+DECL_HANDLER(open_named_pipe);
+DECL_HANDLER(connect_named_pipe);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -310,6 +313,9 @@
     (req_handler)req_get_serial_info,
     (req_handler)req_set_serial_info,
     (req_handler)req_create_async,
+    (req_handler)req_create_named_pipe,
+    (req_handler)req_open_named_pipe,
+    (req_handler)req_connect_named_pipe,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
diff --git a/server/trace.c b/server/trace.c
index 250ffd9..438121c 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1593,6 +1593,41 @@
     fprintf( stderr, " timeout=%d", req->timeout );
 }
 
+static void dump_create_named_pipe_request( const struct create_named_pipe_request *req )
+{
+    fprintf( stderr, " openmode=%08x,", req->openmode );
+    fprintf( stderr, " pipemode=%08x,", req->pipemode );
+    fprintf( stderr, " maxinstances=%08x,", req->maxinstances );
+    fprintf( stderr, " outsize=%08x,", req->outsize );
+    fprintf( stderr, " insize=%08x,", req->insize );
+    fprintf( stderr, " timeout=%08x,", req->timeout );
+    fprintf( stderr, " filename=" );
+    cur_pos += dump_varargs_string( req );
+}
+
+static void dump_create_named_pipe_reply( const struct create_named_pipe_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_open_named_pipe_request( const struct open_named_pipe_request *req )
+{
+    fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " filename=" );
+    cur_pos += dump_varargs_string( req );
+}
+
+static void dump_open_named_pipe_reply( const struct open_named_pipe_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_connect_named_pipe_request( const struct connect_named_pipe_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " event=%d", req->event );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -1712,6 +1747,9 @@
     (dump_func)dump_get_serial_info_request,
     (dump_func)dump_set_serial_info_request,
     (dump_func)dump_create_async_request,
+    (dump_func)dump_create_named_pipe_request,
+    (dump_func)dump_open_named_pipe_request,
+    (dump_func)dump_connect_named_pipe_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -1833,6 +1871,9 @@
     (dump_func)dump_get_serial_info_reply,
     (dump_func)0,
     (dump_func)dump_create_async_reply,
+    (dump_func)dump_create_named_pipe_reply,
+    (dump_func)dump_open_named_pipe_reply,
+    (dump_func)0,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -1954,6 +1995,9 @@
     "get_serial_info",
     "set_serial_info",
     "create_async",
+    "create_named_pipe",
+    "open_named_pipe",
+    "connect_named_pipe",
 };
 
 /* ### make_requests end ### */