Added the ability to open several streams on the same driver.
[wine/multimedia.git] / scheduler / client.c
blobd93ee1d3f7452b19b89625696f2807df1b4a7a8f
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 <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>
25 #include "process.h"
26 #include "thread.h"
27 #include "server.h"
28 #include "winerror.h"
30 /* Some versions of glibc don't define this */
31 #ifndef SCM_RIGHTS
32 #define SCM_RIGHTS 1
33 #endif
35 /* data structure used to pass an fd with sendmsg/recvmsg */
36 struct cmsg_fd
38 int len; /* sizeof structure */
39 int level; /* SOL_SOCKET */
40 int type; /* SCM_RIGHTS */
41 int fd; /* fd to pass */
44 /***********************************************************************
45 * CLIENT_Die
47 * Die on protocol errors or socket close
49 static void CLIENT_Die(void)
51 close( NtCurrentTeb()->socket );
52 SYSDEPS_ExitThread();
55 /***********************************************************************
56 * server_protocol_error
58 void server_protocol_error( const char *err, ... )
60 va_list args;
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();
70 /***********************************************************************
71 * server_perror
73 static void server_perror( const char *err )
75 fprintf( stderr, "Client protocol error:%p: ", NtCurrentTeb()->tid );
76 perror( err );
77 CLIENT_Die();
81 /***********************************************************************
82 * send_request
84 * Send a request to the server.
86 static void send_request( enum request req )
88 int ret;
89 if ((ret = write( NtCurrentTeb()->socket, &req, sizeof(req) )) == sizeof(req))
90 return;
91 if (ret == -1)
93 if (errno == EPIPE) CLIENT_Die();
94 server_perror( "sendmsg" );
96 server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
99 /***********************************************************************
100 * send_request_fd
102 * Send a request to the server, passing a file descriptor.
104 static void send_request_fd( enum request req, int fd )
106 int ret;
107 #ifndef HAVE_MSGHDR_ACCRIGHTS
108 struct cmsg_fd cmsg;
109 #endif
110 struct msghdr msghdr;
111 struct iovec vec;
113 vec.iov_base = (void *)&req;
114 vec.iov_len = sizeof(req);
116 msghdr.msg_name = NULL;
117 msghdr.msg_namelen = 0;
118 msghdr.msg_iov = &vec;
119 msghdr.msg_iovlen = 1;
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 */
134 if ((ret = sendmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(req)) return;
135 if (ret == -1)
137 if (errno == EPIPE) CLIENT_Die();
138 server_perror( "sendmsg" );
140 server_protocol_error( "partial msg sent %d/%d\n", ret, sizeof(req) );
143 /***********************************************************************
144 * wait_reply
146 * Wait for a reply from the server.
148 static unsigned int wait_reply(void)
150 int ret;
151 unsigned int res;
153 for (;;)
155 if ((ret = read( NtCurrentTeb()->socket, &res, sizeof(res) )) == sizeof(res))
156 return res;
157 if (ret == -1)
159 if (errno == EINTR) continue;
160 if (errno == EPIPE) CLIENT_Die();
161 server_perror("read");
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) );
169 /***********************************************************************
170 * wait_reply_fd
172 * Wait for a reply from the server, when a file descriptor is passed.
174 static unsigned int wait_reply_fd( int *fd )
176 struct iovec vec;
177 int ret;
178 unsigned int res;
180 #ifdef HAVE_MSGHDR_ACCRIGHTS
181 struct msghdr msghdr;
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;
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 */
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);
206 for (;;)
208 if ((ret = recvmsg( NtCurrentTeb()->socket, &msghdr, 0 )) == sizeof(res))
210 #ifndef HAVE_MSGHDR_ACCRIGHTS
211 *fd = cmsg.fd;
212 #endif
213 return res;
215 if (ret == -1)
217 if (errno == EINTR) continue;
218 if (errno == EPIPE) CLIENT_Die();
219 server_perror("recvmsg");
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) );
227 /***********************************************************************
228 * server_call_noerr
230 * Perform a server call.
232 unsigned int server_call_noerr( enum request req )
234 send_request( req );
235 return wait_reply();
239 /***********************************************************************
240 * server_call_fd
242 * Perform a server call, passing a file descriptor.
243 * If *fd is != -1, it will be passed to the server.
244 * If the server passes an fd, it will be stored into *fd.
246 unsigned int server_call_fd( enum request req, int fd_out, int *fd_in )
248 unsigned int res;
250 if (fd_out == -1) send_request( req );
251 else send_request_fd( req, fd_out );
253 if (fd_in) res = wait_reply_fd( fd_in );
254 else res = wait_reply();
255 if (res) SetLastError( res );
256 return res; /* error code */
260 /***********************************************************************
261 * CLIENT_InitServer
263 * Start the server and create the initial socket pair.
265 int CLIENT_InitServer(void)
267 int fd[2];
268 char buffer[16];
269 extern void create_initial_thread( int fd );
271 if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
273 perror("socketpair");
274 exit(1);
276 switch(fork())
278 case -1: /* error */
279 perror("fork");
280 exit(1);
281 case 0: /* child */
282 close( fd[1] );
283 fcntl( fd[0], F_SETFD, 1 ); /* set close on exec flag */
284 break;
285 default: /* parent */
286 close( fd[0] );
287 sprintf( buffer, "%d", fd[1] );
288 execl( BINDIR "/wineserver", "wineserver", buffer, NULL );
289 execlp( "wineserver", "wineserver", buffer, NULL );
290 execl( "./server/wineserver", "wineserver", buffer, NULL );
291 create_initial_thread( fd[1] );
292 exit(0);
294 return fd[0];
298 /***********************************************************************
299 * CLIENT_InitThread
301 * Send an init thread request. Return 0 if OK.
303 int CLIENT_InitThread(void)
305 struct init_thread_request *req;
306 TEB *teb = NtCurrentTeb();
307 int fd;
309 if (wait_reply_fd( &fd ) || (fd == -1))
310 server_protocol_error( "no fd passed on first request\n" );
311 if ((teb->buffer_size = lseek( fd, 0, SEEK_END )) == -1) server_perror( "lseek" );
312 teb->buffer = mmap( 0, teb->buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
313 close( fd );
314 if (teb->buffer == (void*)-1) server_perror( "mmap" );
316 req = get_req_buffer();
317 req->unix_pid = getpid();
318 req->teb = teb;
319 if (server_call( REQ_INIT_THREAD )) return -1;
320 teb->process->server_pid = req->pid;
321 teb->tid = req->tid;
322 return 0;
326 /***********************************************************************
327 * CLIENT_SetDebug
329 * Send a set debug level request. Return 0 if OK.
331 int CLIENT_SetDebug( int level )
333 struct set_debug_request *req = get_req_buffer();
334 req->level = level;
335 return server_call( REQ_SET_DEBUG );
338 /***********************************************************************
339 * CLIENT_DebuggerRequest
341 * Send a debugger support request. Return 0 if OK.
343 int CLIENT_DebuggerRequest( int op )
345 struct debugger_request *req = get_req_buffer();
346 req->op = op;
347 return server_call( REQ_DEBUGGER );