/*
* 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 PASS request so as to identify to a server.
*
* \param req Where to store the newly allocated req.
* \param data Where to store the newly allocated data.
* \param user The username to send to the server.
* \param pass The password to send to the server.
*/
int distren_request_pass(struct distren_request **req, void **data, const char *username, const char *pass);
/**
* 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 */