📄 socket.c
字号:
/* * socket.c - socket management implementation * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * Copyright (C) 1999 Martin Grabmueller <mgrabmue@cs.tu-berlin.de> * * 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: socket.c,v 1.16 2001/08/13 06:56:43 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 <errno.h>#include <fcntl.h>#include <sys/types.h>#include <signal.h>#include <time.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#if HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <sys/socket.h># include <netinet/in.h># include <netdb.h>#endif#include "libserveez/snprintf.h"#include "libserveez/alloc.h"#include "libserveez/util.h"#include "libserveez/socket.h"#include "libserveez/core.h"#include "libserveez/pipe-socket.h"#include "libserveez/tcp-socket.h"#include "libserveez/server-core.h"#include "libserveez/server.h"/* * Count the number of currently connected sockets. */int svz_sock_connections = 0;#if ENABLE_FLOOD_PROTECTION/* * This routine can be called if flood protection is wished for * socket readers. Return non-zero if the socket should be kicked * because of flood. */intsvz_sock_flood_protect (svz_socket_t *sock, int num_read){ if (!(sock->flags & SOCK_FLAG_NOFLOOD)) { /* * Since the default flood limit is 100 a reader can produce * 5000 bytes per second before it gets kicked. */ sock->flood_points += 1 + (num_read / 50); if (sock->flood_points > sock->flood_limit) { if (sock->kicked_socket) sock->kicked_socket (sock, 0); return -1; } } return 0;}#endif /* ENABLE_FLOOD_PROTECTION *//* * The default function which gets called when a client shuts down * its socket. @var{sock} is the socket which was closed. */static intsvz_sock_default_disconnect (svz_socket_t *sock){#if ENABLE_DEBUG svz_log (LOG_DEBUG, "socket id %d disconnected\n", sock->id);#endif return 0;}/* * This routine gets called whenever data is read from a client socket * accepted by any connection oriented protocol layer (TCP or PIPE). We * try to detect the data streams protocol here. */intsvz_sock_detect_proto (svz_socket_t *sock){ int n; svz_server_t *server; svz_portcfg_t *port; /* return if there are no servers bound to this socket */ if (sock->data == NULL) return -1; /* get port configuration of parent */ port = svz_sock_portcfg (sock); /* go through each server stored in the data field of this socket */ svz_array_foreach (sock->data, server, n) { /* can occur if it is actually a packet oriented server */ if (server->detect_proto == NULL) { svz_log (LOG_ERROR, "%s: no detect-proto routine\n", server->type->prefix); } /* call protocol detection routine of the server */ else if (server->detect_proto (server, sock)) { sock->idle_func = NULL; sock->data = NULL; sock->cfg = server->cfg; if (!server->connect_socket) return -1; if (server->connect_socket (server, sock)) return -1; return sock->check_request (sock); } } /* * Discard this socket if there were not any valid protocol * detected and its receive buffer fill exceeds a maximum value. */ if (sock->recv_buffer_fill > port->detection_fill) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "socket id %d detection failed\n", sock->id);#endif return -1; } return 0;}/* * Default idle function. This routine simply checks for "dead" * (non-receiving) sockets (connection oriented protocols only) and rejects * them by return a non-zero value. */intsvz_sock_idle_protect (svz_socket_t *sock){ svz_portcfg_t *port = svz_sock_portcfg (sock); if (time (NULL) - sock->last_recv > port->detection_wait) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "socket id %d detection failed\n", sock->id);#endif return -1; } sock->idle_counter = 1; return 0;}/* * This @code{check_request()} routine could be used by any protocol to * detect and finally handle packets depending on a specific packet * boundary. The appropriate @code{handle_request()} is called for each packet * explicitly with the packet length inclusive the packet boundary. */static intsvz_sock_check_request_array (svz_socket_t *sock){ int len = 0; char *p, *packet, *end; packet = p = sock->recv_buffer; end = p + sock->recv_buffer_fill - sock->boundary_size + 1; do { /* Find packet boundary in the receive buffer. */ while (p < end && memcmp (p, sock->boundary, sock->boundary_size)) p++; /* Found ? */ if (p < end && !memcmp (p, sock->boundary, sock->boundary_size)) { p += sock->boundary_size; len += (p - packet); /* Call the handle request callback. */ if (sock->handle_request) { if (sock->handle_request (sock, packet, p - packet)) return -1; } packet = p; } } while (p < end); /* Shuffle data in the receive buffer around. */ svz_sock_reduce_recv (sock, len); return 0;}/* * This is just the same routine as above, but optimized for one byte * packet delimiters. */static intsvz_sock_check_request_byte (svz_socket_t *sock){ int len = 0; char *p, *packet, *end; packet = p = sock->recv_buffer; end = p + sock->recv_buffer_fill; do { /* Find packet boundary in the receive buffer. */ while (p < end && *p != *sock->boundary) p++; /* Found ? */ if (p < end && *p == *sock->boundary) { p++; len += (p - packet); /* Call the handle request callback. */ if (sock->handle_request) { if (sock->handle_request (sock, packet, p - packet)) return -1; } packet = p; } } while (p < end); /* Shuffle data in the receive buffer around. */ svz_sock_reduce_recv (sock, len); return 0;}/* * The following routine checks for fixed size packets in the receive queue * of the socket structure @var{sock} and calls the @code{handle_request()} * callback if so. It is possible to change the fixed packet size in the * @code{handle_request()} callback dynamically. */static intsvz_sock_check_request_size (svz_socket_t *sock){ int len = 0; char *p, *packet, *end; packet = p = sock->recv_buffer; end = p + sock->recv_buffer_fill; while (p + sock->boundary_size < end) { len += sock->boundary_size; p += sock->boundary_size; /* Call the handle request callback. */ if (sock->handle_request) { if (sock->handle_request (sock, packet, sock->boundary_size)) return -1; } packet = p; } /* Shuffle data in the receive buffer around. */ svz_sock_reduce_recv (sock, len); return 0;}/* * This function simply checks for the kind of packet delimiter within the * given socket structure and and assigns one of the default * @code{check_request()} routines (one or more byte delimiters or a fixed * size). Afterwards this routine will never ever be called again because * the callback gets overwritten here. */intsvz_sock_check_request (svz_socket_t *sock){ if (sock->boundary_size <= 0) { svz_log (LOG_ERROR, "invalid boundary size: %d\n", sock->boundary_size); return -1; } if (sock->boundary == NULL) sock->check_request = svz_sock_check_request_size; else if (sock->boundary_size > 1) sock->check_request = svz_sock_check_request_array; else sock->check_request = svz_sock_check_request_byte;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -