Put back visible minimum timer resolution to 1 ms.
[wine/testsucceed.git] / server / request.c
blob62b15e9a4c59503dc1f9464d18abbe86e529dd06
1 /*
2 * Server-side request handling
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include "config.h"
9 #include <assert.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18 #ifdef HAVE_SYS_SOCKET_H
19 # include <sys/socket.h>
20 #endif
21 #include <sys/uio.h>
22 #include <unistd.h>
24 #include "winerror.h"
25 #include "winnt.h"
26 #include "winbase.h"
27 #include "wincon.h"
28 #include "thread.h"
29 #include "server.h"
30 #define WANT_REQUEST_HANDLERS
31 #include "request.h"
33 /* Some versions of glibc don't define this */
34 #ifndef SCM_RIGHTS
35 #define SCM_RIGHTS 1
36 #endif
39 struct thread *current = NULL; /* thread handling the current request */
42 /* socket communication static structures */
43 static struct iovec myiovec;
44 static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
45 #ifndef HAVE_MSGHDR_ACCRIGHTS
46 struct cmsg_fd
48 int len; /* sizeof structure */
49 int level; /* SOL_SOCKET */
50 int type; /* SCM_RIGHTS */
51 int fd; /* fd to pass */
53 static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
54 #endif /* HAVE_MSGHDR_ACCRIGHTS */
56 /* complain about a protocol error and terminate the client connection */
57 void fatal_protocol_error( struct thread *thread, const char *err, ... )
59 va_list args;
61 va_start( args, err );
62 fprintf( stderr, "Protocol error:%p: ", thread );
63 vfprintf( stderr, err, args );
64 va_end( args );
65 kill_thread( thread, PROTOCOL_ERROR );
68 /* call a request handler */
69 static void call_req_handler( struct thread *thread, enum request req, int fd )
71 current = thread;
72 clear_error();
74 if (debug_level) trace_request( req, fd );
76 if (req < REQ_NB_REQUESTS)
78 req_handlers[req].handler( current->buffer, fd );
79 if (current && current->state != SLEEPING) send_reply( current );
80 current = NULL;
81 return;
83 fatal_protocol_error( current, "bad request %d\n", req );
86 /* handle a client timeout */
87 void call_timeout_handler( void *thread )
89 current = (struct thread *)thread;
90 if (debug_level) trace_timeout();
91 clear_error();
92 thread_timeout();
93 current = NULL;
96 /* set the fd to pass to the thread */
97 void set_reply_fd( struct thread *thread, int pass_fd )
99 assert( thread->pass_fd == -1 );
100 thread->pass_fd = pass_fd;
103 /* send a reply to a thread */
104 void send_reply( struct thread *thread )
106 if (thread->state == SLEEPING) thread->state = RUNNING;
107 if (debug_level) trace_reply( thread );
108 if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
111 /* read a message from a client that has something to say */
112 void read_request( struct thread *thread )
114 int ret;
115 enum request req;
117 #ifdef HAVE_MSGHDR_ACCRIGHTS
118 msghdr.msg_accrightslen = sizeof(int);
119 msghdr.msg_accrights = (void *)&thread->pass_fd;
120 #else /* HAVE_MSGHDR_ACCRIGHTS */
121 msghdr.msg_control = &cmsg;
122 msghdr.msg_controllen = sizeof(cmsg);
123 cmsg.fd = -1;
124 #endif /* HAVE_MSGHDR_ACCRIGHTS */
126 assert( thread->pass_fd == -1 );
128 myiovec.iov_base = (void *)&req;
129 myiovec.iov_len = sizeof(req);
131 ret = recvmsg( thread->obj.fd, &msghdr, 0 );
132 #ifndef HAVE_MSGHDR_ACCRIGHTS
133 thread->pass_fd = cmsg.fd;
134 #endif
136 if (ret == sizeof(req))
138 int pass_fd = thread->pass_fd;
139 thread->pass_fd = -1;
140 call_req_handler( thread, req, pass_fd );
141 if (pass_fd != -1) close( pass_fd );
142 return;
144 if (ret == -1)
146 perror("recvmsg");
147 kill_thread( thread, BROKEN_PIPE );
148 return;
150 if (!ret) /* closed pipe */
152 kill_thread( thread, BROKEN_PIPE );
153 return;
155 fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
158 /* send a message to a client that is ready to receive something */
159 int write_request( struct thread *thread )
161 int ret;
163 if (thread->pass_fd == -1)
165 ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
166 if (ret == sizeof(thread->error)) goto ok;
168 else /* we have an fd to send */
170 #ifdef HAVE_MSGHDR_ACCRIGHTS
171 msghdr.msg_accrightslen = sizeof(int);
172 msghdr.msg_accrights = (void *)&thread->pass_fd;
173 #else /* HAVE_MSGHDR_ACCRIGHTS */
174 msghdr.msg_control = &cmsg;
175 msghdr.msg_controllen = sizeof(cmsg);
176 cmsg.fd = thread->pass_fd;
177 #endif /* HAVE_MSGHDR_ACCRIGHTS */
179 myiovec.iov_base = (void *)&thread->error;
180 myiovec.iov_len = sizeof(thread->error);
182 ret = sendmsg( thread->obj.fd, &msghdr, 0 );
183 close( thread->pass_fd );
184 thread->pass_fd = -1;
185 if (ret == sizeof(thread->error)) goto ok;
187 if (ret == -1)
189 if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
190 if (errno != EPIPE) perror("sendmsg");
192 else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
193 kill_thread( thread, BROKEN_PIPE );
194 return -1;
197 set_select_events( &thread->obj, POLLIN );
198 return 1;
201 /* set the debug level */
202 DECL_HANDLER(set_debug)
204 debug_level = req->level;
205 /* Make sure last_req is initialized */
206 current->last_req = REQ_SET_DEBUG;
209 /* debugger support operations */
210 DECL_HANDLER(debugger)
212 switch ( req->op )
214 case DEBUGGER_FREEZE_ALL:
215 suspend_all_threads();
216 break;
218 case DEBUGGER_UNFREEZE_ALL:
219 resume_all_threads();
220 break;