Release 980712
[wine/multimedia.git] / scheduler / client.c
blobc7910b37f8eceae6e1bd5bd39b8308922fafddb6
1 /*
2 * Client part of the client/server communication
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/uio.h>
13 #include <unistd.h>
15 #include "process.h"
16 #include "thread.h"
17 #include "server.h"
18 #include "winerror.h"
21 /***********************************************************************
22 * CLIENT_SendRequest_v
24 * Send a request to the server.
26 static void CLIENT_SendRequest_v( enum request req, int pass_fd,
27 struct iovec *vec, int veclen )
29 THDB *thdb = THREAD_Current();
30 struct { struct cmsghdr hdr; int fd; } cmsg =
31 { { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS }, pass_fd };
32 struct msghdr msghdr;
33 struct header head;
34 int i, ret, len;
36 msghdr.msg_name = NULL;
37 msghdr.msg_namelen = 0;
39 assert( veclen > 0 );
41 vec[0].iov_base = &head;
42 vec[0].iov_len = sizeof(head);
43 msghdr.msg_iov = vec;
44 msghdr.msg_iovlen = veclen;
45 for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
47 assert( len <= MAX_MSG_LENGTH );
48 head.type = req;
49 head.len = len;
50 head.seq = thdb->seq++;
52 if (pass_fd == -1) /* no fd to pass */
54 msghdr.msg_control = NULL;
55 msghdr.msg_controllen = 0;
57 else
59 msghdr.msg_control = &cmsg;
60 msghdr.msg_controllen = sizeof(cmsg);
63 if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
65 fprintf( stderr, "Fatal protocol error: " );
66 if (ret == -1) perror( "sendmsg" );
67 else fprintf( stderr, "partial msg sent %d/%d\n", ret, len );
68 ExitThread(1);
70 /* we passed the fd now we can close it */
71 if (pass_fd != -1) close( pass_fd );
75 /***********************************************************************
76 * CLIENT_SendRequest
78 * Send a request to the server.
80 static void CLIENT_SendRequest( enum request req, int pass_fd,
81 int n, ... /* arg_1, len_1, etc. */ )
83 struct iovec vec[16];
84 va_list args;
85 int i;
87 n++; /* for vec[0] */
88 assert( n < 16 );
89 va_start( args, n );
90 for (i = 1; i < n; i++)
92 vec[i].iov_base = va_arg( args, void * );
93 vec[i].iov_len = va_arg( args, int );
95 va_end( args );
96 return CLIENT_SendRequest_v( req, pass_fd, vec, n );
100 /***********************************************************************
101 * CLIENT_WaitReply_v
103 * Wait for a reply from the server.
104 * Returns the error code (or 0 if OK).
106 static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
107 struct iovec *vec, int veclen )
109 THDB *thdb = THREAD_Current();
110 struct { struct cmsghdr hdr; int fd; } cmsg =
111 { { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS }, -1 };
112 struct msghdr msghdr;
113 struct header head;
114 int ret, remaining;
116 assert( veclen > 0 );
117 vec[0].iov_base = &head;
118 vec[0].iov_len = sizeof(head);
119 msghdr.msg_name = NULL;
120 msghdr.msg_namelen = 0;
121 msghdr.msg_iov = vec;
122 msghdr.msg_iovlen = veclen;
123 msghdr.msg_control = &cmsg;
124 msghdr.msg_controllen = sizeof(cmsg);
126 if ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
128 fprintf( stderr, "Fatal protocol error: " );
129 perror("recvmsg");
130 ExitThread(1);
132 if (ret < sizeof(head))
134 fprintf( stderr,
135 "Fatal protocol error: partial header received %d/%d\n",
136 ret, sizeof(head));
137 ExitThread(1);
139 if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
141 fprintf( stderr, "Fatal protocol error: header length %d\n",
142 head.len );
143 ExitThread(1);
145 if (head.seq != thdb->seq++)
147 fprintf( stderr,
148 "Fatal protocol error: sequence %08x instead of %08x\n",
149 head.seq, thdb->seq - 1 );
150 ExitThread(1);
153 if (head.type != ERROR_SUCCESS)
155 SetLastError( head.type );
157 else if (passed_fd)
159 *passed_fd = cmsg.fd;
160 cmsg.fd = -1;
163 if (len) *len = ret - sizeof(head);
164 if (cmsg.fd != -1) close( cmsg.fd );
165 remaining = head.len - ret;
166 while (remaining > 0) /* drop remaining data */
168 char buffer[1024];
169 int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
170 if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
172 fprintf( stderr, "Fatal protocol error: " );
173 perror( "recv" );
174 ExitThread(1);
176 remaining -= len;
179 return head.type; /* error code */
183 /***********************************************************************
184 * CLIENT_WaitReply
186 * Wait for a reply from the server.
188 static unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
189 int n, ... /* arg_1, len_1, etc. */ )
191 struct iovec vec[16];
192 va_list args;
193 int i;
195 n++; /* for vec[0] */
196 assert( n < 16 );
197 va_start( args, n );
198 for (i = 1; i < n; i++)
200 vec[i].iov_base = va_arg( args, void * );
201 vec[i].iov_len = va_arg( args, int );
203 va_end( args );
204 return CLIENT_WaitReply_v( len, passed_fd, vec, n );
208 /***********************************************************************
209 * send_new_thread
211 * Send a new thread request. Helper function for CLIENT_NewThread.
213 static int send_new_thread( THDB *thdb )
215 struct new_thread_request request;
216 struct new_thread_reply reply;
217 int len, fd[2];
219 if (socketpair( AF_UNIX, SOCK_STREAM, PF_UNIX, fd ) == -1)
221 SetLastError( ERROR_TOO_MANY_OPEN_FILES ); /* FIXME */
222 return -1;
225 request.pid = thdb->process->server_pid;
226 CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
228 if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) goto error;
229 if (len < sizeof(reply)) goto error;
230 thdb->server_tid = reply.tid;
231 thdb->process->server_pid = reply.pid;
232 if (thdb->socket != -1) close( thdb->socket );
233 thdb->socket = fd[0];
234 thdb->seq = 0; /* reset the sequence number for the new fd */
235 return 0;
237 error:
238 close( fd[0] );
239 return -1;
243 /***********************************************************************
244 * CLIENT_NewThread
246 * Send a new thread request.
248 int CLIENT_NewThread( THDB *thdb )
250 extern BOOL32 THREAD_InitDone;
252 if (!THREAD_InitDone) /* first thread -> start the server */
254 int tmpfd[2];
255 char buffer[16];
257 if (socketpair( AF_UNIX, SOCK_STREAM, PF_UNIX, tmpfd ) == -1)
259 perror("socketpair");
260 exit(1);
262 switch(fork())
264 case -1: /* error */
265 perror("fork");
266 exit(1);
267 case 0: /* child */
268 close( tmpfd[0] );
269 sprintf( buffer, "%d", tmpfd[1] );
270 #ifdef EXEC_SERVER
271 execlp( "wineserver", "wineserver", buffer, NULL );
272 execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
273 execl( "./server/wineserver", "wineserver", buffer, NULL );
274 #endif
275 server_main_loop( tmpfd[1] );
276 exit(0);
277 default: /* parent */
278 close( tmpfd[1] );
279 SET_CUR_THREAD( thdb );
280 THREAD_InitDone = TRUE;
281 thdb->socket = tmpfd[0];
282 break;
286 return send_new_thread( thdb );
290 /***********************************************************************
291 * CLIENT_InitThread
293 * Send an init thread request. Return 0 if OK.
295 int CLIENT_InitThread(void)
297 THDB *thdb = THREAD_Current();
298 struct init_thread_request init;
299 int len = strlen( thdb->process->env_db->cmd_line );
301 init.pid = getpid();
302 len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
304 CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
305 &init, sizeof(init),
306 thdb->process->env_db->cmd_line, len );
307 return CLIENT_WaitReply( NULL, NULL, NULL, 0 );