ANSI C fixes.
[wine/testsucceed.git] / server / socket.c
blob371b10b06fb2778c5826cc92e5d82069f2ed4bfc
1 /*
2 * Server-side socket communication functions
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <sys/time.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/uio.h>
17 #include <unistd.h>
19 #include "config.h"
20 #include "server.h"
22 #include "server/object.h"
24 /* Some versions of glibc don't define this */
25 #ifndef SCM_RIGHTS
26 #define SCM_RIGHTS 1
27 #endif
29 /* client state */
30 enum state
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 */
39 struct client
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, ... )
60 va_list args;
62 va_start( args, err );
63 fprintf( stderr, "Protocol error:%d: ", client_fd );
64 vfprintf( stderr, err, args );
65 va_end( 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 )
71 struct iovec vec[2];
72 #ifndef HAVE_MSGHDR_ACCRIGHTS
73 struct cmsg_fd cmsg;
74 #endif
75 struct msghdr msghdr;
76 int ret;
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;
85 msghdr.msg_iov = vec;
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;
95 else
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);
108 else
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);
123 else
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 );
132 if (ret == -1)
134 if (errno != EPIPE) perror("sendmsg");
135 remove_client( client_fd, BROKEN_PIPE );
136 return;
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 );
147 client->data = NULL;
148 client->count = 0;
149 client->state = RUNNING;
150 client->seq++;
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 )
158 struct iovec vec;
159 int pass_fd = -1;
160 int ret;
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;
169 struct cmsg_fd cmsg;
171 cmsg.len = sizeof(cmsg);
172 cmsg.level = SOL_SOCKET;
173 cmsg.type = SCM_RIGHTS;
174 cmsg.fd = -1;
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;
190 else
192 if (!client->data &&
193 !(client->data = malloc(client->head.len-sizeof(client->head))))
195 remove_client( client_fd, OUT_OF_MEMORY );
196 return;
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 );
203 if (ret == -1)
205 perror("recvmsg");
206 remove_client( client_fd, BROKEN_PIPE );
207 return;
209 #ifndef HAVE_MSGHDR_ACCRIGHTS
210 pass_fd = cmsg.fd;
211 #endif
212 if (pass_fd != -1)
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 );
221 return;
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;
232 /* sanity checks */
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 );
238 return;
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",
244 client->head.len );
245 remove_client( client_fd, PROTOCOL_ERROR );
246 return;
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;
262 client->count = 0;
263 client->data = NULL;
264 client->pass_fd = -1;
265 client->state = WAITING;
266 client->seq++;
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 =
294 client_event,
295 client_timeout
298 /*******************************************************************/
299 /* server-side exported functions */
301 /* add a client */
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;
308 client->seq = 0;
309 client->head.len = 0;
310 client->head.type = 0;
311 client->count = 0;
312 client->data = NULL;
313 client->self = self;
314 client->pass_fd = -1;
316 if (add_select_user( client_fd, READ_EVENT, &client_ops, client ) == -1)
318 free( client );
319 return -1;
321 return client_fd;
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 );
328 assert( client );
330 call_kill_handler( client->self, exit_code );
332 remove_select_user( client_fd );
333 close( client_fd );
335 /* Purge messages */
336 if (client->data) free( client->data );
337 if (client->pass_fd != -1) close( client->pass_fd );
338 free( client );
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 )
345 int i;
346 unsigned int len;
347 char *p;
348 struct client *client = (struct client *)get_select_private_data( &client_ops, client_fd );
350 assert( client );
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;
360 client->count = 0;
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 );
369 p += vec[i].iov_len;
372 client->state = READING;
373 set_select_events( client_fd, WRITE_EVENT );
374 return 0;