Added get_page_size function.
[wine] / scheduler / client.c
1 /*
2  * Client part of the client/server communication
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #ifdef HAVE_SYS_SOCKET_H
16 # include <sys/socket.h>
17 #endif
18 #ifdef HAVE_SYS_MMAN_H
19 #include <sys/mman.h>
20 #endif
21 #include <sys/uio.h>
22 #include <unistd.h>
23 #include <stdarg.h>
24
25 #include "process.h"
26 #include "thread.h"
27 #include "server.h"
28 #include "winerror.h"
29
30 /* Some versions of glibc don't define this */
31 #ifndef SCM_RIGHTS
32 #define SCM_RIGHTS 1
33 #endif
34
35 /* data structure used to pass an fd with sendmsg/recvmsg */
36 struct cmsg_fd
37 {
38     int len;   /* sizeof structure */
39     int level; /* SOL_SOCKET */
40     int type;  /* SCM_RIGHTS */
41     int fd;    /* fd to pass */
42 };
43
44 /***********************************************************************
45  *           CLIENT_Die
46  *
47  * Die on protocol errors or socket close
48  */
49 static void CLIENT_Die(void)
50 {
51     close( NtCurrentTeb()->socket );
52     SYSDEPS_ExitThread();
53 }
54
55 /***********************************************************************
56  *           server_protocol_error
57  */
58 void server_protocol_error( const char *err, ... )
59 {
60     va_list args;
61
62     va_start( args, err );
63     fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
64     vfprintf( stderr, err, args );
65     va_end( args );
66     CLIENT_Die();
67 }
68
69
70 /***********************************************************************
71  *           server_perror
72  */
73 static void server_perror( const char *err )
74 {
75     fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
76     perror( err );
77     CLIENT_Die();
78 }
79
80
81 /***********************************************************************
82  *           send_request
83  *
84  * Send a request to the server.
85  */
86 static void send_request( enum request req )
87 {
88     int ret;
89     if ((ret = write( NtCurrentTeb()->socket, &req, sizeof(req) )) == sizeof(req))
90         return;
91     if (ret == -1)
92     {
93         if (errno == EPIPE) CLIENT_Die();
94         server_perror( "sendmsg" );
95     }
96     server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
97 }
98
99 /***********************************************************************
100  *           send_request_fd
101  *
102  * Send a request to the server, passing a file descriptor.
103  */
104 static void send_request_fd( enum request req, int fd )
105 {
106     int ret;
107 #ifndef HAVE_MSGHDR_ACCRIGHTS
108     struct cmsg_fd cmsg;
109 #endif
110     struct msghdr msghdr;
111     struct iovec vec;
112
113     vec.iov_base = (void *)&req;
114     vec.iov_len  = sizeof(req);
115
116     msghdr.msg_name    = NULL;
117     msghdr.msg_namelen = 0;
118     msghdr.msg_iov     = &vec;
119     msghdr.msg_iovlen  = 1;
120
121 #ifdef HAVE_MSGHDR_ACCRIGHTS
122     msghdr.msg_accrights    = (void *)&fd;
123     msghdr.msg_accrightslen = sizeof(fd);
124 #else  /* HAVE_MSGHDR_ACCRIGHTS */
125     cmsg.len   = sizeof(cmsg);
126     cmsg.level = SOL_SOCKET;
127     cmsg.type  = SCM_RIGHTS;
128     cmsg.fd    = fd;
129     msghdr.msg_control    = &cmsg;
130     msghdr.msg_controllen = sizeof(cmsg);
131     msghdr.msg_flags      = 0;
132 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
133
134     if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(req)) return;
135     if (ret == -1)
136     {
137         if (errno == EPIPE) CLIENT_Die();
138         server_perror( "sendmsg" );
139     }
140     server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
141 }
142
143 /***********************************************************************
144  *           wait_reply
145  *
146  * Wait for a reply from the server.
147  */
148 static unsigned int wait_reply(void)
149 {
150     int ret;
151     unsigned int res;
152
153     for (;;)
154     {
155         if ((ret = read( NtCurrentTeb()->socket, &res, sizeof(res) )) == sizeof(res))
156             return res;
157         if (ret == -1)
158         {
159             if (errno == EINTR) continue;
160             if (errno == EPIPE) CLIENT_Die();
161             server_perror("read");
162         }
163         if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
164         server_protocol_error( "partial msg received %d/%d\n", ret, sizeof(res) );
165     }
166 }
167
168
169 /***********************************************************************
170  *           wait_reply_fd
171  *
172  * Wait for a reply from the server, when a file descriptor is passed.
173  */
174 static unsigned int wait_reply_fd( int *fd )
175 {
176     struct iovec vec;
177     int ret;
178     unsigned int res;
179
180 #ifdef HAVE_MSGHDR_ACCRIGHTS
181     struct msghdr msghdr;
182
183     *fd = -1;
184     msghdr.msg_accrights    = (void *)fd;
185     msghdr.msg_accrightslen = sizeof(*fd);
186 #else  /* HAVE_MSGHDR_ACCRIGHTS */
187     struct msghdr msghdr;
188     struct cmsg_fd cmsg;
189
190     cmsg.len   = sizeof(cmsg);
191     cmsg.level = SOL_SOCKET;
192     cmsg.type  = SCM_RIGHTS;
193     cmsg.fd    = -1;
194     msghdr.msg_control    = &cmsg;
195     msghdr.msg_controllen = sizeof(cmsg);
196     msghdr.msg_flags      = 0;
197 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
198
199     msghdr.msg_name    = NULL;
200     msghdr.msg_namelen = 0;
201     msghdr.msg_iov     = &vec;
202     msghdr.msg_iovlen  = 1;
203     vec.iov_base = (void *)&res;
204     vec.iov_len  = sizeof(res);
205
206     for (;;)
207     {
208         if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(res))
209         {
210 #ifndef HAVE_MSGHDR_ACCRIGHTS
211             *fd = cmsg.fd;
212 #endif
213             return res;
214         }
215         if (ret == -1)
216         {
217             if (errno == EINTR) continue;
218             if (errno == EPIPE) CLIENT_Die();
219             server_perror("recvmsg");
220         }
221         if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
222         server_protocol_error( "partial seq received %d/%d\n", ret, sizeof(res) );
223     }
224 }
225
226
227 /***********************************************************************
228  *           server_call
229  *
230  * Perform a server call.
231  */
232 unsigned int server_call( enum request req )
233 {
234     unsigned int res;
235
236     send_request( req );
237     res = wait_reply();
238     if (res) SetLastError( res );
239     return res;  /* error code */
240 }
241
242
243 /***********************************************************************
244  *           server_call_fd
245  *
246  * Perform a server call, passing a file descriptor.
247  * If *fd is != -1, it will be passed to the server.
248  * If the server passes an fd, it will be stored into *fd.
249  */
250 unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
251 {
252     unsigned int res;
253
254     if (fd_out == -1) send_request( req );
255     else send_request_fd( req, fd_out );
256
257     if (fd_in) res = wait_reply_fd( fd_in );
258     else res = wait_reply();
259     if (res) SetLastError( res );
260     return res;  /* error code */
261 }
262
263
264 /***********************************************************************
265  *           CLIENT_InitServer
266  *
267  * Start the server and create the initial socket pair.
268  */
269 int CLIENT_InitServer(void)
270 {
271     int fd[2];
272     char buffer[16];
273     extern void create_initial_thread( int fd );
274
275     if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
276     {
277         perror("socketpair");
278         exit(1);
279     }
280     switch(fork())
281     {
282     case -1:  /* error */
283         perror("fork");
284         exit(1);
285     case 0:  /* child */
286         close( fd[1] );
287         fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
288         break;
289     default:  /* parent */
290         close( fd[0] );
291         sprintf( buffer, "%d", fd[1] );
292         execl( BINDIR "/wineserver", "wineserver", buffer, NULL );
293         execlp( "wineserver", "wineserver", buffer, NULL );
294         execl( "./server/wineserver", "wineserver", buffer, NULL );
295         create_initial_thread( fd[1] );
296         exit(0);
297     }
298     return fd[0];
299 }
300
301
302 /***********************************************************************
303  *           CLIENT_InitThread
304  *
305  * Send an init thread request. Return 0 if OK.
306  */
307 int CLIENT_InitThread(void)
308 {
309     struct init_thread_request *req;
310     TEB *teb = NtCurrentTeb();
311     int fd;
312
313     if (wait_reply_fd( &fd ) || (fd == -1))
314         server_protocol_error( "no fd passed on first request\n" );
315     if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) server_perror( "lseek" );
316     teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
317     close( fd );
318     if (teb->buffer == (void*)-1) server_perror( "mmap" );
319
320     req = get_req_buffer();
321     req->unix_pid = getpid();
322     req->teb      = teb;
323     if (server_call( REQ_INIT_THREAD )) return -1;
324     teb->process->server_pid = req->pid;
325     teb->tid = req->tid;
326     return 0;
327 }
328
329
330 /***********************************************************************
331  *           CLIENT_SetDebug
332  *
333  * Send a set debug level request. Return 0 if OK.
334  */
335 int CLIENT_SetDebug( int level )
336 {
337     struct set_debug_request *req = get_req_buffer();
338     req->level = level;
339     return server_call( REQ_SET_DEBUG );
340 }
341
342 /***********************************************************************
343  *           CLIENT_DebuggerRequest
344  *
345  * Send a debugger support request. Return 0 if OK.
346  */
347 int CLIENT_DebuggerRequest( int op )
348 {
349     struct debugger_request *req = get_req_buffer();
350     req->op = op;
351     return server_call( REQ_DEBUGGER );
352 }
353