2 * Client part of the client/server communication
4 * Copyright (C) 1998 Alexandre Julliard
12 #include <sys/types.h>
13 #include <sys/socket.h>
20 #include "server/request.h"
24 /* Some versions of glibc don't define this */
30 /***********************************************************************
33 * Die on protocol errors or socket close
35 static void CLIENT_Die(void)
37 close( THREAD_Current()->socket
);
41 /***********************************************************************
42 * CLIENT_ProtocolError
44 void CLIENT_ProtocolError( const char *err
, ... )
48 va_start( args
, err
);
49 fprintf( stderr
, "Client protocol error:%p: ", CURRENT()->tid
);
50 vfprintf( stderr
, err
, args
);
56 /***********************************************************************
57 * CLIENT_SendRequest_v
59 * Send a request to the server.
61 static void CLIENT_SendRequest_v( enum request req
, int pass_fd
,
62 struct iovec
*vec
, int veclen
)
64 THDB
*thdb
= THREAD_Current();
65 #ifndef HAVE_MSGHDR_ACCRIGHTS
73 vec
[0].iov_base
= &head
;
74 vec
[0].iov_len
= sizeof(head
);
75 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
77 assert( len
<= MAX_MSG_LENGTH
);
80 head
.seq
= thdb
->seq
++;
82 msghdr
.msg_name
= NULL
;
83 msghdr
.msg_namelen
= 0;
85 msghdr
.msg_iovlen
= veclen
;
87 #ifdef HAVE_MSGHDR_ACCRIGHTS
88 if (pass_fd
!= -1) /* we have an fd to send */
90 msghdr
.msg_accrights
= (void *)&pass_fd
;
91 msghdr
.msg_accrightslen
= sizeof(pass_fd
);
95 msghdr
.msg_accrights
= NULL
;
96 msghdr
.msg_accrightslen
= 0;
98 #else /* HAVE_MSGHDR_ACCRIGHTS */
99 if (pass_fd
!= -1) /* we have an fd to send */
101 cmsg
.len
= sizeof(cmsg
);
102 cmsg
.level
= SOL_SOCKET
;
103 cmsg
.type
= SCM_RIGHTS
;
105 msghdr
.msg_control
= &cmsg
;
106 msghdr
.msg_controllen
= sizeof(cmsg
);
110 msghdr
.msg_control
= NULL
;
111 msghdr
.msg_controllen
= 0;
113 msghdr
.msg_flags
= 0;
114 #endif /* HAVE_MSGHDR_ACCRIGHTS */
116 if ((ret
= sendmsg( thdb
->socket
, &msghdr
, 0 )) < len
)
120 if (errno
== EPIPE
) CLIENT_Die();
123 CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret
, len
);
125 /* we passed the fd now we can close it */
126 if (pass_fd
!= -1) close( pass_fd
);
130 /***********************************************************************
133 * Send a request to the server.
135 void CLIENT_SendRequest( enum request req
, int pass_fd
,
136 int n
, ... /* arg_1, len_1, etc. */ )
138 struct iovec vec
[16];
142 n
++; /* for vec[0] */
145 for (i
= 1; i
< n
; i
++)
147 vec
[i
].iov_base
= va_arg( args
, void * );
148 vec
[i
].iov_len
= va_arg( args
, int );
151 CLIENT_SendRequest_v( req
, pass_fd
, vec
, n
);
155 /***********************************************************************
158 * Wait for a reply from the server.
159 * Returns the error code (or 0 if OK).
161 static unsigned int CLIENT_WaitReply_v( int *len
, int *passed_fd
,
162 struct iovec
*vec
, int veclen
)
164 THDB
*thdb
= THREAD_Current();
169 #ifdef HAVE_MSGHDR_ACCRIGHTS
170 struct msghdr msghdr
;
172 msghdr
.msg_accrights
= (void *)&pass_fd
;
173 msghdr
.msg_accrightslen
= sizeof(int);
174 #else /* HAVE_MSGHDR_ACCRIGHTS */
175 struct msghdr msghdr
;
178 cmsg
.len
= sizeof(cmsg
);
179 cmsg
.level
= SOL_SOCKET
;
180 cmsg
.type
= SCM_RIGHTS
;
182 msghdr
.msg_control
= &cmsg
;
183 msghdr
.msg_controllen
= sizeof(cmsg
);
184 msghdr
.msg_flags
= 0;
185 #endif /* HAVE_MSGHDR_ACCRIGHTS */
187 msghdr
.msg_name
= NULL
;
188 msghdr
.msg_namelen
= 0;
189 msghdr
.msg_iov
= vec
;
190 msghdr
.msg_iovlen
= veclen
;
192 assert( veclen
> 0 );
193 vec
[0].iov_base
= &head
;
194 vec
[0].iov_len
= sizeof(head
);
196 while ((ret
= recvmsg( thdb
->socket
, &msghdr
, 0 )) == -1)
198 if (errno
== EINTR
) continue;
199 if (errno
== EPIPE
) CLIENT_Die();
201 CLIENT_ProtocolError( "recvmsg\n" );
203 if (!ret
) CLIENT_Die(); /* the server closed the connection; time to die... */
207 if (ret
< sizeof(head
))
208 CLIENT_ProtocolError( "partial header received %d/%d\n", ret
, sizeof(head
) );
210 if ((head
.len
< sizeof(head
)) || (head
.len
> MAX_MSG_LENGTH
))
211 CLIENT_ProtocolError( "header length %d\n", head
.len
);
213 if (head
.seq
!= thdb
->seq
++)
214 CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head
.seq
, thdb
->seq
- 1 );
216 #ifndef HAVE_MSGHDR_ACCRIGHTS
222 *passed_fd
= pass_fd
;
226 if (len
) *len
= ret
- sizeof(head
);
227 if (pass_fd
!= -1) close( pass_fd
);
228 remaining
= head
.len
- ret
;
229 while (remaining
> 0) /* get remaining data */
231 char *bufp
, buffer
[1024];
232 int addlen
, i
, iovtot
= 0;
234 /* see if any iovs are still incomplete, otherwise drop the rest */
235 for (i
= 0; i
< veclen
&& remaining
> 0; i
++)
237 if (iovtot
+ vec
[i
].iov_len
> head
.len
- remaining
)
239 addlen
= iovtot
+ vec
[i
].iov_len
- (head
.len
- remaining
);
240 bufp
= (char *)vec
[i
].iov_base
+ (vec
[i
].iov_len
- addlen
);
241 if (addlen
> remaining
) addlen
= remaining
;
242 if ((addlen
= recv( thdb
->socket
, bufp
, addlen
, 0 )) == -1)
245 CLIENT_ProtocolError( "recv\n" );
247 if (!addlen
) CLIENT_Die(); /* the server closed the connection; time to die... */
248 if (len
) *len
+= addlen
;
251 iovtot
+= vec
[i
].iov_len
;
255 addlen
= remaining
< sizeof(buffer
) ? remaining
: sizeof(buffer
);
259 if ((addlen
= recv( thdb
->socket
, buffer
, addlen
, 0 )) == -1)
262 CLIENT_ProtocolError( "recv\n" );
264 if (!addlen
) CLIENT_Die(); /* the server closed the connection; time to die... */
268 if (head
.type
) SetLastError( head
.type
);
269 return head
.type
; /* error code */
273 /***********************************************************************
276 * Wait for a reply from the server.
278 unsigned int CLIENT_WaitReply( int *len
, int *passed_fd
,
279 int n
, ... /* arg_1, len_1, etc. */ )
281 struct iovec vec
[16];
285 n
++; /* for vec[0] */
288 for (i
= 1; i
< n
; i
++)
290 vec
[i
].iov_base
= va_arg( args
, void * );
291 vec
[i
].iov_len
= va_arg( args
, int );
294 return CLIENT_WaitReply_v( len
, passed_fd
, vec
, n
);
298 /***********************************************************************
299 * CLIENT_WaitSimpleReply
301 * Wait for a simple fixed-length reply from the server.
303 unsigned int CLIENT_WaitSimpleReply( void *reply
, int len
, int *passed_fd
)
309 vec
[1].iov_base
= reply
;
310 vec
[1].iov_len
= len
;
311 ret
= CLIENT_WaitReply_v( &got
, passed_fd
, vec
, 2 );
313 CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len
, got
);
318 /***********************************************************************
321 * Start the server and create the initial socket pair.
323 int CLIENT_InitServer(void)
327 extern void create_initial_thread( int fd
);
329 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, fd
) == -1)
331 perror("socketpair");
342 default: /* parent */
344 sprintf( buffer
, "%d", fd
[1] );
345 /*#define EXEC_SERVER*/
347 execlp( "wineserver", "wineserver", buffer
, NULL
);
348 execl( "/usr/local/bin/wineserver", "wineserver", buffer
, NULL
);
349 execl( "./server/wineserver", "wineserver", buffer
, NULL
);
351 create_initial_thread( fd
[1] );
358 /***********************************************************************
361 * Send an init thread request. Return 0 if OK.
363 int CLIENT_InitThread(void)
365 THDB
*thdb
= THREAD_Current();
366 struct init_thread_request req
;
367 struct init_thread_reply reply
;
369 req
.unix_pid
= getpid();
370 req
.teb
= &thdb
->teb
;
371 CLIENT_SendRequest( REQ_INIT_THREAD
, -1, 1, &req
, sizeof(req
) );
372 if (CLIENT_WaitSimpleReply( &reply
, sizeof(reply
), NULL
)) return -1;
373 thdb
->process
->server_pid
= reply
.pid
;
374 thdb
->teb
.tid
= reply
.tid
;
379 /***********************************************************************
382 * Send a set debug level request. Return 0 if OK.
384 int CLIENT_SetDebug( int level
)
386 CLIENT_SendRequest( REQ_SET_DEBUG
, -1, 1, &level
, sizeof(level
) );
387 return CLIENT_WaitReply( NULL
, NULL
, 0 );
390 /***********************************************************************
391 * CLIENT_DebuggerRequest
393 * Send a debugger support request. Return 0 if OK.
395 int CLIENT_DebuggerRequest( int op
)
397 struct debugger_request req
;
399 CLIENT_SendRequest( REQ_DEBUGGER
, -1, 1, &req
, sizeof(req
) );
400 return CLIENT_WaitReply( NULL
, NULL
, 0 );