2 * Server-side socket communication functions
4 * Copyright (C) 1998 Alexandre Julliard
16 #include <sys/types.h>
17 #include <sys/socket.h>
24 #include "server/object.h"
26 /* Some versions of glibc don't define this */
34 RUNNING
, /* running normally */
35 SENDING
, /* sending us a request */
36 WAITING
, /* waiting for us to reply */
37 READING
/* reading our reply */
43 struct timeval when
; /* timeout expiry (absolute time) */
44 struct timeout
*next
; /* next in sorted list */
45 struct timeout
*prev
; /* prev in sorted list */
46 int client
; /* client id */
49 /* client structure */
52 enum state state
; /* client state */
53 unsigned int seq
; /* current sequence number */
54 struct header head
; /* current msg header */
55 char *data
; /* current msg data */
56 int count
; /* bytes sent/received so far */
57 int pass_fd
; /* fd to pass to and from the client */
58 struct thread
*self
; /* client thread (opaque pointer) */
59 struct timeout timeout
; /* client timeout */
63 static struct client
*clients
[FD_SETSIZE
]; /* clients array */
64 static fd_set read_set
, write_set
; /* current select sets */
65 static int nb_clients
; /* current number of clients */
66 static int max_fd
; /* max fd in use */
67 static int initial_client_fd
; /* fd of the first client */
68 static struct timeout
*timeout_head
; /* sorted timeouts list head */
69 static struct timeout
*timeout_tail
; /* sorted timeouts list tail */
71 /* exit code passed to remove_client */
72 #define OUT_OF_MEMORY -1
73 #define BROKEN_PIPE -2
74 #define PROTOCOL_ERROR -3
77 /* signal a client protocol error */
78 static void protocol_error( int client_fd
, const char *err
, ... )
82 va_start( args
, err
);
83 fprintf( stderr
, "Protocol error:%d: ", client_fd
);
84 vfprintf( stderr
, err
, args
);
89 /* send a message to a client that is ready to receive something */
90 static void do_write( int client_fd
)
92 struct client
*client
= clients
[client_fd
];
94 #ifndef HAVE_MSGHDR_ACCRIGHTS
95 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
,
98 struct msghdr msghdr
= { NULL
, 0, vec
, 2, };
101 /* make sure we have something to send */
102 assert( client
->count
< client
->head
.len
);
103 /* make sure the client is listening */
104 assert( client
->state
== READING
);
106 if (client
->count
< sizeof(client
->head
))
108 vec
[0].iov_base
= (char *)&client
->head
+ client
->count
;
109 vec
[0].iov_len
= sizeof(client
->head
) - client
->count
;
110 vec
[1].iov_base
= client
->data
;
111 vec
[1].iov_len
= client
->head
.len
- sizeof(client
->head
);
115 vec
[0].iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
116 vec
[0].iov_len
= client
->head
.len
- client
->count
;
117 msghdr
.msg_iovlen
= 1;
119 if (client
->pass_fd
!= -1) /* we have an fd to send */
121 #ifdef HAVE_MSGHDR_ACCRIGHTS
122 msghdr
.msg_accrights
= (void *)&client
->pass_fd
;
123 msghdr
.msg_accrightslen
= sizeof(client
->pass_fd
);
125 msghdr
.msg_control
= &cmsg
;
126 msghdr
.msg_controllen
= sizeof(cmsg
);
129 ret
= sendmsg( client_fd
, &msghdr
, 0 );
132 if (errno
!= EPIPE
) perror("sendmsg");
133 remove_client( client_fd
, BROKEN_PIPE
);
136 if (client
->pass_fd
!= -1) /* We sent the fd, now we can close it */
138 close( client
->pass_fd
);
139 client
->pass_fd
= -1;
141 if ((client
->count
+= ret
) < client
->head
.len
) return;
143 /* we have finished with this message */
144 if (client
->data
) free( client
->data
);
147 client
->state
= RUNNING
;
149 FD_CLR( client_fd
, &write_set
);
150 FD_SET( client_fd
, &read_set
);
154 /* read a message from a client that has something to say */
155 static void do_read( int client_fd
)
157 struct client
*client
= clients
[client_fd
];
160 #ifdef HAVE_MSGHDR_ACCRIGHTS
161 struct msghdr msghdr
= { NULL
, 0, &vec
, 1, (void*)&pass_fd
, sizeof(int) };
163 struct cmsg_fd cmsg
= { sizeof(cmsg
), SOL_SOCKET
, SCM_RIGHTS
, -1 };
164 struct msghdr msghdr
= { NULL
, 0, &vec
, 1, &cmsg
, sizeof(cmsg
), 0 };
168 if (client
->count
< sizeof(client
->head
))
170 vec
.iov_base
= (char *)&client
->head
+ client
->count
;
171 vec
.iov_len
= sizeof(client
->head
) - client
->count
;
176 !(client
->data
= malloc(client
->head
.len
-sizeof(client
->head
))))
178 remove_client( client_fd
, OUT_OF_MEMORY
);
181 vec
.iov_base
= client
->data
+ client
->count
- sizeof(client
->head
);
182 vec
.iov_len
= client
->head
.len
- client
->count
;
185 ret
= recvmsg( client_fd
, &msghdr
, 0 );
189 remove_client( client_fd
, BROKEN_PIPE
);
192 #ifndef HAVE_MSGHDR_ACCRIGHTS
197 /* can only receive one fd per message */
198 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
199 client
->pass_fd
= pass_fd
;
201 else if (!ret
) /* closed pipe */
203 remove_client( client_fd
, BROKEN_PIPE
);
207 if (client
->state
== RUNNING
) client
->state
= SENDING
;
208 assert( client
->state
== SENDING
);
210 client
->count
+= ret
;
212 /* received the complete header yet? */
213 if (client
->count
< sizeof(client
->head
)) return;
216 if (client
->head
.seq
!= client
->seq
)
218 protocol_error( client_fd
, "bad sequence %08x instead of %08x\n",
219 client
->head
.seq
, client
->seq
);
220 remove_client( client_fd
, PROTOCOL_ERROR
);
223 if ((client
->head
.len
< sizeof(client
->head
)) ||
224 (client
->head
.len
> MAX_MSG_LENGTH
+ sizeof(client
->head
)))
226 protocol_error( client_fd
, "bad header length %08x\n",
228 remove_client( client_fd
, PROTOCOL_ERROR
);
232 /* received the whole message? */
233 if (client
->count
== client
->head
.len
)
235 /* done reading the data, call the callback function */
237 int len
= client
->head
.len
- sizeof(client
->head
);
238 char *data
= client
->data
;
239 int passed_fd
= client
->pass_fd
;
240 enum request type
= client
->head
.type
;
242 /* clear the info now, as the client may be deleted by the callback */
243 client
->head
.len
= 0;
244 client
->head
.type
= 0;
247 client
->pass_fd
= -1;
248 client
->state
= WAITING
;
251 call_req_handler( client
->self
, type
, data
, len
, passed_fd
);
252 if (passed_fd
!= -1) close( passed_fd
);
253 if (data
) free( data
);
258 /* handle a client timeout */
259 static void do_timeout( int client_fd
)
261 struct client
*client
= clients
[client_fd
];
262 set_timeout( client_fd
, 0 ); /* Remove the timeout */
263 call_timeout_handler( client
->self
);
267 /* server main loop */
268 void server_main_loop( int fd
)
273 signal( SIGPIPE
, SIG_IGN
);
275 /* special magic to create the initial thread */
276 initial_client_fd
= fd
;
277 add_client( initial_client_fd
, NULL
);
281 fd_set read
= read_set
, write
= write_set
;
283 printf( "select: " );
284 for (i
= 0; i
<= max_fd
; i
++) printf( "%c", FD_ISSET( i
, &read_set
) ? 'r' :
285 (FD_ISSET( i
, &write_set
) ? 'w' : '-') );
290 struct timeval tv
, now
;
291 gettimeofday( &now
, NULL
);
292 if ((timeout_head
->when
.tv_sec
< now
.tv_sec
) ||
293 ((timeout_head
->when
.tv_sec
== now
.tv_sec
) &&
294 (timeout_head
->when
.tv_usec
< now
.tv_usec
)))
296 do_timeout( timeout_head
->client
);
299 tv
.tv_sec
= timeout_head
->when
.tv_sec
- now
.tv_sec
;
300 if ((tv
.tv_usec
= timeout_head
->when
.tv_usec
- now
.tv_usec
) < 0)
302 tv
.tv_usec
+= 1000000;
305 ret
= select( max_fd
+ 1, &read
, &write
, NULL
, &tv
);
307 else /* no timeout */
309 ret
= select( max_fd
+ 1, &read
, &write
, NULL
, NULL
);
313 if (ret
== -1) perror("select");
315 for (i
= 0; i
<= max_fd
; i
++)
317 if (FD_ISSET( i
, &write
))
319 if (clients
[i
]) do_write( i
);
321 else if (FD_ISSET( i
, &read
))
323 if (clients
[i
]) do_read( i
);
330 /*******************************************************************/
331 /* server-side exported functions */
334 int add_client( int client_fd
, struct thread
*self
)
337 struct client
*client
= malloc( sizeof(*client
) );
338 if (!client
) return -1;
339 assert( !clients
[client_fd
] );
341 client
->state
= RUNNING
;
343 client
->head
.len
= 0;
344 client
->head
.type
= 0;
348 client
->pass_fd
= -1;
349 client
->timeout
.when
.tv_sec
= 0;
350 client
->timeout
.when
.tv_usec
= 0;
351 client
->timeout
.client
= client_fd
;
353 flags
= fcntl( client_fd
, F_GETFL
, 0 );
354 fcntl( client_fd
, F_SETFL
, flags
| O_NONBLOCK
);
356 clients
[client_fd
] = client
;
357 FD_SET( client_fd
, &read_set
);
358 if (client_fd
> max_fd
) max_fd
= client_fd
;
363 /* remove a client */
364 void remove_client( int client_fd
, int exit_code
)
366 struct client
*client
= clients
[client_fd
];
369 call_kill_handler( client
->self
, exit_code
);
371 set_timeout( client_fd
, 0 );
372 clients
[client_fd
] = NULL
;
373 FD_CLR( client_fd
, &read_set
);
374 FD_CLR( client_fd
, &write_set
);
375 if (max_fd
== client_fd
) while (max_fd
&& !clients
[max_fd
]) max_fd
--;
376 if (initial_client_fd
== client_fd
) initial_client_fd
= -1;
381 if (client
->data
) free( client
->data
);
382 if (client
->pass_fd
!= -1) close( client
->pass_fd
);
386 /* return the fd of the initial client */
387 int get_initial_client_fd(void)
389 assert( initial_client_fd
!= -1 );
390 return initial_client_fd
;
393 /* set a client timeout */
394 void set_timeout( int client_fd
, struct timeval
*when
)
396 struct timeout
*tm
, *pos
;
397 struct client
*client
= clients
[client_fd
];
400 tm
= &client
->timeout
;
401 if (tm
->when
.tv_sec
|| tm
->when
.tv_usec
)
403 /* there is already a timeout */
404 if (tm
->next
) tm
->next
->prev
= tm
->prev
;
405 else timeout_tail
= tm
->prev
;
406 if (tm
->prev
) tm
->prev
->next
= tm
->next
;
407 else timeout_head
= tm
->next
;
408 tm
->when
.tv_sec
= tm
->when
.tv_usec
= 0;
410 if (!when
) return; /* no timeout */
413 /* Now insert it in the linked list */
415 for (pos
= timeout_head
; pos
; pos
= pos
->next
)
417 if (pos
->when
.tv_sec
> tm
->when
.tv_sec
) break;
418 if ((pos
->when
.tv_sec
== tm
->when
.tv_sec
) &&
419 (pos
->when
.tv_usec
> tm
->when
.tv_usec
)) break;
422 if (pos
) /* insert it before 'pos' */
424 if ((tm
->prev
= pos
->prev
)) tm
->prev
->next
= tm
;
425 else timeout_head
= tm
;
429 else /* insert it at the tail */
432 if (timeout_tail
) timeout_tail
->next
= tm
;
433 else timeout_head
= tm
;
434 tm
->prev
= timeout_tail
;
440 /* send a reply to a client */
441 int send_reply_v( int client_fd
, int type
, int pass_fd
,
442 struct iovec
*vec
, int veclen
)
447 struct client
*client
= clients
[client_fd
];
450 assert( client
->state
== WAITING
);
451 assert( !client
->data
);
453 if (debug_level
) trace_reply( client
->self
, type
, pass_fd
, vec
, veclen
);
455 for (i
= len
= 0; i
< veclen
; i
++) len
+= vec
[i
].iov_len
;
456 assert( len
< MAX_MSG_LENGTH
);
458 if (len
&& !(client
->data
= malloc( len
))) return -1;
460 client
->head
.len
= len
+ sizeof(client
->head
);
461 client
->head
.type
= type
;
462 client
->head
.seq
= client
->seq
;
463 client
->pass_fd
= pass_fd
;
465 for (i
= 0, p
= client
->data
; i
< veclen
; i
++)
467 memcpy( p
, vec
[i
].iov_base
, vec
[i
].iov_len
);
471 client
->state
= READING
;
472 FD_CLR( client_fd
, &read_set
);
473 FD_SET( client_fd
, &write_set
);