2 * Client part of the client/server communication
4 * Copyright (C) 1998 Alexandre Julliard
11 #include <sys/types.h>
12 #include <sys/socket.h>
18 #include "server/request.h"
22 /* Some versions of glibc don't define this */
28 /***********************************************************************
29 * CLIENT_ProtocolError
31 void CLIENT_ProtocolError( const char *err
, ... )
33 THDB
*thdb
= THREAD_Current();
36 va_start( args
, err
);
37 fprintf( stderr
, "Client protocol error:%p: ", thdb
->server_tid
);
38 vfprintf( stderr
, err
, args
);
44 /***********************************************************************
45 * CLIENT_SendRequest_v
47 * Send a request to the server.
49 static void CLIENT_SendRequest_v( enum request req
, int pass_fd
,
50 struct iovec
*vec
, int veclen
)
52 THDB
*thdb
= THREAD_Current();
53 #ifndef HAVE_MSGHDR_ACCRIGHTS
54 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, pass_fd
};
56 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, };
61 vec
[0].iov_base
= &head
;
62 vec
[0].iov_len
= sizeof(head
);
63 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
65 assert( len
<= MAX_MSG_LENGTH
);
68 head
.seq
= thdb
->seq
++;
70 if (pass_fd
!= -1) /* we have an fd to send */
72 #ifdef HAVE_MSGHDR_ACCRIGHTS
73 msghdr
.msg_accrights
= (void *)&pass_fd
;
74 msghdr
.msg_accrightslen
= sizeof(pass_fd
);
76 msghdr
.msg_control
= &cmsg
;
77 msghdr
.msg_controllen
= sizeof(cmsg
);
81 if ((ret
= sendmsg( thdb
->socket
, &msghdr
, 0 )) < len
)
83 if (ret
== -1) perror( "sendmsg" );
84 CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret
, len
);
86 /* we passed the fd now we can close it */
87 if (pass_fd
!= -1) close( pass_fd
);
91 /***********************************************************************
94 * Send a request to the server.
96 void CLIENT_SendRequest( enum request req
, int pass_fd
,
97 int n
, ... /* arg_1, len_1, etc. */ )
103 n
++; /* for vec[0] */
106 for (i
= 1; i
< n
; i
++)
108 vec
[i
].iov_base
= va_arg( args
, void * );
109 vec
[i
].iov_len
= va_arg( args
, int );
112 return CLIENT_SendRequest_v( req
, pass_fd
, vec
, n
);
116 /***********************************************************************
119 * Wait for a reply from the server.
120 * Returns the error code (or 0 if OK).
122 static unsigned int CLIENT_WaitReply_v( int *len
, int *passed_fd
,
123 struct iovec
*vec
, int veclen
)
125 THDB
*thdb
= THREAD_Current();
127 #ifdef HAVE_MSGHDR_ACCRIGHTS
128 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, (void*)&pass_fd
, sizeof(int) };
130 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, -1 };
131 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, &cmsg
, sizeof(cmsg
), 0 };
136 assert( veclen
> 0 );
137 vec
[0].iov_base
= &head
;
138 vec
[0].iov_len
= sizeof(head
);
140 while ((ret
= recvmsg( thdb
->socket
, &msghdr
, 0 )) == -1)
142 if (errno
== EINTR
) continue;
144 CLIENT_ProtocolError( "recvmsg\n" );
146 if (!ret
) ExitThread(1); /* the server closed the connection; time to die... */
150 if (ret
< sizeof(head
))
151 CLIENT_ProtocolError( "partial header received %d/%d\n", ret
, sizeof(head
) );
153 if ((head
.len
< sizeof(head
)) || (head
.len
> MAX_MSG_LENGTH
))
154 CLIENT_ProtocolError( "header length %d\n", head
.len
);
156 if (head
.seq
!= thdb
->seq
++)
157 CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head
.seq
, thdb
->seq
- 1 );
159 #ifndef HAVE_MSGHDR_ACCRIGHTS
163 if (head
.type
!= ERROR_SUCCESS
)
165 SetLastError( head
.type
);
169 *passed_fd
= pass_fd
;
173 if (len
) *len
= ret
- sizeof(head
);
174 if (pass_fd
!= -1) close( pass_fd
);
175 remaining
= head
.len
- ret
;
176 while (remaining
> 0) /* drop remaining data */
179 int len
= remaining
< sizeof(buffer
) ? remaining
: sizeof(buffer
);
180 if ((len
= recv( thdb
->socket
, buffer
, len
, 0 )) == -1)
183 CLIENT_ProtocolError( "recv\n" );
185 if (!len
) ExitThread(1); /* the server closed the connection; time to die... */
189 return head
.type
; /* error code */
193 /***********************************************************************
196 * Wait for a reply from the server.
198 unsigned int CLIENT_WaitReply( int *len
, int *passed_fd
,
199 int n
, ... /* arg_1, len_1, etc. */ )
201 struct iovec vec
[16];
205 n
++; /* for vec[0] */
208 for (i
= 1; i
< n
; i
++)
210 vec
[i
].iov_base
= va_arg( args
, void * );
211 vec
[i
].iov_len
= va_arg( args
, int );
214 return CLIENT_WaitReply_v( len
, passed_fd
, vec
, n
);
218 /***********************************************************************
221 * Send a new thread request.
223 int CLIENT_NewThread( THDB
*thdb
, int *thandle
, int *phandle
)
225 struct new_thread_request request
;
226 struct new_thread_reply reply
;
228 extern BOOL32 THREAD_InitDone
;
229 extern void server_main_loop( int fd
);
231 if (!THREAD_InitDone
) /* first thread -> start the server */
236 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, tmpfd
) == -1)
238 perror("socketpair");
248 sprintf( buffer
, "%d", tmpfd
[1] );
250 execlp( "wineserver", "wineserver", buffer
, NULL
);
251 execl( "/usr/local/bin/wineserver", "wineserver", buffer
, NULL
);
252 execl( "./server/wineserver", "wineserver", buffer
, NULL
);
254 server_main_loop( tmpfd
[1] );
256 default: /* parent */
258 SET_CUR_THREAD( thdb
);
259 THREAD_InitDone
= TRUE
;
260 thdb
->socket
= tmpfd
[0];
265 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, fd
) == -1)
267 SetLastError( ERROR_TOO_MANY_OPEN_FILES
); /* FIXME */
271 request
.pid
= thdb
->process
->server_pid
;
272 CLIENT_SendRequest( REQ_NEW_THREAD
, fd
[1], 1, &request
, sizeof(request
) );
274 if (CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) )) goto error
;
275 if (len
< sizeof(reply
)) goto error
;
276 thdb
->server_tid
= reply
.tid
;
277 thdb
->process
->server_pid
= reply
.pid
;
278 if (thdb
->socket
!= -1) close( thdb
->socket
);
279 thdb
->socket
= fd
[0];
280 thdb
->seq
= 0; /* reset the sequence number for the new fd */
282 /* we don't need the handles for now */
283 if (thandle
) *thandle
= reply
.thandle
;
284 else if (reply
.thandle
!= -1) CLIENT_CloseHandle( reply
.thandle
);
285 if (phandle
) *phandle
= reply
.phandle
;
286 else if (reply
.phandle
!= -1) CLIENT_CloseHandle( reply
.phandle
);
295 /***********************************************************************
298 * Send an init thread request. Return 0 if OK.
300 int CLIENT_InitThread(void)
302 THDB
*thdb
= THREAD_Current();
303 struct init_thread_request init
;
304 int len
= strlen( thdb
->process
->env_db
->cmd_line
);
306 init
.unix_pid
= getpid();
307 len
= MIN( len
, MAX_MSG_LENGTH
- sizeof(init
) );
309 CLIENT_SendRequest( REQ_INIT_THREAD
, -1, 2,
311 thdb
->process
->env_db
->cmd_line
, len
);
312 return CLIENT_WaitReply( NULL
, NULL
, 0 );
316 /***********************************************************************
317 * CLIENT_TerminateProcess
319 * Send a terminate process request. Return 0 if OK.
321 int CLIENT_TerminateProcess( int handle
, int exit_code
)
323 CLIENT_SendRequest( REQ_TERMINATE_PROCESS
, -1, 2,
324 &handle
, sizeof(handle
),
325 &exit_code
, sizeof(exit_code
) );
326 return CLIENT_WaitReply( NULL
, NULL
, 0 );
329 /***********************************************************************
330 * CLIENT_TerminateThread
332 * Send a terminate thread request. Return 0 if OK.
334 int CLIENT_TerminateThread( int handle
, int exit_code
)
336 CLIENT_SendRequest( REQ_TERMINATE_THREAD
, -1, 2,
337 &handle
, sizeof(handle
),
338 &exit_code
, sizeof(exit_code
) );
339 return CLIENT_WaitReply( NULL
, NULL
, 0 );
342 /***********************************************************************
345 * Send a close handle request. Return 0 if OK.
347 int CLIENT_CloseHandle( int handle
)
349 CLIENT_SendRequest( REQ_CLOSE_HANDLE
, -1, 1, &handle
, sizeof(handle
) );
350 return CLIENT_WaitReply( NULL
, NULL
, 0 );
353 /***********************************************************************
354 * CLIENT_DuplicateHandle
356 * Send a duplicate handle request. Return 0 if OK.
358 int CLIENT_DuplicateHandle( int src_process
, int src_handle
, int dst_process
, int dst_handle
,
359 DWORD access
, BOOL32 inherit
, DWORD options
)
361 struct dup_handle_request req
;
362 struct dup_handle_reply reply
;
365 req
.src_process
= src_process
;
366 req
.src_handle
= src_handle
;
367 req
.dst_process
= dst_process
;
368 req
.dst_handle
= dst_handle
;
370 req
.inherit
= inherit
;
371 req
.options
= options
;
373 CLIENT_SendRequest( REQ_DUP_HANDLE
, -1, 1, &req
, sizeof(req
) );
374 CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) );
375 CHECK_LEN( len
, sizeof(reply
) );
380 /***********************************************************************
381 * CLIENT_GetProcessInfo
383 * Send a get process info request. Return 0 if OK.
385 int CLIENT_GetProcessInfo( int handle
, struct get_process_info_reply
*reply
)
389 CLIENT_SendRequest( REQ_GET_PROCESS_INFO
, -1, 1, &handle
, sizeof(handle
) );
390 err
= CLIENT_WaitReply( &len
, NULL
, 1, reply
, sizeof(*reply
) );
391 CHECK_LEN( len
, sizeof(*reply
) );
396 /***********************************************************************
397 * CLIENT_GetThreadInfo
399 * Send a get thread info request. Return 0 if OK.
401 int CLIENT_GetThreadInfo( int handle
, struct get_thread_info_reply
*reply
)
405 CLIENT_SendRequest( REQ_GET_THREAD_INFO
, -1, 1, &handle
, sizeof(handle
) );
406 err
= CLIENT_WaitReply( &len
, NULL
, 1, reply
, sizeof(*reply
) );
407 CHECK_LEN( len
, sizeof(*reply
) );
412 /***********************************************************************
415 * Open a handle to a process.
417 int CLIENT_OpenProcess( void *pid
, DWORD access
, BOOL32 inherit
)
419 struct open_process_request req
;
420 struct open_process_reply reply
;
425 req
.inherit
= inherit
;
427 CLIENT_SendRequest( REQ_OPEN_PROCESS
, -1, 1, &req
, sizeof(req
) );
428 CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) );
429 CHECK_LEN( len
, sizeof(reply
) );
434 /***********************************************************************
437 int CLIENT_Select( int count
, int *handles
, int flags
, int timeout
)
439 struct select_request req
;
440 struct select_reply reply
;
445 req
.timeout
= timeout
;
447 CLIENT_SendRequest( REQ_SELECT
, -1, 2,
449 handles
, count
* sizeof(int) );
450 CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) );
451 CHECK_LEN( len
, sizeof(reply
) );
452 return reply
.signaled
;