/* ** Copyright (C) 2003-2006 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ #ifndef _SKTRANSFER_H #define _SKTRANSFER_H #include "silk.h" RCSIDENTVAR(rcsID_SKTRANSFER_H, "$SiLK: sktransfer.h 2920 2006-02-06 18:02:36Z mthomas $"); /* ** sktransfer.h ** ** SiLK file transfer protocol ** */ #include "skdeque.h" #include "utils.h" #if !HAVE_DECL_INADDR_NONE #define INADDR_NONE 0xffffffff #endif /* The type of transfer objects */ typedef struct sk_transfer_t *skTransfer_t; /* Error values */ typedef enum sk_transfer_error { SK_TRANSFER_ESUCCESS = 0, /* Success */ SK_TRANSFER_ESHUTDOWN = 1, /* Received shutdown message */ SK_TRANSFER_ESHUTDOWN_EXTERNAL = 2, /* Shutdown by program */ SK_TRANSFER_EBADARG = -1, /* Bad argument to function */ SK_TRANSFER_EFAILED = -2, /* File failed, but should be retried. Sock in consistant state. */ SK_TRANSFER_EFAILED_CLOSE = -3, /* File failed, but should be retried; Sock in inconsistant state. */ SK_TRANSFER_ESYSTEM = -4, /* System failed badly. errno should be set properly. Sock should bs considered inconsistant. */ SK_TRANSFER_ESYSTEM_THREAD = -5, /* System failed badly in thread call. errno will be set to a Posix thread error value.. Sock should bs considered inconsistant. */ SK_TRANSFER_EFATAL = -6, /* File failed fatally. Sock in consistant state. */ SK_TRANSFER_EFATAL_CLOSE = -7, /* File failed fatally. Sock in inconsistant state. */ SK_TRANSFER_ETIMEOUT = -8 /* Timeout */ } sktErr_t; /* Detailed explanation of the above error conditions: ESUCCESS : This is not an error. Everything worked properly. Guaranteed to be equivalent to zero. ESHUTDOWN : Only returned by skRcvFile. Indicates the the receiver received a shutdown message. Indicates the end of a transfer session. ESHUTDOWN_EXTERNAL : Indicates that the transfer session was stopped by the program via skDestroyTransfer or skTransferStop. EBADARG : Programmer error. The function was passed an argument it did not expect, or cannor handle. EFAILED : Transfer of the file failed, but can (should?) be retried. The transfer session is still in a consitant state. This could be caused by network transmission errors (random bitflip errors). EFAILED_CLOSE : Transfer of the file failed, but can (should?) be retried. The transfer session is no longer in a consistant state, however, and should be reinitiated. ESYSTEM : A low level system call which was expected to succeed has failed. The errno value contains the system level error. Usually this means that something is either dreadfully wrong with the system, or with the library itself. Should probably be responded to by a shutdown of the program. ESYSTEM_THREAD : A thread system call which was expected to succeed has failed. The errno value contains the thread error. Be warned that this is not necessary an ordinary system errno, and as such should not be used with functions like strerror. See the POSIX threads specification for more information on error values. Usually this error means that something is either dreadfully wrong with the system, or with the library itself. Should probably be responded to by a shutdown of the program. EFATAL : Transfer of the file failed, and has failed in such a way that the file should not be retried. The transfer session is still in a consistant state, however. This error can be triggered by a file which has failed through multiple retries. EFATAL_CLOSE : Transfer of the file failed, and has failed in such a way that the file should not be retried. The transfer session is no longer in a consistant state, and should be reinitiated. ETIMEOUT : The function or file did not complete, due to a timeout. In a transfer session, this implies that the session did not complete properly, and therefore should be considered inconsistant, and should be reinitiated. */ /* The type of transfer callback functions */ typedef void (*skt_callback_t)(char *file, void *item, sktErr_t error, skTransfer_t transfer); /* The type of logging functions */ typedef sk_msg_fn_t skt_logfn_t; /* The type of pathname extraction functions */ typedef void (*skt_filename_fn_t)(void *, char *path, char *name); /* The type of filename transformation functions */ typedef void (*skt_fn_xform_fn_t)(char *oldname, char *newname); /****************************/ /*** High-level functions ***/ /****************************/ /* There are two components here, which come in two different varieties each. There is a sender, whose job is to send files, and a receiver, whose job is to receive them. With the high-level functions, they act as daemons, connecting and sending/receiving until they are told to stop. As a result, each comes in a server and a client variation. The server will bind to a port and listen for connections, while a client will be the one connecting to the bound port. Each client will attempt to reconnect to the server if its session is disrupted. */ /*** SENDERS ***/ /* Creates a sender transfer session server object. You should add a queue using skTransferSetQueue before starting a sender server. skTransfer_t *sender The skTransfer_t object whose address is passed through this argument will be initialized to a handle which can be used to communicate with the session. (I.e., you can query or stop the sender using this handle. int port The port upon which to listen for incoming connections. */ sktErr_t skCreateSenderServer( skTransfer_t *sender, /* returns sender handle */ int port /* Port to listen upon */ ); /* Creates a sender transfer session client object. You should add a queue using skTransferSetQueue before starting a sender server. skTransfer_t *sender The skTransfer_t object whose address is passed through this argument will be initialized to a handle which can be used to communicate with the session. (I.e., you can query or stop the sender using this handle. int port The receiver server to which the client is connecting's port. in_addr_t server The address of the server to which to connect. */ sktErr_t skCreateSenderClient( skTransfer_t *sender, /* returns sender handle */ int port, /* Port to connect to */ in_addr_t server /* server address */ ); /* This sets the item->filename conversion function. This function is handed items from the sendQ deque, and is required to fill two strings. The first is a string which represents a path to the file to be sent. The second indicates what the name the file should be given in the transfer session. If this function is not set, then items on the deque are assumed to already be c-strings, with the sending name identical to the filename. */ sktErr_t skSenderSetFilenameFn( skTransfer_t transfer, skt_filename_fn_t filename_function); /*** RECEIVERS ***/ /* Creates a receiver transfer session server object. skTransfer_t *rcvr The skTransfer_t object whose address is passed through this argument will be initialized to a handle which can be used to communicate with the session. (I.e., you can query or stop the receiver using this handle. int port The port upon which to listen for incoming connections. uint8_t maxclients The maximum number of sender clients allowed to connect. char *where The location (path) in which to place files as they are received. */ sktErr_t skCreateReceiverServer( skTransfer_t *rcvr, /* returns rcvr handle */ int port, /* Port to listen upon */ uint8_t maxclients, /* Max number of clients */ const char *where /* Where to place files */ ); /* Creates a receiver transfer session client. skTransfer_t *rcvr The skTransfer_t object whose address is passed through this argument will be initialized to a handle which can be used to communicate with the session. (I.e., you can query or stop the receiver using this handle. int port The sender server to which the client is connecting's port. in_addr_t server The address of the server to which to connect. char *where The location (path) in which to place files as they are received. */ sktErr_t skCreateReceiverClient( skTransfer_t *rcvr, /* returns rcvr handle */ int port, /* Port to connect to */ in_addr_t saddr, /* server address */ const char* where /* Where to place files */ ); /* Sets the receiver's filename generator. If this function is non-null, it will be used to generate a new path based on the transfered filename. The first argument is the original constructed path of the file. The second argument is a pointer to a buffer in which to store the new file name. If the second argument is set to the empty string, the name is taken to be the last element of the path. The buffers are of size PATH_MAX. */ sktErr_t skReceiverSetTransformFn( skTransfer_t rcvr, skt_fn_xform_fn_t fn_xform_function); /*** SERVER FUNCTIONS ***/ /* Adds a valid client address to the server object. This will revert a server that is currently accepting connections from any client address. Server must not yet have been started. */ sktErr_t skServerValidClientAdd(skTransfer_t server, in_addr_t client); /* Removes a valid client address from the server object. This has no effect on a server which is currently acccepting connections from any client. Server must not yet have been started. */ sktErr_t skServerValidClientRemove(skTransfer_t server, in_addr_t client); /* Sets the server to accept connections from any client. This is the default. Server must not yet have been started. */ sktErr_t skServerValidClientAny(skTransfer_t server); /* Sets the local address the listening port is tied to. The default it for the listening port to listen across all valid local addresses. Server must not yet have been started.*/ sktErr_t skServerSetListeningAddress(skTransfer_t server, in_addr_t addr); /*** TRANSFER OBJECT FUNCTIONS ***/ /* Starts a transfer session. This creates its own threads and immediately returns. */ sktErr_t skTransferStart(skTransfer_t transfer); /* Stops a transfer session. */ sktErr_t skTransferStop(skTransfer_t transfer, uint32_t timeout); /* Shuts down and destroys a transfer session. */ sktErr_t skDestroyTransfer(skTransfer_t transfer); /* Sets the queue (implemented as a skDeque_t) for a transfer session. This queue is used differently depending on whether the session is a sender or a receiver. Transfer session must not yet have been started. If the session is a sender the queue will be used to commuinicate the paths of the files to transmit. The server will pop items off the back of the deque to determine which file should be sent next. The filename is extracted from the item using the current filename function. If a filename function is not set (using skSenderSetTransformFn), then the items are assumed to be c-strings containing the path. Items in the queue are never freed by this library. If the session is a sender, the queue will be used to communicate the paths of the files which have been transferred successfully. The receiver will push pathnames onto the front of the deque to be retrieved by the rest of the application. These strings must be freed by the application after use. */ sktErr_t skTransferSetQueue(skTransfer_t transfer, skDeque_t queue); /* Sets the minimum number of bits-per-second to expect for file transfer on the transport medium. This is used to calculate timeouts for the sending of files. The deafult if not set is 2400. Transfer session must not yet have been started. */ sktErr_t skTransferSetMinimumBitrate(skTransfer_t transfer, uint32_t bitrate); /* Sets the number of seconds to wait for an aknowledgement from the receiver that it has successfully received the file. A timeout of zero implies that it should wait potentially forever. The default if not set is 3. Transfer session must not yet have been started. */ sktErr_t skTransferSetAckTimeout(skTransfer_t transfer, uint8_t timeout); /* Sets a function via which the transfer session can produce verbose error messages in the event of error conditions. If not set, there will be no logging. Transfer session must not yet have been started. */ sktErr_t skTransferSetLogFn(skTransfer_t transfer, skt_logfn_t logfn); /* Sets a callback associated with the transfer session. Transfer session must not yet have been started. The function has the type: void (*skt_callback_t)(char *file, void *item, sktErr_t error, skTransfer_t transfer) If the session is a sender: After a file is either sent, or has failed to be sent, this function will be called with the result. The function will be called with the pathname it attempted to send, the item from which the pathname was generated (from the sendQ), the result of the sending of that file, and a handle to the session that tried to send it. After this callback function is called, the item is no longer used, and can be freed from within the callback if desired. In the event of a fatal error not connected with the sending of a file, the file and item values will be NULL. If the session is a receiver: After a file has been received, the pathname is added to the deque (if successful), and the callback is executed. The function will be called with the pathname it attempted to receive, a NULL for item, the error result of the receiving of that file, and a handle to the session that tried to send it. The path will be be freed by the library after the callback is executed, so copy it if you wish to store it past the lifetime of the function call. In the event of a fatal error not connected with the receiving of a file, the file and item values will be NULL. If the callback is not set, it is not used. */ sktErr_t skTransferSetCallback(skTransfer_t transfer, skt_callback_t callback); /* Returns whether a transfer session object is a receiver. */ int skTransferIsReceiver(skTransfer_t transfer); /* Returns whether a transfer session object is a sender. */ int skTransferIsSender(skTransfer_t transfer); /* Returns whether a transfer session object is a client. */ int skTransferIsClient(skTransfer_t transfer); /* Returns whether a transfer session object is a server. */ int skTransferIsServer(skTransfer_t transfer); /* Returns in `queue' the deque used by the transfer session. */ sktErr_t skTransferQueue(skTransfer_t transfer, skDeque_t *queue); /***************************/ /*** Mid-level functions ***/ /***************************/ /* Given a connected socket, will manage a file communications stream (sending). This function runs asynchronously, creating its own threads. The calling convention is similar to that of the above sender creation functions. The only difference is that an already connected socket is used. If that socket dies, then the threads will end, unless skTransferChangeSock is used to refurbish the socket from within the callback function. */ sktErr_t skCreateSender( skTransfer_t *sender, /* returns sender handle */ int sock); /* Socket to create sender on */ /* Given a connected socket, will manage a file communications stream (receiving). This function runs asynchronously, creating its own threads. The calling convention is similar to that of the above receiver creation functions. The only difference is that an already connected socket is used. If that socket dies, then the threads will end, unless skTransferChangeSock is used to refurbish the socket from within the callback function. */ sktErr_t skCreateReceiver( skTransfer_t *receiver, /* returns receiver handle */ int sock, /* Socket to create receiver on */ const char *where /* Where to place files */ ); /* Changes the socket used by the session. If possible, it will complete any file currently being transferred, shutdown the connection gracefully (but not close the socket), and send a new handshake on the new socket. */ sktErr_t skTransferChangeSock(skTransfer_t transfer, int sock); /***************************/ /*** Low-level functions ***/ /***************************/ /* Explanation of the protocol: A protocol session requires an open stream of communications (an opened socket) between the sending and receiving entities. During a single session, the roles of the sender and the receiver remain constant. I.E., one side is the sender, and the other side the receiver throughout the entire session; their roles may not swap in the course of the session. The receiver's half of a session proceeds as follows: skRcvHandshake // Initiate the session do { skRcvFile // Receive a file) } until a SK_TRANSFER_ESHUTDOWN is received The sender's half of a session proceeds as follows: skSendHandshake // Initiate the session while (filesToSend) { skSendFile // Send a file } skSendShutdown // Terminate the session gracefully */ /* When using a control pipe, send SKT_NOTIFY_ABORT as an intention to abort. (This won't abort a read or write in progress.) Send SKT_ABORT in order to do an immediate abort. */ #define SKT_NOTIFY_ABORT '\0' #define SKT_ABORT '\1' /* Does the low-level work of sending a file. */ sktErr_t skSendFile(int sock, char *path, char *name, skt_logfn_t logf, int *control); /* Sends a shutdown message. */ sktErr_t skSendShutdown(int sock, skt_logfn_t logf, int *control); /* Sends a handshake. */ sktErr_t skSendHandshake(int sock, skt_logfn_t logf, int *control); typedef struct _skRcvInfo_t { char path[PATH_MAX]; int fd; } skRcvInfo_t; /* Does the low-level work of receiving a file. */ sktErr_t skRcvFile(int sock, char *where, skRcvInfo_t *file, skt_logfn_t logf, int *control); /* Receive a handshake. */ sktErr_t skRcvHandshake(int sock, skt_logfn_t logf, int *control); #endif /* _SKTRANSFER_H */