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>
29 #define WANT_REQUEST_HANDLERS
32 /* Some versions of glibc don't define this */
38 struct thread *current = NULL; /* thread handling the current request */
41 /* socket communication static structures */
42 static struct iovec myiovec;
43 static struct msghdr msghdr = { NULL, 0, &myiovec, 1, };
44 #ifndef HAVE_MSGHDR_ACCRIGHTS
47 int len; /* sizeof structure */
48 int level; /* SOL_SOCKET */
49 int type; /* SCM_RIGHTS */
50 int fd; /* fd to pass */
52 static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 };
53 #endif /* HAVE_MSGHDR_ACCRIGHTS */
55 /* complain about a protocol error and terminate the client connection */
56 void fatal_protocol_error( struct thread *thread, const char *err, ... )
60 va_start( args, err );
61 fprintf( stderr, "Protocol error:%p: ", thread );
62 vfprintf( stderr, err, args );
64 kill_thread( thread, PROTOCOL_ERROR );
67 /* call a request handler */
68 static void call_req_handler( struct thread *thread, enum request req, int fd )
73 if (debug_level) trace_request( req, fd );
75 if (req < REQ_NB_REQUESTS)
77 req_handlers[req].handler( current->buffer, fd );
78 if (current && !current->wait) send_reply( current );
82 fatal_protocol_error( current, "bad request %d\n", req );
85 /* set the fd to pass to the thread */
86 void set_reply_fd( struct thread *thread, int pass_fd )
88 assert( thread->pass_fd == -1 );
89 thread->pass_fd = pass_fd;
92 /* send a reply to a thread */
93 void send_reply( struct thread *thread )
95 assert( !thread->wait );
96 if (debug_level) trace_reply( thread );
97 if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT );
100 /* read a message from a client that has something to say */
101 void read_request( struct thread *thread )
106 #ifdef HAVE_MSGHDR_ACCRIGHTS
107 msghdr.msg_accrightslen = sizeof(int);
108 msghdr.msg_accrights = (void *)&thread->pass_fd;
109 #else /* HAVE_MSGHDR_ACCRIGHTS */
110 msghdr.msg_control = &cmsg;
111 msghdr.msg_controllen = sizeof(cmsg);
113 #endif /* HAVE_MSGHDR_ACCRIGHTS */
115 assert( thread->pass_fd == -1 );
117 myiovec.iov_base = (void *)&req;
118 myiovec.iov_len = sizeof(req);
120 ret = recvmsg( thread->obj.fd, &msghdr, 0 );
121 #ifndef HAVE_MSGHDR_ACCRIGHTS
122 thread->pass_fd = cmsg.fd;
125 if (ret == sizeof(req))
127 int pass_fd = thread->pass_fd;
128 thread->pass_fd = -1;
129 call_req_handler( thread, req, pass_fd );
130 if (pass_fd != -1) close( pass_fd );
136 kill_thread( thread, BROKEN_PIPE );
139 if (!ret) /* closed pipe */
141 kill_thread( thread, BROKEN_PIPE );
144 fatal_protocol_error( thread, "partial message received %d/%d\n", ret, sizeof(req) );
147 /* send a message to a client that is ready to receive something */
148 int write_request( struct thread *thread )
152 if (thread->pass_fd == -1)
154 ret = write( thread->obj.fd, &thread->error, sizeof(thread->error) );
155 if (ret == sizeof(thread->error)) goto ok;
157 else /* we have an fd to send */
159 #ifdef HAVE_MSGHDR_ACCRIGHTS
160 msghdr.msg_accrightslen = sizeof(int);
161 msghdr.msg_accrights = (void *)&thread->pass_fd;
162 #else /* HAVE_MSGHDR_ACCRIGHTS */
163 msghdr.msg_control = &cmsg;
164 msghdr.msg_controllen = sizeof(cmsg);
165 cmsg.fd = thread->pass_fd;
166 #endif /* HAVE_MSGHDR_ACCRIGHTS */
168 myiovec.iov_base = (void *)&thread->error;
169 myiovec.iov_len = sizeof(thread->error);
171 ret = sendmsg( thread->obj.fd, &msghdr, 0 );
172 close( thread->pass_fd );
173 thread->pass_fd = -1;
174 if (ret == sizeof(thread->error)) goto ok;
178 if (errno == EWOULDBLOCK) return 0; /* not a fatal error */
179 if (errno != EPIPE) perror("sendmsg");
181 else fprintf( stderr, "Partial message sent %d/%d\n", ret, sizeof(thread->error) );
182 kill_thread( thread, BROKEN_PIPE );
186 set_select_events( &thread->obj, POLLIN );
190 /* set the debug level */
191 DECL_HANDLER(set_debug)
193 debug_level = req->level;
194 /* Make sure last_req is initialized */
195 current->last_req = REQ_SET_DEBUG;
198 /* debugger support operations */
199 DECL_HANDLER(debugger)
203 case DEBUGGER_FREEZE_ALL:
204 suspend_all_threads();
207 case DEBUGGER_UNFREEZE_ALL:
208 resume_all_threads();