# HG changeset patch # User Nathan Phillip Brink # Date 2010-07-25 17:23:16 # Node ID 7c0e60f07a51caa1f29592b6d5041785f22711a7 # Parent da79b5082151f262e46b8b21de1bc36f091e1789 Server and client will connect and send DISTREN_REQUEST_VERSION packets immediately. diff --git a/doc/architecture.txt b/doc/architecture.txt --- a/doc/architecture.txt +++ b/doc/architecture.txt @@ -57,6 +57,8 @@ Concepts: - servers: A server, though having many more functions, shall be able to also perform the list of actions a client may perform. +- user: A user is an entity which is given access to a distren server. + - file: There are different uses of files above and distributed rendering requires file distribution. - file identification: Every file mentioned above was at least in the context of a job. Thus, file identification numbers shall be assigned in the context of a job identification number. diff --git a/src/client/libdistren.c b/src/client/libdistren.c --- a/src/client/libdistren.c +++ b/src/client/libdistren.c @@ -23,7 +23,9 @@ #include "common/config.h" #include "common/options.h" +#include "common/protocol.h" #include "common/remoteio.h" +#include "common/request.h" #include "libdistren.h" @@ -31,10 +33,18 @@ #include #include +/** + * Handle common cleanup actions for distren_init(). + */ +static void distren_init_cleanup(distren_t distren); + int distren_init(distren_t *handle) { int tmp; + struct distren_request *req; + void *data; + if(!handle) return 1; @@ -48,7 +58,7 @@ int distren_init(distren_t *handle) if(_distren_getoptions(*handle)) { fprintf(stderr, "error getting configuration\n"); - distren_free(*handle); + distren_init_cleanup(*handle); return 1; } @@ -62,18 +72,43 @@ int distren_init(distren_t *handle) { fprintf(stderr, "error: unable to connect to server\n"); - (*handle)->rem = NULL; - distren_free(*handle); + distren_init_cleanup(*handle); return 1; } - multiio_poll((*handle)->multiio, 2000); - multiio_poll((*handle)->multiio, 2000); - multiio_poll((*handle)->multiio, 2000); - + /* send off a DISTREN_REQUEST_VERSION to the server */ + tmp = distren_request_version(&req, &data, DISTREN_SERVERTYPE_CLIENT, PACKAGE_STRING); + if(tmp) + { + fprintf(stderr, "error: unable to allocate request"); + + distren_init_cleanup(*handle); + return 1; + } + distren_request_send((*handle)->rem, req, data); + distren_request_free_with_data(req, data); + + while((*handle)->rem + && (*handle)->state == DISTREN_STATE_VERSION) + multiio_poll((*handle)->multiio, 500); + + if(!(*handle)->rem) + { + distren_init_cleanup(*handle); + return 1; + } + return 0; } +static void distren_init_cleanup(distren_t distren) +{ + if(distren->rem) + remoteio_close(distren->rem); + distren->rem = NULL; + distren_free(distren); +} + /** * @todo Stub */ diff --git a/src/client/libdistren.h b/src/client/libdistren.h --- a/src/client/libdistren.h +++ b/src/client/libdistren.h @@ -30,12 +30,33 @@ #include "common/options.h" #include "common/remoteio.h" +#include + +enum distren_state + { + /** + * client is waiting for a VERSION packet from the server. + */ + DISTREN_STATE_VERSION, + /** + * We are waiting to be authenticated. + */ + DISTREN_STATE_AUTH, + DISTREN_STATE_NORMAL, + DISTREN_STATE_UPLOADING, + }; + struct distren { struct options_common *options; char *server; - /* if rem is NULL, we're not connected to the server */ + enum distren_state state; + + /* + * If rem is NULL, we're not connected to the server. This is the + * way to detect a communication error. + */ struct remoteio *rem; /* * for libdistren_remoteio_read_handle(): determine whether or not @@ -43,8 +64,15 @@ struct distren */ short done_ad; + /* + * The servertype bitmask of the remote server. + */ + uint32_t servertype; + /* something on which to call multiio_poll() ;-) */ multiio_context_t multiio; + + }; struct distren_job diff --git a/src/client/libdistren_request.c b/src/client/libdistren_request.c --- a/src/client/libdistren_request.c +++ b/src/client/libdistren_request.c @@ -26,7 +26,7 @@ #include "common/request.h" static void handle_ping(struct remoteio *rem, struct distren_request *req, void *req_data); -static void handle_version(struct remoteio *rem, struct distren_request *req, void *req_data); +static void handle_version(distren_t distren, struct distren_request *req, void *req_data); static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data); size_t libdistren_remoteio_read_handle(struct remoteio *rem, void *garbage, void *buf, size_t len, distren_t distren) @@ -73,7 +73,7 @@ size_t libdistren_remoteio_read_handle(s break; case DISTREN_REQUEST_VERSION: - handle_version(rem, req, req_data); + handle_version(distren, req, req_data); break; case DISTREN_REQUEST_DISCONNECT: @@ -118,18 +118,34 @@ static void handle_ping(struct remoteio distren_request_free_with_data(pong_req, pong_req_data); } -static void handle_version(struct remoteio *rem, struct distren_request *req, void *req_data) +static void handle_version(distren_t distren, struct distren_request *req, void *req_data) { - static const char *package_string = PACKAGE_STRING; - - size_t counter; + struct distren_request_version version; + int tmp; - fprintf(stderr, "info: connected to a server running "); - for(counter = 0; counter < req->len; counter ++) - putc(((char *)req_data)[counter], stderr); - putc('\n', stderr); + tmp = distren_request_parse_version(req, req_data, &version); + if(tmp) + { + fprintf(stderr, "error: Invalid DISTREN_REQUEST_VERSION, disconnecting from server\n"); + /* + * our remoteio_close handler sets distren->rem to NULL, thus we + * don't need to return an error code. + */ + remoteio_close(distren->rem); + return; + } + distren->servertype = version.servertype; + distren->state = DISTREN_STATE_AUTH; - /* am I supposed to respond here? ;-) */ + fprintf(stderr, "info: connected to a server running %s\n", version.package_string); + if(version.servertype & DISTREN_SERVERTYPE_CLIENT) + fprintf(stderr, "\tis a client\n"); + if(version.servertype & DISTREN_SERVERTYPE_SUBMIT) + fprintf(stderr, "\taccepts frame submissions\n"); + if(version.servertype & DISTREN_SERVERTYPE_RENDER) + fprintf(stderr, "\trenders frames\n"); + if(version.servertype & DISTREN_SERVERTYPE_DISTRIBUTE) + fprintf(stderr, "\thandles file distribution\n"); } static void handle_disconnect(distren_t distren, struct remoteio *rem, struct distren_request *req, void *req_data) diff --git a/src/common/protocol.h b/src/common/protocol.h --- a/src/common/protocol.h +++ b/src/common/protocol.h @@ -190,13 +190,16 @@ struct distren_request uint32_t /* enum distren_request_type */ type; }; +#define DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN (32) /** * A DISTREN_REQUEST_VERSION is started with a bitmask specification * of the DISTREN_SERVERTYPE_* values. */ struct distren_request_version { - + uint32_t servertype; + /* + 1 is for terminating NULL */ + char package_string[DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN + 1]; }; /** diff --git a/src/common/request.c b/src/common/request.c --- a/src/common/request.c +++ b/src/common/request.c @@ -30,6 +30,41 @@ int distren_request_free_with_data(struc return distren_request_free(req); } +int distren_request_version(struct distren_request **req, void **data, uint32_t servertype, const char *package_string) +{ + struct distren_request_version *version; + + distren_request_new(req, sizeof(struct distren_request_version), DISTREN_REQUEST_VERSION); + version = malloc(sizeof(struct distren_request_version)); + if(!version || !*req) + { + free(version); + if(*req) + distren_request_free(*req); + return 1; + } + + memset(version, 0, sizeof(struct distren_request_version)); + version->servertype = servertype; + strncpy(version->package_string, package_string, DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN); + + *data = version; + + return 0; +} + +int distren_request_parse_version(struct distren_request *req, void *data, struct distren_request_version *version) +{ + if(req->len < sizeof(struct distren_request_version)) + return 1; + + memcpy(version, data, sizeof(struct distren_request_version)); + /* there is space for another '\0' */ + version->package_string[DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN] = '\0'; + + return 0; +} + int distren_request_poing(struct distren_request **req, void **data, short is_ping, const void *poing_cookie, size_t poing_data_len) { enum distren_request_type type; diff --git a/src/common/request.h b/src/common/request.h --- a/src/common/request.h +++ b/src/common/request.h @@ -20,6 +20,8 @@ #ifndef _DISTREN_REQUEST_H #define _DISTREN_REQUEST_H +#include "common/protocol.h" + /** * @file functions to initialize various requests that the server and * client may both use. @@ -32,6 +34,26 @@ int distren_request_free_with_data(struct distren_request *req, void *data); /** + * Initialize a VERSION request. + * + * @param req pointer to where the poitner to the new req should be stored.. + * @param data pointer to where the newly allocated data's address should go. + * @param servertype the ORing of different DISTREN_SERVERTYPE_* constants. + * @param package_string the PACKAGE_STRING constant. + */ +int distren_request_version(struct distren_request **req, void **data, uint32_t servertype, const char *package_string); + +/** + * Parses a DISTREN_REQUEST_VERSION packet. + * + * @param req the request to parse. + * @param data the request's data. + * @param version where the result should be stored. + * @return 0 on success, 1 if the packet is invalid (if the length of package_version is longer than 32-bytes, for example). + */ +int distren_request_parse_version(struct distren_request *req, void *data, struct distren_request_version *version); + +/** * Initialize a PING or PONG request. * * @param data a place to allocate storage for the data associated with this request diff --git a/src/server/distrend.c b/src/server/distrend.c --- a/src/server/distrend.c +++ b/src/server/distrend.c @@ -31,6 +31,7 @@ #include "common/execio.h" #include "common/options.h" #include "common/protocol.h" +#include "common/request.h" #include #include @@ -89,7 +90,7 @@ int distrend_handle_request(struct distr /** client request handlers */ -int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data); +int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data); /* **************XML Functions**************** */ void update_general_info(struct general_info *geninfo); @@ -207,46 +208,48 @@ int main(int argc, char *argv[]) /* ********************** Functions ************************* */ -int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data) +int distrend_handle_version(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data) { char *tmp_str; - char fixedbuf[32]; + struct distren_request_version version; - struct distren_request *newreq; + if(distren_request_parse_version(req, req_data, &version)) + { + distrend_send_disconnect(client, "Invalid DISTREN_REQUEST_VERSION packet."); + return 1; + } if(client->state != DISTREND_CLIENT_PREVERSION) { distrend_send_disconnect(client, "You have already sent the VERSION command."); + return 1; } - if(strlen(PACKAGE_STRING) == req_len - && !strncmp(PACKAGE_STRING, req_data, req_len)) + if(!strncmp(PACKAGE_STRING, version.package_string, DISTREN_REQUEST_VERSION_PACKAGE_STRING_LEN)) { /** - The client and I claim to be of the same version of distren :-D - Now we will mark the client as valid. - - We won't increment his time to live, though, because it shouldn't take - him that long to auth. - */ + * The client and I claim to be of the same version of distren :-D + * Now we will mark the client as valid. + * + * We won't increment his time to live, though, because it shouldn't take + * him that long to auth. + */ client->state = DISTREND_CLIENT_PREAUTH; - - distren_request_new(&newreq, strlen(PACKAGE_STRING), DISTREN_REQUEST_VERSION); - distrend_client_write_request(client, newreq, PACKAGE_STRING); - distren_request_free(newreq); } 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, req_data, 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); + * The client claims to be of a different version of distren. + * Now we will just send a disconnect packet and disconnect the client. + */ + _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, version.package_string); + if(tmp_str) + { + distrend_send_disconnect(client, tmp_str); + free(tmp_str); + } + else + distrend_send_disconnect(client, "Invalid PACKAGE_VERSION :-|."); + return 1; } return 0; diff --git a/src/server/listen.c b/src/server/listen.c --- a/src/server/listen.c +++ b/src/server/listen.c @@ -23,6 +23,7 @@ #include "common/protocol.h" #include "common/remoteio.h" +#include "common/request.h" #include #include @@ -280,8 +281,12 @@ int listen_handle_accept(multiio_context struct distrend_client *newclient; int newclientsock; + struct remoteio *rem; + struct distren_request *req; + void *data; + newclientsock = accept(fd, (struct sockaddr *)NULL, (socklen_t *)NULL); /* used to call int distrend_client_add(struct distrend_listens *listens, int sock, DISTREND_CLIENT_PREVERSION)*/ @@ -309,6 +314,15 @@ int listen_handle_accept(multiio_context /* using sizeof() - 1 because the sizeof() includes a NULL byte we want to ignore. */ remoteio_write(newclient->rem, DISTREN_GREETING, sizeof(DISTREN_GREETING) - 1); + /* send a DISTREN_REQUEST_VERSION immediately as per protocol */ + distren_request_version(&req, &data, + DISTREN_SERVERTYPE_SUBMIT + | DISTREN_SERVERTYPE_DISTRIBUTE + | DISTREN_SERVERTYPE_RENDER, + PACKAGE_STRING); + distren_request_send(rem, req, data); + distren_request_free_with_data(req, data); + /* list_mvfront(listens->clients); newclient = list_curr(listens->clients); @@ -565,7 +579,7 @@ struct distrend_dispatch_request_data int _distrend_dispatch_request_trav(struct distrend_dispatch_request_data *data, struct distrend_request_handler_info *handler_info) { if(handler_info->request_type == data->req->type) - (*handler_info->handler)(data->geninfo, data->client, data->req->len, data->req_data); + (*handler_info->handler)(data->geninfo, data->client, data->req, data->req_data); return TRUE; } diff --git a/src/server/listen.h b/src/server/listen.h --- a/src/server/listen.h +++ b/src/server/listen.h @@ -140,11 +140,11 @@ struct distrend_client A function signature that may be registered as a client request handler. - @param client the client that sent the request - @param len the length of the message in bytes - @param data the message received from the client + @param client the client that sent the request. + @param req the distren request header. + @param data the message received from the client. */ -typedef int(*distrend_handle_request_func_t)(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data); +typedef int(*distrend_handle_request_func_t)(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data); /** Initializes the listens member of struct distrend_config. diff --git a/src/server/tabletennis.c b/src/server/tabletennis.c --- a/src/server/tabletennis.c +++ b/src/server/tabletennis.c @@ -45,8 +45,8 @@ struct tabletennis struct timespec time_last_check; }; -static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data); -static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data); +static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data); +static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data); tabletennis_t tabletennis_new(struct distrend_listens *listens, unsigned int ping_interval, unsigned int pong_time) { @@ -193,25 +193,25 @@ void tabletennis_free(tabletennis_t tabl * * @todo throttling? */ -static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data) +static int tabletennis_ping_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data) { struct distren_request *pong_req; - if(req_len > 32) + if(req->len > 32) distrend_send_disconnect(client, "You have tried to send a PING packet with a length longer than 32 bytes."); /** respond to the client using the data he sent in his PONG command. */ - distren_request_new(&pong_req, req_len, DISTREN_REQUEST_PONG); + distren_request_new(&pong_req, req->len, DISTREN_REQUEST_PONG); distrend_client_write_request(client, pong_req, req_data); distren_request_free(pong_req); return 0; } -static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, size_t req_len, void *req_data) +static int tabletennis_pong_request_handle(struct general_info *geninfo, struct distrend_client *client, struct distren_request *req, void *req_data) { fprintf(stderr, "got pong\n"); @@ -221,7 +221,7 @@ static int tabletennis_pong_request_hand * client->tabletennis_client.time_next_check as the cookie. */ if(client->tabletennis_client.state == TABLETENNIS_NEED_PONG - && req_len == sizeof(client->tabletennis_client.time_next_check) + && req->len == sizeof(client->tabletennis_client.time_next_check) && !memcmp(req_data, &client->tabletennis_client.time_next_check, sizeof(client->tabletennis_client.time_next_check))) { /* valid match */