blob: 81e6b40426a7983a8488a3a4e32938d25a9e52c0 [file] [log] [blame]
Alexandre Julliard642d3131998-07-12 19:29:36 +00001/*
2 * Client part of the client/server communication
3 *
4 * Copyright (C) 1998 Alexandre Julliard
5 */
6
7#include <assert.h>
8#include <errno.h>
Alexandre Julliard62a8b431999-01-19 17:48:23 +00009#include <fcntl.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000010#include <stdio.h>
11#include <string.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000012#include <sys/types.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000013#include <sys/socket.h>
14#include <sys/uio.h>
15#include <unistd.h>
16
17#include "process.h"
18#include "thread.h"
Alexandre Julliard767e6f61998-08-09 12:47:43 +000019#include "server/request.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000020#include "server.h"
Alexandre Julliard642d3131998-07-12 19:29:36 +000021#include "winerror.h"
22
Alexandre Julliard829fe321998-07-26 14:27:39 +000023/* Some versions of glibc don't define this */
24#ifndef SCM_RIGHTS
25#define SCM_RIGHTS 1
26#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000027
Alexandre Julliard767e6f61998-08-09 12:47:43 +000028
29/***********************************************************************
30 * CLIENT_ProtocolError
31 */
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +000032static void CLIENT_ProtocolError( const char *err, ... )
Alexandre Julliard767e6f61998-08-09 12:47:43 +000033{
34 THDB *thdb = THREAD_Current();
35 va_list args;
36
37 va_start( args, err );
38 fprintf( stderr, "Client protocol error:%p: ", thdb->server_tid );
39 vfprintf( stderr, err, args );
40 va_end( args );
41 ExitThread(1);
42}
43
44
Alexandre Julliard642d3131998-07-12 19:29:36 +000045/***********************************************************************
46 * CLIENT_SendRequest_v
47 *
48 * Send a request to the server.
49 */
50static void CLIENT_SendRequest_v( enum request req, int pass_fd,
51 struct iovec *vec, int veclen )
52{
53 THDB *thdb = THREAD_Current();
Alexandre Julliard829fe321998-07-26 14:27:39 +000054#ifndef HAVE_MSGHDR_ACCRIGHTS
55 struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, pass_fd };
56#endif
57 struct msghdr msghdr = { NULL, 0, vec, veclen, };
Alexandre Julliard642d3131998-07-12 19:29:36 +000058 struct header head;
59 int i, ret, len;
60
Alexandre Julliard642d3131998-07-12 19:29:36 +000061 assert( veclen > 0 );
Alexandre Julliard829fe321998-07-26 14:27:39 +000062 vec[0].iov_base = &head;
63 vec[0].iov_len = sizeof(head);
Alexandre Julliard642d3131998-07-12 19:29:36 +000064 for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
65
66 assert( len <= MAX_MSG_LENGTH );
67 head.type = req;
68 head.len = len;
69 head.seq = thdb->seq++;
70
Alexandre Julliard829fe321998-07-26 14:27:39 +000071 if (pass_fd != -1) /* we have an fd to send */
Alexandre Julliard642d3131998-07-12 19:29:36 +000072 {
Alexandre Julliard829fe321998-07-26 14:27:39 +000073#ifdef HAVE_MSGHDR_ACCRIGHTS
74 msghdr.msg_accrights = (void *)&pass_fd;
75 msghdr.msg_accrightslen = sizeof(pass_fd);
76#else
77 msghdr.msg_control = &cmsg;
Alexandre Julliard642d3131998-07-12 19:29:36 +000078 msghdr.msg_controllen = sizeof(cmsg);
Alexandre Julliard829fe321998-07-26 14:27:39 +000079#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000080 }
81
82 if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
83 {
Alexandre Julliard642d3131998-07-12 19:29:36 +000084 if (ret == -1) perror( "sendmsg" );
Alexandre Julliard767e6f61998-08-09 12:47:43 +000085 CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
Alexandre Julliard642d3131998-07-12 19:29:36 +000086 }
87 /* we passed the fd now we can close it */
88 if (pass_fd != -1) close( pass_fd );
89}
90
91
92/***********************************************************************
93 * CLIENT_SendRequest
94 *
95 * Send a request to the server.
96 */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000097void CLIENT_SendRequest( enum request req, int pass_fd,
98 int n, ... /* arg_1, len_1, etc. */ )
Alexandre Julliard642d3131998-07-12 19:29:36 +000099{
100 struct iovec vec[16];
101 va_list args;
102 int i;
103
104 n++; /* for vec[0] */
105 assert( n < 16 );
106 va_start( args, n );
107 for (i = 1; i < n; i++)
108 {
109 vec[i].iov_base = va_arg( args, void * );
110 vec[i].iov_len = va_arg( args, int );
111 }
112 va_end( args );
113 return CLIENT_SendRequest_v( req, pass_fd, vec, n );
114}
115
116
117/***********************************************************************
118 * CLIENT_WaitReply_v
119 *
120 * Wait for a reply from the server.
121 * Returns the error code (or 0 if OK).
122 */
123static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
124 struct iovec *vec, int veclen )
125{
126 THDB *thdb = THREAD_Current();
Alexandre Julliard829fe321998-07-26 14:27:39 +0000127 int pass_fd = -1;
128#ifdef HAVE_MSGHDR_ACCRIGHTS
129 struct msghdr msghdr = { NULL, 0, vec, veclen, (void*)&pass_fd, sizeof(int) };
130#else
131 struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
132 struct msghdr msghdr = { NULL, 0, vec, veclen, &cmsg, sizeof(cmsg), 0 };
133#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +0000134 struct header head;
135 int ret, remaining;
136
137 assert( veclen > 0 );
138 vec[0].iov_base = &head;
139 vec[0].iov_len = sizeof(head);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000140
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000141 while ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000142 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000143 if (errno == EINTR) continue;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000144 perror("recvmsg");
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000145 CLIENT_ProtocolError( "recvmsg\n" );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000146 }
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000147 if (!ret) ExitThread(1); /* the server closed the connection; time to die... */
148
149 /* sanity checks */
150
Alexandre Julliard642d3131998-07-12 19:29:36 +0000151 if (ret < sizeof(head))
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000152 CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
153
Alexandre Julliard642d3131998-07-12 19:29:36 +0000154 if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000155 CLIENT_ProtocolError( "header length %d\n", head.len );
156
Alexandre Julliard642d3131998-07-12 19:29:36 +0000157 if (head.seq != thdb->seq++)
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000158 CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head.seq, thdb->seq - 1 );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000159
Alexandre Julliard829fe321998-07-26 14:27:39 +0000160#ifndef HAVE_MSGHDR_ACCRIGHTS
161 pass_fd = cmsg.fd;
162#endif
163
Alexandre Julliardd757fc61999-01-31 15:06:28 +0000164 if (passed_fd)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000165 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000166 *passed_fd = pass_fd;
167 pass_fd = -1;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000168 }
169
170 if (len) *len = ret - sizeof(head);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000171 if (pass_fd != -1) close( pass_fd );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000172 remaining = head.len - ret;
Geoff Clare0b78af71999-01-31 18:57:28 +0000173 while (remaining > 0) /* get remaining data */
Alexandre Julliard642d3131998-07-12 19:29:36 +0000174 {
Geoff Clare0b78af71999-01-31 18:57:28 +0000175 char *bufp, buffer[1024];
176 int addlen, i, iovtot = 0;
177
178 /* see if any iovs are still incomplete, otherwise drop the rest */
179 for (i = 0; i < veclen && remaining > 0; i++)
180 {
181 if (iovtot + vec[i].iov_len > head.len - remaining)
182 {
183 addlen = iovtot + vec[i].iov_len - (head.len - remaining);
184 bufp = (char *)vec[i].iov_base + (vec[i].iov_len - addlen);
185 if (addlen > remaining) addlen = remaining;
186 if ((addlen = recv( thdb->socket, bufp, addlen, 0 )) == -1)
187 {
188 perror( "recv" );
189 CLIENT_ProtocolError( "recv\n" );
190 }
191 if (!addlen) ExitThread(1); /* the server closed the connection; time to die... */
192 if (len) *len += addlen;
193 remaining -= addlen;
194 }
195 iovtot += vec[i].iov_len;
196 }
197
198 if (remaining > 0)
199 addlen = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
200 else
201 break;
202
203 if ((addlen = recv( thdb->socket, buffer, addlen, 0 )) == -1)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000204 {
Alexandre Julliard642d3131998-07-12 19:29:36 +0000205 perror( "recv" );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000206 CLIENT_ProtocolError( "recv\n" );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000207 }
Geoff Clare0b78af71999-01-31 18:57:28 +0000208 if (!addlen) ExitThread(1); /* the server closed the connection; time to die... */
209 remaining -= addlen;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000210 }
211
Alexandre Julliardd757fc61999-01-31 15:06:28 +0000212 SetLastError( head.type );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000213 return head.type; /* error code */
214}
215
216
217/***********************************************************************
218 * CLIENT_WaitReply
219 *
220 * Wait for a reply from the server.
221 */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000222unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
223 int n, ... /* arg_1, len_1, etc. */ )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000224{
225 struct iovec vec[16];
226 va_list args;
227 int i;
228
229 n++; /* for vec[0] */
230 assert( n < 16 );
231 va_start( args, n );
232 for (i = 1; i < n; i++)
233 {
234 vec[i].iov_base = va_arg( args, void * );
235 vec[i].iov_len = va_arg( args, int );
236 }
237 va_end( args );
238 return CLIENT_WaitReply_v( len, passed_fd, vec, n );
239}
240
241
242/***********************************************************************
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000243 * CLIENT_WaitSimpleReply
244 *
245 * Wait for a simple fixed-length reply from the server.
246 */
247unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
248{
249 struct iovec vec[2];
250 unsigned int ret;
251 int got;
252
253 vec[1].iov_base = reply;
254 vec[1].iov_len = len;
255 ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
256 if (got != len)
257 CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
258 return ret;
259}
260
261
262/***********************************************************************
Alexandre Julliard642d3131998-07-12 19:29:36 +0000263 * CLIENT_NewThread
264 *
265 * Send a new thread request.
266 */
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000267int CLIENT_NewThread( THDB *thdb, int *thandle, int *phandle )
Alexandre Julliard642d3131998-07-12 19:29:36 +0000268{
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000269 struct new_thread_request request;
270 struct new_thread_reply reply;
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000271 int fd[2];
Alexandre Julliard642d3131998-07-12 19:29:36 +0000272 extern BOOL32 THREAD_InitDone;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000273 extern void server_init( int fd );
274 extern void select_loop(void);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000275
276 if (!THREAD_InitDone) /* first thread -> start the server */
277 {
278 int tmpfd[2];
279 char buffer[16];
280
Alexandre Julliard829fe321998-07-26 14:27:39 +0000281 if (socketpair( AF_UNIX, SOCK_STREAM, 0, tmpfd ) == -1)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000282 {
283 perror("socketpair");
284 exit(1);
285 }
286 switch(fork())
287 {
288 case -1: /* error */
289 perror("fork");
290 exit(1);
291 case 0: /* child */
292 close( tmpfd[0] );
293 sprintf( buffer, "%d", tmpfd[1] );
Alexandre Julliard47b3f321999-01-26 13:29:00 +0000294/*#define EXEC_SERVER*/
Alexandre Julliard642d3131998-07-12 19:29:36 +0000295#ifdef EXEC_SERVER
296 execlp( "wineserver", "wineserver", buffer, NULL );
297 execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
298 execl( "./server/wineserver", "wineserver", buffer, NULL );
299#endif
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000300 server_init( tmpfd[1] );
301 select_loop();
Alexandre Julliard642d3131998-07-12 19:29:36 +0000302 exit(0);
303 default: /* parent */
304 close( tmpfd[1] );
305 SET_CUR_THREAD( thdb );
306 THREAD_InitDone = TRUE;
307 thdb->socket = tmpfd[0];
308 break;
309 }
310 }
311
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000312 if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
313 {
314 SetLastError( ERROR_TOO_MANY_OPEN_FILES ); /* FIXME */
315 return -1;
316 }
317
318 request.pid = thdb->process->server_pid;
319 CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000320 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000321 thdb->server_tid = reply.tid;
322 thdb->process->server_pid = reply.pid;
323 if (thdb->socket != -1) close( thdb->socket );
324 thdb->socket = fd[0];
325 thdb->seq = 0; /* reset the sequence number for the new fd */
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000326 fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000327
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000328 if (thandle) *thandle = reply.thandle;
329 else if (reply.thandle != -1) CLIENT_CloseHandle( reply.thandle );
330 if (phandle) *phandle = reply.phandle;
331 else if (reply.phandle != -1) CLIENT_CloseHandle( reply.phandle );
332 return 0;
333
334 error:
335 close( fd[0] );
336 return -1;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000337}
338
339
340/***********************************************************************
341 * CLIENT_InitThread
342 *
343 * Send an init thread request. Return 0 if OK.
344 */
345int CLIENT_InitThread(void)
346{
347 THDB *thdb = THREAD_Current();
348 struct init_thread_request init;
349 int len = strlen( thdb->process->env_db->cmd_line );
350
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000351 init.unix_pid = getpid();
Alexandre Julliard642d3131998-07-12 19:29:36 +0000352 len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
353
354 CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
355 &init, sizeof(init),
356 thdb->process->env_db->cmd_line, len );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000357 return CLIENT_WaitReply( NULL, NULL, 0 );
358}
359
360
361/***********************************************************************
Alexandre Julliard338e7571998-12-27 15:28:54 +0000362 * CLIENT_SetDebug
363 *
364 * Send a set debug level request. Return 0 if OK.
365 */
366int CLIENT_SetDebug( int level )
367{
368 CLIENT_SendRequest( REQ_SET_DEBUG, -1, 1, &level, sizeof(level) );
369 return CLIENT_WaitReply( NULL, NULL, 0 );
370}
371
372/***********************************************************************
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000373 * CLIENT_CloseHandle
374 *
375 * Send a close handle request. Return 0 if OK.
376 */
377int CLIENT_CloseHandle( int handle )
378{
379 CLIENT_SendRequest( REQ_CLOSE_HANDLE, -1, 1, &handle, sizeof(handle) );
380 return CLIENT_WaitReply( NULL, NULL, 0 );
381}
382
383/***********************************************************************
384 * CLIENT_DuplicateHandle
385 *
386 * Send a duplicate handle request. Return 0 if OK.
387 */
388int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process, int dst_handle,
389 DWORD access, BOOL32 inherit, DWORD options )
390{
391 struct dup_handle_request req;
392 struct dup_handle_reply reply;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000393
394 req.src_process = src_process;
395 req.src_handle = src_handle;
396 req.dst_process = dst_process;
397 req.dst_handle = dst_handle;
398 req.access = access;
399 req.inherit = inherit;
400 req.options = options;
401
402 CLIENT_SendRequest( REQ_DUP_HANDLE, -1, 1, &req, sizeof(req) );
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000403 CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000404 return reply.handle;
405}
406
Alexandre Julliard85ed45e1998-08-22 19:03:56 +0000407
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000408/***********************************************************************
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000409 * CLIENT_OpenProcess
410 *
411 * Open a handle to a process.
412 */
413int CLIENT_OpenProcess( void *pid, DWORD access, BOOL32 inherit )
414{
415 struct open_process_request req;
416 struct open_process_reply reply;
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000417
418 req.pid = pid;
419 req.access = access;
420 req.inherit = inherit;
421
422 CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
Alexandre Julliard6ebbe3c1999-01-01 17:04:00 +0000423 CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000424 return reply.handle;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000425}