If there is enough space in the buffer and the type is REG_SZ and the
[wine.git] / server / request.c
blobfa9ccc7767d6ff46df254bf75ce034472d634aae
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->wait) send_reply( current );
80 current = NULL;
81 return;
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 )
104 int ret;
105 enum request req;
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);
113 cmsg.fd = -1;
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;
124 #endif
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 );
132 return;
134 if (ret == -1)
136 perror("recvmsg");
137 kill_thread( thread, BROKEN_PIPE );
138 return;
140 if (!ret) /* closed pipe */
142 kill_thread( thread, BROKEN_PIPE );
143 return;
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 )
151 int ret;
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;
177 if (ret == -1)
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 );
184 return -1;
187 set_select_events( &thread->obj, POLLIN );
188 return 1;
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)
202 switch ( req->op )
204 case DEBUGGER_FREEZE_ALL:
205 suspend_all_threads();
206 break;
208 case DEBUGGER_UNFREEZE_ALL:
209 resume_all_threads();
210 break;