diff --git a/src/common/protocol.h b/src/common/protocol.h --- a/src/common/protocol.h +++ b/src/common/protocol.h @@ -47,6 +47,11 @@ enum distren_request_type DISTREN_REQUEST_VERSION = 1, DISTREN_REQUEST_PING = 2, DISTREN_REQUEST_PONG = 3, + /** + The data is the a reason describing why the one end is + disconnecting. The other end should respectfully close() + the socket or the sender will timeout shortly. + */ DISTREN_REQUEST_DISCONNECT = 4, /** diff --git a/src/server/distrend.c b/src/server/distrend.c --- a/src/server/distrend.c +++ b/src/server/distrend.c @@ -85,6 +85,7 @@ int distrend_do_config(int argc, char *a int distrend_config_free(struct distrend_config *config); int distrend_handle_request(struct distrend_client *client, struct distren_request *req, void *reqdata, struct general_info *geninfo); + /* **************XML Functions**************** */ void update_general_info(struct general_info *geninfo); int import_general_info(struct general_info *general_info); @@ -210,6 +211,8 @@ int main(int argc, char *argv[]) int distrend_handle_request(struct distrend_client *client, struct distren_request *req, void *reqdata, struct general_info *geninfo) { size_t counter; + char *tmp_str; + char fixedbuf[32]; /* for response requests... if that makes any less sense ;-) */ struct distren_request *newreq; @@ -222,6 +225,30 @@ int distrend_handle_request(struct distr switch(req->type) { case DISTREN_REQUEST_VERSION: + if(strlen(PACKAGE_STRING) == req->len + && !strncmp(PACKAGE_STRING, reqdata, req->len)) + { + /** + The client and I claim to be of the same version of distren :-D + Now we will mark the client as valid. + */ + + } + else + { + /** + The client claims to be of a different version of distren. + Now we will just send a disconnect packet and disconnect the client. + */ + strncpy(fixedbuf, reqdata, 31); + fixedbuf[31] = '\0'; + if(req->len < 31) + fixedbuf[req->len] = '\0'; + + _distren_asprintf(&tmp_str, "You have tried to connect to a %s server when your client claims to be running %s. Bye ;-)\n", PACKAGE_STRING, fixedbuf); + distrend_send_disconnect(client, tmp_str); + } + distren_request_new(&newreq, strlen(VERSION), DISTREN_REQUEST_VERSION); distrend_client_write_request(client, newreq, VERSION); distren_request_free(newreq); diff --git a/src/server/listen.c b/src/server/listen.c --- a/src/server/listen.c +++ b/src/server/listen.c @@ -304,6 +304,7 @@ struct distrend_accept_client_proc_data distrend_handle_request_t handlereq; void *handlereqdata; enum {DISTREND_ACCEPT_CLIENT_READ, DISTREND_ACCEPT_CLIENT_WRITE} mode; + time_t current_time; }; int distrend_accept_client_proc(struct distrend_accept_client_proc_data *data, struct distrend_client *client) @@ -314,6 +315,25 @@ int distrend_accept_client_proc(struct d if(client->state == DISTREND_CLIENT_DEAD) return TRUE; + if(data->current_time > client->cleanup_time) + switch(client->state) + { + case DISTREND_CLIENT_PREAUTH: + distrend_send_disconnect(client, "You have failed to present authentication information in a timely manner. Cya ;-)"); + break; + + case DISTREND_CLIENT_GOOD: + distrend_send_disconnect(client, "Ping timeout :-p"); + break; + + case DISTREND_CLIENT_BAD: + client->state = DISTREND_CLIENT_DEAD; + return TRUE; + + default: + break; + } + if(!FD_ISSET(client->sock, data->fdset)) /** continue iteration through the list */ return TRUE; @@ -403,6 +423,7 @@ int distrend_accept(struct distrend_conf travinfo.handlereq = handlereq; travinfo.handlereqdata = handlereqdata; travinfo.mode = DISTREND_ACCEPT_CLIENT_WRITE; + travinfo.current_time = time(NULL); /*< cache the time */ list_traverse(clients->clients, &travinfo, (list_traverse_func_t)&distrend_accept_client_proc, LIST_FRNT | LIST_ALTR); travinfo.fdset = &fdsets.readfds; @@ -484,6 +505,7 @@ int distrend_client_new(struct distrend_ } (*client)->sock = sock; (*client)->state = state; + (*client)->cleanup_time = time(NULL) + DISTREND_LISTEN_AUTHTIME; (*client)->inlen = 0; (*client)->expectlen = 0; (*client)->inmsgs = q_init(); @@ -646,3 +668,18 @@ int distrend_packets_collapse(QUEUE *que return 0; } + + +int distrend_send_disconnect(struct distrend_client *client, char *quit_msg) +{ + struct distren_request *req; + + distren_request_new(&req, strlen(quit_msg), DISTREN_REQUEST_DISCONNECT); + distrend_client_write_request(client, req, quit_msg); + distren_request_free(req); + + client->state = DISTREND_CLIENT_BAD; + client->cleanup_time = time(NULL) + DISTREND_LISTEN_DISCONNECT_GRACE; + + return 0; +} diff --git a/src/server/listen.h b/src/server/listen.h --- a/src/server/listen.h +++ b/src/server/listen.h @@ -28,12 +28,44 @@ struct distrend_client; #include "common/protocol.h" #include +#include + +/** + How long a client has after connecting to send + authentication information before his connection is cleaned + up. + */ +#define DISTREND_LISTEN_AUTHTIME 32 + +/** + How long a client has when in DISTREND_CLIENT_BAD before + his connection is dropped. This grace time is intended so that + the client will actually see his disconnect message instead of + just having his connection reset. + */ +#define DISTREND_LISTEN_DISCONNECT_GRACE 8 enum distrend_client_state { + /** + We don't yet know the client. It may only use authentication + commands. + */ DISTREND_CLIENT_PREAUTH, - DISTREND_CLIENT_GOODDOGGY, - DISTREND_CLIENT_BADBOY, + /** + The client is authenticated, etc. + */ + DISTREND_CLIENT_GOOD, + /** + The client is queued to be disconnected. (This state exists + so that the client at least has a chance to recieve its + disconnect message/error before being dumped). + */ + DISTREND_CLIENT_BAD, + /** + The socket used to communicate with the client is closed. Its entry + in the client list should be removed on the next garbage clean-up round. + */ DISTREND_CLIENT_DEAD }; @@ -48,6 +80,14 @@ struct distrend_client int sock; enum distrend_client_state state; + /** + The absolute time at which this client's entry in the client list will be + expired, closed, and marked as dead so that it may be cleaned up. This is + used to implement ping timeouts (if state == DISTREND_CLIENT_GOOD) and + disconnect message grace time (if state == DISTREND_CLIENT_BAD). + */ + time_t cleanup_time; + size_t inlen; /*< number of bytes waiting to be processed */ size_t expectlen; /*< number of bytes that inlen has to be for a complete request to be had, 0 when waiting on header */ QUEUE *inmsgs; @@ -100,4 +140,11 @@ int distrend_client_write_request(struct */ void remotio_send_to_client(); +/** + Queue a DISTREN_REQUEST_DISCONNECT and prepare a client + to be disconnected. + */ +int distrend_send_disconnect(struct distrend_client *client, char *quit_msg); + + #endif