diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index aa6484b7659..d693cb36f19 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -186,7 +186,7 @@ debug_channels (comm debugstr dll int resource stress thunk toolhelp win32) @ stdcall CompareFileTime(ptr ptr) CompareFileTime @ stdcall CompareStringA(long long str long str long) CompareStringA @ stdcall CompareStringW(long long wstr long wstr long) CompareStringW -@ stub ConnectNamedPipe +@ stdcall ConnectNamedPipe(long ptr) ConnectNamedPipe @ stdcall ContinueDebugEvent(long long long) ContinueDebugEvent @ stdcall ConvertDefaultLocale (long) ConvertDefaultLocale @ stdcall ConvertToGlobalHandle(long) ConvertToGlobalHandle @@ -231,7 +231,7 @@ debug_channels (comm debugstr dll int resource stress thunk toolhelp win32) @ stdcall DeleteFileW(wstr) DeleteFileW @ stdcall DeviceIoControl(long long ptr long ptr long ptr ptr) DeviceIoControl @ stdcall DisableThreadLibraryCalls(long) DisableThreadLibraryCalls -@ stub DisconnectNamedPipe +@ stdcall DisconnectNamedPipe(long) DisconnectNamedPipe @ stdcall DosDateTimeToFileTime(long long ptr) DosDateTimeToFileTime @ stdcall DuplicateHandle(long long long ptr long long long) DuplicateHandle @ stub EndUpdateResourceA diff --git a/dlls/kernel/sync.c b/dlls/kernel/sync.c index b19f6e54785..f4fb1857065 100644 --- a/dlls/kernel/sync.c +++ b/dlls/kernel/sync.c @@ -512,11 +512,35 @@ HANDLE WINAPI CreateNamedPipeA( LPCSTR name, DWORD dwOpenMode, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr ) { - FIXME("(Name=%s, OpenMode=%#08lx, dwPipeMode=%#08lx, MaxInst=%ld, OutBSize=%ld, InBuffSize=%ld, DefTimeOut=%ld, SecAttr=%p): stub\n", + HANDLE ret; + DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0; + + TRACE("(%s, %#08lx, %#08lx, %ld, %ld, %ld, %ld, %p): stub\n", debugstr_a(name), dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr ); - SetLastError (ERROR_UNKNOWN); - return INVALID_HANDLE_VALUE; + + if (len >= MAX_PATH) + { + SetLastError( ERROR_FILENAME_EXCED_RANGE ); + return 0; + } + SERVER_START_VAR_REQ( create_named_pipe, len * sizeof(WCHAR) ) + { + req->openmode = dwOpenMode; + req->pipemode = dwPipeMode; + req->maxinstances = nMaxInstances; + req->outsize = nOutBufferSize; + req->insize = nInBufferSize; + req->timeout = nDefaultTimeOut; + + if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len ); + SetLastError(0); + SERVER_CALL_ERR(); + ret = req->handle; + } + SERVER_END_VAR_REQ; + TRACE("Returned %d\n",ret); + return ret; } @@ -528,12 +552,34 @@ HANDLE WINAPI CreateNamedPipeW( LPCWSTR name, DWORD dwOpenMode, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES attr ) { - FIXME("(Name=%s, OpenMode=%#08lx, dwPipeMode=%#08lx, MaxInst=%ld, OutBSize=%ld, InBuffSize=%ld, DefTimeOut=%ld, SecAttr=%p): stub\n", + HANDLE ret; + DWORD len = name ? strlenW(name) : 0; + + TRACE("(%s, %#08lx, %#08lx, %ld, %ld, %ld, %ld, %p)\n", debugstr_w(name), dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, attr ); - SetLastError (ERROR_UNKNOWN); - return INVALID_HANDLE_VALUE; + if (len >= MAX_PATH) + { + SetLastError( ERROR_FILENAME_EXCED_RANGE ); + return 0; + } + SERVER_START_VAR_REQ( create_named_pipe, len * sizeof(WCHAR) ) + { + req->openmode = dwOpenMode; + req->pipemode = dwPipeMode; + req->maxinstances = nMaxInstances; + req->outsize = nOutBufferSize; + req->insize = nInBufferSize; + req->timeout = nDefaultTimeOut; + + memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) ); + SetLastError(0); + SERVER_CALL_ERR(); + ret = req->handle; + } + SERVER_END_VAR_REQ; + return ret; } @@ -570,3 +616,56 @@ BOOL WINAPI WaitNamedPipeW (LPCWSTR lpNamedPipeName, DWORD nTimeOut) SetLastError(ERROR_PIPE_NOT_CONNECTED); return FALSE; } + +/*********************************************************************** + * ConnectNamedPipe (KERNEL32.@) + */ +BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped) +{ + BOOL ret; + HANDLE event; + + TRACE("(%d,%p):stub\n",hPipe, overlapped); + + if(overlapped) + { + FIXME("overlapped operation not supported\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + + event = CreateEventA(NULL,0,0,NULL); + if(event==INVALID_HANDLE_VALUE) + { + ERR("create event failed!\n"); + return FALSE; + } + + SERVER_START_REQ( connect_named_pipe ) + { + req->handle = hPipe; + req->event = event; + ret = SERVER_CALL_ERR(); + } + SERVER_END_REQ; + + if(ret) { + ERR("server returned status %08lx\n",GetLastError()); + return FALSE; + } + + WaitForSingleObject(event,INFINITE); + + return TRUE; +} + +/*********************************************************************** + * DisconnectNamedPipe (KERNEL32.@) + */ +BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe) +{ + FIXME("(%d):stub\n",hPipe); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + diff --git a/files/file.c b/files/file.c index fecfce3a203..e976bf3a478 100644 --- a/files/file.c +++ b/files/file.c @@ -339,6 +339,31 @@ HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa return ret; } +static HANDLE FILE_OpenPipe(LPCSTR name, DWORD access) +{ + HANDLE ret; + DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0; + + TRACE("name %s access %lx\n",name,access); + + if (len >= MAX_PATH) + { + SetLastError( ERROR_FILENAME_EXCED_RANGE ); + return 0; + } + SERVER_START_VAR_REQ( open_named_pipe, len * sizeof(WCHAR) ) + { + req->access = access; + + if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len ); + SetLastError(0); + SERVER_CALL_ERR(); + ret = req->handle; + } + SERVER_END_VAR_REQ; + TRACE("Returned %d\n",ret); + return ret; +} /************************************************************************* * CreateFileA [KERNEL32.@] Creates or opens a file or other object @@ -365,7 +390,7 @@ HANDLE FILE_CreateDevice( int client_id, DWORD access, LPSECURITY_ATTRIBUTES sa * * BUGS * - * Doesn't support character devices, pipes, template files, or a + * Doesn't support character devices, template files, or a * lot of the 'attributes' flags yet. */ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, @@ -406,7 +431,12 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing, } if (!strncmp(filename, "\\\\.\\", 4)) { - if (!DOSFS_GetDevice( filename )) + if(!strncasecmp(&filename[4],"pipe\\",5)) + { + TRACE("Opening a pipe: %s\n",filename); + return FILE_OpenPipe(filename,access); + } + else if (!DOSFS_GetDevice( filename )) { ret = DEVICE_Open( filename+4, access, sa ); goto done; diff --git a/include/server.h b/include/server.h index 6c2907e58b6..6882959cc52 100644 --- a/include/server.h +++ b/include/server.h @@ -1489,6 +1489,33 @@ struct create_async_request #define ASYNC_TYPE_WRITE 0x02 #define ASYNC_TYPE_WAIT 0x03 +struct create_named_pipe_request +{ + REQUEST_HEADER; /* request header */ + IN unsigned int openmode; + IN unsigned int pipemode; + IN unsigned int maxinstances; + IN unsigned int outsize; + IN unsigned int insize; + IN unsigned int timeout; + OUT handle_t handle; /* handle to the pipe */ + IN VARARG(filename,string); /* pipe name */ +}; + +struct open_named_pipe_request +{ + REQUEST_HEADER; /* request header */ + IN unsigned int access; + OUT handle_t handle; /* handle to the pipe */ + IN VARARG(filename,string); /* pipe name */ +}; + +struct connect_named_pipe_request +{ + REQUEST_HEADER; + IN handle_t handle; + IN handle_t event; /* set this event when it's ready */ +}; /* Everything below this line is generated automatically by tools/make_requests */ /* ### make_requests begin ### */ @@ -1613,6 +1640,9 @@ enum request REQ_get_serial_info, REQ_set_serial_info, REQ_create_async, + REQ_create_named_pipe, + REQ_open_named_pipe, + REQ_connect_named_pipe, REQ_NB_REQUESTS }; @@ -1738,9 +1768,12 @@ union generic_request struct get_serial_info_request get_serial_info; struct set_serial_info_request set_serial_info; struct create_async_request create_async; + struct create_named_pipe_request create_named_pipe; + struct open_named_pipe_request open_named_pipe; + struct connect_named_pipe_request connect_named_pipe; }; -#define SERVER_PROTOCOL_VERSION 47 +#define SERVER_PROTOCOL_VERSION 48 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/include/winbase.h b/include/winbase.h index 67f0670ce1b..4b107e7748d 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -793,6 +793,20 @@ typedef struct int nFileIndexLow; } BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION ; +#define PIPE_ACCESS_INBOUND 1 +#define PIPE_ACCESS_OUTBOUND 2 +#define PIPE_ACCESS_DUPLEX 3 + +#define PIPE_TYPE_BYTE 0 +#define PIPE_TYPE_MESSAGE 4 + +#define PIPE_READMODE_BYTE 0 +#define PIPE_READMODE_MESSAGE 2 + +#define PIPE_WAIT 0 +#define PIPE_NOWAIT 1 + +#define PIPE_UNLIMITED_INSTANCES 255 typedef struct _SYSTEM_POWER_STATUS { diff --git a/server/Makefile.in b/server/Makefile.in index e0bb99ee082..bb82aa775fb 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -20,6 +20,7 @@ C_SRCS = \ 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 00000000000..60777e7a383 --- /dev/null +++ b/server/named_pipe.c @@ -0,0 +1,299 @@ +/* + * Server-side pipe management + * + * Copyright (C) 1998 Alexandre Julliard + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 6a5bc406f53..8afa8dae577 100644 --- a/server/request.h +++ b/server/request.h @@ -186,6 +186,9 @@ DECL_HANDLER(create_serial); 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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (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 250ffd93fe7..438121c4fd6 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1593,6 +1593,41 @@ static void dump_create_async_reply( const struct create_async_request *req ) 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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (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 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_serial_info", "set_serial_info", "create_async", + "create_named_pipe", + "open_named_pipe", + "connect_named_pipe", }; /* ### make_requests end ### */