Added macros to header file for easier function calling.
[wine] / scheduler / client.c
1 /*
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>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
15
16 #include "process.h"
17 #include "thread.h"
18 #include "server/request.h"
19 #include "server.h"
20 #include "winerror.h"
21
22 /* Some versions of glibc don't define this */
23 #ifndef SCM_RIGHTS
24 #define SCM_RIGHTS 1
25 #endif
26
27
28 /***********************************************************************
29  *           CLIENT_ProtocolError
30  */
31 void CLIENT_ProtocolError( const char *err, ... )
32 {
33     THDB *thdb = THREAD_Current();
34     va_list args;
35
36     va_start( args, err );
37     fprintf( stderr, "Client protocol error:%p: ", thdb->server_tid );
38     vfprintf( stderr, err, args );
39     va_end( args );
40     ExitThread(1);
41 }
42
43
44 /***********************************************************************
45  *           CLIENT_SendRequest_v
46  *
47  * Send a request to the server.
48  */
49 static void CLIENT_SendRequest_v( enum request req, int pass_fd,
50                                   struct iovec *vec, int veclen )
51 {
52     THDB *thdb = THREAD_Current();
53 #ifndef HAVE_MSGHDR_ACCRIGHTS
54     struct cmsg_fd cmsg  = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, pass_fd };
55 #endif
56     struct msghdr msghdr = { NULL, 0, vec, veclen, };
57     struct header head;
58     int i, ret, len;
59
60     assert( veclen > 0 );
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;
64
65     assert( len <= MAX_MSG_LENGTH );
66     head.type = req;
67     head.len  = len;
68     head.seq  = thdb->seq++;
69
70     if (pass_fd != -1)  /* we have an fd to send */
71     {
72 #ifdef HAVE_MSGHDR_ACCRIGHTS
73         msghdr.msg_accrights = (void *)&pass_fd;
74         msghdr.msg_accrightslen = sizeof(pass_fd);
75 #else
76         msghdr.msg_control    = &cmsg;
77         msghdr.msg_controllen = sizeof(cmsg);
78 #endif
79     }
80
81     if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
82     {
83         if (ret == -1) perror( "sendmsg" );
84         CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
85     }
86     /* we passed the fd now we can close it */
87     if (pass_fd != -1) close( pass_fd );
88 }
89
90
91 /***********************************************************************
92  *           CLIENT_SendRequest
93  *
94  * Send a request to the server.
95  */
96 void CLIENT_SendRequest( enum request req, int pass_fd,
97                          int n, ... /* arg_1, len_1, etc. */ )
98 {
99     struct iovec vec[16];
100     va_list args;
101     int i;
102
103     n++;  /* for vec[0] */
104     assert( n < 16 );
105     va_start( args, n );
106     for (i = 1; i < n; i++)
107     {
108         vec[i].iov_base = va_arg( args, void * );
109         vec[i].iov_len  = va_arg( args, int );
110     }
111     va_end( args );
112     return CLIENT_SendRequest_v( req, pass_fd, vec, n );
113 }
114
115
116 /***********************************************************************
117  *           CLIENT_WaitReply_v
118  *
119  * Wait for a reply from the server.
120  * Returns the error code (or 0 if OK).
121  */
122 static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
123                                         struct iovec *vec, int veclen )
124 {
125     THDB *thdb = THREAD_Current();
126     int pass_fd = -1;
127 #ifdef HAVE_MSGHDR_ACCRIGHTS
128     struct msghdr msghdr = { NULL, 0, vec, veclen, (void*)&pass_fd, sizeof(int) };
129 #else
130     struct cmsg_fd cmsg  = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
131     struct msghdr msghdr = { NULL, 0, vec, veclen, &cmsg, sizeof(cmsg), 0 };
132 #endif
133     struct header head;
134     int ret, remaining;
135
136     assert( veclen > 0 );
137     vec[0].iov_base       = &head;
138     vec[0].iov_len        = sizeof(head);
139
140     while ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
141     {
142         if (errno == EINTR) continue;
143         perror("recvmsg");
144         CLIENT_ProtocolError( "recvmsg\n" );
145     }
146     if (!ret) ExitThread(1); /* the server closed the connection; time to die... */
147
148     /* sanity checks */
149
150     if (ret < sizeof(head))
151         CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
152
153     if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
154         CLIENT_ProtocolError( "header length %d\n", head.len );
155
156     if (head.seq != thdb->seq++)
157         CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head.seq, thdb->seq - 1 );
158
159 #ifndef HAVE_MSGHDR_ACCRIGHTS
160     pass_fd = cmsg.fd;
161 #endif
162
163     if (head.type != ERROR_SUCCESS)
164     {
165         SetLastError( head.type );
166     }
167     else if (passed_fd)
168     {
169         *passed_fd = pass_fd;
170         pass_fd = -1;
171     }
172
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 */
177     {
178         char buffer[1024];
179         int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
180         if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
181         {
182             perror( "recv" );
183             CLIENT_ProtocolError( "recv\n" );
184         }
185         if (!len) ExitThread(1); /* the server closed the connection; time to die... */
186         remaining -= len;
187     }
188
189     return head.type;  /* error code */
190 }
191
192
193 /***********************************************************************
194  *           CLIENT_WaitReply
195  *
196  * Wait for a reply from the server.
197  */
198 unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
199                                int n, ... /* arg_1, len_1, etc. */ )
200 {
201     struct iovec vec[16];
202     va_list args;
203     int i;
204
205     n++;  /* for vec[0] */
206     assert( n < 16 );
207     va_start( args, n );
208     for (i = 1; i < n; i++)
209     {
210         vec[i].iov_base = va_arg( args, void * );
211         vec[i].iov_len  = va_arg( args, int );
212     }
213     va_end( args );
214     return CLIENT_WaitReply_v( len, passed_fd, vec, n );
215 }
216
217
218 /***********************************************************************
219  *           CLIENT_NewThread
220  *
221  * Send a new thread request.
222  */
223 int CLIENT_NewThread( THDB *thdb, int *thandle, int *phandle )
224 {
225     struct new_thread_request request;
226     struct new_thread_reply reply;
227     int len, fd[2];
228     extern BOOL32 THREAD_InitDone;
229     extern void server_main_loop( int fd );
230
231     if (!THREAD_InitDone)  /* first thread -> start the server */
232     {
233         int tmpfd[2];
234         char buffer[16];
235
236         if (socketpair( AF_UNIX, SOCK_STREAM, 0, tmpfd ) == -1)
237         {
238             perror("socketpair");
239             exit(1);
240         }
241         switch(fork())
242         {
243         case -1:  /* error */
244             perror("fork");
245             exit(1);
246         case 0:  /* child */
247             close( tmpfd[0] );
248             sprintf( buffer, "%d", tmpfd[1] );
249 #ifdef EXEC_SERVER
250             execlp( "wineserver", "wineserver", buffer, NULL );
251             execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
252             execl( "./server/wineserver", "wineserver", buffer, NULL );
253 #endif
254             server_main_loop( tmpfd[1] );
255             exit(0);
256         default:  /* parent */
257             close( tmpfd[1] );
258             SET_CUR_THREAD( thdb );
259             THREAD_InitDone = TRUE;
260             thdb->socket = tmpfd[0];
261             break;
262         }
263     }
264
265     if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
266     {
267         SetLastError( ERROR_TOO_MANY_OPEN_FILES );  /* FIXME */
268         return -1;
269     }
270
271     request.pid = thdb->process->server_pid;
272     CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
273
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 */
281
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 );
287     return 0;
288
289  error:
290     close( fd[0] );
291     return -1;
292 }
293
294
295 /***********************************************************************
296  *           CLIENT_InitThread
297  *
298  * Send an init thread request. Return 0 if OK.
299  */
300 int CLIENT_InitThread(void)
301 {
302     THDB *thdb = THREAD_Current();
303     struct init_thread_request init;
304     int len = strlen( thdb->process->env_db->cmd_line );
305
306     init.unix_pid = getpid();
307     len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
308
309     CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
310                         &init, sizeof(init),
311                         thdb->process->env_db->cmd_line, len );
312     return CLIENT_WaitReply( NULL, NULL, 0 );
313 }
314
315
316 /***********************************************************************
317  *           CLIENT_TerminateProcess
318  *
319  * Send a terminate process request. Return 0 if OK.
320  */
321 int CLIENT_TerminateProcess( int handle, int exit_code )
322 {
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 );
327 }
328
329 /***********************************************************************
330  *           CLIENT_TerminateThread
331  *
332  * Send a terminate thread request. Return 0 if OK.
333  */
334 int CLIENT_TerminateThread( int handle, int exit_code )
335 {
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 );
340 }
341
342 /***********************************************************************
343  *           CLIENT_CloseHandle
344  *
345  * Send a close handle request. Return 0 if OK.
346  */
347 int CLIENT_CloseHandle( int handle )
348 {
349     CLIENT_SendRequest( REQ_CLOSE_HANDLE, -1, 1, &handle, sizeof(handle) );
350     return CLIENT_WaitReply( NULL, NULL, 0 );
351 }
352
353 /***********************************************************************
354  *           CLIENT_DuplicateHandle
355  *
356  * Send a duplicate handle request. Return 0 if OK.
357  */
358 int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process, int dst_handle,
359                             DWORD access, BOOL32 inherit, DWORD options )
360 {
361     struct dup_handle_request req;
362     struct dup_handle_reply reply;
363     int len;
364
365     req.src_process = src_process;
366     req.src_handle  = src_handle;
367     req.dst_process = dst_process;
368     req.dst_handle  = dst_handle;
369     req.access      = access;
370     req.inherit     = inherit;
371     req.options     = options;
372
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) );
376     return reply.handle;
377 }
378
379
380 /***********************************************************************
381  *           CLIENT_GetProcessInfo
382  *
383  * Send a get process info request. Return 0 if OK.
384  */
385 int CLIENT_GetProcessInfo( int handle, struct get_process_info_reply *reply )
386 {
387     int len, err;
388
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) );
392     return err;
393 }
394
395
396 /***********************************************************************
397  *           CLIENT_GetThreadInfo
398  *
399  * Send a get thread info request. Return 0 if OK.
400  */
401 int CLIENT_GetThreadInfo( int handle, struct get_thread_info_reply *reply )
402 {
403     int len, err;
404
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) );
408     return err;
409 }
410
411
412 /***********************************************************************
413  *           CLIENT_OpenProcess
414  *
415  * Open a handle to a process.
416  */
417 int CLIENT_OpenProcess( void *pid, DWORD access, BOOL32 inherit )
418 {
419     struct open_process_request req;
420     struct open_process_reply reply;
421     int len;
422
423     req.pid     = pid;
424     req.access  = access;
425     req.inherit = inherit;
426
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) );
430     return reply.handle;
431 }
432
433
434 /***********************************************************************
435  *           CLIENT_Select
436  */
437 int CLIENT_Select( int count, int *handles, int flags, int timeout )
438 {
439     struct select_request req;
440     struct select_reply reply;
441     int len;
442
443     req.count   = count;
444     req.flags   = flags;
445     req.timeout = timeout;
446
447     CLIENT_SendRequest( REQ_SELECT, -1, 2,
448                         &req, sizeof(req),
449                         handles, count * sizeof(int) );
450     CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) );
451     CHECK_LEN( len, sizeof(reply) );
452     return reply.signaled;
453 }