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