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
->wait
) send_reply( current
);
83 fatal_protocol_error( current
, "bad request %d\n", req
);
86 /* set the fd to pass to the thread */
87 void set_reply_fd( struct thread
*thread
, int pass_fd
)
89 assert( thread
->pass_fd
== -1 );
90 thread
->pass_fd
= pass_fd
;
93 /* send a reply to a thread */
94 void send_reply( struct thread
*thread
)
96 assert( !thread
->wait
);
97 if (debug_level
) trace_reply( thread
);
98 if (!write_request( thread
)) set_select_events( &thread
->obj
, POLLOUT
);
101 /* read a message from a client that has something to say */
102 void read_request( struct thread
*thread
)
107 #ifdef HAVE_MSGHDR_ACCRIGHTS
108 msghdr
.msg_accrightslen
= sizeof(int);
109 msghdr
.msg_accrights
= (void *)&thread
->pass_fd
;
110 #else /* HAVE_MSGHDR_ACCRIGHTS */
111 msghdr
.msg_control
= &cmsg
;
112 msghdr
.msg_controllen
= sizeof(cmsg
);
114 #endif /* HAVE_MSGHDR_ACCRIGHTS */
116 assert( thread
->pass_fd
== -1 );
118 myiovec
.iov_base
= (void *)&req
;
119 myiovec
.iov_len
= sizeof(req
);
121 ret
= recvmsg( thread
->obj
.fd
, &msghdr
, 0 );
122 #ifndef HAVE_MSGHDR_ACCRIGHTS
123 thread
->pass_fd
= cmsg
.fd
;
126 if (ret
== sizeof(req
))
128 int pass_fd
= thread
->pass_fd
;
129 thread
->pass_fd
= -1;
130 call_req_handler( thread
, req
, pass_fd
);
131 if (pass_fd
!= -1) close( pass_fd
);
137 kill_thread( thread
, BROKEN_PIPE
);
140 if (!ret
) /* closed pipe */
142 kill_thread( thread
, BROKEN_PIPE
);
145 fatal_protocol_error( thread
, "partial message received %d/%d\n", ret
, sizeof(req
) );
148 /* send a message to a client that is ready to receive something */
149 int write_request( struct thread
*thread
)
153 if (thread
->pass_fd
== -1)
155 ret
= write( thread
->obj
.fd
, &thread
->error
, sizeof(thread
->error
) );
156 if (ret
== sizeof(thread
->error
)) goto ok
;
158 else /* we have an fd to send */
160 #ifdef HAVE_MSGHDR_ACCRIGHTS
161 msghdr
.msg_accrightslen
= sizeof(int);
162 msghdr
.msg_accrights
= (void *)&thread
->pass_fd
;
163 #else /* HAVE_MSGHDR_ACCRIGHTS */
164 msghdr
.msg_control
= &cmsg
;
165 msghdr
.msg_controllen
= sizeof(cmsg
);
166 cmsg
.fd
= thread
->pass_fd
;
167 #endif /* HAVE_MSGHDR_ACCRIGHTS */
169 myiovec
.iov_base
= (void *)&thread
->error
;
170 myiovec
.iov_len
= sizeof(thread
->error
);
172 ret
= sendmsg( thread
->obj
.fd
, &msghdr
, 0 );
173 close( thread
->pass_fd
);
174 thread
->pass_fd
= -1;
175 if (ret
== sizeof(thread
->error
)) goto ok
;
179 if (errno
== EWOULDBLOCK
) return 0; /* not a fatal error */
180 if (errno
!= EPIPE
) perror("sendmsg");
182 else fprintf( stderr
, "Partial message sent %d/%d\n", ret
, sizeof(thread
->error
) );
183 kill_thread( thread
, BROKEN_PIPE
);
187 set_select_events( &thread
->obj
, POLLIN
);
191 /* set the debug level */
192 DECL_HANDLER(set_debug
)
194 debug_level
= req
->level
;
195 /* Make sure last_req is initialized */
196 current
->last_req
= REQ_SET_DEBUG
;
199 /* debugger support operations */
200 DECL_HANDLER(debugger
)
204 case DEBUGGER_FREEZE_ALL
:
205 suspend_all_threads();
208 case DEBUGGER_UNFREEZE_ALL
:
209 resume_all_threads();