Commit bf55457f authored by Mike McCormack's avatar Mike McCormack Committed by Alexandre Julliard

Implement WaitNamedPipe and DisconnectNamedPipe.

Add a state for each pipe handle in the server. Create a socket on when the pipe is opened, not before.
parent c86517fc
......@@ -605,24 +605,73 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer,
/***********************************************************************
* WaitNamedPipeA (KERNEL32.@)
*/
BOOL WINAPI WaitNamedPipeA (LPCSTR lpNamedPipeName, DWORD nTimeOut)
BOOL WINAPI WaitNamedPipeA (LPCSTR name, DWORD nTimeOut)
{
FIXME("%s 0x%08lx\n",lpNamedPipeName,nTimeOut);
SetLastError(ERROR_PIPE_NOT_CONNECTED);
return FALSE;
DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
HANDLE event;
BOOL ret;
TRACE("%s 0x%08lx\n",debugstr_a(name),nTimeOut);
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return FALSE;
}
if (!(event = CreateEventA( NULL, 0, 0, NULL ))) return FALSE;
SERVER_START_VAR_REQ( wait_named_pipe, len * sizeof(WCHAR) )
{
req->timeout = nTimeOut;
req->event = event;
if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
if (ret) WaitForSingleObject(event,INFINITE);
CloseHandle(event);
return ret;
}
/***********************************************************************
* WaitNamedPipeW (KERNEL32.@)
*/
BOOL WINAPI WaitNamedPipeW (LPCWSTR lpNamedPipeName, DWORD nTimeOut)
BOOL WINAPI WaitNamedPipeW (LPCWSTR name, DWORD nTimeOut)
{
FIXME("%s 0x%08lx\n",debugstr_w(lpNamedPipeName),nTimeOut);
SetLastError(ERROR_PIPE_NOT_CONNECTED);
return FALSE;
DWORD len = name ? strlenW(name) : 0;
HANDLE event;
BOOL ret;
TRACE("%s 0x%08lx\n",debugstr_w(name),nTimeOut);
if (len >= MAX_PATH)
{
SetLastError( ERROR_FILENAME_EXCED_RANGE );
return FALSE;
}
if (!(event = CreateEventA( NULL, 0, 0, NULL ))) return FALSE;
SERVER_START_VAR_REQ( wait_named_pipe, len * sizeof(WCHAR) )
{
req->timeout = nTimeOut;
req->event = event;
memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
if (ret) WaitForSingleObject(event,INFINITE);
CloseHandle(event);
return ret;
}
/***********************************************************************
* ConnectNamedPipe (KERNEL32.@)
*/
......@@ -631,7 +680,7 @@ BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
BOOL ret;
HANDLE event;
TRACE("(%d,%p):stub\n",hPipe, overlapped);
TRACE("(%d,%p)\n",hPipe, overlapped);
if(overlapped)
{
......@@ -640,29 +689,20 @@ BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
return FALSE;
}
event = CreateEventA(NULL,0,0,NULL);
if(event==INVALID_HANDLE_VALUE)
{
ERR("create event failed!\n");
return FALSE;
}
if (!(event = CreateEventA(NULL,0,0,NULL))) return FALSE;
SERVER_START_REQ( connect_named_pipe )
{
req->handle = hPipe;
req->event = event;
ret = SERVER_CALL_ERR();
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
if(ret) {
ERR("server returned status %08lx\n",GetLastError());
return FALSE;
}
if (ret) WaitForSingleObject(event,INFINITE);
WaitForSingleObject(event,INFINITE);
return TRUE;
CloseHandle(event);
return ret;
}
/***********************************************************************
......@@ -670,8 +710,17 @@ BOOL WINAPI ConnectNamedPipe(HANDLE hPipe, LPOVERLAPPED overlapped)
*/
BOOL WINAPI DisconnectNamedPipe(HANDLE hPipe)
{
FIXME("(%d):stub\n",hPipe);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
BOOL ret;
TRACE("(%d)\n",hPipe);
SERVER_START_REQ( disconnect_named_pipe )
{
req->handle = hPipe;
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
return ret;
}
......@@ -1532,6 +1532,24 @@ struct connect_named_pipe_request
};
struct wait_named_pipe_request
{
struct request_header __header;
unsigned int timeout;
handle_t event;
/* VARARG(filename,string); */
};
struct disconnect_named_pipe_request
{
struct request_header __header;
handle_t handle;
};
enum request
{
REQ_new_process,
......@@ -1654,6 +1672,8 @@ enum request
REQ_create_named_pipe,
REQ_open_named_pipe,
REQ_connect_named_pipe,
REQ_wait_named_pipe,
REQ_disconnect_named_pipe,
REQ_NB_REQUESTS
};
......@@ -1781,8 +1801,10 @@ union generic_request
struct create_named_pipe_request create_named_pipe;
struct open_named_pipe_request open_named_pipe;
struct connect_named_pipe_request connect_named_pipe;
struct wait_named_pipe_request wait_named_pipe;
struct disconnect_named_pipe_request disconnect_named_pipe;
};
#define SERVER_PROTOCOL_VERSION 49
#define SERVER_PROTOCOL_VERSION 50
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -2,6 +2,10 @@
* Server-side pipe management
*
* Copyright (C) 1998 Alexandre Julliard
* Copyright (C) 2001 Mike McCormack
*
* TODO:
* improve error handling
*/
#include "config.h"
......@@ -23,12 +27,24 @@
#include "thread.h"
#include "request.h"
enum pipe_state
{
ps_none,
ps_idle_server,
ps_wait_open,
ps_wait_connect,
ps_connected_server,
ps_connected_client,
ps_disconnected
};
struct named_pipe;
struct pipe_user
{
struct object obj;
int other_fd;
enum pipe_state state;
struct pipe_user *other;
struct named_pipe *pipe;
struct pipe_user *next;
struct pipe_user *prev;
......@@ -96,8 +112,7 @@ 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" );
fprintf( stderr, "named pipe user %p (state %d)\n", user, user->state );
}
static void named_pipe_destroy( struct object *obj)
......@@ -118,6 +133,25 @@ static void pipe_user_destroy( struct object *obj)
release_object(user->event);
user->event = NULL;
}
if(user->other)
{
close(user->other->obj.fd);
user->other->obj.fd = -1;
switch(user->other->state)
{
case ps_connected_server:
user->other->state = ps_idle_server;
break;
case ps_connected_client:
user->other->state = ps_disconnected;
break;
default:
fprintf(stderr,"connected pipe has strange state %d!\n",
user->other->state);
}
user->other->other=NULL;
user->other = NULL;
}
/* remove user from pipe's user list */
if (user->next) user->next->prev = user->prev;
......@@ -157,29 +191,15 @@ static struct pipe_user *get_pipe_user_obj( struct process *process, handle_t ha
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] );
user = alloc_object( &pipe_user_ops, fd );
if(!user)
{
if (fds[1] != -1) close( fds[1] );
return NULL;
}
user->pipe = pipe;
user->other_fd = fds[1];
user->state = ps_none;
user->event = NULL; /* thread wait on this pipe */
user->other = NULL;
/* add to list of pipe users */
if ((user->next = pipe->users)) user->next->prev = user;
......@@ -189,29 +209,21 @@ static struct pipe_user *create_pipe_user( struct named_pipe *pipe, int fd )
grab_object(pipe);
return user;
error:
file_set_error();
return NULL;
}
static struct pipe_user *find_partner(struct named_pipe *pipe)
static struct pipe_user *find_partner(struct named_pipe *pipe, enum pipe_state state)
{
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;
if(x->state==state)
break;
}
if(!x)
return NULL;
return (struct pipe_user *)grab_object( x );
}
......@@ -229,6 +241,7 @@ DECL_HANDLER(create_named_pipe)
if(user)
{
user->state = ps_idle_server;
req->handle = alloc_handle( current->process, user, GENERIC_READ|GENERIC_WRITE, 0 );
release_object( user );
}
......@@ -239,7 +252,6 @@ DECL_HANDLER(create_named_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) );
......@@ -248,26 +260,43 @@ DECL_HANDLER(open_named_pipe)
if (get_error() == STATUS_OBJECT_NAME_COLLISION)
{
if ((partner = find_partner(pipe)))
struct pipe_user *partner;
if ((partner = find_partner(pipe, ps_wait_open)))
{
user = create_pipe_user (pipe, partner->other_fd);
if(user)
int fds[2];
if(!socketpair(PF_UNIX, SOCK_STREAM, 0, fds))
{
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);
struct pipe_user *user;
if( (user = create_pipe_user (pipe, fds[1])) )
{
partner->obj.fd = fds[0];
set_event(partner->event);
release_object(partner->event);
partner->event = NULL;
partner->state = ps_connected_server;
partner->other = user;
user->state = ps_connected_client;
user->other = partner;
req->handle = alloc_handle( current->process, user, req->access, 0 );
release_object(user);
}
else
{
close(fds[0]);
}
}
release_object( partner );
}
else {
else
{
set_error(STATUS_PIPE_NOT_AVAILABLE);
}
}
else {
else
{
set_error(STATUS_NO_SUCH_FILE);
}
......@@ -276,24 +305,101 @@ DECL_HANDLER(open_named_pipe)
DECL_HANDLER(connect_named_pipe)
{
struct pipe_user *user;
struct pipe_user *user, *partner;
struct event *event;
user = get_pipe_user_obj(current->process, req->handle, 0);
if(!user)
return;
if( user->event || user->other_fd == -1)
if( user->state != ps_idle_server )
{
/* fprintf(stderr,"fd = %x event = %p\n",user->obj.fd,user->event);*/
set_error(STATUS_PORT_ALREADY_SET);
}
else
{
user->state = ps_wait_open;
event = get_event_obj(current->process, req->event, 0);
if(event)
user->event = event;
/* notify all waiters that a pipe just became available */
while( (partner = find_partner(user->pipe,ps_wait_connect)) )
{
set_event(partner->event);
release_object(partner->event);
partner->event = NULL;
release_object(partner);
release_object(partner);
}
}
release_object(user);
}
DECL_HANDLER(wait_named_pipe)
{
struct event *event;
struct named_pipe *pipe;
event = get_event_obj(current->process, req->event, 0);
if(!event)
return;
pipe = create_named_pipe( get_req_data(req), get_req_data_size(req) );
if( pipe )
{
/* only wait if the pipe already exists */
if(get_error() == STATUS_OBJECT_NAME_COLLISION)
{
struct pipe_user *partner;
set_error(STATUS_SUCCESS);
if( (partner = find_partner(pipe,ps_wait_open)) )
{
set_event(event);
release_object(partner);
}
else
{
struct pipe_user *user;
if( (user = create_pipe_user (pipe, -1)) )
{
user->event = (struct event *)grab_object( event );
user->state = ps_wait_connect;
/* don't release it */
}
}
}
else
{
set_error(STATUS_PIPE_NOT_AVAILABLE);
}
release_object(pipe);
}
release_object(event);
}
DECL_HANDLER(disconnect_named_pipe)
{
struct pipe_user *user;
user = get_pipe_user_obj(current->process, req->handle, 0);
if(!user)
return;
if( (user->state == ps_connected_server) &&
(user->other->state == ps_connected_client) )
{
close(user->other->obj.fd);
user->other->obj.fd = -1;
user->other->state = ps_disconnected;
user->other->other = NULL;
close(user->obj.fd);
user->obj.fd = -1;
user->state = ps_idle_server;
user->other = NULL;
}
release_object(user);
}
......@@ -1368,3 +1368,17 @@ enum message_type
handle_t handle;
handle_t event; /* set this event when it's ready */
@END
/* Wait for a named pipe */
@REQ(wait_named_pipe)
unsigned int timeout;
handle_t event; /* set this event when it's ready */
VARARG(filename,string); /* pipe name */
@END
/* Disconnect a named pipe */
@REQ(disconnect_named_pipe)
handle_t handle;
@END
......@@ -185,6 +185,8 @@ DECL_HANDLER(create_async);
DECL_HANDLER(create_named_pipe);
DECL_HANDLER(open_named_pipe);
DECL_HANDLER(connect_named_pipe);
DECL_HANDLER(wait_named_pipe);
DECL_HANDLER(disconnect_named_pipe);
#ifdef WANT_REQUEST_HANDLERS
......@@ -311,6 +313,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_create_named_pipe,
(req_handler)req_open_named_pipe,
(req_handler)req_connect_named_pipe,
(req_handler)req_wait_named_pipe,
(req_handler)req_disconnect_named_pipe,
};
#endif /* WANT_REQUEST_HANDLERS */
......
......@@ -1626,6 +1626,19 @@ static void dump_connect_named_pipe_request( const struct connect_named_pipe_req
fprintf( stderr, " event=%d", req->event );
}
static void dump_wait_named_pipe_request( const struct wait_named_pipe_request *req )
{
fprintf( stderr, " timeout=%08x,", req->timeout );
fprintf( stderr, " event=%d,", req->event );
fprintf( stderr, " filename=" );
cur_pos += dump_varargs_string( req );
}
static void dump_disconnect_named_pipe_request( const struct disconnect_named_pipe_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
......@@ -1747,6 +1760,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_named_pipe_request,
(dump_func)dump_open_named_pipe_request,
(dump_func)dump_connect_named_pipe_request,
(dump_func)dump_wait_named_pipe_request,
(dump_func)dump_disconnect_named_pipe_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
......@@ -1870,6 +1885,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_named_pipe_reply,
(dump_func)dump_open_named_pipe_reply,
(dump_func)0,
(dump_func)0,
(dump_func)0,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
......@@ -1993,6 +2010,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"create_named_pipe",
"open_named_pipe",
"connect_named_pipe",
"wait_named_pipe",
"disconnect_named_pipe",
};
/* ### make_requests end ### */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment