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 /***********************************************************************
31 * CLIENT_ProtocolError
33 static void CLIENT_ProtocolError( const char *err
, ... )
35 THDB
*thdb
= THREAD_Current();
38 va_start( args
, err
);
39 fprintf( stderr
, "Client protocol error:%p: ", thdb
->server_tid
);
40 vfprintf( stderr
, err
, args
);
46 /***********************************************************************
47 * CLIENT_SendRequest_v
49 * Send a request to the server.
51 static void CLIENT_SendRequest_v( enum request req
, int pass_fd
,
52 struct iovec
*vec
, int veclen
)
54 THDB
*thdb
= THREAD_Current();
55 #ifndef HAVE_MSGHDR_ACCRIGHTS
56 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, pass_fd
};
58 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, };
63 vec
[0].iov_base
= &head
;
64 vec
[0].iov_len
= sizeof(head
);
65 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
67 assert( len
<= MAX_MSG_LENGTH
);
70 head
.seq
= thdb
->seq
++;
72 if (pass_fd
!= -1) /* we have an fd to send */
74 #ifdef HAVE_MSGHDR_ACCRIGHTS
75 msghdr
.msg_accrights
= (void *)&pass_fd
;
76 msghdr
.msg_accrightslen
= sizeof(pass_fd
);
78 msghdr
.msg_control
= &cmsg
;
79 msghdr
.msg_controllen
= sizeof(cmsg
);
83 if ((ret
= sendmsg( thdb
->socket
, &msghdr
, 0 )) < len
)
85 if (ret
== -1) perror( "sendmsg" );
86 CLIENT_ProtocolError( "partial msg sent %d/%d\n", ret
, len
);
88 /* we passed the fd now we can close it */
89 if (pass_fd
!= -1) close( pass_fd
);
93 /***********************************************************************
96 * Send a request to the server.
98 void CLIENT_SendRequest( enum request req
, int pass_fd
,
99 int n
, ... /* arg_1, len_1, etc. */ )
101 struct iovec vec
[16];
105 n
++; /* for vec[0] */
108 for (i
= 1; i
< n
; i
++)
110 vec
[i
].iov_base
= va_arg( args
, void * );
111 vec
[i
].iov_len
= va_arg( args
, int );
114 return CLIENT_SendRequest_v( req
, pass_fd
, vec
, n
);
118 /***********************************************************************
121 * Wait for a reply from the server.
122 * Returns the error code (or 0 if OK).
124 static unsigned int CLIENT_WaitReply_v( int *len
, int *passed_fd
,
125 struct iovec
*vec
, int veclen
)
127 THDB
*thdb
= THREAD_Current();
129 #ifdef HAVE_MSGHDR_ACCRIGHTS
130 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, (void*)&pass_fd
, sizeof(int) };
132 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, -1 };
133 struct msghdr msghdr
= { NULL
, 0, vec
, veclen
, &cmsg
, sizeof(cmsg
), 0 };
138 assert( veclen
> 0 );
139 vec
[0].iov_base
= &head
;
140 vec
[0].iov_len
= sizeof(head
);
142 while ((ret
= recvmsg( thdb
->socket
, &msghdr
, 0 )) == -1)
144 if (errno
== EINTR
) continue;
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
167 *passed_fd
= pass_fd
;
171 if (len
) *len
= ret
- sizeof(head
);
172 if (pass_fd
!= -1) close( pass_fd
);
173 remaining
= head
.len
- ret
;
174 while (remaining
> 0) /* get remaining data */
176 char *bufp
, buffer
[1024];
177 int addlen
, i
, iovtot
= 0;
179 /* see if any iovs are still incomplete, otherwise drop the rest */
180 for (i
= 0; i
< veclen
&& remaining
> 0; i
++)
182 if (iovtot
+ vec
[i
].iov_len
> head
.len
- remaining
)
184 addlen
= iovtot
+ vec
[i
].iov_len
- (head
.len
- remaining
);
185 bufp
= (char *)vec
[i
].iov_base
+ (vec
[i
].iov_len
- addlen
);
186 if (addlen
> remaining
) addlen
= remaining
;
187 if ((addlen
= recv( thdb
->socket
, bufp
, addlen
, 0 )) == -1)
190 CLIENT_ProtocolError( "recv\n" );
192 if (!addlen
) ExitThread(1); /* the server closed the connection; time to die... */
193 if (len
) *len
+= addlen
;
196 iovtot
+= vec
[i
].iov_len
;
200 addlen
= remaining
< sizeof(buffer
) ? remaining
: sizeof(buffer
);
204 if ((addlen
= recv( thdb
->socket
, buffer
, addlen
, 0 )) == -1)
207 CLIENT_ProtocolError( "recv\n" );
209 if (!addlen
) ExitThread(1); /* the server closed the connection; time to die... */
213 SetLastError( head
.type
);
214 return head
.type
; /* error code */
218 /***********************************************************************
221 * Wait for a reply from the server.
223 unsigned int CLIENT_WaitReply( int *len
, int *passed_fd
,
224 int n
, ... /* arg_1, len_1, etc. */ )
226 struct iovec vec
[16];
230 n
++; /* for vec[0] */
233 for (i
= 1; i
< n
; i
++)
235 vec
[i
].iov_base
= va_arg( args
, void * );
236 vec
[i
].iov_len
= va_arg( args
, int );
239 return CLIENT_WaitReply_v( len
, passed_fd
, vec
, n
);
243 /***********************************************************************
244 * CLIENT_WaitSimpleReply
246 * Wait for a simple fixed-length reply from the server.
248 unsigned int CLIENT_WaitSimpleReply( void *reply
, int len
, int *passed_fd
)
254 vec
[1].iov_base
= reply
;
255 vec
[1].iov_len
= len
;
256 ret
= CLIENT_WaitReply_v( &got
, passed_fd
, vec
, 2 );
258 CLIENT_ProtocolError( "WaitSimpleReply: len %d != %d\n", len
, got
);
263 /***********************************************************************
266 * Send a new thread request.
268 int CLIENT_NewThread( THDB
*thdb
, int *thandle
, int *phandle
)
270 struct new_thread_request request
;
271 struct new_thread_reply reply
;
274 if (socketpair( AF_UNIX
, SOCK_STREAM
, 0, fd
) == -1)
276 SetLastError( ERROR_TOO_MANY_OPEN_FILES
); /* FIXME */
280 request
.pid
= thdb
->process
->server_pid
;
281 CLIENT_SendRequest( REQ_NEW_THREAD
, fd
[1], 1, &request
, sizeof(request
) );
282 if (CLIENT_WaitSimpleReply( &reply
, sizeof(reply
), NULL
)) goto error
;
283 thdb
->server_tid
= reply
.tid
;
284 thdb
->process
->server_pid
= reply
.pid
;
285 if (thdb
->socket
!= -1) close( thdb
->socket
);
286 thdb
->socket
= fd
[0];
287 thdb
->seq
= 0; /* reset the sequence number for the new fd */
288 fcntl( fd
[0], F_SETFD
, 1 ); /* set close on exec flag */
290 if (thandle
) *thandle
= reply
.thandle
;
291 else if (reply
.thandle
!= -1) CLIENT_CloseHandle( reply
.thandle
);
292 if (phandle
) *phandle
= reply
.phandle
;
293 else if (reply
.phandle
!= -1) CLIENT_CloseHandle( reply
.phandle
);
302 /***********************************************************************
305 * Send an init thread request. Return 0 if OK.
307 int CLIENT_InitThread(void)
309 THDB
*thdb
= THREAD_Current();
310 struct init_thread_request init
;
311 int len
= strlen( thdb
->process
->env_db
->cmd_line
);
313 init
.unix_pid
= getpid();
314 len
= MIN( len
, MAX_MSG_LENGTH
- sizeof(init
) );
316 CLIENT_SendRequest( REQ_INIT_THREAD
, -1, 2,
318 thdb
->process
->env_db
->cmd_line
, len
);
319 return CLIENT_WaitReply( NULL
, NULL
, 0 );
323 /***********************************************************************
326 * Send a set debug level request. Return 0 if OK.
328 int CLIENT_SetDebug( int level
)
330 CLIENT_SendRequest( REQ_SET_DEBUG
, -1, 1, &level
, sizeof(level
) );
331 return CLIENT_WaitReply( NULL
, NULL
, 0 );
334 /***********************************************************************
337 * Send a close handle request. Return 0 if OK.
339 int CLIENT_CloseHandle( int handle
)
341 CLIENT_SendRequest( REQ_CLOSE_HANDLE
, -1, 1, &handle
, sizeof(handle
) );
342 return CLIENT_WaitReply( NULL
, NULL
, 0 );
345 /***********************************************************************
346 * CLIENT_DuplicateHandle
348 * Send a duplicate handle request. Return 0 if OK.
350 int CLIENT_DuplicateHandle( int src_process
, int src_handle
, int dst_process
, int dst_handle
,
351 DWORD access
, BOOL inherit
, DWORD options
)
353 struct dup_handle_request req
;
354 struct dup_handle_reply reply
;
356 req
.src_process
= src_process
;
357 req
.src_handle
= src_handle
;
358 req
.dst_process
= dst_process
;
359 req
.dst_handle
= dst_handle
;
361 req
.inherit
= inherit
;
362 req
.options
= options
;
364 CLIENT_SendRequest( REQ_DUP_HANDLE
, -1, 1, &req
, sizeof(req
) );
365 CLIENT_WaitSimpleReply( &reply
, sizeof(reply
), NULL
);
370 /***********************************************************************
373 * Open a handle to a process.
375 int CLIENT_OpenProcess( void *pid
, DWORD access
, BOOL inherit
)
377 struct open_process_request req
;
378 struct open_process_reply reply
;
382 req
.inherit
= inherit
;
384 CLIENT_SendRequest( REQ_OPEN_PROCESS
, -1, 1, &req
, sizeof(req
) );
385 CLIENT_WaitSimpleReply( &reply
, sizeof(reply
), NULL
);