📄 coserver.c
字号:
/* * coserver.c - basic internal coserver routines * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: coserver.c,v 1.22 2001/10/07 17:10:28 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#define _GNU_SOURCE#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <sys/types.h>#include <errno.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#include <signal.h>#ifdef __MINGW32__# include <winsock2.h>#endif#ifndef __MINGW32__# if HAVE_WAIT_H# include <wait.h># endif# if HAVE_SYS_WAIT_H# include <sys/wait.h># endif# include <netinet/in.h>#endif#include "libserveez/snprintf.h"#include "libserveez/alloc.h"#include "libserveez/util.h"#include "libserveez/core.h"#include "libserveez/hash.h"#include "libserveez/array.h"#include "libserveez/pipe-socket.h"#include "libserveez/server-core.h"#include "libserveez/coserver/coserver.h"/* coserver-TODO: include header here */#include "dns.h"#include "reverse-dns.h"#include "ident.h"#ifdef __MINGW32__/* define for the thread priority in Win32 */#define COSERVER_THREAD_PRIORITY THREAD_PRIORITY_IDLE#endif /* not __MINGW32__ */#define COSERVER_PACKET_BOUNDARY '\n' /* packet boundary */#define COSERVER_ID_BOUNDARY ':' /* id boundary *//* * Both of these variables are for storing the given callbacks which get * called when the coservers delivered some result. */static unsigned svz_coserver_callback_id = 1;static svz_hash_t *svz_coserver_callbacks = NULL;/* coserver-TODO: place an appropiate wrapper function here *//* * This is a wrapper function for the reverse DNS lookup coserver. */voidsvz_coserver_rdns_invoke (unsigned long ip, svz_coserver_handle_result_t cb, svz_coserver_args_t){ svz_coserver_send_request (COSERVER_REVERSE_DNS, svz_inet_ntoa (ip), cb, arg0, arg1);}/* * Wrapper for the DNS coserver. */voidsvz_coserver_dns_invoke (char *host, svz_coserver_handle_result_t cb, svz_coserver_args_t){ svz_coserver_send_request (COSERVER_DNS, host, cb, arg0, arg1);}/* * Wrapper for the ident coserver. */voidsvz_coserver_ident_invoke (svz_socket_t *sock, svz_coserver_handle_result_t cb, svz_coserver_args_t){ char buffer[COSERVER_BUFSIZE]; svz_snprintf (buffer, COSERVER_BUFSIZE, "%s:%u:%u", svz_inet_ntoa (sock->remote_addr), ntohs (sock->remote_port), ntohs (sock->local_port)); svz_coserver_send_request (COSERVER_IDENT, buffer, cb, arg0, arg1);}/* * This static array contains the coserver structure for each type of * internal coserver the core library provides. */svz_coservertype_t svz_coservertypes[] ={ /* coserver-TODO: place coserver callbacks and identification here */ { COSERVER_REVERSE_DNS, "reverse dns", reverse_dns_handle_request, 1, reverse_dns_init, 0 }, { COSERVER_IDENT, "ident", ident_handle_request, 1, NULL, 0}, { COSERVER_DNS, "dns", dns_handle_request, 1, NULL, 0 }};/* * Internal coserver instances. */svz_array_t *svz_coservers = NULL;/* * This routine gets the coserver hash id from a given response and * cuts it from the given response buffer. */static unsignedsvz_coserver_get_id (char *response){ char *p = response; unsigned id = 0; while (*p >= '0' && *p <= '9') { id *= 10; id += *p - '0'; p++; } if (*p != COSERVER_ID_BOUNDARY) { svz_log (LOG_WARNING, "coserver: invalid protocol character (0x%02x)\n", *p); return 0; } p++; while (*p != COSERVER_PACKET_BOUNDARY) { *response++ = *p++; } *response = '\0'; return id;}/* * This function adds a given coserver hash id to the response. */static voidsvz_coserver_put_id (unsigned id, char *response){ char buffer[COSERVER_BUFSIZE]; svz_snprintf (buffer, COSERVER_BUFSIZE, "%u:%s\n", id, response); strcpy (response, buffer);}/*************************************************************************//* This is part of the coserver process / thread. *//*************************************************************************//* * Win32: * svz_coserver_loop() is the actual thread routine being an infinite loop. * It MUST be resumed via ResumeThread() by the server. * When running it first checks if there is any request lingering * in the client structure "sock", reads it out, processes it * (can be blocking) and finally sends back a respond to the * server. * * Unices: * svz_coserver_loop() is a infinite loop in a separate process. It reads * blocking from a receive pipe, processes the request and puts the * result to a sending pipe to the server. * * The coserver loop heavily differs in Win32 and Unices... *//* Debug info Macro. */#if ENABLE_DEBUG# define COSERVER_REQUEST_INFO() \ svz_log (LOG_DEBUG, "%s: coserver request occurred\n", \ svz_coservertypes[coserver->type].name);#else# define COSERVER_REQUEST_INFO()#endif/* Post-Processing Macro. */#if ENABLE_DEBUG# define COSERVER_RESULT() \ svz_log (LOG_DEBUG, "%s: coserver request processed\n", \ svz_coservertypes[coserver->type].name);#else# define COSERVER_RESULT()#endif/* Pre-Processing Macro. */#define COSERVER_REQUEST() \ COSERVER_REQUEST_INFO (); \ /* Process the request here. Might be blocking indeed ! */ \ if ((id = svz_coserver_get_id (request)) != 0) \ { \ if ((result = coserver->callback (request)) == NULL) \ { \ result = request; \ *result = '\0'; \ } \ svz_coserver_put_id (id, result); \ } \#ifdef __MINGW32__static voidsvz_coserver_loop (svz_coserver_t *coserver, svz_socket_t *sock){ char *p; int len; char request[COSERVER_BUFSIZE]; char *result = NULL; unsigned id; /* wait until the thread handle has been passed */ while (coserver->thread == INVALID_HANDLE_VALUE); /* infinite loop */ for (;;) { /* check if there is anything in the receive buffer */ while (sock->send_buffer_fill > 0) { p = sock->send_buffer; while (*p != COSERVER_PACKET_BOUNDARY && p < sock->send_buffer + sock->send_buffer_fill) p++; len = p - sock->send_buffer + 1; /* Copy the coserver request to static buffer. */ assert (len <= COSERVER_BUFSIZE); memcpy (request, sock->send_buffer, len); /* Enter a synchronized section (exclusive access to all data). */ EnterCriticalSection (&coserver->sync); if (sock->send_buffer_fill > len) { memmove (sock->send_buffer, p + 1, sock->send_buffer_fill - len); } sock->send_buffer_fill -= len; LeaveCriticalSection (&coserver->sync); COSERVER_REQUEST (); if (id && result) { EnterCriticalSection (&coserver->sync); memcpy (sock->recv_buffer + sock->recv_buffer_fill, result, strlen (result)); sock->recv_buffer_fill += strlen (result); LeaveCriticalSection (&coserver->sync); COSERVER_RESULT (); } } /* suspend myself and wait for being resumed ... */ if (SuspendThread (coserver->thread) == 0xFFFFFFFF) { svz_log (LOG_ERROR, "SuspendThread: %s\n", SYS_ERROR); } }}#else /* not __MINGW32__ */static voidsvz_coserver_loop (svz_coserver_t *coserver, int in_pipe, int out_pipe){ FILE *in, *out; char request[COSERVER_BUFSIZE]; char *result = NULL; unsigned id; if ((in = fdopen (in_pipe, "r")) == NULL) { svz_log (LOG_ERROR, "coserver: fdopen (%d): %s\n", in_pipe, SYS_ERROR); return; } if ((out = fdopen (out_pipe, "w")) == NULL) { svz_log (LOG_ERROR, "coserver: fdopen (%d): %s\n", out_pipe, SYS_ERROR); return; } while (NULL != fgets (request, COSERVER_BUFSIZE, in)) { COSERVER_REQUEST (); if (id && result) { fprintf (out, "%s", result); fflush (out); COSERVER_RESULT (); } } /* error in reading pipe */ if (fclose (in)) svz_log (LOG_ERROR, "fclose: %s\n", SYS_ERROR); if (fclose (out)) svz_log (LOG_ERROR, "fclose: %s\n", SYS_ERROR);}#endif /* not __MINGW32__ *//*************************************************************************//* This is part of the server process. *//*************************************************************************/#ifdef __MINGW32__/* * This routine is the actual threads callback, but calls the coservers * callback indeed. It is a wrapper routine for Win32, because you can pass * only a single argument to a thread routine. */static DWORD WINAPI svz_coserver_thread (LPVOID thread){ svz_coserver_t *coserver; coserver = (svz_coserver_t *) thread; svz_coserver_loop (coserver, coserver->sock); ExitThread (0); return 0;}/* * Reactivate all specific coservers with type @var{type}. In Win32 * you have to call this if you want the coserver start working. */static voidsvz_coserver_activate (int type){ int n, count = 0, res; svz_coserver_t *coserver; /* go through all internal coserver threads */ svz_array_foreach (svz_coservers, coserver, n) { /* is this structure of the requested type ? */ if (coserver->type == type) { /* activated the thread */ while ((res = ResumeThread (coserver->thread)) > 0); if (res == 0) count++; } }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "%d internal %s coserver activated\n", count, svz_coservertypes[type].name);#endif /* ENABLE_DEBUG */}#endif /* __MINGW32__ *//* * Return the number of currently running coservers with the type @var{type}. */static intsvz_coserver_count (int type){ int n, count = 0; svz_coserver_t *coserver; svz_array_foreach (svz_coservers, coserver, n) if (coserver->type == type) count++; return count;}/* * Delete the n'th internal coserver from coserver array. */static voidsvz_coserver_delete (int n){ svz_coserver_t *coserver; if ((coserver = svz_array_get (svz_coservers, n)) != NULL) { svz_free (coserver); svz_array_del (svz_coservers, n); } if (svz_array_size (svz_coservers) == 0) { svz_array_destroy (svz_coservers); svz_coservers = NULL; }}#ifndef __MINGW32__/* * Disconnects a internal coserver. This is the callback routine for the * socket structure entry `disconnected_socket'. */static intsvz_coserver_disconnect (svz_socket_t *sock){ int n; svz_coserver_t *coserver; svz_array_foreach (svz_coservers, coserver, n) { if (coserver->sock == sock) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "%s: killing coserver pid %d\n", svz_coservertypes[coserver->type].name, coserver->pid);#endif /* ENABLE_DEBUG */ if (kill (coserver->pid, SIGKILL) == -1) svz_log (LOG_ERROR, "kill: %s\n", SYS_ERROR);#if HAVE_WAITPID /* cleanup coserver child process */ else if (waitpid (coserver->pid, NULL, WNOHANG) == -1) svz_log (LOG_ERROR, "waitpid: %s\n", SYS_ERROR);#endif /* HAVE_WAITPID */ /* re-arrange the internal coserver array */ svz_coserver_delete (n); break; } } return 0;}#endif /* not __MINGW32__ *//* * This routine has to be called for coservers requests. It is the default * @code{check_request()} routine for coservers detecting full responses as * lines (trailing '\n'). */static intsvz_coserver_check_request (svz_socket_t *sock){ char *packet = sock->recv_buffer; char *p = packet; int request_len; int len = 0; svz_coserver_t *coserver; do { /* find a line (trailing '\n') */ while (*p != COSERVER_PACKET_BOUNDARY && p < sock->recv_buffer + sock->recv_buffer_fill) p++; if (*p == COSERVER_PACKET_BOUNDARY && p < sock->recv_buffer + sock->recv_buffer_fill) { coserver = sock->data; assert (coserver); coserver->busy--; p++; request_len = p - packet; len += request_len; if (sock->handle_request) sock->handle_request (sock, packet, request_len); packet = p; } } while (p < sock->recv_buffer + sock->recv_buffer_fill); #if ENABLE_DEBUG svz_log (LOG_DEBUG, "coserver: %d byte response\n", len);#endif /* remove data from receive buffer if necessary */ if (len > 0 && sock->recv_buffer_fill > len) { memmove (sock->recv_buffer, packet, sock->recv_buffer_fill - len); } sock->recv_buffer_fill -= len; return 0;}/* * The standard coserver @code{handle_request()} routine is called whenever * the standard @code{check_request()} detected a full packet by any coserver. */static intsvz_coserver_handle_request (svz_socket_t *sock, char *request, int len){ int ret; unsigned id; char *p, *end, *data; svz_coserver_callback_t *cb; /* Search for coserver hash id. */ id = 0; p = request; end = p + len; while (*p != COSERVER_ID_BOUNDARY && p < end) { if (*p < '0' || *p > '9') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -