/* * Copyright 2010 Nathan Phillip Brink * * This file is a part of DistRen. * * DistRen is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DistRen 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with DistRen. If not, see . */ #ifndef _DISTREN_REQUEST_H #define _DISTREN_REQUEST_H #include "common/protocol.h" #include /** * @file functions to initialize various requests that the server and * client may both use. */ /** * Free any request made with one of the functions below */ 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 * @param is_ping 1 if this is a DISTREN_REQUEST_PING or 0 if this is a DISTREN_REQUEST_PONG * @param poing_cookie chocolate chip, chocolate chunk, or oatmeal chocolate chip * @param poing_data_len bytes in the poing_cookie * @return the length of the data allocated for this request */ int distren_request_poing(struct distren_request **req, void **data, short is_ping, const void *poing_cookie, size_t poing_data_len); struct distren_request_file_post_context; typedef struct distren_request_file_post_context *distren_request_file_post_context_t; /** * Frees a post_context for if a client is disconnected or an upload * otherwise interrupted. */ int distren_request_file_post_context_free(distren_request_file_post_context_t post_context); /** * Prepares for a file upload and initializes a * distren_request_file_post_context_t. * * If you call this function and you never finish an upload, you * _must_ call distren_request_file_post_finish() on post_context at * least to free the post_context. * * @param req where to store the new distren_request pointer. * @param data where to store the new request's data pointer. * @param post_context where the newly allocated distren_request_file_post_context_t's addrss should be stored. * @param post_id a number that uniquely identifies this upload for this connection. * @param filename a user-friendly filename for the file posting. */ int distren_request_file_post_start(struct distren_request **req, void **data, distren_request_file_post_context_t *post_context, uint32_t post_id, const char *filename); /** * Parses a DISTREN_REQUEST_FILE_POST_START request. * * @param req the recieved request. * @param data the request's data. * @param post_context a post_context to be initialized for a continued download. Must be free()d with a call to distren_request_parse_file_post_finish() or distren_request_file_post_context_free(), however. * @param post_id will be set to the post_id contained in the packet. * @param filename will be made to point at the filename the client requested. *filename must be free()d. * @return 0 upon no problem, 1 if there's an error. If 1, then *filename should not be used (it will be set NULL, so no problem calling free() on it though). */ int distren_request_parse_file_post_start(struct distren_request *req, void *data, distren_request_file_post_context_t *post_context, uint32_t *post_id, char **filename); /** * Initializes a DISTREN_REQUEST_FILE_POST packet's header. * * As file posting requires an acceptable chunk of memory, we don't * malloc() the data portion of the packet here to encourage reading * files in through static buffers. * * As a single file takes multiple DISTREN_REQUEST_FILE_POST packets * before it's completely uploaded, certain state information has to * persist between calls to distren_request_file_post(). This is what * the post_context argument is for. This pointer must be preserved * between calls to distren_request_file_post(). * * @param req place to store the new req's pointer * @param data_header where the data's header should be stored * @param post_context what this points to must be preserved between calls to distren_request_file_post(), for keeping state. FILE_POST_DATA_LEN. * @param data a hunk of the file being posted. * @param len the length of the data argument. This must be less than or equal to DISTREN_REQUEST_ */ int distren_request_file_post(struct distren_request **req, struct distren_request_file_post *data_header, distren_request_file_post_context_t post_context, const void *data, size_t len); /** * A callback to find a distren_request_file_post_context_t for a * specified post_id. * * This exists because it is recognized that two servers may be * transfering more than one file at a time between eachother. At the * time that distren_request_parse_file_post() is called, the caller * doesn't know post_id and thus can't provide the proper * post_context. Yet distren_request_parse_file_post() needs the * post_context to get its job done ;-). * * @param post_id the post_id for which to find a distren_request_file_post_context_t * @param find_post_context_data the same find_post_context_data pointer passed to distren_request_parse_file_post() or distren_request_parse_file_post_finish(). * @return NULL if the context could not be found or the context. */ typedef distren_request_file_post_context_t(*distren_request_parse_file_post_find_context_func_t)(uint32_t post_id, void *find_post_context_data); /** * Parse a DISTREN_REQUEST_FILE_POST packet and update the * post_context. * * @param req the request header. * @param data the request data section. * @param post_id will be filled with the request's post_id. * @param find_context_func a function that can look up the necessary context_post given a post_id. * @param find_post_context_data the pointer to pass as context data to find_context_func * @param file_data will be set to the beginning of the file data portion of the packet. Do not free() this pointer. * @param file_data_len the number of bytes of file data that may be accessed at *file_data. * @return 0 on success and 1 on failure, in which case the client should be kicked and you should free the post_context with distren_request_file_post_context_free(). */ int distren_request_parse_file_post(struct distren_request *req, void *data, uint32_t *post_id, distren_request_parse_file_post_find_context_func_t find_context_func, void *find_post_context_data, void **file_data, size_t *file_data_len); /** * Construct a packet signalling that a file posting is finished. * * Frees the memory used to store the post_context. Must be called * once for every call to distren_request_file_post_start(), * regardless of whether or not you actually call * distren_request_send() on the result. * * @param req where to store the pointer of the newly allocated request * @param data where to store the pointer t othe newly allocated request data * @param post_context the post_context which will be used and then freed. * @param cancel 0 if the file was uploaded successfully, 1 if the upload is cancelled or failed. */ int distren_request_file_post_finish(struct distren_request **req, void **data, distren_request_file_post_context_t post_context, uint32_t cancel); /** * Parses a DISTREN_REQUEST_FILE_POST_FINISH packet. * * You must still call distren_request_file_post_context_free() on the * post_context which you must find yourself. If you are a server, you * must keep a list of these contexts per-client so that when a client * exits, you may reclaim these contexts. * * @param req the request header * @param data the data section of the packet * @param post_id a place where the post_id will be set. * @param find_context_func a function pointer to let me find a post_context based on the post_id of the request. * @param find_post_context_data the pointer to pass to the find_context_func callback. * @return 0 for a good packet, 1 for a bad packet or if the post_context can't be found (post_id won't be valid), 2 if the request asks for the user to cancel the file upload (post_id will be valid), and 3 if the checksums don't match (post_id will be valid). */ int distren_request_parse_file_post_finish(struct distren_request *req, void *data, uint32_t *post_id, distren_request_parse_file_post_find_context_func_t find_context_func, void *find_post_context_data); #endif /* _DISTREN_REQUEST_H */