Rearrange winver detection code and cache the winver value we
[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_Die
32  *
33  * Die on protocol errors or socket close
34  */
35 static void CLIENT_Die(void)
36 {
37     close( THREAD_Current()->socket );
38     SYSDEPS_ExitThread();
39 }
40
41 /***********************************************************************
42  *           CLIENT_ProtocolError
43  */
44 void CLIENT_ProtocolError( const char *err, ... )
45 {
46     va_list args;
47
48     va_start( args, err );
49     fprintf( stderr, "Client protocol error:%p: ", CURRENT()->tid );
50     vfprintf( stderr, err, args );
51     va_end( args );
52     CLIENT_Die();
53 }
54
55
56 /***********************************************************************
57  *           CLIENT_SendRequest_v
58  *
59  * Send a request to the server.
60  */
61 static void CLIENT_SendRequest_v( enum request req, int pass_fd,
62                                   struct iovec *vec, int veclen )
63 {
64     THDB *thdb = THREAD_Current();
65 #ifndef HAVE_MSGHDR_ACCRIGHTS
66     struct cmsg_fd cmsg;
67 #endif
68     struct msghdr msghdr;
69     struct header head;
70     int i, ret, len;
71
72     assert( veclen > 0 );
73     vec[0].iov_base = &head;
74     vec[0].iov_len  = sizeof(head);
75     for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
76
77     assert( len <= MAX_MSG_LENGTH );
78     head.type = req;
79     head.len  = len;
80     head.seq  = thdb->seq++;
81
82     msghdr.msg_name    = NULL;
83     msghdr.msg_namelen = 0;
84     msghdr.msg_iov     = vec;
85     msghdr.msg_iovlen  = veclen;
86
87 #ifdef HAVE_MSGHDR_ACCRIGHTS
88     if (pass_fd != -1)  /* we have an fd to send */
89     {
90         msghdr.msg_accrights    = (void *)&pass_fd;
91         msghdr.msg_accrightslen = sizeof(pass_fd);
92     }
93     else
94     {
95         msghdr.msg_accrights    = NULL;
96         msghdr.msg_accrightslen = 0;
97     }
98 #else  /* HAVE_MSGHDR_ACCRIGHTS */
99     if (pass_fd != -1)  /* we have an fd to send */
100     {
101         cmsg.len   = sizeof(cmsg);
102         cmsg.level = SOL_SOCKET;
103         cmsg.type  = SCM_RIGHTS;
104         cmsg.fd    = pass_fd;
105         msghdr.msg_control    = &cmsg;
106         msghdr.msg_controllen = sizeof(cmsg);
107     }
108     else
109     {
110         msghdr.msg_control    = NULL;
111         msghdr.msg_controllen = 0;
112     }
113     msghdr.msg_flags = 0;
114 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
115
116     if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
117     {
118         if (ret == -1)
119         {
120             if (errno == EPIPE) CLIENT_Die();
121             perror( "sendmsg" );
122         }
123         CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret, len );
124     }
125     /* we passed the fd now we can close it */
126     if (pass_fd != -1) close( pass_fd );
127 }
128
129
130 /***********************************************************************
131  *           CLIENT_SendRequest
132  *
133  * Send a request to the server.
134  */
135 void CLIENT_SendRequest( enum request req, int pass_fd,
136                          int n, ... /* arg_1, len_1, etc. */ )
137 {
138     struct iovec vec[16];
139     va_list args;
140     int i;
141
142     n++;  /* for vec[0] */
143     assert( n < 16 );
144     va_start( args, n );
145     for (i = 1; i < n; i++)
146     {
147         vec[i].iov_base = va_arg( args, void * );
148         vec[i].iov_len  = va_arg( args, int );
149     }
150     va_end( args );
151     CLIENT_SendRequest_v( req, pass_fd, vec, n );
152 }
153
154
155 /***********************************************************************
156  *           CLIENT_WaitReply_v
157  *
158  * Wait for a reply from the server.
159  * Returns the error code (or 0 if OK).
160  */
161 static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
162                                         struct iovec *vec, int veclen )
163 {
164     THDB *thdb = THREAD_Current();
165     int pass_fd = -1;
166     struct header head;
167     int ret, remaining;
168
169 #ifdef HAVE_MSGHDR_ACCRIGHTS
170     struct msghdr msghdr;
171
172     msghdr.msg_accrights    = (void *)&pass_fd;
173     msghdr.msg_accrightslen = sizeof(int);
174 #else  /* HAVE_MSGHDR_ACCRIGHTS */
175     struct msghdr msghdr;
176     struct cmsg_fd cmsg;
177
178     cmsg.len   = sizeof(cmsg);
179     cmsg.level = SOL_SOCKET;
180     cmsg.type  = SCM_RIGHTS;
181     cmsg.fd    = -1;
182     msghdr.msg_control    = &cmsg;
183     msghdr.msg_controllen = sizeof(cmsg);
184     msghdr.msg_flags      = 0;
185 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
186
187     msghdr.msg_name    = NULL;
188     msghdr.msg_namelen = 0;
189     msghdr.msg_iov     = vec;
190     msghdr.msg_iovlen  = veclen;
191
192     assert( veclen > 0 );
193     vec[0].iov_base       = &head;
194     vec[0].iov_len        = sizeof(head);
195
196     while ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
197     {
198         if (errno == EINTR) continue;
199         if (errno == EPIPE) CLIENT_Die();
200         perror("recvmsg");
201         CLIENT_ProtocolError( "recvmsg\n" );
202     }
203     if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
204
205     /* sanity checks */
206
207     if (ret < sizeof(head))
208         CLIENT_ProtocolError( "partial header received %d/%d\n", ret, sizeof(head) );
209
210     if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
211         CLIENT_ProtocolError( "header length %d\n", head.len );
212
213     if (head.seq != thdb->seq++)
214         CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head.seq, thdb->seq - 1 );
215
216 #ifndef HAVE_MSGHDR_ACCRIGHTS
217     pass_fd = cmsg.fd;
218 #endif
219
220     if (passed_fd)
221     {
222         *passed_fd = pass_fd;
223         pass_fd = -1;
224     }
225
226     if (len) *len = ret - sizeof(head);
227     if (pass_fd != -1) close( pass_fd );
228     remaining = head.len - ret;
229     while (remaining > 0)  /* get remaining data */
230     {
231         char *bufp, buffer[1024];
232         int addlen, i, iovtot = 0;
233
234         /* see if any iovs are still incomplete, otherwise drop the rest */
235         for (i = 0; i < veclen && remaining > 0; i++)
236         {
237             if (iovtot + vec[i].iov_len > head.len - remaining)
238             {
239                 addlen = iovtot + vec[i].iov_len - (head.len - remaining);
240                 bufp = (char *)vec[i].iov_base + (vec[i].iov_len - addlen);
241                 if (addlen > remaining) addlen = remaining;
242                 if ((addlen = recv( thdb->socket, bufp, addlen, 0 )) == -1)
243                 {
244                     perror( "recv" );
245                     CLIENT_ProtocolError( "recv\n" );
246                 }
247                 if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
248                 if (len) *len += addlen;
249                 remaining -= addlen;
250             }
251             iovtot += vec[i].iov_len;
252         }
253
254         if (remaining > 0)
255             addlen = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
256         else
257             break;
258
259         if ((addlen = recv( thdb->socket, buffer, addlen, 0 )) == -1)
260         {
261             perror( "recv" );
262             CLIENT_ProtocolError( "recv\n" );
263         }
264         if (!addlen) CLIENT_Die(); /* the server closed the connection; time to die... */
265         remaining -= addlen;
266     }
267
268     if (head.type) SetLastError( head.type );
269     return head.type;  /* error code */
270 }
271
272
273 /***********************************************************************
274  *           CLIENT_WaitReply
275  *
276  * Wait for a reply from the server.
277  */
278 unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
279                                int n, ... /* arg_1, len_1, etc. */ )
280 {
281     struct iovec vec[16];
282     va_list args;
283     int i;
284
285     n++;  /* for vec[0] */
286     assert( n < 16 );
287     va_start( args, n );
288     for (i = 1; i < n; i++)
289     {
290         vec[i].iov_base = va_arg( args, void * );
291         vec[i].iov_len  = va_arg( args, int );
292     }
293     va_end( args );
294     return CLIENT_WaitReply_v( len, passed_fd, vec, n );
295 }
296
297
298 /***********************************************************************
299  *           CLIENT_WaitSimpleReply
300  *
301  * Wait for a simple fixed-length reply from the server.
302  */
303 unsigned int CLIENT_WaitSimpleReply( void *reply, int len, int *passed_fd )
304 {
305     struct iovec vec[2];
306     unsigned int ret;
307     int got;
308
309     vec[1].iov_base = reply;
310     vec[1].iov_len  = len;
311     ret = CLIENT_WaitReply_v( &got, passed_fd, vec, 2 );
312     if (got != len)
313         CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len, got );
314     return ret;
315 }
316
317
318 /***********************************************************************
319  *           CLIENT_InitServer
320  *
321  * Start the server and create the initial socket pair.
322  */
323 int CLIENT_InitServer(void)
324 {
325     int fd[2];
326     char buffer[16];
327     extern void create_initial_thread( int fd );
328
329     if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
330     {
331         perror("socketpair");
332         exit(1);
333     }
334     switch(fork())
335     {
336     case -1:  /* error */
337         perror("fork");
338         exit(1);
339     case 0:  /* child */
340         close( fd[1] );
341         break;
342     default:  /* parent */
343         close( fd[0] );
344         sprintf( buffer, "%d", fd[1] );
345 /*#define EXEC_SERVER*/
346 #ifdef EXEC_SERVER
347         execlp( "wineserver", "wineserver", buffer, NULL );
348         execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
349         execl( "./server/wineserver", "wineserver", buffer, NULL );
350 #endif
351         create_initial_thread( fd[1] );
352         exit(0);
353     }
354     return fd[0];
355 }
356
357
358 /***********************************************************************
359  *           CLIENT_InitThread
360  *
361  * Send an init thread request. Return 0 if OK.
362  */
363 int CLIENT_InitThread(void)
364 {
365     THDB *thdb = THREAD_Current();
366     struct init_thread_request req;
367     struct init_thread_reply reply;
368
369     req.unix_pid = getpid();
370     req.teb      = &thdb->teb;
371     CLIENT_SendRequest( REQ_INIT_THREAD, -1, 1, &req, sizeof(req) );
372     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return -1;
373     thdb->process->server_pid = reply.pid;
374     thdb->teb.tid = reply.tid;
375     return 0;
376 }
377
378
379 /***********************************************************************
380  *           CLIENT_SetDebug
381  *
382  * Send a set debug level request. Return 0 if OK.
383  */
384 int CLIENT_SetDebug( int level )
385 {
386     CLIENT_SendRequest( REQ_SET_DEBUG, -1, 1, &level, sizeof(level) );
387     return CLIENT_WaitReply( NULL, NULL, 0 );
388 }
389
390 /***********************************************************************
391  *           CLIENT_DebuggerRequest
392  *
393  * Send a debugger support request. Return 0 if OK.
394  */
395 int CLIENT_DebuggerRequest( int op )
396 {
397     struct debugger_request req;
398     req.op = op;
399     CLIENT_SendRequest( REQ_DEBUGGER, -1, 1, &req, sizeof(req) );
400     return CLIENT_WaitReply( NULL, NULL, 0 );
401 }
402