2 * Server-side request handling
4 * Copyright (C) 1998 Alexandre Julliard
11 #include <sys/types.h>
18 #define WANT_REQUEST_HANDLERS
20 #include "server/request.h"
21 #include "server/thread.h"
23 /* check that the string is NULL-terminated and that the len is correct */
24 #define CHECK_STRING(func,str,len) \
25 do { if (((str)[(len)-1] || strlen(str) != (len)-1)) \
26 fatal_protocol_error( "%s: invalid string '%.*s'\n", (func), (len), (str) ); \
29 struct thread
*current
= NULL
; /* thread handling the current request */
31 /* complain about a protocol error and terminate the client connection */
32 static void fatal_protocol_error( const char *err
, ... )
36 va_start( args
, err
);
37 fprintf( stderr
, "Protocol error:%p: ", current
);
38 vfprintf( stderr
, err
, args
);
40 remove_client( current
->client_fd
, -2 );
43 /* call a request handler */
44 void call_req_handler( struct thread
*thread
, enum request req
,
45 void *data
, int len
, int fd
)
47 const struct handler
*handler
= &req_handlers
[req
];
51 if ((req
< 0) || (req
>= REQ_NB_REQUESTS
))
53 fatal_protocol_error( "unknown request %d\n", req
);
57 if (len
< handler
->min_size
)
59 fatal_protocol_error( "req %d bad length %d < %d)\n", req
, len
, handler
->min_size
);
63 /* now call the handler */
67 if (debug_level
) trace_request( req
, data
, len
, fd
);
69 len
-= handler
->min_size
;
70 ptr
= (char *)data
+ handler
->min_size
;
71 handler
->handler( data
, ptr
, len
, fd
);
75 /* handle a client timeout (unused for now) */
76 void call_timeout_handler( struct thread
*thread
)
79 if (debug_level
) trace_timeout();
85 /* a thread has been killed */
86 void call_kill_handler( struct thread
*thread
, int exit_code
)
88 /* must be reentrant WRT call_req_handler */
89 struct thread
*old_current
= current
;
93 if (debug_level
) trace_kill( exit_code
);
94 thread_killed( current
, exit_code
);
96 current
= (old_current
!= thread
) ? old_current
: NULL
;
100 /* create a new thread */
101 DECL_HANDLER(new_thread
)
103 struct new_thread_reply reply
;
104 struct thread
*new_thread
;
107 if ((new_fd
= dup(fd
)) == -1)
110 err
= ERROR_TOO_MANY_OPEN_FILES
;
113 if (!(new_thread
= create_thread( new_fd
, req
->pid
, &reply
.thandle
,
117 err
= ERROR_OUTOFMEMORY
;
120 reply
.tid
= new_thread
;
121 reply
.pid
= new_thread
->process
;
127 /* first client doesn't have a current */
128 struct iovec vec
= { &reply
, sizeof(reply
) };
129 send_reply_v( get_initial_client_fd(), err
, -1, &vec
, 1 );
134 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
138 /* create a new thread */
139 DECL_HANDLER(init_thread
)
141 if (current
->state
!= STARTING
)
143 fatal_protocol_error( "init_thread: already running\n" );
146 current
->state
= RUNNING
;
147 current
->unix_pid
= req
->unix_pid
;
148 if (!(current
->name
= mem_alloc( len
+ 1 ))) goto done
;
149 memcpy( current
->name
, data
, len
);
150 current
->name
[len
] = '\0';
153 send_reply( current
, -1, 0 );
156 /* set the debug level */
157 DECL_HANDLER(set_debug
)
159 debug_level
= req
->level
;
160 /* Make sure last_req is initialized */
161 current
->last_req
= REQ_SET_DEBUG
;
163 send_reply( current
, -1, 0 );
166 /* terminate a process */
167 DECL_HANDLER(terminate_process
)
169 struct process
*process
;
171 if ((process
= get_process_from_handle( req
->handle
, PROCESS_TERMINATE
)))
173 kill_process( process
, req
->exit_code
);
174 release_object( process
);
176 if (current
) send_reply( current
, -1, 0 );
179 /* terminate a thread */
180 DECL_HANDLER(terminate_thread
)
182 struct thread
*thread
;
184 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_TERMINATE
)))
186 kill_thread( thread
, req
->exit_code
);
187 release_object( thread
);
189 if (current
) send_reply( current
, -1, 0 );
193 DECL_HANDLER(close_handle
)
195 close_handle( current
->process
, req
->handle
);
196 send_reply( current
, -1, 0 );
199 /* duplicate a handle */
200 DECL_HANDLER(dup_handle
)
202 struct dup_handle_reply reply
= { -1 };
203 struct process
*src
, *dst
;
205 if ((src
= get_process_from_handle( req
->src_process
, PROCESS_DUP_HANDLE
)))
207 if (req
->options
& DUP_HANDLE_MAKE_GLOBAL
)
209 reply
.handle
= duplicate_handle( src
, req
->src_handle
, NULL
, -1,
210 req
->access
, req
->inherit
, req
->options
);
212 else if ((dst
= get_process_from_handle( req
->dst_process
, PROCESS_DUP_HANDLE
)))
214 reply
.handle
= duplicate_handle( src
, req
->src_handle
, dst
, req
->dst_handle
,
215 req
->access
, req
->inherit
, req
->options
);
216 release_object( dst
);
218 /* close the handle no matter what happened */
219 if (req
->options
& DUP_HANDLE_CLOSE_SOURCE
)
220 close_handle( src
, req
->src_handle
);
221 release_object( src
);
223 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
226 /* fetch information about a process */
227 DECL_HANDLER(get_process_info
)
229 struct process
*process
;
230 struct get_process_info_reply reply
= { 0, 0, 0 };
232 if ((process
= get_process_from_handle( req
->handle
, PROCESS_QUERY_INFORMATION
)))
234 get_process_info( process
, &reply
);
235 release_object( process
);
237 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
240 /* set information about a process */
241 DECL_HANDLER(set_process_info
)
243 struct process
*process
;
245 if ((process
= get_process_from_handle( req
->handle
, PROCESS_SET_INFORMATION
)))
247 set_process_info( process
, req
);
248 release_object( process
);
250 send_reply( current
, -1, 0 );
253 /* fetch information about a thread */
254 DECL_HANDLER(get_thread_info
)
256 struct thread
*thread
;
257 struct get_thread_info_reply reply
= { 0, 0 };
259 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_QUERY_INFORMATION
)))
261 get_thread_info( thread
, &reply
);
262 release_object( thread
);
264 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
267 /* set information about a thread */
268 DECL_HANDLER(set_thread_info
)
270 struct thread
*thread
;
272 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_INFORMATION
)))
274 set_thread_info( thread
, req
);
275 release_object( thread
);
277 send_reply( current
, -1, 0 );
280 /* suspend a thread */
281 DECL_HANDLER(suspend_thread
)
283 struct thread
*thread
;
284 struct suspend_thread_reply reply
= { -1 };
285 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SUSPEND_RESUME
)))
287 reply
.count
= suspend_thread( thread
);
288 release_object( thread
);
290 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
294 /* resume a thread */
295 DECL_HANDLER(resume_thread
)
297 struct thread
*thread
;
298 struct resume_thread_reply reply
= { -1 };
299 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SUSPEND_RESUME
)))
301 reply
.count
= resume_thread( thread
);
302 release_object( thread
);
304 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
308 /* queue an APC for a thread */
309 DECL_HANDLER(queue_apc
)
311 struct thread
*thread
;
312 if ((thread
= get_thread_from_handle( req
->handle
, THREAD_SET_CONTEXT
)))
314 thread_queue_apc( thread
, req
->func
, req
->param
);
315 release_object( thread
);
317 send_reply( current
, -1, 0 );
320 /* open a handle to a process */
321 DECL_HANDLER(open_process
)
323 struct open_process_reply reply
= { -1 };
324 struct process
*process
= get_process_from_id( req
->pid
);
327 reply
.handle
= alloc_handle( current
->process
, process
,
328 req
->access
, req
->inherit
);
329 release_object( process
);
331 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
334 /* select on a handle list */
337 if (len
!= req
->count
* sizeof(int))
338 fatal_protocol_error( "select: bad length %d for %d handles\n",
340 sleep_on( current
, req
->count
, (int *)data
, req
->flags
, req
->timeout
);
343 /* create an event */
344 DECL_HANDLER(create_event
)
346 struct create_event_reply reply
= { -1 };
348 char *name
= (char *)data
;
349 if (!len
) name
= NULL
;
350 else CHECK_STRING( "create_event", name
, len
);
352 obj
= create_event( name
, req
->manual_reset
, req
->initial_state
);
355 reply
.handle
= alloc_handle( current
->process
, obj
, EVENT_ALL_ACCESS
, req
->inherit
);
356 release_object( obj
);
358 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
361 /* do an event operation */
362 DECL_HANDLER(event_op
)
367 pulse_event( req
->handle
);
370 set_event( req
->handle
);
373 reset_event( req
->handle
);
376 fatal_protocol_error( "event_op: invalid operation %d\n", req
->op
);
378 send_reply( current
, -1, 0 );
382 DECL_HANDLER(create_mutex
)
384 struct create_mutex_reply reply
= { -1 };
386 char *name
= (char *)data
;
387 if (!len
) name
= NULL
;
388 else CHECK_STRING( "create_mutex", name
, len
);
390 obj
= create_mutex( name
, req
->owned
);
393 reply
.handle
= alloc_handle( current
->process
, obj
, MUTEX_ALL_ACCESS
, req
->inherit
);
394 release_object( obj
);
396 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
399 /* release a mutex */
400 DECL_HANDLER(release_mutex
)
402 if (release_mutex( req
->handle
)) CLEAR_ERROR();
403 send_reply( current
, -1, 0 );
406 /* create a semaphore */
407 DECL_HANDLER(create_semaphore
)
409 struct create_semaphore_reply reply
= { -1 };
411 char *name
= (char *)data
;
412 if (!len
) name
= NULL
;
413 else CHECK_STRING( "create_semaphore", name
, len
);
415 obj
= create_semaphore( name
, req
->initial
, req
->max
);
418 reply
.handle
= alloc_handle( current
->process
, obj
, SEMAPHORE_ALL_ACCESS
, req
->inherit
);
419 release_object( obj
);
421 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
424 /* release a semaphore */
425 DECL_HANDLER(release_semaphore
)
427 struct release_semaphore_reply reply
;
428 if (release_semaphore( req
->handle
, req
->count
, &reply
.prev_count
)) CLEAR_ERROR();
429 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
432 /* open a handle to a named object (event, mutex, semaphore) */
433 DECL_HANDLER(open_named_obj
)
435 struct open_named_obj_reply reply
;
436 char *name
= (char *)data
;
437 if (!len
) name
= NULL
;
438 else CHECK_STRING( "open_named_obj", name
, len
);
443 reply
.handle
= open_event( req
->access
, req
->inherit
, name
);
446 reply
.handle
= open_mutex( req
->access
, req
->inherit
, name
);
449 reply
.handle
= open_semaphore( req
->access
, req
->inherit
, name
);
452 reply
.handle
= open_mapping( req
->access
, req
->inherit
, name
);
455 fatal_protocol_error( "open_named_obj: invalid type %d\n", req
->type
);
457 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
461 DECL_HANDLER(create_file
)
463 struct create_file_reply reply
= { -1 };
465 char *name
= (char *)data
;
466 if (!len
) name
= NULL
;
467 else CHECK_STRING( "create_file", name
, len
);
469 if ((obj
= create_file( fd
, name
, req
->access
,
470 req
->sharing
, req
->create
, req
->attrs
)) != NULL
)
472 reply
.handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
473 release_object( obj
);
475 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
478 /* get a Unix fd to read from a file */
479 DECL_HANDLER(get_read_fd
)
484 if ((obj
= get_handle_obj( current
->process
, req
->handle
, GENERIC_READ
, NULL
)))
486 read_fd
= obj
->ops
->get_read_fd( obj
);
487 release_object( obj
);
490 send_reply( current
, read_fd
, 0 );
493 /* get a Unix fd to write to a file */
494 DECL_HANDLER(get_write_fd
)
499 if ((obj
= get_handle_obj( current
->process
, req
->handle
, GENERIC_WRITE
, NULL
)))
501 write_fd
= obj
->ops
->get_write_fd( obj
);
502 release_object( obj
);
505 send_reply( current
, write_fd
, 0 );
508 /* set a file current position */
509 DECL_HANDLER(set_file_pointer
)
511 struct set_file_pointer_reply reply
= { req
->low
, req
->high
};
512 set_file_pointer( req
->handle
, &reply
.low
, &reply
.high
, req
->whence
);
513 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
516 /* truncate (or extend) a file */
517 DECL_HANDLER(truncate_file
)
519 truncate_file( req
->handle
);
520 send_reply( current
, -1, 0 );
523 /* flush a file buffers */
524 DECL_HANDLER(flush_file
)
528 if ((obj
= get_handle_obj( current
->process
, req
->handle
, GENERIC_WRITE
, NULL
)))
530 obj
->ops
->flush( obj
);
531 release_object( obj
);
533 send_reply( current
, -1, 0 );
536 /* set a file access and modification times */
537 DECL_HANDLER(set_file_time
)
539 set_file_time( req
->handle
, req
->access_time
, req
->write_time
);
540 send_reply( current
, -1, 0 );
543 /* get a file information */
544 DECL_HANDLER(get_file_info
)
547 struct get_file_info_reply reply
;
549 if ((obj
= get_handle_obj( current
->process
, req
->handle
, 0, NULL
)))
551 obj
->ops
->get_file_info( obj
, &reply
);
552 release_object( obj
);
554 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
557 /* lock a region of a file */
558 DECL_HANDLER(lock_file
)
562 if ((file
= get_file_obj( current
->process
, req
->handle
, 0 )))
564 file_lock( file
, req
->offset_high
, req
->offset_low
,
565 req
->count_high
, req
->count_low
);
566 release_object( file
);
568 send_reply( current
, -1, 0 );
572 /* unlock a region of a file */
573 DECL_HANDLER(unlock_file
)
577 if ((file
= get_file_obj( current
->process
, req
->handle
, 0 )))
579 file_unlock( file
, req
->offset_high
, req
->offset_low
,
580 req
->count_high
, req
->count_low
);
581 release_object( file
);
583 send_reply( current
, -1, 0 );
587 /* create an anonymous pipe */
588 DECL_HANDLER(create_pipe
)
590 struct create_pipe_reply reply
= { -1, -1 };
591 struct object
*obj
[2];
592 if (create_pipe( obj
))
594 reply
.handle_read
= alloc_handle( current
->process
, obj
[0],
595 STANDARD_RIGHTS_REQUIRED
|SYNCHRONIZE
|GENERIC_READ
,
597 if (reply
.handle_read
!= -1)
599 reply
.handle_write
= alloc_handle( current
->process
, obj
[1],
600 STANDARD_RIGHTS_REQUIRED
|SYNCHRONIZE
|GENERIC_WRITE
,
602 if (reply
.handle_write
== -1)
603 close_handle( current
->process
, reply
.handle_read
);
605 release_object( obj
[0] );
606 release_object( obj
[1] );
608 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
611 /* allocate a console for the current process */
612 DECL_HANDLER(alloc_console
)
614 alloc_console( current
->process
);
615 send_reply( current
, -1, 0 );
618 /* free the console of the current process */
619 DECL_HANDLER(free_console
)
621 free_console( current
->process
);
622 send_reply( current
, -1, 0 );
625 /* open a handle to the process console */
626 DECL_HANDLER(open_console
)
629 struct open_console_reply reply
= { -1 };
630 if ((obj
= get_console( current
->process
, req
->output
)))
632 reply
.handle
= alloc_handle( current
->process
, obj
, req
->access
, req
->inherit
);
633 release_object( obj
);
635 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
638 /* set info about a console (output only) */
639 DECL_HANDLER(set_console_info
)
641 char *name
= (char *)data
;
642 if (!len
) name
= NULL
;
643 else CHECK_STRING( "set_console_info", name
, len
);
644 set_console_info( req
->handle
, req
, name
);
645 send_reply( current
, -1, 0 );
648 /* get info about a console (output only) */
649 DECL_HANDLER(get_console_info
)
651 struct get_console_info_reply reply
;
653 get_console_info( req
->handle
, &reply
, &title
);
654 send_reply( current
, -1, 2, &reply
, sizeof(reply
),
655 title
, title
? strlen(title
)+1 : 0 );
658 /* set a console fd */
659 DECL_HANDLER(set_console_fd
)
661 set_console_fd( req
->handle
, fd
, req
->pid
);
662 send_reply( current
, -1, 0 );
665 /* get a console mode (input or output) */
666 DECL_HANDLER(get_console_mode
)
668 struct get_console_mode_reply reply
;
669 get_console_mode( req
->handle
, &reply
.mode
);
670 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
673 /* set a console mode (input or output) */
674 DECL_HANDLER(set_console_mode
)
676 set_console_mode( req
->handle
, req
->mode
);
677 send_reply( current
, -1, 0 );
680 /* create a change notification */
681 DECL_HANDLER(create_change_notification
)
684 struct create_change_notification_reply reply
= { -1 };
686 if ((obj
= create_change_notification( req
->subtree
, req
->filter
)))
688 reply
.handle
= alloc_handle( current
->process
, obj
,
689 STANDARD_RIGHTS_REQUIRED
|SYNCHRONIZE
, 0 );
690 release_object( obj
);
692 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
695 /* create a file mapping */
696 DECL_HANDLER(create_mapping
)
699 struct create_mapping_reply reply
= { -1 };
700 char *name
= (char *)data
;
701 if (!len
) name
= NULL
;
702 else CHECK_STRING( "create_mapping", name
, len
);
704 if ((obj
= create_mapping( req
->size_high
, req
->size_low
,
705 req
->protect
, req
->handle
, name
)))
707 int access
= FILE_MAP_ALL_ACCESS
;
708 if (!(req
->protect
& VPROT_WRITE
)) access
&= ~FILE_MAP_WRITE
;
709 reply
.handle
= alloc_handle( current
->process
, obj
, access
, 0 );
710 release_object( obj
);
712 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );
715 /* get a mapping information */
716 DECL_HANDLER(get_mapping_info
)
718 struct get_mapping_info_reply reply
;
719 int map_fd
= get_mapping_info( req
->handle
, &reply
);
720 send_reply( current
, map_fd
, 1, &reply
, sizeof(reply
) );
723 /* create a device */
724 DECL_HANDLER(create_device
)
727 struct create_device_reply reply
= { -1 };
729 if ((obj
= create_device( req
->id
)))
731 reply
.handle
= alloc_handle( current
->process
, obj
,
732 req
->access
, req
->inherit
);
733 release_object( obj
);
735 send_reply( current
, -1, 1, &reply
, sizeof(reply
) );