⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coserver.c

📁 Serveez是一个服务器框架
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -