blob: 98f4f753b9530a0266ba0d3352b08bf6938acbad [file] [log] [blame]
Alexandre Julliard642d3131998-07-12 19:29:36 +00001/*
2 * Client part of the client/server communication
3 *
4 * Copyright (C) 1998 Alexandre Julliard
5 */
6
7#include <assert.h>
8#include <errno.h>
9#include <stdio.h>
10#include <string.h>
Alexandre Julliard829fe321998-07-26 14:27:39 +000011#include <sys/types.h>
Alexandre Julliard642d3131998-07-12 19:29:36 +000012#include <sys/socket.h>
13#include <sys/uio.h>
14#include <unistd.h>
15
16#include "process.h"
17#include "thread.h"
18#include "server.h"
19#include "winerror.h"
20
Alexandre Julliard829fe321998-07-26 14:27:39 +000021/* Some versions of glibc don't define this */
22#ifndef SCM_RIGHTS
23#define SCM_RIGHTS 1
24#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000025
26/***********************************************************************
27 * CLIENT_SendRequest_v
28 *
29 * Send a request to the server.
30 */
31static void CLIENT_SendRequest_v( enum request req, int pass_fd,
32 struct iovec *vec, int veclen )
33{
34 THDB *thdb = THREAD_Current();
Alexandre Julliard829fe321998-07-26 14:27:39 +000035#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, };
Alexandre Julliard642d3131998-07-12 19:29:36 +000039 struct header head;
40 int i, ret, len;
41
Alexandre Julliard642d3131998-07-12 19:29:36 +000042 assert( veclen > 0 );
Alexandre Julliard829fe321998-07-26 14:27:39 +000043 vec[0].iov_base = &head;
44 vec[0].iov_len = sizeof(head);
Alexandre Julliard642d3131998-07-12 19:29:36 +000045 for (i = len = 0; i < veclen; i++) len += vec[i].iov_len;
46
47 assert( len <= MAX_MSG_LENGTH );
48 head.type = req;
49 head.len = len;
50 head.seq = thdb->seq++;
51
Alexandre Julliard829fe321998-07-26 14:27:39 +000052 if (pass_fd != -1) /* we have an fd to send */
Alexandre Julliard642d3131998-07-12 19:29:36 +000053 {
Alexandre Julliard829fe321998-07-26 14:27:39 +000054#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;
Alexandre Julliard642d3131998-07-12 19:29:36 +000059 msghdr.msg_controllen = sizeof(cmsg);
Alexandre Julliard829fe321998-07-26 14:27:39 +000060#endif
Alexandre Julliard642d3131998-07-12 19:29:36 +000061 }
62
63 if ((ret = sendmsg( thdb->socket, &msghdr, 0 )) < len)
64 {
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);
69 }
70 /* we passed the fd now we can close it */
71 if (pass_fd != -1) close( pass_fd );
72}
73
74
75/***********************************************************************
76 * CLIENT_SendRequest
77 *
78 * Send a request to the server.
79 */
80static void CLIENT_SendRequest( enum request req, int pass_fd,
81 int n, ... /* arg_1, len_1, etc. */ )
82{
83 struct iovec vec[16];
84 va_list args;
85 int i;
86
87 n++; /* for vec[0] */
88 assert( n < 16 );
89 va_start( args, n );
90 for (i = 1; i < n; i++)
91 {
92 vec[i].iov_base = va_arg( args, void * );
93 vec[i].iov_len = va_arg( args, int );
94 }
95 va_end( args );
96 return CLIENT_SendRequest_v( req, pass_fd, vec, n );
97}
98
99
100/***********************************************************************
101 * CLIENT_WaitReply_v
102 *
103 * Wait for a reply from the server.
104 * Returns the error code (or 0 if OK).
105 */
106static unsigned int CLIENT_WaitReply_v( int *len, int *passed_fd,
107 struct iovec *vec, int veclen )
108{
109 THDB *thdb = THREAD_Current();
Alexandre Julliard829fe321998-07-26 14:27:39 +0000110 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
Alexandre Julliard642d3131998-07-12 19:29:36 +0000117 struct header head;
118 int ret, remaining;
119
120 assert( veclen > 0 );
121 vec[0].iov_base = &head;
122 vec[0].iov_len = sizeof(head);
Alexandre Julliard642d3131998-07-12 19:29:36 +0000123
124 if ((ret = recvmsg( thdb->socket, &msghdr, 0 )) == -1)
125 {
126 fprintf( stderr, "Fatal protocol error: " );
127 perror("recvmsg");
128 ExitThread(1);
129 }
130 if (ret < sizeof(head))
131 {
132 fprintf( stderr,
133 "Fatal protocol error: partial header received %d/%d\n",
134 ret, sizeof(head));
135 ExitThread(1);
136 }
137 if ((head.len < sizeof(head)) || (head.len > MAX_MSG_LENGTH))
138 {
139 fprintf( stderr, "Fatal protocol error: header length %d\n",
140 head.len );
141 ExitThread(1);
142 }
143 if (head.seq != thdb->seq++)
144 {
145 fprintf( stderr,
146 "Fatal protocol error: sequence %08x instead of %08x\n",
147 head.seq, thdb->seq - 1 );
148 ExitThread(1);
149 }
150
Alexandre Julliard829fe321998-07-26 14:27:39 +0000151#ifndef HAVE_MSGHDR_ACCRIGHTS
152 pass_fd = cmsg.fd;
153#endif
154
Alexandre Julliard642d3131998-07-12 19:29:36 +0000155 if (head.type != ERROR_SUCCESS)
156 {
157 SetLastError( head.type );
158 }
159 else if (passed_fd)
160 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000161 *passed_fd = pass_fd;
162 pass_fd = -1;
Alexandre Julliard642d3131998-07-12 19:29:36 +0000163 }
164
165 if (len) *len = ret - sizeof(head);
Alexandre Julliard829fe321998-07-26 14:27:39 +0000166 if (pass_fd != -1) close( pass_fd );
Alexandre Julliard642d3131998-07-12 19:29:36 +0000167 remaining = head.len - ret;
168 while (remaining > 0) /* drop remaining data */
169 {
170 char buffer[1024];
171 int len = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
172 if ((len = recv( thdb->socket, buffer, len, 0 )) == -1)
173 {
174 fprintf( stderr, "Fatal protocol error: " );
175 perror( "recv" );
176 ExitThread(1);
177 }
178 remaining -= len;
179 }
180
181 return head.type; /* error code */
182}
183
184
185/***********************************************************************
186 * CLIENT_WaitReply
187 *
188 * Wait for a reply from the server.
189 */
190static unsigned int CLIENT_WaitReply( int *len, int *passed_fd,
191 int n, ... /* arg_1, len_1, etc. */ )
192{
193 struct iovec vec[16];
194 va_list args;
195 int i;
196
197 n++; /* for vec[0] */
198 assert( n < 16 );
199 va_start( args, n );
200 for (i = 1; i < n; i++)
201 {
202 vec[i].iov_base = va_arg( args, void * );
203 vec[i].iov_len = va_arg( args, int );
204 }
205 va_end( args );
206 return CLIENT_WaitReply_v( len, passed_fd, vec, n );
207}
208
209
210/***********************************************************************
211 * send_new_thread
212 *
213 * Send a new thread request. Helper function for CLIENT_NewThread.
214 */
215static int send_new_thread( THDB *thdb )
216{
217 struct new_thread_request request;
218 struct new_thread_reply reply;
219 int len, fd[2];
220
Alexandre Julliard829fe321998-07-26 14:27:39 +0000221 if (socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000222 {
223 SetLastError( ERROR_TOO_MANY_OPEN_FILES ); /* FIXME */
224 return -1;
225 }
226
227 request.pid = thdb->process->server_pid;
228 CLIENT_SendRequest( REQ_NEW_THREAD, fd[1], 1, &request, sizeof(request) );
229
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;
238
239 error:
240 close( fd[0] );
241 return -1;
242}
243
244
245/***********************************************************************
246 * CLIENT_NewThread
247 *
248 * Send a new thread request.
249 */
250int CLIENT_NewThread( THDB *thdb )
251{
252 extern BOOL32 THREAD_InitDone;
253
254 if (!THREAD_InitDone) /* first thread -> start the server */
255 {
256 int tmpfd[2];
257 char buffer[16];
258
Alexandre Julliard829fe321998-07-26 14:27:39 +0000259 if (socketpair( AF_UNIX, SOCK_STREAM, 0, tmpfd ) == -1)
Alexandre Julliard642d3131998-07-12 19:29:36 +0000260 {
261 perror("socketpair");
262 exit(1);
263 }
264 switch(fork())
265 {
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;
285 }
286 }
287
288 return send_new_thread( thdb );
289}
290
291
292/***********************************************************************
293 * CLIENT_InitThread
294 *
295 * Send an init thread request. Return 0 if OK.
296 */
297int CLIENT_InitThread(void)
298{
299 THDB *thdb = THREAD_Current();
300 struct init_thread_request init;
301 int len = strlen( thdb->process->env_db->cmd_line );
302
303 init.pid = getpid();
304 len = MIN( len, MAX_MSG_LENGTH - sizeof(init) );
305
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 );
310}