📄 awcs-proto.c
字号:
while (*cmd && *cmd != ' ') { awcs_process_id (address, cmd); sock = (svz_socket_t *) svz_hash_get (cfg->clients, (char *) &address); if (sock) { if (svz_sock_write (sock, msg, cmd_len)) svz_sock_schedule_for_shutdown (sock); }#if ENABLE_DEBUG else { svz_log (LOG_DEBUG, "awcs: master sent invalid id (multicast %d)\n", address); }#endif /* ENABLE_DEBUG */ } return 0;}/* * Process a status request. */static intawcs_process_status (awcs_config_t *cfg, char *cmd, int cmd_len){#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: sending status message\n");#endif /* ENABLE_DEBUG */ awcs_status_alive (cfg); return 0;}/* * Kick all clients in the client list at the beginning of @var{cmd}. * The rest of @var{cmd} is the kicking reason. */static intawcs_process_kick (awcs_config_t *cfg, char *cmd, int cmd_len){ svz_socket_t *sock; int address; while (*cmd && *cmd != ' ') { awcs_process_id (address, cmd); sock = (svz_socket_t *) svz_hash_get (cfg->clients, (char *) &address); if (sock) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: kicking socket %d\n", sock->sock_desc);#endif /* ENABLE_DEBUG */ /* * This is a hack. We set the handler to NULL to be sure * that the master server will not get a KICKED status * message for a kick he initiated. */ sock->kicked_socket = NULL; svz_sock_schedule_for_shutdown (sock); }#if ENABLE_DEBUG else { svz_log (LOG_DEBUG, "awcs: master sent invalid id (kick %d)\n", address); }#endif /* ENABLE_DEBUG */ } return 0;}/* * Turn off flood protection for clients listed in command if flag is * false, turn it on otherwise. */static intawcs_process_floodcmd (awcs_config_t *cfg, char *cmd, int cmd_len, int flag){ svz_socket_t *sock; int address; while (*cmd && *cmd != ' ') { awcs_process_id (address, cmd); sock = (svz_socket_t *) svz_hash_get (cfg->clients, (char *) &address); if (sock) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: switching flood control for socket " "%d %s\n", sock->sock_desc, flag ? "on" : "off");#endif /* ENABLE_DEBUG */ if (flag) sock->flags &= ~SOCK_FLAG_NOFLOOD; else sock->flags |= SOCK_FLAG_NOFLOOD; }#if ENABLE_DEBUG else { svz_log (LOG_DEBUG, "awcs: master sent invalid id (floodcmd %d)\n", address); }#endif /* ENABLE_DEBUG */ } return 0;}/* * Handle a request from the master server. Return a non-zero value * on error. */static intawcs_handle_master_request (awcs_config_t *cfg, char *request, int request_len){ if (request_len <= 0) return -1;#if 0 svz_hexdump (stdout, "master request", cfg->server->sock_desc, request, request_len, 0);#endif request_len--; switch (*request++) { case '0': request++; request_len--; awcs_process_broadcast (cfg, request, request_len); break; case '1': request++; request_len--; awcs_process_multicast (cfg, request, request_len); break; case '2': request++; request_len--; awcs_process_status (cfg, request, request_len); break; case '3': request++; request_len--; awcs_process_kick (cfg, request, request_len); break; case '4': request++; request_len--; awcs_process_floodcmd (cfg, request, request_len, 0); break; case '5': request++; request_len--; awcs_process_floodcmd (cfg, request, request_len, 1); break; case '6': /* The following code should not be executed anymore. */ svz_log (LOG_NOTICE, "awcs: skipping '6' ...\n"); break; default: svz_log (LOG_ERROR, "awcs: bad master server request\n"); break; } return 0;}/* * Schedule all aWCS clients for shutdown. Call this if the * connection to the master server has been lost. */voidawcs_disconnect_clients (awcs_config_t *cfg){ svz_socket_t **sock; int n; if ((sock = (svz_socket_t **) svz_hash_values (cfg->clients)) != NULL) { for (n = 0; n < svz_hash_size (cfg->clients); n++) svz_sock_schedule_for_shutdown (sock[n]); svz_hash_xfree (sock); }}/* * Handle the request REQUEST of length REQUEST_LEN from socket * SOCK. Return a non-zero value on error. */static intawcs_handle_request (svz_socket_t *sock, char *request, int request_len){ int ret; awcs_config_t *cfg = sock->cfg;#if 0 svz_hexdump (stdout, "awcs request", sock->sock_desc, request, request_len, 1000);#endif if (!cfg->server) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: no master server (awcs_handle_request)\n");#endif awcs_disconnect_clients (cfg); return -1; } if (sock == cfg->server) { awcs_handle_master_request (cfg, request, request_len); } else { ret = svz_sock_printf (cfg->server, AWCS_ID_FMT " ", sock->id); if (ret == 0) { ret = svz_sock_write (cfg->server, request, request_len); } if (ret) { 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;}/* * Checks whether a complete request has been accumulated in socket * @var{sock}'s receive queue. If yes, then the request gets handled * and removed from the queue. */intawcs_check_request (svz_socket_t *sock){ int retval = 0; int request_len = 0; char * p, * packet; p = sock->recv_buffer; packet = p; do { while (p < sock->recv_buffer + sock->recv_buffer_fill && *p != '\0') p++; if (*p == '\0' && p < sock->recv_buffer + sock->recv_buffer_fill) { p++; request_len += (p - packet); retval = awcs_handle_request (sock, packet, p - packet); packet = p; } } while (p < sock->recv_buffer + sock->recv_buffer_fill); if (request_len > 0) { memmove (sock->recv_buffer, packet, sock->recv_buffer_fill - request_len); } sock->recv_buffer_fill -= request_len; return 0;}/* * Gets called when a client has connected as socket SOCK and has been * identified as an aWCS client. MASTER ist set if it was a master * server detection. */intawcs_connect_socket (svz_server_t *server, svz_socket_t *sock){ awcs_config_t *cfg = server->cfg; /* * Don't allow clients without master server or multiple master servers. */ if ((!cfg->server && !cfg->master) || (cfg->server && cfg->master)) { if (!cfg->server && !cfg->master) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: master not present, cannot connect socket %d\n", sock->sock_desc);#endif } if (cfg->server && cfg->master) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "awcs: master is present, cannot connect socket %d\n", sock->sock_desc);#endif } return -1; }#if ENABLE_DEBUG if (sock->flags & SOCK_FLAG_PIPE) { svz_log (LOG_DEBUG, "awcs: connection on pipe (%d-%d)\n", sock->pipe_desc[READ], sock->pipe_desc[WRITE]); } else { svz_log (LOG_DEBUG, "awcs: connection on socket %d\n", sock->sock_desc); }#endif /* ENABLE_DEBUG */ sock->disconnected_socket = awcs_disconnected_socket; sock->check_request = awcs_check_request; if (cfg->master) {#if ENABLE_DEBUG if (sock->flags & SOCK_FLAG_PIPE) { svz_log (LOG_NOTICE, "awcs: master server connected on pipe (%d-%d)\n", sock->pipe_desc[READ], sock->pipe_desc[WRITE]); } else { svz_log (LOG_NOTICE, "awcs: master server connected on socket %d\n", sock->sock_desc); }#endif /* ENABLE_DEBUG */ cfg->server = sock; sock->idle_func = awcs_idle_func; sock->idle_counter = 3; sock->flags |= (SOCK_FLAG_NOFLOOD | SOCK_FLAG_PRIORITY); svz_log (LOG_NOTICE, "awcs: resizing master buffers: %d, %d\n", MASTER_SEND_BUFSIZE, MASTER_RECV_BUFSIZE); svz_sock_resize_buffers (sock, MASTER_SEND_BUFSIZE, MASTER_RECV_BUFSIZE); sock->flags |= SOCK_FLAG_INITED; } else { svz_hash_put (cfg->clients, (char *) &sock->id, sock); sock->kicked_socket = awcs_kicked_socket; } /* * Tell the master server about the connection (even itself). */ awcs_status_connected (sock); return 0;}/* * Gets called when the socket SOCK had disconnected. All clients are * kicked when the socket was the master server, otherwise a diconnection * message is sent to the master server. */intawcs_disconnected_socket (svz_socket_t *sock){ awcs_config_t *cfg = sock->cfg; if (sock == cfg->server) { svz_log (LOG_ERROR, "awcs: lost master server\n"); cfg->server = NULL; awcs_disconnect_clients (cfg); } else { awcs_status_disconnected (sock, 1); svz_hash_delete (cfg->clients, (char *) &sock->id); } return 0;}/* * Gets called when the socket SOCK got kicked. REASON is true when * a output buffer overflow occured and false, when it was an input * buffer overflow or flooding. */intawcs_kicked_socket (svz_socket_t *sock, int reason){ if (!reason) awcs_status_kicked (sock, KICK_FLOODING); else awcs_status_kicked (sock, KICK_CRAWLING); return 0;}/* * The socket for the master server gets set this function as the timer * function. The function sends an idle message to the master server * and resets its timeout counter. */intawcs_idle_func (svz_socket_t *sock){ awcs_config_t *cfg = sock->cfg; if (sock == cfg->server) { sock->idle_counter = 3; awcs_status_notify (cfg); } return 0;}/* * This function gets called for new sockets which are not yet * identified. It returns a non-zero value when the contents in * the receive buffer looks like an aWCS identification request. */intawcs_detect_proto (svz_server_t *server, svz_socket_t *sock){ awcs_config_t *cfg = server->cfg; int len = 0;#if 0 svz_hexdump (stdout, "detecting awcs", sock->sock_desc, sock->recv_buffer, sock->recv_buffer_fill, 0);#endif if (sock->recv_buffer_fill >= MASTER_DETECTION && !memcmp (sock->recv_buffer, AWCS_MASTER, MASTER_DETECTION)) { cfg->master = 1; svz_log (LOG_NOTICE, "awcs: master detected\n"); len = MASTER_DETECTION; } else if (sock->recv_buffer_fill >= CLIENT_DETECTION && !memcmp (sock->recv_buffer, AWCS_CLIENT, CLIENT_DETECTION)) { cfg->master = 0; svz_log (LOG_NOTICE, "awcs: client detected\n"); len = CLIENT_DETECTION; } if (len == 0) return 0; if (sock->recv_buffer_fill > len) { memmove (sock->recv_buffer, sock->recv_buffer + len, sock->recv_buffer_fill - len); } sock->recv_buffer_fill -= len; return len;}int have_awcs = 1;#else /* ENABLE_AWCS_PROTO */int have_awcs = 0; /* Shut compiler warnings up, make runtime checking possible */#endif /* not ENABLE_AWCS_PROTO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -