2 * Server-side socket communication functions
4 * Copyright (C) 1998 Alexandre Julliard
15 #include <sys/types.h>
16 #include <sys/socket.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 struct select_user select
; /* select user */
43 unsigned int seq
; /* current sequence number */
44 struct header head
; /* current msg header */
45 char *data
; /* current msg data */
46 int count
; /* bytes sent/received so far */
47 int pass_fd
; /* fd to pass to and from the client */
48 struct thread
*self
; /* client thread (opaque pointer) */
49 struct timeout_user
*timeout
; /* current timeout (opaque pointer) */
53 /* exit code passed to remove_client */
54 #define OUT_OF_MEMORY -1
55 #define BROKEN_PIPE -2
56 #define PROTOCOL_ERROR -3
59 /* signal a client protocol error */
60 static void protocol_error( struct client
*client
, const char *err
, ... )
64 va_start( args
, err
);
65 fprintf( stderr
, "Protocol error:%d: ", client
->select
.fd
);
66 vfprintf( stderr
, err
, args
);
70 /* send a message to a client that is ready to receive something */
71 static void do_write( struct client
*client
, int client_fd
)
74 #ifndef HAVE_MSGHDR_ACCRIGHTS
80 /* make sure we have something to send */
81 assert( client
->count
< client
->head
.len
);
82 /* make sure the client is listening */
83 assert( client
->state
== READING
);
85 msghdr
.msg_name
= NULL
;
86 msghdr
.msg_namelen
= 0;
89 if (client
->count
< sizeof(client
->head
))
91 vec
[0].iov_base
= (char *)&client
->head
+ client
->count
;
92 vec
[0].iov_len
= sizeof(client
->head
) - client
->count
;
93 vec
[1].iov_base
= client
->data
;
94 vec
[1].iov_len
= client
->head
.len
- sizeof(client
->head
);
95 msghdr
.msg_iovlen
= 2;
99 vec
[0].iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
100 vec
[0].iov_len
= client
->head
.len
- client
->count
;
101 msghdr
.msg_iovlen
= 1;
104 #ifdef HAVE_MSGHDR_ACCRIGHTS
105 if (client
->pass_fd
!= -1) /* we have an fd to send */
107 msghdr
.msg_accrights
= (void *)&client
->pass_fd
;
108 msghdr
.msg_accrightslen
= sizeof(client
->pass_fd
);
112 msghdr
.msg_accrights
= NULL
;
113 msghdr
.msg_accrightslen
= 0;
115 #else /* HAVE_MSGHDR_ACCRIGHTS */
116 if (client
->pass_fd
!= -1) /* we have an fd to send */
118 cmsg
.len
= sizeof(cmsg
);
119 cmsg
.level
= SOL_SOCKET
;
120 cmsg
.type
= SCM_RIGHTS
;
121 cmsg
.fd
= client
->pass_fd
;
122 msghdr
.msg_control
= &cmsg
;
123 msghdr
.msg_controllen
= sizeof(cmsg
);
127 msghdr
.msg_control
= NULL
;
128 msghdr
.msg_controllen
= 0;
130 msghdr
.msg_flags
= 0;
131 #endif /* HAVE_MSGHDR_ACCRIGHTS */
133 ret
= sendmsg( client_fd
, &msghdr
, 0 );
136 if (errno
!= EPIPE
) perror("sendmsg");
137 remove_client( client
, BROKEN_PIPE
);
140 if (client
->pass_fd
!= -1) /* We sent the fd, now we can close it */
142 close( client
->pass_fd
);
143 client
->pass_fd
= -1;
145 if ((client
->count
+= ret
) < client
->head
.len
) return;
147 /* we have finished with this message */
148 if (client
->data
) free( client
->data
);
151 client
->state
= RUNNING
;
153 set_select_events( &client
->select
, READ_EVENT
);
157 /* read a message from a client that has something to say */
158 static void do_read( struct client
*client
, int client_fd
)
164 #ifdef HAVE_MSGHDR_ACCRIGHTS
165 struct msghdr msghdr
;
167 msghdr
.msg_accrights
= (void *)&pass_fd
;
168 msghdr
.msg_accrightslen
= sizeof(int);
169 #else /* HAVE_MSGHDR_ACCRIGHTS */
170 struct msghdr msghdr
;
173 cmsg
.len
= sizeof(cmsg
);
174 cmsg
.level
= SOL_SOCKET
;
175 cmsg
.type
= SCM_RIGHTS
;
177 msghdr
.msg_control
= &cmsg
;
178 msghdr
.msg_controllen
= sizeof(cmsg
);
179 msghdr
.msg_flags
= 0;
180 #endif /* HAVE_MSGHDR_ACCRIGHTS */
182 msghdr
.msg_name
= NULL
;
183 msghdr
.msg_namelen
= 0;
184 msghdr
.msg_iov
= &vec
;
185 msghdr
.msg_iovlen
= 1;
187 if (client
->count
< sizeof(client
->head
))
189 vec
.iov_base
= (char *)&client
->head
+ client
->count
;
190 vec
.iov_len
= sizeof(client
->head
) - client
->count
;
195 !(client
->data
= malloc(client
->head
.len
-sizeof(client
->head
))))
197 remove_client( client
, OUT_OF_MEMORY
);
200 vec
.iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
201 vec
.iov_len
= client
->head
.len
- client
->count
;
204 ret
= recvmsg( client_fd
, &msghdr
, 0 );
208 remove_client( client
, BROKEN_PIPE
);
211 #ifndef HAVE_MSGHDR_ACCRIGHTS
216 /* can only receive one fd per message */
217 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
218 client
->pass_fd
= pass_fd
;
220 else if (!ret
) /* closed pipe */
222 remove_client( client
, BROKEN_PIPE
);
226 if (client
->state
== RUNNING
) client
->state
= SENDING
;
227 assert( client
->state
== SENDING
);
229 client
->count
+= ret
;
231 /* received the complete header yet? */
232 if (client
->count
< sizeof(client
->head
)) return;
235 if (client
->head
.seq
!= client
->seq
)
237 protocol_error( client
, "bad sequence %08x instead of %08x\n",
238 client
->head
.seq
, client
->seq
);
239 remove_client( client
, PROTOCOL_ERROR
);
242 if ((client
->head
.len
< sizeof(client
->head
)) ||
243 (client
->head
.len
> MAX_MSG_LENGTH
+ sizeof(client
->head
)))
245 protocol_error( client
, "bad header length %08x\n",
247 remove_client( client
, PROTOCOL_ERROR
);
251 /* received the whole message? */
252 if (client
->count
== client
->head
.len
)
254 /* done reading the data, call the callback function */
256 int len
= client
->head
.len
- sizeof(client
->head
);
257 char *data
= client
->data
;
258 int passed_fd
= client
->pass_fd
;
259 enum request type
= client
->head
.type
;
261 /* clear the info now, as the client may be deleted by the callback */
262 client
->head
.len
= 0;
263 client
->head
.type
= 0;
266 client
->pass_fd
= -1;
267 client
->state
= WAITING
;
270 call_req_handler( client
->self
, type
, data
, len
, passed_fd
);
271 if (passed_fd
!= -1) close( passed_fd
);
272 if (data
) free( data
);
276 /* handle a client event */
277 static void client_event( int event
, void *private )
279 struct client
*client
= (struct client
*)private;
280 if (event
& WRITE_EVENT
) do_write( client
, client
->select
.fd
);
281 if (event
& READ_EVENT
) do_read( client
, client
->select
.fd
);
285 /*******************************************************************/
286 /* server-side exported functions */
289 struct client
*add_client( int fd
, struct thread
*self
)
292 struct client
*client
= mem_alloc( sizeof(*client
) );
293 if (!client
) return NULL
;
295 flags
= fcntl( fd
, F_GETFL
, 0 );
296 fcntl( fd
, F_SETFL
, flags
| O_NONBLOCK
);
298 client
->state
= RUNNING
;
299 client
->select
.fd
= fd
;
300 client
->select
.func
= client_event
;
301 client
->select
.private = client
;
303 client
->head
.len
= 0;
304 client
->head
.type
= 0;
308 client
->timeout
= NULL
;
309 client
->pass_fd
= -1;
310 register_select_user( &client
->select
);
311 set_select_events( &client
->select
, READ_EVENT
);
315 /* remove a client */
316 void remove_client( struct client
*client
, int exit_code
)
320 call_kill_handler( client
->self
, exit_code
);
322 if (client
->timeout
) remove_timeout_user( client
->timeout
);
323 unregister_select_user( &client
->select
);
324 close( client
->select
.fd
);
327 if (client
->data
) free( client
->data
);
328 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
332 /* send a reply to a client */
333 int send_reply_v( struct client
*client
, int type
, int pass_fd
,
334 struct iovec
*vec
, int veclen
)
341 assert( client
->state
== WAITING
);
342 assert( !client
->data
);
344 if (debug_level
) trace_reply( client
->self
, type
, pass_fd
, vec
, veclen
);
346 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
347 assert( len
< MAX_MSG_LENGTH
);
349 if (len
&& !(client
->data
= malloc( len
))) return -1;
351 client
->head
.len
= len
+ sizeof(client
->head
);
352 client
->head
.type
= type
;
353 client
->head
.seq
= client
->seq
;
354 client
->pass_fd
= pass_fd
;
356 for (i
= 0, p
= client
->data
; i
< veclen
; i
++)
358 memcpy( p
, vec
[i
].iov_base
, vec
[i
].iov_len
);
362 client
->state
= READING
;
363 set_select_events( &client
->select
, WRITE_EVENT
);