/* * Server-side request handling * * Copyright (C) 1998 Alexandre Julliard */ #include #include #include #include #include #include #include #include #include #include "winerror.h" #include "winnt.h" #include "winbase.h" #include "wincon.h" #include "thread.h" #include "server.h" #define WANT_REQUEST_HANDLERS #include "request.h" struct thread *current = NULL; /* thread handling the current request */ /* complain about a protocol error and terminate the client connection */ void fatal_protocol_error( const char *err ) { unsigned char *p; fprintf( stderr, "Protocol error:%p: %s\n request:", current, err ); for (p = (unsigned char *)current->buffer; p < (unsigned char *)current->req_end; p++) fprintf( stderr, " %02x", *p ); fprintf( stderr, "\n" ); remove_client( current->client, -2 ); } /* call a request handler */ void call_req_handler( struct thread *thread, int fd ) { const struct handler *handler; struct header *head; unsigned int req, len; current = thread; assert (current); head = (struct header *)current->buffer; req = head->type; len = head->len; /* set the buffer pointers */ current->req_pos = current->reply_pos = (char *)current->buffer + sizeof(struct header); current->req_end = (char *)current->buffer + len; clear_error(); if ((len < sizeof(struct header)) || (len > MAX_MSG_LENGTH)) goto bad_header; if (req >= REQ_NB_REQUESTS) goto bad_header; if (debug_level) trace_request( req, fd ); /* now call the handler */ handler = &req_handlers[req]; if (!check_req_data( handler->min_size )) goto bad_request; handler->handler( get_req_data( handler->min_size ), fd ); if (current && current->state != SLEEPING) send_reply( current ); current = NULL; return; bad_header: /* dump only the header */ current->req_end = (char *)current->buffer + sizeof(struct header); bad_request: fatal_protocol_error( "bad request" ); } /* handle a client timeout */ void call_timeout_handler( void *thread ) { current = (struct thread *)thread; if (debug_level) trace_timeout(); clear_error(); thread_timeout(); current = NULL; } /* a thread has been killed */ void call_kill_handler( struct thread *thread, int exit_code ) { /* must be reentrant WRT call_req_handler */ struct thread *old_current = current; current = thread; if (current) { if (debug_level) trace_kill( exit_code ); thread_killed( current, exit_code ); } current = (old_current != thread) ? old_current : NULL; } /* set the fd to pass to the thread */ void set_reply_fd( struct thread *thread, int pass_fd ) { client_pass_fd( thread->client, pass_fd ); } /* send a reply to a thread */ void send_reply( struct thread *thread ) { struct header *head = thread->buffer; int len = (char *)thread->reply_pos - (char *)thread->buffer; assert( len < MAX_MSG_LENGTH ); head->len = len; head->type = thread->error; if (thread->state == SLEEPING) thread->state = RUNNING; client_reply( thread->client ); } /* set the debug level */ DECL_HANDLER(set_debug) { debug_level = req->level; /* Make sure last_req is initialized */ current->last_req = REQ_SET_DEBUG; } /* debugger support operations */ DECL_HANDLER(debugger) { switch ( req->op ) { case DEBUGGER_FREEZE_ALL: suspend_all_threads(); break; case DEBUGGER_UNFREEZE_ALL: resume_all_threads(); break; } }