Release 980726
[wine.git] / scheduler / client.c
blob98f4f753b9530a0266ba0d3352b08bf6938acbad
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/types.h>
12 #include <sys/socket.h>
13 #include <sys/uio.h>
14 #include <unistd.h>
16 #include "process.h"
17 #include "thread.h"
18 #include "server.h"
19 #include "winerror.h"
21 /* Some versions of glibc don't define this */
22 #ifndef SCM_RIGHTS
23 #define SCM_RIGHTS 1
24 #endif
26 /***********************************************************************
27 * CLIENT_SendRequest_v
29 * Send a request to the server.
31 static void CLIENT_SendRequest_v( enum request req, int pass_fd,
32 struct iovec *vec, int veclen )
34 THDB *thdb = THREAD_Current();
35 #ifndef HAVE_MSGHDR_ACCRIGHTS
36 struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, pass_fd };
37 #endif
38 struct msghdr msghdr = { NULL, 0, vec, veclen, };
39 struct header head;
40 int i, ret, len;
42 assert( veclen > 0 );
43 vec[0].iov_base = &head;
44 vec[0].iov_len = sizeof(head);
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) /* we have an fd to send */
54 #ifdef HAVE_MSGHDR_ACCRIGHTS
55 msghdr.msg_accrights = (void *)&pass_fd;
56 msghdr.msg_accrightslen = sizeof(pass_fd);
57 #else
58 msghdr.msg_control = &cmsg;
59 msghdr.msg_controllen = sizeof(cmsg);
60 #endif
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 int pass_fd = -1;
111 #ifdef HAVE_MSGHDR_ACCRIGHTS
112 struct msghdr msghdr = { NULL, 0, vec, veclen, (void*)&pass_fd, sizeof(int) };
113 #else
114 struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
115 struct msghdr msghdr = { NULL, 0, vec, veclen, &cmsg, sizeof(cmsg), 0 };
116 #endif
117 struct header head;
118 int ret, remaining;
120 assert( veclen > 0 );
121 vec[0].iov_base = &head;
122 vec[0].iov_len = sizeof(head);
124 if ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
126 fprintf( stderr, "Fatal protocol error: " );
127 perror("recvmsg");
128 ExitThread(1);
130 if (ret < sizeof(head))
132 fprintf( stderr,
133 "Fatal protocol error: partial header received %d/%d\n",
134 ret, sizeof(head));
135 ExitThread(1);
137 if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
139 fprintf( stderr, "Fatal protocol error: header length %d\n",
140 head.len );
141 ExitThread(1);
143 if (head.seq != thdb->seq++)
145 fprintf( stderr,
146 "Fatal protocol error: sequence %08x instead of %08x\n",
147 head.seq, thdb->seq - 1 );
148 ExitThread(1);
151 #ifndef HAVE_MSGHDR_ACCRIGHTS
152 pass_fd = cmsg.fd;
153 #endif
155 if (head.type != ERROR_SUCCESS)
157 SetLastError( head.type );
159 else if (passed_fd)
161 *passed_fd = pass_fd;
162 pass_fd = -1;
165 if (len) *len = ret - sizeof(head);
166 if (pass_fd != -1) close( pass_fd );
167 remaining = head.len - ret;
168 while (remaining > 0) /* drop remaining data */
170 char buffer[1024];
171 int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
172 if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
174 fprintf( stderr, "Fatal protocol error: " );
175 perror( "recv" );
176 ExitThread(1);
178 remaining -= len;
181 return head.type; /* error code */
185 /***********************************************************************
186 * CLIENT_WaitReply
188 * Wait for a reply from the server.
190 static unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
191 int n, ... /* arg_1, len_1, etc. */ )
193 struct iovec vec[16];
194 va_list args;
195 int i;
197 n++; /* for vec[0] */
198 assert( n < 16 );
199 va_start( args, n );
200 for (i = 1; i < n; i++)
202 vec[i].iov_base = va_arg( args, void * );
203 vec[i].iov_len = va_arg( args, int );
205 va_end( args );
206 return CLIENT_WaitReply_v( len, passed_fd, vec, n );
210 /***********************************************************************
211 * send_new_thread
213 * Send a new thread request. Helper function for CLIENT_NewThread.
215 static int send_new_thread( THDB *thdb )
217 struct new_thread_request request;
218 struct new_thread_reply reply;
219 int len, fd[2];
221 if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
223 SetLastError( ERROR_TOO_MANY_OPEN_FILES ); /* FIXME */
224 return -1;
227 request.pid = thdb->process->server_pid;
228 CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
230 if (CLIENT_WaitReply( &len, NULL, 1, &reply, sizeof(reply) )) goto error;
231 if (len < sizeof(reply)) goto error;
232 thdb->server_tid = reply.tid;
233 thdb->process->server_pid = reply.pid;
234 if (thdb->socket != -1) close( thdb->socket );
235 thdb->socket = fd[0];
236 thdb->seq = 0; /* reset the sequence number for the new fd */
237 return 0;
239 error:
240 close( fd[0] );
241 return -1;
245 /***********************************************************************
246 * CLIENT_NewThread
248 * Send a new thread request.
250 int CLIENT_NewThread( THDB *thdb )
252 extern BOOL32 THREAD_InitDone;
254 if (!THREAD_InitDone) /* first thread -> start the server */
256 int tmpfd[2];
257 char buffer[16];
259 if (socketpair( AF_UNIX, SOCK_STREAM, 0, tmpfd ) == -1)
261 perror("socketpair");
262 exit(1);
264 switch(fork())
266 case -1: /* error */
267 perror("fork");
268 exit(1);
269 case 0: /* child */
270 close( tmpfd[0] );
271 sprintf( buffer, "%d", tmpfd[1] );
272 #ifdef EXEC_SERVER
273 execlp( "wineserver", "wineserver", buffer, NULL );
274 execl( "/usr/local/bin/wineserver", "wineserver", buffer, NULL );
275 execl( "./server/wineserver", "wineserver", buffer, NULL );
276 #endif
277 server_main_loop( tmpfd[1] );
278 exit(0);
279 default: /* parent */
280 close( tmpfd[1] );
281 SET_CUR_THREAD( thdb );
282 THREAD_InitDone = TRUE;
283 thdb->socket = tmpfd[0];
284 break;
288 return send_new_thread( thdb );
292 /***********************************************************************
293 * CLIENT_InitThread
295 * Send an init thread request. Return 0 if OK.
297 int CLIENT_InitThread(void)
299 THDB *thdb = THREAD_Current();
300 struct init_thread_request init;
301 int len = strlen( thdb->process->env_db->cmd_line );
303 init.pid = getpid();
304 len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
306 CLIENT_SendRequest( REQ_INIT_THREAD, -1, 2,
307 &init, sizeof(init),
308 thdb->process->env_db->cmd_line, len );
309 return CLIENT_WaitReply( NULL, NULL, NULL, 0 );