Add new subdirectories dlls/ver and dlls/version.
[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
17 #include "process.h"
18 #include "thread.h"
19 #include "server/request.h"
20 #include "server.h"
21 #include "winerror.h"
22
23 /* Some versions of glibc don't define this */
24 #ifndef SCM_RIGHTS
25 #define SCM_RIGHTS 1
26 #endif
27
28
29 /***********************************************************************
30  *           CLIENT_ProtocolError
31  */
32 static void CLIENT_ProtocolError( const char *err, ... )
33 {
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
45 /***********************************************************************
46  *           CLIENT_SendRequest_v
47  *
48  * Send a request to the server.
49  */
50 static void CLIENT_SendRequest_v( enum request req, int pass_fd,
51                                   struct iovec *vec, int veclen )
52 {
53     THDB *thdb = THREAD_Current();
54 #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, };
58     struct header head;
59     int i, ret, len;
60
61     assert( veclen > 0 );
62     vec[0].iov_base = &head;
63     vec[0].iov_len  = sizeof(head);
64     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
71     if (pass_fd != -1)  /* we have an fd to send */
72     {
73 #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;
78         msghdr.msg_controllen = sizeof(cmsg);
79 #endif
80     }
81
82     if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
83     {
84         if (ret == -1) perror( "sendmsg" );
85         CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
86     }
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  */
97 void CLIENT_SendRequest( enum request req, int pass_fd,
98                          int n, ... /* arg_1, len_1, etc. */ )
99 {
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  */
123 static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
124                                         struct iovec *vec, int veclen )
125 {
126     THDB *thdb = THREAD_Current();
127     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
134     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);
140
141     while ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
142     {
143         if (errno == EINTR) continue;
144         perror("recvmsg");
145         CLIENT_ProtocolError( "recvmsg\n" );
146     }
147     if (!ret) ExitThread(1); /* the server closed the connection; time to die... */
148
149     /* sanity checks */
150
151     if (ret < sizeof(head))
152         CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
153
154     if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
155         CLIENT_ProtocolError( "header length %d\n", head.len );
156
157     if (head.seq != thdb->seq++)
158         CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head.seq, thdb->seq - 1 );
159
160 #ifndef HAVE_MSGHDR_ACCRIGHTS
161     pass_fd = cmsg.fd;
162 #endif
163
164     if (head.type != ERROR_SUCCESS)
165     {
166         SetLastError( head.type );
167     }
168     else if (passed_fd)
169     {
170         *passed_fd = pass_fd;
171         pass_fd = -1;
172     }
173
174     if (len) *len = ret - sizeof(head);
175     if (pass_fd != -1) close( pass_fd );
176     remaining = head.len - ret;
177     while (remaining > 0)  /* drop remaining data */
178     {
179         char buffer[1024];
180         int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
181         if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
182         {
183             perror( "recv" );
184             CLIENT_ProtocolError( "recv\n" );
185         }
186         if (!len) ExitThread(1); /* the server closed the connection; time to die... */
187         remaining -= len;
188     }
189
190     return head.type;  /* error code */
191 }
192
193
194 /***********************************************************************
195  *           CLIENT_WaitReply
196  *
197  * Wait for a reply from the server.
198  */
199 unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
200                                int n, ... /* arg_1, len_1, etc. */ )
201 {
202     struct iovec vec[16];
203     va_list args;
204     int i;
205
206     n++;  /* for vec[0] */
207     assert( n < 16 );
208     va_start( args, n );
209     for (i = 1; i < n; i++)
210     {
211         vec[i].iov_base = va_arg( args, void * );
212         vec[i].iov_len  = va_arg( args, int );
213     }
214     va_end( args );
215     return CLIENT_WaitReply_v( len, passed_fd, vec, n );
216 }
217
218
219 /***********************************************************************
220  *           CLIENT_WaitSimpleReply
221  *
222  * Wait for a simple fixed-length reply from the server.
223  */
224 unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
225 {
226     struct iovec vec[2];
227     unsigned int ret;
228     int got;
229
230     vec[1].iov_base = reply;
231     vec[1].iov_len  = len;
232     ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
233     if (got != len)
234         CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
235     return ret;
236 }
237
238
239 /***********************************************************************
240  *           CLIENT_NewThread
241  *
242  * Send a new thread request.
243  */
244 int CLIENT_NewThread( THDB *thdb, int *thandle, int *phandle )
245 {
246     struct new_thread_request request;
247     struct new_thread_reply reply;
248     int fd[2];
249     extern BOOL32 THREAD_InitDone;
250     extern void server_init( int fd );
251     extern void select_loop(void);
252
253     if (!THREAD_InitDone)  /* first thread -> start the server */
254     {
255         int tmpfd[2];
256         char buffer[16];
257
258         if (socketpair( AF_UNIX, SOCK_STREAM, 0, tmpfd ) == -1)
259         {
260             perror("socketpair");
261             exit(1);
262         }
263         switch(fork())
264         {
265         case -1:  /* error */
266             perror("fork");
267             exit(1);
268         case 0:  /* child */
269             close( tmpfd[0] );
270             sprintf( buffer, "%d", tmpfd[1] );
271 /*#define EXEC_SERVER*/
272 #ifdef EXEC_SERVER
273             execlp( "wineserver", "wineserver", buffer, NULL );
274             execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
275             execl( "./server/wineserver", "wineserver", buffer, NULL );
276 #endif
277             server_init( tmpfd[1] );
278             select_loop();
279             exit(0);
280         default:  /* parent */
281             close( tmpfd[1] );
282             SET_CUR_THREAD( thdb );
283             THREAD_InitDone = TRUE;
284             thdb->socket = tmpfd[0];
285             break;
286         }
287     }
288
289     if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
290     {
291         SetLastError( ERROR_TOO_MANY_OPEN_FILES );  /* FIXME */
292         return -1;
293     }
294
295     request.pid = thdb->process->server_pid;
296     CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
297     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
298     thdb->server_tid = reply.tid;
299     thdb->process->server_pid = reply.pid;
300     if (thdb->socket != -1) close( thdb->socket );
301     thdb->socket = fd[0];
302     thdb->seq = 0;  /* reset the sequence number for the new fd */
303     fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
304
305     if (thandle) *thandle = reply.thandle;
306     else if (reply.thandle != -1) CLIENT_CloseHandle( reply.thandle );
307     if (phandle) *phandle = reply.phandle;
308     else if (reply.phandle != -1) CLIENT_CloseHandle( reply.phandle );
309     return 0;
310
311  error:
312     close( fd[0] );
313     return -1;
314 }
315
316
317 /***********************************************************************
318  *           CLIENT_InitThread
319  *
320  * Send an init thread request. Return 0 if OK.
321  */
322 int CLIENT_InitThread(void)
323 {
324     THDB *thdb = THREAD_Current();
325     struct init_thread_request init;
326     int len = strlen( thdb->process->env_db->cmd_line );
327
328     init.unix_pid = getpid();
329     len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
330
331     CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
332                         &init, sizeof(init),
333                         thdb->process->env_db->cmd_line, len );
334     return CLIENT_WaitReply( NULL, NULL, 0 );
335 }
336
337
338 /***********************************************************************
339  *           CLIENT_SetDebug
340  *
341  * Send a set debug level request. Return 0 if OK.
342  */
343 int CLIENT_SetDebug( int level )
344 {
345     CLIENT_SendRequest( REQ_SET_DEBUG, -1, 1, &level, sizeof(level) );
346     return CLIENT_WaitReply( NULL, NULL, 0 );
347 }
348
349 /***********************************************************************
350  *           CLIENT_CloseHandle
351  *
352  * Send a close handle request. Return 0 if OK.
353  */
354 int CLIENT_CloseHandle( int handle )
355 {
356     CLIENT_SendRequest( REQ_CLOSE_HANDLE, -1, 1, &handle, sizeof(handle) );
357     return CLIENT_WaitReply( NULL, NULL, 0 );
358 }
359
360 /***********************************************************************
361  *           CLIENT_DuplicateHandle
362  *
363  * Send a duplicate handle request. Return 0 if OK.
364  */
365 int CLIENT_DuplicateHandle( int src_process, int src_handle, int dst_process, int dst_handle,
366                             DWORD access, BOOL32 inherit, DWORD options )
367 {
368     struct dup_handle_request req;
369     struct dup_handle_reply reply;
370
371     req.src_process = src_process;
372     req.src_handle  = src_handle;
373     req.dst_process = dst_process;
374     req.dst_handle  = dst_handle;
375     req.access      = access;
376     req.inherit     = inherit;
377     req.options     = options;
378
379     CLIENT_SendRequest( REQ_DUP_HANDLE, -1, 1, &req, sizeof(req) );
380     CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
381     return reply.handle;
382 }
383
384
385 /***********************************************************************
386  *           CLIENT_OpenProcess
387  *
388  * Open a handle to a process.
389  */
390 int CLIENT_OpenProcess( void *pid, DWORD access, BOOL32 inherit )
391 {
392     struct open_process_request req;
393     struct open_process_reply reply;
394
395     req.pid     = pid;
396     req.access  = access;
397     req.inherit = inherit;
398
399     CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
400     CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL );
401     return reply.handle;
402 }