mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-21 17:09:06 -07:00
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.
This commit is contained in:
parent
c86517fcb6
commit
bf55457f24
6 changed files with 290 additions and 76 deletions
|
@ -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 ### */
|
||||
|
|
Loading…
Reference in a new issue