2 * Server-side socket communication functions
4 * Copyright (C) 1998 Alexandre Julliard
14 #include <sys/types.h>
15 #include <sys/socket.h>
22 #include "server/object.h"
24 /* Some versions of glibc don't define this */
32 RUNNING
, /* running normally */
33 SENDING
, /* sending us a request */
34 WAITING
, /* waiting for us to reply */
35 READING
/* reading our reply */
38 /* client structure */
41 enum state state
; /* client state */
42 unsigned int seq
; /* current sequence number */
43 struct header head
; /* current msg header */
44 char *data
; /* current msg data */
45 int count
; /* bytes sent/received so far */
46 int pass_fd
; /* fd to pass to and from the client */
47 struct thread
*self
; /* client thread (opaque pointer) */
51 /* exit code passed to remove_client */
52 #define OUT_OF_MEMORY -1
53 #define BROKEN_PIPE -2
54 #define PROTOCOL_ERROR -3
57 /* signal a client protocol error */
58 static void protocol_error( int client_fd
, const char *err
, ... )
62 va_start( args
, err
);
63 fprintf( stderr
, "Protocol error:%d: ", client_fd
);
64 vfprintf( stderr
, err
, args
);
68 /* send a message to a client that is ready to receive something */
69 static void do_write( struct client
*client
, int client_fd
)
72 #ifndef HAVE_MSGHDR_ACCRIGHTS
78 /* make sure we have something to send */
79 assert( client
->count
< client
->head
.len
);
80 /* make sure the client is listening */
81 assert( client
->state
== READING
);
83 msghdr
.msg_name
= NULL
;
84 msghdr
.msg_namelen
= 0;
87 if (client
->count
< sizeof(client
->head
))
89 vec
[0].iov_base
= (char *)&client
->head
+ client
->count
;
90 vec
[0].iov_len
= sizeof(client
->head
) - client
->count
;
91 vec
[1].iov_base
= client
->data
;
92 vec
[1].iov_len
= client
->head
.len
- sizeof(client
->head
);
93 msghdr
.msg_iovlen
= 2;
97 vec
[0].iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
98 vec
[0].iov_len
= client
->head
.len
- client
->count
;
99 msghdr
.msg_iovlen
= 1;
102 #ifdef HAVE_MSGHDR_ACCRIGHTS
103 if (client
->pass_fd
!= -1) /* we have an fd to send */
105 msghdr
.msg_accrights
= (void *)&client
->pass_fd
;
106 msghdr
.msg_accrightslen
= sizeof(client
->pass_fd
);
110 msghdr
.msg_accrights
= NULL
;
111 msghdr
.msg_accrightslen
= 0;
113 #else /* HAVE_MSGHDR_ACCRIGHTS */
114 if (client
->pass_fd
!= -1) /* we have an fd to send */
116 cmsg
.len
= sizeof(cmsg
);
117 cmsg
.level
= SOL_SOCKET
;
118 cmsg
.type
= SCM_RIGHTS
;
119 cmsg
.fd
= client
->pass_fd
;
120 msghdr
.msg_control
= &cmsg
;
121 msghdr
.msg_controllen
= sizeof(cmsg
);
125 msghdr
.msg_control
= NULL
;
126 msghdr
.msg_controllen
= 0;
128 msghdr
.msg_flags
= 0;
129 #endif /* HAVE_MSGHDR_ACCRIGHTS */
131 ret
= sendmsg( client_fd
, &msghdr
, 0 );
134 if (errno
!= EPIPE
) perror("sendmsg");
135 remove_client( client_fd
, BROKEN_PIPE
);
138 if (client
->pass_fd
!= -1) /* We sent the fd, now we can close it */
140 close( client
->pass_fd
);
141 client
->pass_fd
= -1;
143 if ((client
->count
+= ret
) < client
->head
.len
) return;
145 /* we have finished with this message */
146 if (client
->data
) free( client
->data
);
149 client
->state
= RUNNING
;
151 set_select_events( client_fd
, READ_EVENT
);
155 /* read a message from a client that has something to say */
156 static void do_read( struct client
*client
, int client_fd
)
162 #ifdef HAVE_MSGHDR_ACCRIGHTS
163 struct msghdr msghdr
;
165 msghdr
.msg_accrights
= (void *)&pass_fd
;
166 msghdr
.msg_accrightslen
= sizeof(int);
167 #else /* HAVE_MSGHDR_ACCRIGHTS */
168 struct msghdr msghdr
;
171 cmsg
.len
= sizeof(cmsg
);
172 cmsg
.level
= SOL_SOCKET
;
173 cmsg
.type
= SCM_RIGHTS
;
175 msghdr
.msg_control
= &cmsg
;
176 msghdr
.msg_controllen
= sizeof(cmsg
);
177 msghdr
.msg_flags
= 0;
178 #endif /* HAVE_MSGHDR_ACCRIGHTS */
180 msghdr
.msg_name
= NULL
;
181 msghdr
.msg_namelen
= 0;
182 msghdr
.msg_iov
= &vec
;
183 msghdr
.msg_iovlen
= 1;
185 if (client
->count
< sizeof(client
->head
))
187 vec
.iov_base
= (char *)&client
->head
+ client
->count
;
188 vec
.iov_len
= sizeof(client
->head
) - client
->count
;
193 !(client
->data
= malloc(client
->head
.len
-sizeof(client
->head
))))
195 remove_client( client_fd
, OUT_OF_MEMORY
);
198 vec
.iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
199 vec
.iov_len
= client
->head
.len
- client
->count
;
202 ret
= recvmsg( client_fd
, &msghdr
, 0 );
206 remove_client( client_fd
, BROKEN_PIPE
);
209 #ifndef HAVE_MSGHDR_ACCRIGHTS
214 /* can only receive one fd per message */
215 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
216 client
->pass_fd
= pass_fd
;
218 else if (!ret
) /* closed pipe */
220 remove_client( client_fd
, BROKEN_PIPE
);
224 if (client
->state
== RUNNING
) client
->state
= SENDING
;
225 assert( client
->state
== SENDING
);
227 client
->count
+= ret
;
229 /* received the complete header yet? */
230 if (client
->count
< sizeof(client
->head
)) return;
233 if (client
->head
.seq
!= client
->seq
)
235 protocol_error( client_fd
, "bad sequence %08x instead of %08x\n",
236 client
->head
.seq
, client
->seq
);
237 remove_client( client_fd
, PROTOCOL_ERROR
);
240 if ((client
->head
.len
< sizeof(client
->head
)) ||
241 (client
->head
.len
> MAX_MSG_LENGTH
+ sizeof(client
->head
)))
243 protocol_error( client_fd
, "bad header length %08x\n",
245 remove_client( client_fd
, PROTOCOL_ERROR
);
249 /* received the whole message? */
250 if (client
->count
== client
->head
.len
)
252 /* done reading the data, call the callback function */
254 int len
= client
->head
.len
- sizeof(client
->head
);
255 char *data
= client
->data
;
256 int passed_fd
= client
->pass_fd
;
257 enum request type
= client
->head
.type
;
259 /* clear the info now, as the client may be deleted by the callback */
260 client
->head
.len
= 0;
261 client
->head
.type
= 0;
264 client
->pass_fd
= -1;
265 client
->state
= WAITING
;
268 call_req_handler( client
->self
, type
, data
, len
, passed_fd
);
269 if (passed_fd
!= -1) close( passed_fd
);
270 if (data
) free( data
);
274 /* handle a client timeout */
275 static void client_timeout( int client_fd
, void *private )
277 struct client
*client
= (struct client
*)private;
278 set_select_timeout( client_fd
, 0 ); /* Remove the timeout */
279 call_timeout_handler( client
->self
);
282 /* handle a client event */
283 static void client_event( int client_fd
, int event
, void *private )
285 struct client
*client
= (struct client
*)private;
286 if (event
& WRITE_EVENT
)
287 do_write( client
, client_fd
);
288 if (event
& READ_EVENT
)
289 do_read( client
, client_fd
);
292 static const struct select_ops client_ops
=
298 /*******************************************************************/
299 /* server-side exported functions */
302 int add_client( int client_fd
, struct thread
*self
)
304 struct client
*client
= malloc( sizeof(*client
) );
305 if (!client
) return -1;
307 client
->state
= RUNNING
;
309 client
->head
.len
= 0;
310 client
->head
.type
= 0;
314 client
->pass_fd
= -1;
316 if (add_select_user( client_fd
, READ_EVENT
, &client_ops
, client
) == -1)
324 /* remove a client */
325 void remove_client( int client_fd
, int exit_code
)
327 struct client
*client
= (struct client
*)get_select_private_data( &client_ops
, client_fd
);
330 call_kill_handler( client
->self
, exit_code
);
332 remove_select_user( client_fd
);
336 if (client
->data
) free( client
->data
);
337 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
341 /* send a reply to a client */
342 int send_reply_v( int client_fd
, int type
, int pass_fd
,
343 struct iovec
*vec
, int veclen
)
348 struct client
*client
= (struct client
*)get_select_private_data( &client_ops
, client_fd
);
351 assert( client
->state
== WAITING
);
352 assert( !client
->data
);
354 if (debug_level
) trace_reply( client
->self
, type
, pass_fd
, vec
, veclen
);
356 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
357 assert( len
< MAX_MSG_LENGTH
);
359 if (len
&& !(client
->data
= malloc( len
))) return -1;
361 client
->head
.len
= len
+ sizeof(client
->head
);
362 client
->head
.type
= type
;
363 client
->head
.seq
= client
->seq
;
364 client
->pass_fd
= pass_fd
;
366 for (i
= 0, p
= client
->data
; i
< veclen
; i
++)
368 memcpy( p
, vec
[i
].iov_base
, vec
[i
].iov_len
);
372 client
->state
= READING
;
373 set_select_events( client_fd
, WRITE_EVENT
);