2 * Client part of the client/server communication
4 * Copyright (C) 1998 Alexandre Julliard
11 #include <sys/types.h>
12 #include <sys/socket.h>
19 #include "server/request.h"
22 /* Some versions of glibc don't define this */
27 #define CHECK_LEN(len,wanted) \
28 if ((len) == (wanted)) ; \
29 else CLIENT_ProtocolError( __FUNCTION__ ": len %d != %d\n", (len), (wanted) );
31 /***********************************************************************
32 * CLIENT_ProtocolError
34 static void CLIENT_ProtocolError( const char *err
, ... )
36 THDB
*thdb
= THREAD_Current();
39 va_start( args
, err
);
40 fprintf( stderr
, "Client protocol error:%p: ", thdb
->server_tid
);
41 vfprintf( stderr
, err
, args
);
47 /***********************************************************************
48 * CLIENT_SendRequest_v
50 * Send a request to the server.
52 static void CLIENT_SendRequest_v( enum request req
, int pass_fd
,
53 struct iovec
*vec
, int veclen
)
55 THDB
*thdb
= THREAD_Current();
56 #ifndef HAVE_MSGHDR_ACCRIGHTS
57 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, pass_fd
};
59 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, };
64 vec
[0].iov_base
= &head
;
65 vec
[0].iov_len
= sizeof(head
);
66 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
68 assert( len
<= MAX_MSG_LENGTH
);
71 head
.seq
= thdb
->seq
++;
73 if (pass_fd
!= -1) /* we have an fd to send */
75 #ifdef HAVE_MSGHDR_ACCRIGHTS
76 msghdr
.msg_accrights
= (void *)&pass_fd
;
77 msghdr
.msg_accrightslen
= sizeof(pass_fd
);
79 msghdr
.msg_control
= &cmsg
;
80 msghdr
.msg_controllen
= sizeof(cmsg
);
84 if ((ret
= sendmsg( thdb
->socket
, &msghdr
, 0 )) < len
)
86 if (ret
== -1) perror( "sendmsg" );
87 CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret
, len
);
89 /* we passed the fd now we can close it */
90 if (pass_fd
!= -1) close( pass_fd
);
94 /***********************************************************************
97 * Send a request to the server.
99 static void CLIENT_SendRequest( enum request req
, int pass_fd
,
100 int n
, ... /* arg_1, len_1, etc. */ )
102 struct iovec vec
[16];
106 n
++; /* for vec[0] */
109 for (i
= 1; i
< n
; i
++)
111 vec
[i
].iov_base
= va_arg( args
, void * );
112 vec
[i
].iov_len
= va_arg( args
, int );
115 return CLIENT_SendRequest_v( req
, pass_fd
, vec
, n
);
119 /***********************************************************************
122 * Wait for a reply from the server.
123 * Returns the error code (or 0 if OK).
125 static unsigned int CLIENT_WaitReply_v( int *len
, int *passed_fd
,
126 struct iovec
*vec
, int veclen
)
128 THDB
*thdb
= THREAD_Current();
130 #ifdef HAVE_MSGHDR_ACCRIGHTS
131 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, (void*)&pass_fd
, sizeof(int) };
133 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, -1 };
134 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, &cmsg
, sizeof(cmsg
), 0 };
139 assert( veclen
> 0 );
140 vec
[0].iov_base
= &head
;
141 vec
[0].iov_len
= sizeof(head
);
143 if ((ret
= recvmsg( thdb
->socket
, &msghdr
, 0 )) == -1)
146 CLIENT_ProtocolError( "recvmsg\n" );
148 if (!ret
) ExitThread(1); /* the server closed the connection; time to die... */
152 if (ret
< sizeof(head
))
153 CLIENT_ProtocolError( "partial header received %d/%d\n", ret
, sizeof(head
) );
155 if ((head
.len
< sizeof(head
)) || (head
.len
> MAX_MSG_LENGTH
))
156 CLIENT_ProtocolError( "header length %d\n", head
.len
);
158 if (head
.seq
!= thdb
->seq
++)
159 CLIENT_ProtocolError( "sequence %08x instead of %08x\n", head
.seq
, thdb
->seq
- 1 );
161 #ifndef HAVE_MSGHDR_ACCRIGHTS
165 if (head
.type
!= ERROR_SUCCESS
)
167 SetLastError( head
.type
);
171 *passed_fd
= pass_fd
;
175 if (len
) *len
= ret
- sizeof(head
);
176 if (pass_fd
!= -1) close( pass_fd
);
177 remaining
= head
.len
- ret
;
178 while (remaining
> 0) /* drop remaining data */
181 int len
= remaining
< sizeof(buffer
) ? remaining
: sizeof(buffer
);
182 if ((len
= recv( thdb
->socket
, buffer
, len
, 0 )) == -1)
185 CLIENT_ProtocolError( "recv\n" );
187 if (!len
) ExitThread(1); /* the server closed the connection; time to die... */
191 return head
.type
; /* error code */
195 /***********************************************************************
198 * Wait for a reply from the server.
200 static unsigned int CLIENT_WaitReply( int *len
, int *passed_fd
,
201 int n
, ... /* arg_1, len_1, etc. */ )
203 struct iovec vec
[16];
207 n
++; /* for vec[0] */
210 for (i
= 1; i
< n
; i
++)
212 vec
[i
].iov_base
= va_arg( args
, void * );
213 vec
[i
].iov_len
= va_arg( args
, int );
216 return CLIENT_WaitReply_v( len
, passed_fd
, vec
, n
);
220 /***********************************************************************
223 * Send a new thread request.
225 int CLIENT_NewThread( THDB
*thdb
, int *thandle
, int *phandle
)
227 struct new_thread_request request
;
228 struct new_thread_reply reply
;
230 extern BOOL32 THREAD_InitDone
;
231 extern void server_main_loop( int fd
);
233 if (!THREAD_InitDone
) /* first thread -> start the server */
238 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, tmpfd
) == -1)
240 perror("socketpair");
250 sprintf( buffer
, "%d", tmpfd
[1] );
252 execlp( "wineserver", "wineserver", buffer
, NULL
);
253 execl( "/usr/local/bin/wineserver", "wineserver", buffer
, NULL
);
254 execl( "./server/wineserver", "wineserver", buffer
, NULL
);
256 server_main_loop( tmpfd
[1] );
258 default: /* parent */
260 SET_CUR_THREAD( thdb
);
261 THREAD_InitDone
= TRUE
;
262 thdb
->socket
= tmpfd
[0];
267 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, fd
) == -1)
269 SetLastError( ERROR_TOO_MANY_OPEN_FILES
); /* FIXME */
273 request
.pid
= thdb
->process
->server_pid
;
274 CLIENT_SendRequest( REQ_NEW_THREAD
, fd
[1], 1, &request
, sizeof(request
) );
276 if (CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) )) goto error
;
277 if (len
< sizeof(reply
)) goto error
;
278 thdb
->server_tid
= reply
.tid
;
279 thdb
->process
->server_pid
= reply
.pid
;
280 if (thdb
->socket
!= -1) close( thdb
->socket
);
281 thdb
->socket
= fd
[0];
282 thdb
->seq
= 0; /* reset the sequence number for the new fd */
284 /* we don't need the handles for now */
285 if (thandle
) *thandle
= reply
.thandle
;
286 else if (reply
.thandle
!= -1) CLIENT_CloseHandle( reply
.thandle
);
287 if (phandle
) *phandle
= reply
.phandle
;
288 else if (reply
.phandle
!= -1) CLIENT_CloseHandle( reply
.phandle
);
297 /***********************************************************************
300 * Send an init thread request. Return 0 if OK.
302 int CLIENT_InitThread(void)
304 THDB
*thdb
= THREAD_Current();
305 struct init_thread_request init
;
306 int len
= strlen( thdb
->process
->env_db
->cmd_line
);
308 init
.unix_pid
= getpid();
309 len
= MIN( len
, MAX_MSG_LENGTH
- sizeof(init
) );
311 CLIENT_SendRequest( REQ_INIT_THREAD
, -1, 2,
313 thdb
->process
->env_db
->cmd_line
, len
);
314 return CLIENT_WaitReply( NULL
, NULL
, 0 );
318 /***********************************************************************
319 * CLIENT_TerminateProcess
321 * Send a terminate process request. Return 0 if OK.
323 int CLIENT_TerminateProcess( int handle
, int exit_code
)
325 CLIENT_SendRequest( REQ_TERMINATE_PROCESS
, -1, 2,
326 &handle
, sizeof(handle
),
327 &exit_code
, sizeof(exit_code
) );
328 return CLIENT_WaitReply( NULL
, NULL
, 0 );
331 /***********************************************************************
332 * CLIENT_TerminateThread
334 * Send a terminate thread request. Return 0 if OK.
336 int CLIENT_TerminateThread( int handle
, int exit_code
)
338 CLIENT_SendRequest( REQ_TERMINATE_THREAD
, -1, 2,
339 &handle
, sizeof(handle
),
340 &exit_code
, sizeof(exit_code
) );
341 return CLIENT_WaitReply( NULL
, NULL
, 0 );
344 /***********************************************************************
347 * Send a close handle request. Return 0 if OK.
349 int CLIENT_CloseHandle( int handle
)
351 CLIENT_SendRequest( REQ_CLOSE_HANDLE
, -1, 1, &handle
, sizeof(handle
) );
352 return CLIENT_WaitReply( NULL
, NULL
, 0 );
355 /***********************************************************************
356 * CLIENT_DuplicateHandle
358 * Send a duplicate handle request. Return 0 if OK.
360 int CLIENT_DuplicateHandle( int src_process
, int src_handle
, int dst_process
, int dst_handle
,
361 DWORD access
, BOOL32 inherit
, DWORD options
)
363 struct dup_handle_request req
;
364 struct dup_handle_reply reply
;
367 req
.src_process
= src_process
;
368 req
.src_handle
= src_handle
;
369 req
.dst_process
= dst_process
;
370 req
.dst_handle
= dst_handle
;
372 req
.inherit
= inherit
;
373 req
.options
= options
;
375 CLIENT_SendRequest( REQ_DUP_HANDLE
, -1, 1, &req
, sizeof(req
) );
376 CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) );
377 CHECK_LEN( len
, sizeof(reply
) );
381 /***********************************************************************
382 * CLIENT_GetProcessInfo
384 * Send a get process info request. Return 0 if OK.
386 int CLIENT_GetProcessInfo( int handle
, struct get_process_info_reply
*reply
)
390 CLIENT_SendRequest( REQ_GET_PROCESS_INFO
, -1, 1, &handle
, sizeof(handle
) );
391 err
= CLIENT_WaitReply( &len
, NULL
, 1, reply
, sizeof(*reply
) );
392 CHECK_LEN( len
, sizeof(*reply
) );
397 /***********************************************************************
400 * Open a handle to a process.
402 int CLIENT_OpenProcess( void *pid
, DWORD access
, BOOL32 inherit
)
404 struct open_process_request req
;
405 struct open_process_reply reply
;
410 req
.inherit
= inherit
;
412 CLIENT_SendRequest( REQ_OPEN_PROCESS
, -1, 1, &req
, sizeof(req
) );
413 CLIENT_WaitReply( &len
, NULL
, 1, &reply
, sizeof(reply
) );
414 CHECK_LEN( len
, sizeof(reply
) );