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();