Implemented StrCmpNIA like the other StrCmpXX 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 "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 #include <sys/socket.h>
16 #ifdef HAVE_SYS_MMAN_H
17 #include <sys/mman.h>
18 #endif
19 #include <sys/uio.h>
20 #include <unistd.h>
21 #include <stdarg.h>
22
23 #include "process.h"
24 #include "thread.h"
25 #include "server.h"
26 #include "winerror.h"
27
28 /* Some versions of glibc don't define this */
29 #ifndef SCM_RIGHTS
30 #define SCM_RIGHTS 1
31 #endif
32
33 /* data structure used to pass an fd with sendmsg/recvmsg */
34 struct cmsg_fd
35 {
36     int len;   /* sizeof structure */
37     int level; /* SOL_SOCKET */
38     int type;  /* SCM_RIGHTS */
39     int fd;    /* fd to pass */
40 };
41
42 /***********************************************************************
43  *           CLIENT_Die
44  *
45  * Die on protocol errors or socket close
46  */
47 static void CLIENT_Die(void)
48 {
49     close( NtCurrentTeb()->socket );
50     SYSDEPS_ExitThread();
51 }
52
53 /***********************************************************************
54  *           server_protocol_error
55  */
56 void server_protocol_error( const char *err, ... )
57 {
58     va_list args;
59
60     va_start( args, err );
61     fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
62     vfprintf( stderr, err, args );
63     va_end( args );
64     CLIENT_Die();
65 }
66
67
68 /***********************************************************************
69  *           server_perror
70  */
71 static void server_perror( const char *err )
72 {
73     fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
74     perror( err );
75     CLIENT_Die();
76 }
77
78
79 /***********************************************************************
80  *           send_request
81  *
82  * Send a request to the server.
83  */
84 static void send_request( enum request req )
85 {
86     int ret;
87     if ((ret = write( NtCurrentTeb()->socket, &req, sizeof(req) )) == sizeof(req))
88         return;
89     if (ret == -1)
90     {
91         if (errno == EPIPE) CLIENT_Die();
92         server_perror( "sendmsg" );
93     }
94     server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
95 }
96
97 /***********************************************************************
98  *           send_request_fd
99  *
100  * Send a request to the server, passing a file descriptor.
101  */
102 static void send_request_fd( enum request req, int fd )
103 {
104     int ret;
105 #ifndef HAVE_MSGHDR_ACCRIGHTS
106     struct cmsg_fd cmsg;
107 #endif
108     struct msghdr msghdr;
109     struct iovec vec;
110
111     vec.iov_base = (void *)&req;
112     vec.iov_len  = sizeof(req);
113
114     msghdr.msg_name    = NULL;
115     msghdr.msg_namelen = 0;
116     msghdr.msg_iov     = &vec;
117     msghdr.msg_iovlen  = 1;
118
119 #ifdef HAVE_MSGHDR_ACCRIGHTS
120     msghdr.msg_accrights    = (void *)&fd;
121     msghdr.msg_accrightslen = sizeof(fd);
122 #else  /* HAVE_MSGHDR_ACCRIGHTS */
123     cmsg.len   = sizeof(cmsg);
124     cmsg.level = SOL_SOCKET;
125     cmsg.type  = SCM_RIGHTS;
126     cmsg.fd    = fd;
127     msghdr.msg_control    = &cmsg;
128     msghdr.msg_controllen = sizeof(cmsg);
129     msghdr.msg_flags      = 0;
130 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
131
132     if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(req)) return;
133     if (ret == -1)
134     {
135         if (errno == EPIPE) CLIENT_Die();
136         server_perror( "sendmsg" );
137     }
138     server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
139 }
140
141 /***********************************************************************
142  *           wait_reply
143  *
144  * Wait for a reply from the server.
145  */
146 static unsigned int wait_reply(void)
147 {
148     int ret;
149     unsigned int res;
150
151     for (;;)
152     {
153         if ((ret = read( NtCurrentTeb()->socket, &res, sizeof(res) )) == sizeof(res))
154             return res;
155         if (ret == -1)
156         {
157             if (errno == EINTR) continue;
158             if (errno == EPIPE) CLIENT_Die();
159             server_perror("read");
160         }
161         if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
162         server_protocol_error( "partial msg received %d/%d\n", ret, sizeof(res) );
163     }
164 }
165
166
167 /***********************************************************************
168  *           wait_reply_fd
169  *
170  * Wait for a reply from the server, when a file descriptor is passed.
171  */
172 static unsigned int wait_reply_fd( int *fd )
173 {
174     struct iovec vec;
175     int ret;
176     unsigned int res;
177
178 #ifdef HAVE_MSGHDR_ACCRIGHTS
179     struct msghdr msghdr;
180
181     *fd = -1;
182     msghdr.msg_accrights    = (void *)fd;
183     msghdr.msg_accrightslen = sizeof(*fd);
184 #else  /* HAVE_MSGHDR_ACCRIGHTS */
185     struct msghdr msghdr;
186     struct cmsg_fd cmsg;
187
188     cmsg.len   = sizeof(cmsg);
189     cmsg.level = SOL_SOCKET;
190     cmsg.type  = SCM_RIGHTS;
191     cmsg.fd    = -1;
192     msghdr.msg_control    = &cmsg;
193     msghdr.msg_controllen = sizeof(cmsg);
194     msghdr.msg_flags      = 0;
195 #endif  /* HAVE_MSGHDR_ACCRIGHTS */
196
197     msghdr.msg_name    = NULL;
198     msghdr.msg_namelen = 0;
199     msghdr.msg_iov     = &vec;
200     msghdr.msg_iovlen  = 1;
201     vec.iov_base = (void *)&res;
202     vec.iov_len  = sizeof(res);
203
204     for (;;)
205     {
206         if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(res))
207         {
208 #ifndef HAVE_MSGHDR_ACCRIGHTS
209             *fd = cmsg.fd;
210 #endif
211             return res;
212         }
213         if (ret == -1)
214         {
215             if (errno == EINTR) continue;
216             if (errno == EPIPE) CLIENT_Die();
217             server_perror("recvmsg");
218         }
219         if (!ret) CLIENT_Die(); /* the server closed the connection; time to die... */
220         server_protocol_error( "partial seq received %d/%d\n", ret, sizeof(res) );
221     }
222 }
223
224
225 /***********************************************************************
226  *           server_call
227  *
228  * Perform a server call.
229  */
230 unsigned int server_call( enum request req )
231 {
232     unsigned int res;
233
234     send_request( req );
235     res = wait_reply();
236     if (res) SetLastError( res );
237     return res;  /* error code */
238 }
239
240
241 /***********************************************************************
242  *           server_call_fd
243  *
244  * Perform a server call, passing a file descriptor.
245  * If *fd is != -1, it will be passed to the server.
246  * If the server passes an fd, it will be stored into *fd.
247  */
248 unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
249 {
250     unsigned int res;
251
252     if (fd_out == -1) send_request( req );
253     else send_request_fd( req, fd_out );
254
255     if (fd_in) res = wait_reply_fd( fd_in );
256     else res = wait_reply();
257     if (res) SetLastError( res );
258     return res;  /* error code */
259 }
260
261
262 /***********************************************************************
263  *           CLIENT_InitServer
264  *
265  * Start the server and create the initial socket pair.
266  */
267 int CLIENT_InitServer(void)
268 {
269     int fd[2];
270     char buffer[16];
271     extern void create_initial_thread( int fd );
272
273     if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
274     {
275         perror("socketpair");
276         exit(1);
277     }
278     switch(fork())
279     {
280     case -1:  /* error */
281         perror("fork");
282         exit(1);
283     case 0:  /* child */
284         close( fd[1] );
285         break;
286     default:  /* parent */
287         close( fd[0] );
288         sprintf( buffer, "%d", fd[1] );
289 /*#define EXEC_SERVER*/
290 #ifdef EXEC_SERVER
291         execlp( "wineserver", "wineserver", buffer, NULL );
292         execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
293         execl( "./server/wineserver", "wineserver", buffer, NULL );
294 #endif
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