Stub for NtAllocateUuids.
[wine/testsucceed.git] / scheduler / client.c
blob17433235d5ca294945c17f9bd9dd4e5674e024bf
1 /*
2 * Client part of the client/server communication
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include "config.h"
9 #include <assert.h>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <pwd.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #ifdef HAVE_SYS_SOCKET_H
18 # include <sys/socket.h>
19 #endif
20 #include <sys/un.h>
21 #ifdef HAVE_SYS_MMAN_H
22 #include <sys/mman.h>
23 #endif
24 #include <sys/stat.h>
25 #include <sys/uio.h>
26 #include <unistd.h>
27 #include <stdarg.h>
29 #include "process.h"
30 #include "thread.h"
31 #include "server.h"
32 #include "winerror.h"
33 #include "options.h"
35 /* Some versions of glibc don't define this */
36 #ifndef SCM_RIGHTS
37 #define SCM_RIGHTS 1
38 #endif
40 #define CONFDIR "/.wine" /* directory for Wine config relative to $HOME */
41 #define SERVERDIR "/wineserver-" /* server socket directory (hostname appended) */
42 #define SOCKETNAME "socket" /* name of the socket file */
44 /* data structure used to pass an fd with sendmsg/recvmsg */
45 struct cmsg_fd
47 int len; /* sizeof structure */
48 int level; /* SOL_SOCKET */
49 int type; /* SCM_RIGHTS */
50 int fd; /* fd to pass */
53 static void *boot_thread_id;
56 /* die on a fatal error; use only during initialization */
57 static void fatal_error( const char *err, ... )
59 va_list args;
61 va_start( args, err );
62 fprintf( stderr, "wine: " );
63 vfprintf( stderr, err, args );
64 va_end( args );
65 exit(1);
68 /* die on a fatal error; use only during initialization */
69 static void fatal_perror( const char *err, ... )
71 va_list args;
73 va_start( args, err );
74 fprintf( stderr, "wine: " );
75 vfprintf( stderr, err, args );
76 perror( " " );
77 va_end( args );
78 exit(1);
81 /***********************************************************************
82 * server_protocol_error
84 void server_protocol_error( const char *err, ... )
86 va_list args;
88 va_start( args, err );
89 fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
90 vfprintf( stderr, err, args );
91 va_end( args );
92 SYSDEPS_ExitThread(1);
96 /***********************************************************************
97 * server_perror
99 static void server_perror( const char *err )
101 fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
102 perror( err );
103 SYSDEPS_ExitThread(1);
107 /***********************************************************************
108 * send_request
110 * Send a request to the server.
112 static void send_request( enum request req )
114 int ret;
115 if ((ret = write( NtCurrentTeb()->socket, &req, sizeof(req) )) == sizeof(req))
116 return;
117 if (ret == -1)
119 if (errno == EPIPE) SYSDEPS_ExitThread(0);
120 server_perror( "sendmsg" );
122 server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
125 /***********************************************************************
126 * send_request_fd
128 * Send a request to the server, passing a file descriptor.
130 static void send_request_fd( enum request req, int fd )
132 int ret;
133 #ifndef HAVE_MSGHDR_ACCRIGHTS
134 struct cmsg_fd cmsg;
135 #endif
136 struct msghdr msghdr;
137 struct iovec vec;
139 vec.iov_base = (void *)&req;
140 vec.iov_len = sizeof(req);
142 msghdr.msg_name = NULL;
143 msghdr.msg_namelen = 0;
144 msghdr.msg_iov = &vec;
145 msghdr.msg_iovlen = 1;
147 #ifdef HAVE_MSGHDR_ACCRIGHTS
148 msghdr.msg_accrights = (void *)&fd;
149 msghdr.msg_accrightslen = sizeof(fd);
150 #else /* HAVE_MSGHDR_ACCRIGHTS */
151 cmsg.len = sizeof(cmsg);
152 cmsg.level = SOL_SOCKET;
153 cmsg.type = SCM_RIGHTS;
154 cmsg.fd = fd;
155 msghdr.msg_control = &cmsg;
156 msghdr.msg_controllen = sizeof(cmsg);
157 msghdr.msg_flags = 0;
158 #endif /* HAVE_MSGHDR_ACCRIGHTS */
160 if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(req)) return;
161 if (ret == -1)
163 if (errno == EPIPE) SYSDEPS_ExitThread(0);
164 server_perror( "sendmsg" );
166 server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
169 /***********************************************************************
170 * wait_reply
172 * Wait for a reply from the server.
174 static unsigned int wait_reply(void)
176 int ret;
177 unsigned int res;
179 for (;;)
181 if ((ret = read( NtCurrentTeb()->socket, &res, sizeof(res) )) == sizeof(res))
182 return res;
183 if (!ret) break;
184 if (ret == -1)
186 if (errno == EINTR) continue;
187 if (errno == EPIPE) break;
188 server_perror("read");
190 server_protocol_error( "partial msg received %d/%d\n", ret, sizeof(res) );
192 /* the server closed the connection; time to die... */
193 SYSDEPS_ExitThread(0);
197 /***********************************************************************
198 * wait_reply_fd
200 * Wait for a reply from the server, when a file descriptor is passed.
202 static unsigned int wait_reply_fd( int *fd )
204 struct iovec vec;
205 int ret;
206 unsigned int res;
208 #ifdef HAVE_MSGHDR_ACCRIGHTS
209 struct msghdr msghdr;
211 *fd = -1;
212 msghdr.msg_accrights = (void *)fd;
213 msghdr.msg_accrightslen = sizeof(*fd);
214 #else /* HAVE_MSGHDR_ACCRIGHTS */
215 struct msghdr msghdr;
216 struct cmsg_fd cmsg;
218 cmsg.len = sizeof(cmsg);
219 cmsg.level = SOL_SOCKET;
220 cmsg.type = SCM_RIGHTS;
221 cmsg.fd = -1;
222 msghdr.msg_control = &cmsg;
223 msghdr.msg_controllen = sizeof(cmsg);
224 msghdr.msg_flags = 0;
225 #endif /* HAVE_MSGHDR_ACCRIGHTS */
227 msghdr.msg_name = NULL;
228 msghdr.msg_namelen = 0;
229 msghdr.msg_iov = &vec;
230 msghdr.msg_iovlen = 1;
231 vec.iov_base = (void *)&res;
232 vec.iov_len = sizeof(res);
234 for (;;)
236 if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(res))
238 #ifndef HAVE_MSGHDR_ACCRIGHTS
239 *fd = cmsg.fd;
240 #endif
241 return res;
243 if (!ret) break;
244 if (ret == -1)
246 if (errno == EINTR) continue;
247 if (errno == EPIPE) break;
248 server_perror("recvmsg");
250 server_protocol_error( "partial seq received %d/%d\n", ret, sizeof(res) );
252 /* the server closed the connection; time to die... */
253 SYSDEPS_ExitThread(0);
257 /***********************************************************************
258 * server_call_noerr
260 * Perform a server call.
262 unsigned int server_call_noerr( enum request req )
264 send_request( req );
265 return wait_reply();
269 /***********************************************************************
270 * server_call_fd
272 * Perform a server call, passing a file descriptor.
273 * If *fd is != -1, it will be passed to the server.
274 * If the server passes an fd, it will be stored into *fd.
276 unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
278 unsigned int res;
280 if (fd_out == -1) send_request( req );
281 else send_request_fd( req, fd_out );
283 if (fd_in) res = wait_reply_fd( fd_in );
284 else res = wait_reply();
285 if (res) SetLastError( RtlNtStatusToDosError(res) );
286 return res; /* error code */
290 /***********************************************************************
291 * get_config_dir
293 * Return the configuration directory ($WINEPREFIX or $HOME/.wine)
295 const char *get_config_dir(void)
297 static char *confdir;
298 if (!confdir)
300 const char *prefix = getenv( "WINEPREFIX" );
301 if (prefix)
303 int len = strlen(prefix);
304 if (!(confdir = strdup( prefix ))) fatal_error( "out of memory\n" );
305 if (len > 1 && confdir[len-1] == '/') confdir[len-1] = 0;
307 else
309 const char *home = getenv( "HOME" );
310 if (!home)
312 struct passwd *pwd = getpwuid( getuid() );
313 if (!pwd) fatal_error( "could not find your home directory\n" );
314 home = pwd->pw_dir;
316 if (!(confdir = malloc( strlen(home) + strlen(CONFDIR) + 1 )))
317 fatal_error( "out of memory\n" );
318 strcpy( confdir, home );
319 strcat( confdir, CONFDIR );
321 mkdir( confdir, 0755 ); /* just in case */
323 return confdir;
327 /***********************************************************************
328 * start_server
330 * Start a new wine server.
332 static void start_server( const char *oldcwd )
334 static int started; /* we only try once */
335 if (!started)
337 int pid = fork();
338 if (pid == -1) fatal_perror( "fork" );
339 if (!pid)
341 char *path, *p;
342 /* first try the installation dir */
343 execl( BINDIR "/wineserver", "wineserver", NULL );
344 if (oldcwd) chdir( oldcwd );
345 /* now try the dir we were launched from */
346 if (!(path = malloc( strlen(argv0) + 20 )))
347 fatal_error( "out of memory\n" );
348 if ((p = strrchr( strcpy( path, argv0 ), '/' )))
350 strcpy( p, "/wineserver" );
351 execl( path, "wineserver", NULL );
352 strcpy( p, "/server/wineserver" );
353 execl( path, "wineserver", NULL );
355 /* now try the path */
356 execlp( "wineserver", "wineserver", NULL );
357 /* and finally the current dir */
358 execl( "./server/wineserver", "wineserver", NULL );
359 fatal_error( "could not exec wineserver\n" );
361 started = 1;
365 /***********************************************************************
366 * server_connect
368 * Attempt to connect to an existing server socket.
369 * We need to be in the server directory already.
371 static int server_connect( const char *oldcwd, const char *serverdir )
373 struct sockaddr_un addr;
374 struct stat st;
375 int s, slen;
377 if (chdir( serverdir ) == -1)
379 if (errno != ENOENT) fatal_perror( "chdir to %s", serverdir );
380 start_server( NULL );
381 return -1;
383 if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir );
384 if (st.st_uid != getuid()) fatal_error( "'%s' is not owned by you\n", serverdir );
385 if (st.st_mode & 077) fatal_error( "'%s' must not be accessible by other users\n", serverdir );
387 if (lstat( SOCKETNAME, &st ) == -1)
389 if (errno != ENOENT) fatal_perror( "lstat %s/%s", serverdir, SOCKETNAME );
390 start_server( oldcwd );
391 return -1;
393 if (!S_ISSOCK(st.st_mode))
394 fatal_error( "'%s/%s' is not a socket\n", serverdir, SOCKETNAME );
395 if (st.st_uid != getuid())
396 fatal_error( "'%s/%s' is not owned by you\n", serverdir, SOCKETNAME );
398 if ((s = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" );
399 addr.sun_family = AF_UNIX;
400 strcpy( addr.sun_path, SOCKETNAME );
401 slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1;
402 #ifdef HAVE_SOCKADDR_SUN_LEN
403 addr.sun_len = slen;
404 #endif
405 if (connect( s, (struct sockaddr *)&addr, slen ) == -1)
407 close( s );
408 return -2;
410 fcntl( s, F_SETFD, 1 ); /* set close on exec flag */
411 return s;
415 /***********************************************************************
416 * CLIENT_InitServer
418 * Start the server and create the initial socket pair.
420 int CLIENT_InitServer(void)
422 int delay, fd, size;
423 const char *env_fd;
424 char hostname[64];
425 char *oldcwd, *serverdir;
426 const char *configdir;
428 /* first check if we inherited the socket fd */
429 if ((env_fd = getenv( "__WINE_FD" )) && isdigit(env_fd[0]))
431 fd = atoi( env_fd );
432 if (fcntl( fd, F_SETFD, 1 ) != -1) return fd; /* set close on exec flag */
435 /* retrieve the current directory */
436 for (size = 512; ; size *= 2)
438 if (!(oldcwd = malloc( size ))) break;
439 if (getcwd( oldcwd, size )) break;
440 free( oldcwd );
441 if (errno == ERANGE) continue;
442 oldcwd = NULL;
443 break;
446 /* get the server directory name */
447 if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" );
448 configdir = get_config_dir();
449 serverdir = malloc( strlen(configdir) + strlen(SERVERDIR) + strlen(hostname) + 1 );
450 if (!serverdir) fatal_error( "out of memory\n" );
451 strcpy( serverdir, configdir );
452 strcat( serverdir, SERVERDIR );
453 strcat( serverdir, hostname );
455 /* try to connect, leaving some time for the server to start up */
456 for (delay = 10000; delay < 500000; delay += delay / 2)
458 if ((fd = server_connect( oldcwd, serverdir )) >= 0) goto done;
459 usleep( delay );
462 if (fd == -2)
464 fatal_error( "'%s/%s' exists,\n"
465 " but I cannot connect to it; maybe the server has crashed?\n"
466 " If this is the case, you should remove the socket file and try again.\n",
467 serverdir, SOCKETNAME );
469 fatal_error( "could not start wineserver, giving up\n" );
471 done:
472 /* switch back to the starting directory */
473 if (oldcwd)
475 chdir( oldcwd );
476 free( oldcwd );
478 return fd;
482 /***********************************************************************
483 * CLIENT_InitThread
485 * Send an init thread request. Return 0 if OK.
487 int CLIENT_InitThread(void)
489 struct get_thread_buffer_request *first_req;
490 struct init_thread_request *req;
491 TEB *teb = NtCurrentTeb();
492 int fd;
494 if (wait_reply_fd( &fd ) || (fd == -1))
495 server_protocol_error( "no fd passed on first request\n" );
496 if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) server_perror( "lseek" );
497 teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
498 close( fd );
499 if (teb->buffer == (void*)-1) server_perror( "mmap" );
500 first_req = teb->buffer;
501 teb->process->server_pid = first_req->pid;
502 teb->pid = first_req->pid;
503 teb->tid = first_req->tid;
504 if (first_req->version != SERVER_PROTOCOL_VERSION)
505 server_protocol_error( "version mismatch %d/%d.\n"
506 "Your %s binary was not upgraded correctly,\n"
507 "or you have an older one somewhere in your PATH.\n",
508 first_req->version, SERVER_PROTOCOL_VERSION,
509 (first_req->version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
510 if (first_req->boot) boot_thread_id = teb->tid;
511 else if (boot_thread_id == teb->tid) boot_thread_id = 0;
513 req = teb->buffer;
514 req->unix_pid = getpid();
515 req->teb = teb;
516 req->entry = teb->entry_point;
517 return server_call_noerr( REQ_INIT_THREAD );
520 /***********************************************************************
521 * CLIENT_BootDone
523 * Signal that we have finished booting, and set debug level.
525 int CLIENT_BootDone( int debug_level )
527 struct boot_done_request *req = get_req_buffer();
528 req->debug_level = debug_level;
529 return server_call( REQ_BOOT_DONE );
533 /***********************************************************************
534 * CLIENT_IsBootThread
536 * Return TRUE if current thread is the boot thread.
538 int CLIENT_IsBootThread(void)
540 return (GetCurrentThreadId() == (DWORD)boot_thread_id);