📄 awcs-proto.c
字号:
/* * awcs-proto.c - aWCS protocol 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: awcs-proto.c,v 1.34 2001/08/12 10:59:04 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_AWCS_PROTO#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#if HAVE_UNISTD_H# include <unistd.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#ifndef __MINGW32__# include <netinet/in.h>#endif#include "libserveez.h"#include "awcs-proto.h"/* * The aWCS server instance configuration. */awcs_config_t awcs_config ={ NULL, /* aWCS Master server */ 0, /* Was Master server detected ? */ NULL /* aWCS clients user base hash */};/* * Definition of the configuration items delivered by the * configuration language. */svz_key_value_pair_t awcs_config_prototype [] ={ SVZ_REGISTER_END ()};/* * The aWCS server definition. */svz_servertype_t awcs_server_definition ={ "aWCS server", /* server description */ "aWCS", /* server prefix used in the config file "aWCS?" */ NULL, /* global initialization */ awcs_init, /* server instance initialization */ awcs_detect_proto, /* protocol detection routine */ awcs_connect_socket, /* callback when detected */ awcs_finalize, /* server instance finalization */ NULL, /* global finalization */ NULL, /* client info */ NULL, /* server info */ NULL, /* server timer */ NULL, /* handle request callback */ &awcs_config, /* the instance configuration */ sizeof (awcs_config), /* sizeof the instance configuration */ awcs_config_prototype /* configuration definitions */};/* * These 3 (three) routines are for modifying the client hash key * processing. Because we are using unique IDs for identifying aWCS * clients it is not necessary to have character strings here. */static unsignedawcs_hash_keylen (char *id){ return 4;}static int awcs_hash_equals (char *id1, char *id2){ return memcmp (id1, id2, 4);} static unsigned long awcs_hash_code (char *id){ unsigned long code = SVZ_UINT32 (id); return code;}/* * Local aWCS server instance initialization routine. */intawcs_init (svz_server_t *server){ awcs_config_t *cfg = server->cfg; /* initialize server instance */ cfg->master = 0; cfg->clients = svz_hash_create (4); cfg->clients->code = awcs_hash_code; cfg->clients->keylen = awcs_hash_keylen; cfg->clients->equals = awcs_hash_equals; cfg->server = NULL; return 0;}/* * Local aWCS server instance finalizer. */intawcs_finalize (svz_server_t *server){ awcs_config_t *cfg = server->cfg; svz_hash_destroy (cfg->clients); return 0;}/* * Gets called when a nslookup coserver has resolved a IP address * for socket SOCK to name and has been identified as an aWCS client. */intawcs_nslookup_done (char *host, int id, int version){ awcs_config_t *cfg; svz_socket_t *sock = svz_sock_find (id, version); if (host && sock) { cfg = sock->cfg; if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (nslookup_done)\n");#endif return -1; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: sending resolved ip to master\n");#endif if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d " AWCS_ID_FMT " %s%c", cfg->server->id, STATUS_NSLOOKUP, sock->id, host, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } } return 0;}/* * Gets called when a ident coserver has resolved a IP address * for socket SOCK to name and has been identified as an aWCS client. */intawcs_ident_done (char *user, int id, int version){ svz_socket_t *sock = svz_sock_find (id, version); awcs_config_t *cfg; if (user && sock) { cfg = sock->cfg; if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (ident_done)\n");#endif return -1; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: sending identified client to master\n");#endif if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d " AWCS_ID_FMT " %s%c", cfg->server->id, STATUS_IDENT, sock->id, user, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } } return 0;}/* * This is called when a valid aWCS client has been connected. * The routine reports this to the Master server and invokes * a reverse nslookup and a ident request. */static intawcs_status_connected (svz_socket_t *sock){ unsigned short port; unsigned long addr; awcs_config_t *cfg = sock->cfg; if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (status_connected)\n");#endif return -1; } addr = sock->remote_addr; port = sock->remote_port;#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: sending connect on socket id %d to master\n", sock->id);#endif if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d " AWCS_ID_FMT " %s:%u%c", cfg->server->id, STATUS_CONNECT, sock->id, svz_inet_ntoa (addr), htons (port), '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } /* * Initiate a reverse nslookup and ident request for a real client. */ if (sock != cfg->server) { svz_coserver_rdns (addr, awcs_nslookup_done, sock->id, sock->version); svz_coserver_ident (sock, awcs_ident_done, sock->id, sock->version); } return 0;}/* * Send a status message to the master server * telling it that client `client' has disconnected. `reason' * is an error code telling how the client got disconnected. */static intawcs_status_disconnected (svz_socket_t *sock, int reason){ awcs_config_t *cfg = sock->cfg; if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (status_disconnected)\n");#endif return -1; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: sending disconnect on socket %d to master\n", sock->sock_desc);#endif /* ENABLE_DEBUG */ if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d " AWCS_ID_FMT " %d%c", cfg->server->id, STATUS_DISCONNECT, sock->id, reason, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } return 0;}/* * Send a status message to the master server * telling it that client `client' has been kicked. `reason' * is an error code telling why the client got kicked. */static intawcs_status_kicked (svz_socket_t *sock, int reason){ awcs_config_t *cfg = sock->cfg; if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (status_kicked)\n");#endif return -1; } if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d " AWCS_ID_FMT " %d%c", cfg->server->id, STATUS_KICK, sock->id, reason, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } return 0;}/* * Send a message to the master server indicating this server * is still alive. */static intawcs_status_alive (awcs_config_t *cfg){ if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (status_alive)\n");#endif /* ENABLE_DEBUG */ return -1; } if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d 42%c", cfg->server->id, STATUS_ALIVE, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } return 0;}static intawcs_status_notify (awcs_config_t *cfg) { if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (status_notify)\n");#endif /* ENABLE_DEBUG */ return -1; } if (svz_sock_printf (cfg->server, AWCS_ID_FMT " %d 42%c", cfg->server->id, STATUS_NOTIFY, '\0')) { svz_log (LOG_FATAL, "awcs: master write error\n"); svz_sock_schedule_for_shutdown (cfg->server); cfg->server = NULL; awcs_disconnect_clients (cfg); return -1; } return 0;}/* * Broadcast message `cmd' to all connected aWCS clients. */static intawcs_process_broadcast (awcs_config_t *cfg, char *cmd, int cmd_len){ svz_socket_t **sock; int n; #if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: broadcasting\n");#endif /* ENABLE_DEBUG */ if ((sock = (svz_socket_t **) svz_hash_values (cfg->clients)) != NULL) { for (n = 0; n < svz_hash_size (cfg->clients); n++) { if (svz_sock_write (sock[n], cmd, cmd_len)) { svz_sock_schedule_for_shutdown (sock[n]); } } svz_hash_xfree (sock); } return 0;}/* * This macro parse an aWCS id at the given memory location @var{ptr}. The * result will be stored in @var{id} and @var{ptr} points to the following * non numerical byte afterwards. */#define awcs_process_id(id, ptr) \ (id) = 0; \ while (*(ptr) >= '0' && *(ptr) <= '9') { \ (id) *= 10; \ (id) += *(ptr) - '0'; \ (ptr)++; } \ if (*(ptr) == ',') (ptr)++/* * Send message @var{cmd} to all clients in the client list at the start * of @var{cmd}. */static intawcs_process_multicast (awcs_config_t *cfg, char *cmd, int cmd_len){ char *msg; int address; svz_socket_t *sock; /* Parse the actual message first. */ msg = cmd; while (*msg++ != ' '); cmd_len -= (msg - cmd); /* Go through the client list. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -