2 * Server-side request handling
4 * Copyright (C) 1998 Alexandre Julliard
17 #include <sys/types.h>
18 #ifdef HAVE_SYS_SOCKET_H
19 # include <sys/socket.h>
30 #define WANT_REQUEST_HANDLERS
33 /* Some versions of glibc don't define this */
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
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, ... )
61 va_start( args, err );
62 fprintf( stderr, "Protocol error:%p: ", thread );
63 vfprintf( stderr, err, 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 )
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 );
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();
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 )
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);
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;
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 );
147 kill_thread( thread, BROKEN_PIPE );
150 if (!ret) /* closed pipe */
152 kill_thread( thread, BROKEN_PIPE );
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 )
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;
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 );
197 set_select_events( &thread->obj, POLLIN );
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)
214 case DEBUGGER_FREEZE_ALL:
215 suspend_all_threads();
218 case DEBUGGER_UNFREEZE_ALL:
219 resume_all_threads();