743 lines
26 KiB
C
743 lines
26 KiB
C
/*
|
|
************************************************************************
|
|
**
|
|
** Copyright (c) 2010..2013 by
|
|
** Core|Vision B.V.
|
|
** Cereslaan 10b
|
|
** 5384 VT Heesch
|
|
** The Netherlands
|
|
**
|
|
** All Rights Reserved
|
|
**
|
|
************************************************************************
|
|
*/
|
|
/*
|
|
************************************************************************
|
|
**
|
|
** Project name: Dual Inventive: Utility Library
|
|
** Filename: cp3000.h
|
|
** Author: Jack Weeland
|
|
** Date: January 27, 2010
|
|
** File version: $Revision: 1.23 $
|
|
** $Date: 2014/01/23 15:57:28 $
|
|
**
|
|
************************************************************************
|
|
*/
|
|
/*
|
|
************************************************************************
|
|
**
|
|
** CP3000 high(er) level protocol handling
|
|
**
|
|
** High level functions:
|
|
** - Create a server socket, accept clients
|
|
** - Create a client socket
|
|
** Utility functions:
|
|
** - The I/O buffers
|
|
** - Checking the validity of a message (checksum)
|
|
** - Escape and unescape strings, etc
|
|
**
|
|
************************************************************************
|
|
*/
|
|
|
|
#ifndef __CP3000_H
|
|
#define __CP3000_H
|
|
|
|
#include <di-util/list.h>
|
|
#include <stddef.h>
|
|
#include <stdarg.h>
|
|
#include <sys/select.h> // for 'fd_set'
|
|
|
|
/*
|
|
** Definitions - tokenizer
|
|
*/
|
|
|
|
// Flags for 'token_definition_t.flags'
|
|
// - Do not send the status in a reply to the originator; must be set also
|
|
// when the handler sends a status reply itself (but _not_ when it only
|
|
// sends intermediate replies, leaving the status reply to the library)
|
|
// or when the reply is sent asynchronously.
|
|
// - The handler _cannot_ send additional information in the reply, only
|
|
// a status code. If handler needs to supply additional information, it
|
|
// _must_ define the CP3000_SELF_REPLY flag.
|
|
#define CP3000_DEFAULT_REPLY 0
|
|
#define CP3000_NO_REPLY 0x00000001
|
|
#define CP3000_SELF_REPLY (CP3000_NO_REPLY)
|
|
#define CP3000_ASYNC_REPLY (CP3000_NO_REPLY)
|
|
// - Match only the first part of a token; as the 'token_definition_t'
|
|
// array will be handled in order, a partial match must always follow
|
|
// the entries that must be matched exactly
|
|
#define CP3000_MATCH_PARTIAL 0x00000100
|
|
// - Handle tokens (data) externally; must be the last item in the list
|
|
// and the "cmd" _must_ be NULL
|
|
#define CP3000_MATCH_ANY 0x00000200
|
|
// Security clearance level; a CP3000 command is only executed when the
|
|
// security level of a command is less than or equal to the security
|
|
// level of a device, as set with 'cp3000_set_authorization()'
|
|
#define CP3000_CLEARANCE(level) ((level) << 16)
|
|
#define CP3000_CLEARANCE_MASK 0xFFFF0000
|
|
|
|
// - Special flag for the reply code, to be used in the token_definition_t
|
|
// array as:
|
|
// { CP3000_REPLY, reply_handler, CP3000_REPLY_TOKEN }
|
|
// It also inhibits cp3000_process_data() from sending a reply, as this
|
|
// would result in a bouncing of replies on replies
|
|
#define CP3000_REPLY_TOKEN (CP3000_MATCH_PARTIAL | CP3000_NO_REPLY)
|
|
#define CP3000_CMD_TOKEN (CP3000_MATCH_PARTIAL | CP3000_NO_REPLY)
|
|
|
|
// Special characters in CP3000 commands
|
|
#define CP3000_REPLY (TCPFMT_TOKEN_REPLY)
|
|
#define CP3000_CMD (TCPFMT_TOKEN_CMD)
|
|
#define CP3000_SEP (TCPFMT_TOKEN_SEP)
|
|
#define CP3000_CLIENT (TCPFMT_TOKEN_CLIENTSEP)
|
|
#define CP3000_CHKSUM (TCPFMT_TOKEN_CHECKSUM)
|
|
|
|
// Placeholder for 'token_info_t.datasz', most notably for the 'datasz'
|
|
// argument for 'cp3000_create_token()'
|
|
#define CP3000_CMDTOKEN (-1)
|
|
|
|
/*
|
|
** Definitions - device flags
|
|
*/
|
|
|
|
// Flags for the default CP3000 parser, set with 'cp3000_set_flags()'
|
|
// - Don't check the checksum in the message
|
|
#define CP3000_IGNORE_CHECKSUM 0x00010000
|
|
// - Return raw data in 'token->cmd'; the argument list will be empty
|
|
// No checksum will be calculated nor checked
|
|
#define CP3000_RAW_TOKENS 0x00020000
|
|
// - Return binary data in 'token->data'; the size of the data buffer
|
|
// is stored in 'token->data_len'; the argument list will be empty
|
|
// No checksum will be calculated nor checked
|
|
#define CP3000_BINARY 0x00040000
|
|
// Temporary flag while receiving replies: do not process the putback
|
|
// list (should be modified with 'cp3000_set_flag()' and 'cp3000_clear_flag()'
|
|
#define CP3000_DONT_PROCESS_PUTBACK 0x80000000
|
|
|
|
/*
|
|
** Definitions - data types
|
|
*/
|
|
|
|
// Structure to hold the internal state
|
|
typedef struct CP3000_DEVICE *cp3000_device_t;
|
|
|
|
// Public and private keys and security certificates
|
|
typedef struct CP3000_KEY *cp3000_key_t;
|
|
|
|
// CP3000 tokens in the message from the client
|
|
typedef struct TOKEN_INFO
|
|
{
|
|
union {
|
|
const char *cmd; // command (or reply), the first token
|
|
void *data; // generic, binary data; 'args' is not used
|
|
};
|
|
int datasz; // number of bytes in the buffer pointed to by 'data';
|
|
// not used for strings
|
|
lst_t args; // argument list
|
|
int client; // client identifier, or '-1' when missing or not used
|
|
int status; // '-1' for a command or the status code from the client
|
|
} *token_info_t;
|
|
|
|
// Handler definition, which is called with the arguments of the
|
|
// command and an application defined context
|
|
typedef int (*token_handler_t)(cp3000_device_t, token_info_t, void*);
|
|
|
|
// token definition
|
|
typedef struct TOKEN_DEFINITION
|
|
{
|
|
const char *cmd; // command or place holder for a reply (CP3000_REPLY below)
|
|
token_handler_t handler; // handler
|
|
void *param; // pointer to paramters for the handler
|
|
unsigned int flags; // flags as defined above
|
|
} token_definition_t;
|
|
|
|
/*
|
|
** Definitions - extended mode parser
|
|
*/
|
|
|
|
// Place-holder for default CP3000 command processing
|
|
#define CP3000_DEFAULT_PARSER NULL
|
|
|
|
// Callback functions for the command parser
|
|
//
|
|
// Functions to initialize and destroy an optional private data structure for the
|
|
// parser
|
|
// Parameters:
|
|
// - parent cp3000_device_t object
|
|
// - parser parameters; see below
|
|
// Remark:
|
|
// For the 'init' function, the pointer 'param' initially points to 'param' argument
|
|
// for 'cp3000_add_parser()'. The 'init' function can allocate its own data structure
|
|
// (thus overriding the original 'param', which should be NULL in that case to avoid
|
|
// confusion).
|
|
// The 'destroy' function must deallocate this data structure in this scenario.
|
|
// Note:
|
|
// These functions can be NULL when they are not needed.
|
|
typedef int (*cp3000_parser_initfcn_t)(cp3000_device_t, void**);
|
|
typedef int (*cp3000_parser_destroyfcn_t)(cp3000_device_t, void*);
|
|
// Match the data in the buffer to check if it is the format expected by the parser
|
|
// Parameters:
|
|
// - parent cp3000_device_t object
|
|
// - parser parameters
|
|
// - pointer to the data buffer (data to match)
|
|
// - number of bytes in the data buffer
|
|
// Returns:
|
|
// < 0 on error or data not for this parser
|
|
// 0 if there isn't enough data, but buffer could contain a valid command
|
|
// > 0 successful match; return value is the number of bytes that can be
|
|
// processed
|
|
// Note:
|
|
// The value returned by the string match function determines how many bytes
|
|
// will be consumed from the I/O buffers. The data in the I/O buffers therefore
|
|
// _must_ be processed by this parser.
|
|
typedef int (*cp3000_parser_strmatchfcn_t)(cp3000_device_t, void *param, const void *buffer, size_t n);
|
|
// Process data
|
|
// Parameters:
|
|
// - parent cp3000_device_t object
|
|
// - parser parameters
|
|
// - pointer to the data buffer (data to process)
|
|
// - number of bytes in the data buffer
|
|
// Returns:
|
|
// < 0 on error or data not for this parser
|
|
// >= 0 command processed succesfully
|
|
// Note:
|
|
// At this point, the data has already been removed from the I/O buffers, so
|
|
// it is too late to determine during processor that the data is not intended
|
|
// for this parser. This _must_ be correctly determined in the string match
|
|
// member function.
|
|
typedef int (*cp3000_parser_processfcn_t)(cp3000_device_t, void *param, const void *buffer, size_t n);
|
|
// The command parser definition simply contains the the callback functions.
|
|
typedef const struct TOKEN_PARSER
|
|
{
|
|
// parser name, for debugging
|
|
const char *name;
|
|
|
|
// callbacks
|
|
cp3000_parser_initfcn_t cp3000_parser_init;
|
|
cp3000_parser_destroyfcn_t cp3000_parser_destroy;
|
|
cp3000_parser_strmatchfcn_t cp3000_parser_strmatch;
|
|
cp3000_parser_processfcn_t cp3000_parser_process;
|
|
} *token_parser_t;
|
|
|
|
/*
|
|
** Initialization
|
|
*/
|
|
|
|
// Initialization, must be called before anything else at the start of
|
|
// the application.
|
|
// The multi-threaded version also initializes multi-threading specific
|
|
// stuff. The 'mt' function calls the normal 'cp3000_init()'.
|
|
// Returns -1 on failure and 0 on success
|
|
int cp3000_init();
|
|
int cp3000_init_mt();
|
|
|
|
// De-initialization
|
|
int cp3000_deinit();
|
|
int cp3000_deinit_mt();
|
|
|
|
/*
|
|
** Client and server
|
|
*/
|
|
|
|
// Create a device. The device must be initialized to be a server or
|
|
// client using one of the 'cp3000_init_xxx()' functions that follow
|
|
// in the next sections.
|
|
// Returns NULL on error
|
|
cp3000_device_t cp3000_create_device();
|
|
|
|
// Destruction
|
|
// - Closes socket(s) and delete all OpenSSL related objects
|
|
// - Destroys the cp3000_device_t object
|
|
// Parameters:
|
|
// cp3000_device_t object to close and destroy
|
|
// Returns:
|
|
// -1 on error
|
|
int cp3000_destroy_device(cp3000_device_t);
|
|
|
|
// Attach security certificates to a device to enable transport layer
|
|
// security using OpenSSL. This must be done _before_ the device is
|
|
// initialized as a server or client.
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// See also the functions defined in 'cp3000-cert.h'
|
|
// Important note: the OpenSSL functions have the peculiarity that they
|
|
// destroy their keys after use; the 'cp3000_key_t' parameters are
|
|
// therefore copied.
|
|
int cp3000_make_secure(
|
|
cp3000_device_t,
|
|
cp3000_key_t public_cert, // signed public certificate
|
|
cp3000_key_t trust_cert, // certificate of the CA Server
|
|
cp3000_key_t private_key // private key
|
|
);
|
|
|
|
// Test if the connection is secure
|
|
int cp3000_is_secure(cp3000_device_t);
|
|
|
|
// Initialize the SSL context, connect the read and write BIO to TLS/SSL
|
|
// and do the SSL handshake. Also sets the peer's address for non-secure
|
|
// clients.
|
|
// Parameters:
|
|
// The cp3000_device_t object
|
|
// Returns:
|
|
// 0 on succes, -1 on error
|
|
int cp3000_init_connection(cp3000_device_t);
|
|
|
|
// Close connection or file associated with this CP3000 object.
|
|
// User objects, flags and security descriptors will be retained and can be reused.
|
|
// Parameters:
|
|
// The cp3000_device_t object
|
|
// Returns:
|
|
// 0 on succes, -1 on error
|
|
int cp3000_disconnect(cp3000_device_t);
|
|
|
|
/*
|
|
** Server side
|
|
*/
|
|
|
|
// Initialize server
|
|
// - Creates a server socket.
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// port - port number to listen to (-1 to use default from config or /etc/services)
|
|
int cp3000_init_server(
|
|
cp3000_device_t,
|
|
int port
|
|
);
|
|
|
|
// Wait for a client and accept the client.
|
|
// After accepting the client, the function 'cp3000_init_connection()'
|
|
// must be called, usually after the 'fork(2)'.
|
|
// Parameters:
|
|
// cp3000_device_t object for the server
|
|
// Returns:
|
|
// cp3000_device_t for the client
|
|
// NULL on error
|
|
// Remarks:
|
|
// Initializes the SSL object from 'server'.
|
|
cp3000_device_t cp3000_accept_client(
|
|
cp3000_device_t server
|
|
);
|
|
|
|
/*
|
|
** Client side
|
|
*/
|
|
|
|
// Connect to a server
|
|
// The function 'cp3000_init_connection()' must be called after this function.
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// server - hostname:port
|
|
// Returns:
|
|
// 0 on succes, -1 on error
|
|
int cp3000_connect_to_server(
|
|
cp3000_device_t,
|
|
const char *server
|
|
);
|
|
|
|
/*
|
|
** Files and sockets (file descriptor interface)
|
|
*/
|
|
|
|
// Attach a file descriptor to it.
|
|
// The function 'cp3000_init_connection()' must be called after this function.
|
|
// Used for all clients, also those of a Unix-socket so they can use the
|
|
// CP3000 tokenizer and iobuffers
|
|
// Returns 0 on success and -1 on error;
|
|
int cp3000_attach_socket(
|
|
cp3000_device_t,
|
|
int fd
|
|
);
|
|
|
|
// Attach a read and write file descriptor to it.
|
|
// Used when a server is started from 'inetd' or 'xinetd'
|
|
// The function 'cp3000_init_connection()' must be called after this function.
|
|
// Returns 0 on success and -1 on error;
|
|
// Remark: the file descriptors are _not_ closed when the cp3000_device_t object
|
|
// is destroyed.
|
|
int cp3000_attach_fd(
|
|
cp3000_device_t,
|
|
int rfd,
|
|
int wfd
|
|
);
|
|
|
|
// Open a file using 'open(2)' and attach if to the CP3000 object
|
|
int cp3000_open_file(
|
|
cp3000_device_t,
|
|
const char *path,
|
|
int open_flags
|
|
);
|
|
|
|
|
|
/*
|
|
** Additional information
|
|
*/
|
|
|
|
// Get port number; returns -1 on error
|
|
int cp3000_get_port(cp3000_device_t);
|
|
|
|
// Get name of the peer
|
|
const char *cp3000_get_peername(cp3000_device_t);
|
|
|
|
// Byte counts
|
|
unsigned long cp3000_get_recv_bytes(cp3000_device_t);
|
|
unsigned long cp3000_get_send_bytes(cp3000_device_t);
|
|
|
|
// Special flags; see the definitions above
|
|
// The 'cp3000_set_flags()' function _replaces_ the flags
|
|
int cp3000_set_flags(cp3000_device_t, unsigned int flags);
|
|
unsigned int cp3000_get_flags(cp3000_device_t);
|
|
// Set or clear individual flag(s)
|
|
int cp3000_set_flag(cp3000_device_t, unsigned int flags);
|
|
int cp3000_clear_flag(cp3000_device_t, unsigned int flags);
|
|
|
|
/*
|
|
** Exported functions - user data
|
|
*/
|
|
|
|
// These two functions allow for adding user data to a cp3000_device_t
|
|
// object. The 'set' function makes a copy of the user data, so it is
|
|
// allowed to add an automatic object.
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// data - Optional initial data; may be NULL
|
|
// datasz - Size of the user data, or '0' to delete the current data
|
|
// Returns:
|
|
// Pointer to the allocated buffer.
|
|
// Remark:
|
|
// This function always allocates a buffer when 'datasz' is non-zero
|
|
// and it returns a pointer to this buffer. When 'data' is NULL, this
|
|
// buffer will be uninitialized, otherwise 'data' is copied into it.
|
|
void *cp3000_set_user_data(cp3000_device_t device, const void *data, size_t datasz);
|
|
void *cp3000_get_user_data(cp3000_device_t);
|
|
int cp3000_destroy_user_data(cp3000_device_t);
|
|
|
|
/*
|
|
** Exported functions - extended (token) parser
|
|
*/
|
|
|
|
// Clear all parsers and add new ones
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// token_parser_t object (pointer to a 'struct TOKEN_PARSER')
|
|
// parameter(s) for the parser functions
|
|
// Returns:
|
|
// Negative value on error
|
|
// Remark:
|
|
// The members of the 'token_parser_t' object are copied to an internal structure,
|
|
// so the object passed to this function may be a local object (i.e. it doesn't
|
|
// have to be a global or static object).
|
|
int cp3000_clear_parsers(cp3000_device_t);
|
|
int cp3000_add_parser(cp3000_device_t, token_parser_t, void *param);
|
|
// Replace all existing parsers, if any, by this (single) parser
|
|
// Simply calls 'cp3000_clear_parsers()' followed by 'cp3000_add_parser()'.
|
|
int cp3000_set_parser(cp3000_device_t, token_parser_t, void *param);
|
|
|
|
// Put data back into the buffer for later processing.
|
|
// Parameters:
|
|
// cp3000_device_t object
|
|
// data
|
|
// number of bytes
|
|
// Returns:
|
|
// < 0 on error, number of bytes otherwise
|
|
// Notes:
|
|
// The putback data is in fact consumed and stored an a separate buffer. When
|
|
// calling 'cp3000_process_data()', the putback buffer will be consumed first.
|
|
// The putback list is used to store data while waiting for a specific reply.
|
|
int cp3000_parser_putback(cp3000_device_t, const void *data, size_t datasz);
|
|
|
|
/*
|
|
** Exported functions - token parser main routine and default CP3000 command processor
|
|
*/
|
|
|
|
// Set a devices authorization level of executed comands
|
|
int cp3000_set_authorization(cp3000_device_t, int level);
|
|
// Check authorization
|
|
// Returns boolean
|
|
int cp3000_check_authorization(cp3000_device_t, int level);
|
|
|
|
// Receive data from a CP3000 communication channel
|
|
// Parameters:
|
|
// cp3000_device_t object (the communication channel)
|
|
// tokens - array of tokens that are recognised _or_ NULL to use
|
|
// the (token) parsers attached to the device with 'cp3000_add_parser()'
|
|
// Returns:
|
|
// Negative value ('-1') on any error; there is no way to distinguish
|
|
// which command returned the error, but 'di_errno' will be set to
|
|
// the last error.
|
|
// Negative value when the peer closed the communication channel;
|
|
// 'di_errno' will be set to TCPERR_EOF in this case.
|
|
// Number of commands/replies handled otherwise.
|
|
// Remarks:
|
|
// This function can be used to handle CP3000 commands only (simple
|
|
// behaviour) or a mixture of CP3000 and foreign data formats (the
|
|
// new, extended behaviour).
|
|
// The following, using the extended usage, is equivalent to the old,
|
|
// simple usage:
|
|
// // extended
|
|
// cp3000_clear_parsers(device);
|
|
// cp3000_add_parser(device, CP3000_DEFAULT_PARSER, token_definitions);
|
|
// ...
|
|
// cp3000_process_data(device, NULL);
|
|
// instead of
|
|
// // simple
|
|
// cp3000_process_data(device, token_definitions);
|
|
// Remarks (CP3000 i.e. old style behaviour):
|
|
// - Processes the putback list, filled by 'cp3000_recv_reply()', first
|
|
// - Checks the I/O buffer before reading from the socket
|
|
// - For each command read from the socket it will
|
|
// - Check the input (checksum, authentification)
|
|
// - Tokenize the input
|
|
// - Call the associated handler
|
|
// - Reply to the peer (if needed for the command, unless CP3000_NO_REPLY
|
|
// is set in the flags for the token definition)
|
|
int cp3000_process_data(cp3000_device_t, const token_definition_t *token_ctx);
|
|
|
|
/*
|
|
** Exported functions - old-style tokenizer for manual parsing
|
|
** NB: these functions are called from 'cp3000_process_data()'
|
|
*/
|
|
|
|
// Check if data is available in the internal buffers; if there is,
|
|
// the caller _mustn't_ call 'select(2)' to wait for data on the
|
|
// socket, but consume the pending data fist
|
|
// Returns '0' if there is none or a positive number otherwise
|
|
int cp3000_data_pending(cp3000_device_t);
|
|
|
|
// Process a tokenized CP3000 command
|
|
int cp3000_process_token(cp3000_device_t, const token_definition_t*, token_info_t);
|
|
|
|
// Tokenize a string buffer; returns the tokens found or NULL
|
|
// in the case of an error
|
|
// Parameters:
|
|
// buffer - string to tokenize
|
|
// Returns:
|
|
// Token object; must be deleted by cp3000_destroy_tokens().
|
|
// Remark:
|
|
// Called from cp3000_process_data().
|
|
// To be used for CP3000 commands only.
|
|
token_info_t cp3000_tokenize(const char *buffer);
|
|
|
|
// Duplicate a token
|
|
// Parameters:
|
|
// tokens
|
|
// Returns:
|
|
// Token object; must be deleted by cp3000_destroy_tokens().
|
|
// Note:
|
|
// Token found in a 'cp3000_process_data()' cycle only have a limited
|
|
// lifetime. To store them for later use, they must be duplicated with
|
|
// this function.
|
|
token_info_t cp3000_duplicate_token(const token_info_t);
|
|
|
|
// Create an empty token or make a binary token
|
|
// Parameters:
|
|
// data
|
|
// number of bytes, or zero when 'data' is a string
|
|
// Returns:
|
|
// Token object; must be deleted by cp3000_destroy_tokens().
|
|
// Notes:
|
|
// Creates an empty token when 'datasz' is zero and 'data' is NULL.
|
|
// Duplicates the string pointed to by 'data' when 'datasz' is zero.
|
|
// Duplicates a binary data buffer of size 'datasz' otherwise.
|
|
token_info_t cp3000_create_token(const void *data, size_t datasz);
|
|
// Set arguments, status and client identifier in a token created with 'cp3000_create_token()'
|
|
int cp3000_token_add_arg(token_info_t tokens, const char *arg);
|
|
int cp3000_token_set_status(token_info_t tokens, int status);
|
|
int cp3000_token_set_client(token_info_t tokens, int client_id);
|
|
|
|
// Delete the token found by 'cp3000_tokenize()' or duplicated with 'cp3000_duplicate_token()'
|
|
int cp3000_destroy_token(token_info_t tokens);
|
|
// old name
|
|
#define cp3000_delete_token(t) cp3000_destroy_token(t)
|
|
|
|
/*
|
|
** Exported functions - CP3000 commands and replies
|
|
*/
|
|
|
|
// Send a command over the TCP channel.
|
|
// Parameters:
|
|
// cp3000_device_t object (the communication channel)
|
|
// fmt - a TCPFMT_xxx with the command and its parameters
|
|
// ... - arguments
|
|
// Returns:
|
|
// Negative value on error.
|
|
// Remarks:
|
|
// Caller must escape all parameters.
|
|
int cp3000_send_cmd(cp3000_device_t, const char *fmt, ...);
|
|
int cp3000_vsend_cmd(cp3000_device_t, const char *fmt, va_list ap);
|
|
|
|
// Send a reply; 'reply' is optional and may be NULL
|
|
// Parameters:
|
|
// cp3000_device_t object (the communication channel)
|
|
// status_code - two byte (0..255) status code as defined in <cp3000-errno.h>
|
|
// fmt - optional additional reply text format (may be NULL)
|
|
// Returns:
|
|
// Negative value on error.
|
|
int cp3000_send_reply(cp3000_device_t, int status_code, const char *fmt, ...);
|
|
int cp3000_vsend_reply(cp3000_device_t, int status_code, const char *fmt, va_list ap);
|
|
|
|
// Receive a reply
|
|
// Parameters:
|
|
// cp3000_device_t object (the communication channel)
|
|
// status code (pointer to)
|
|
// msg - text part of the reply (may be NULL)
|
|
// msg_sz - size of 'msg'
|
|
// Returns:
|
|
// Number of bytes in 'msg' or '-1' on error
|
|
// Remarks:
|
|
// Fills the putback list, which must be processed
|
|
int cp3000_recv_reply(cp3000_device_t device, int *status_code, char *msg, size_t msg_sz);
|
|
int cp3000_recv_reply_for_client(cp3000_device_t device, int client_id, int *status_code, char *msg, size_t msg_sz);
|
|
|
|
// Forward the tokens received
|
|
// Parameters:
|
|
// cp3000_device_t object (the communication channel)
|
|
// tokens to send
|
|
// Returns:
|
|
// Negative value on error.
|
|
int cp3000_forward_tokens(cp3000_device_t, token_info_t tokens);
|
|
|
|
// find the definition of the token returned by 'cp3000_tokenize()'
|
|
// in the list 'definitions' (the last entry in this list must have
|
|
// its 'cmd' field set to NULL)
|
|
const token_definition_t *cp3000_match_token(const token_definition_t *definitions, token_info_t token);
|
|
|
|
/*
|
|
** Checksum calculation and checking
|
|
*/
|
|
|
|
// calculate the checksum of a message
|
|
int cp3000_checksum(const char *buffer);
|
|
// check checksum in a message; return '0' when the checksum matches,
|
|
// '-1' when the message does not contain a checksum or a positive
|
|
// value when the checksum does not match.
|
|
int cp3000_match_checksum(const char *buffer);
|
|
|
|
/*
|
|
** Wait for data
|
|
*/
|
|
|
|
// Read data from a CP3000 communication channel, in three steps
|
|
// 1. Optionally, wait until data is availble using 'cp3000_select()'
|
|
// 2. Read it and store it in the internal buffer
|
|
// 3. Read strings from the internal buffer
|
|
|
|
// Wait until data is ready to be read, with optional time-out.
|
|
// Similar to 'select(2)' (which _could_ be called, for that matter),
|
|
// but also checks the internal buffers.
|
|
// OpenSSL safe, as 'select(2)' may not always work as intended.
|
|
// Parameters:
|
|
// - An array (with count) of cp3000_device_t's to check. The array
|
|
// is _changed_ and contains the devices with data available upon
|
|
// exit.
|
|
// - Optional time-out if not NULL; when the time-out is specified and
|
|
// set to 0.0 seconds, the function will return immediately
|
|
// Returns:
|
|
// < 0 on error
|
|
// 0 when the time-out was triggered
|
|
// - number of entries in the cp3000_device_t; these are the device(s)
|
|
// that have data available
|
|
int cp3000_select(cp3000_device_t*, int n_devices, struct timeval*);
|
|
|
|
// Check if a device is in the array upon returning from 'cp3000_wait_data()'
|
|
int cp3000_in_select(const cp3000_device_t, const cp3000_device_t *devices, int n_devices);
|
|
|
|
/*
|
|
** Raw data access
|
|
** It is recommended to use the 'tokenizer' functions above
|
|
*/
|
|
|
|
// Synchronise with the peer, as good as possible
|
|
// Returns:
|
|
// 1 on success
|
|
// 0 or < 0 on failure
|
|
int cp3000_sync(cp3000_device_t);
|
|
|
|
// Send data over a CP3000 communication channel
|
|
int cp3000_send_data(cp3000_device_t, const char *data, int len);
|
|
|
|
// Read data from the CP3000 channel into the internal buffer
|
|
// Returns:
|
|
// > 0: number of bytes read from the communication channel in
|
|
// this call
|
|
// 0: channel was closed
|
|
// < 0 on error
|
|
int cp3000_recv_data(cp3000_device_t);
|
|
|
|
// Read a string or binary data from the internal buffer
|
|
// Returns:
|
|
// 0 if there is not enough data, i.e. not a full strings worth
|
|
// > 0: lenght of the string returned in 'buffer'
|
|
// < 0 on error
|
|
// Remarks:
|
|
// The string reader will read upto the next new line and it returns the length
|
|
// of the string in the buffer. The binary reader will return 'n_bytes' or zero
|
|
// if the buffer does not contain enough data to satisfy the request.
|
|
int cp3000_recv_string(cp3000_device_t, char *buffer, int bufsz);
|
|
int cp3000_recv_bytes(cp3000_device_t, unsigned char *buffer, int n_bytes);
|
|
|
|
// Access to the file descriptors for low level access
|
|
int cp3000_get_rfd(cp3000_device_t);
|
|
int cp3000_get_wfd(cp3000_device_t);
|
|
|
|
// Wrappers for FD_SET and FD_ISSET; the parameter 'max' is used to determine
|
|
// the file descriptor with the greatest number (if fd > max then max := fd;)
|
|
int cp3000_fd_set(cp3000_device_t, fd_set*, int *max);
|
|
int cp3000_in_fd_set(cp3000_device_t, fd_set*);
|
|
|
|
/*
|
|
** Escape and unescape strings
|
|
*/
|
|
|
|
// escape quotes and other characters in a string and returns 'dest' or
|
|
// NULL when 'dest' is too small
|
|
// - the size of 'dest' is, worst case, four times as great as 'src'
|
|
const char *cp3000_escape(const char *src, char *dest, size_t dest_sz);
|
|
// escape binary data
|
|
const char *cp3000_nescape(const unsigned char *src, size_t src_sz, char *dest, size_t dest_sz);
|
|
// remove the escapes and returns 'dest' or NULL if 'dest' is too small
|
|
// - 'src' and 'dest' may overlap
|
|
// - 'dest' will never be longer than 'src'
|
|
const char *cp3000_unescape(const char *src, char *dest, size_t dest_sz);
|
|
|
|
/*
|
|
** Convert an array of bytes to a string with hexadecimal numbers and v.v.
|
|
*/
|
|
|
|
// escape an array of bytes (the 'dest' string will contain the hexa-
|
|
// decimal representation of each byte) and v.v.
|
|
// - the size of 'dest' must be (2*src_sz + 1) characters
|
|
// - always returns the number of characters is 'dest' for success
|
|
int cp3000_bin2hex(const unsigned char *src, size_t src_sz, char *dest);
|
|
// the reverse function may fail if the destination is not large enough
|
|
// (in which case this function returns '-1', however 'dest' will be
|
|
// filled up to 'dest_sz' bytes), otherwise it returns the number of
|
|
// bytes in 'dest'.
|
|
int cp3000_hex2bin(const char *src, unsigned char *dest, size_t dest_sz);
|
|
|
|
/*
|
|
** Convert a string to an enumeration value or set (bitfield)
|
|
*/
|
|
|
|
// for both functions, the input array 'members' must be in order, i.e.
|
|
// the first entry returns enumeration value '0' resp. set value 0x0001;
|
|
// NULL values can be used as place holders (they are never matched)
|
|
|
|
// convert a string to an enumeration; returning the first match
|
|
// return '-1' on error
|
|
int cp3000_str2enum(const char *str, const char **members, int n_members);
|
|
|
|
// convert a string to a set value (bitfield)
|
|
// 'str' contains zero or more comma separated values that are to be
|
|
// matched in 'members'
|
|
unsigned long cp3000_str2set(const char *str, const char **members, int n_members);
|
|
|
|
/*
|
|
** Errors
|
|
*/
|
|
|
|
// get error string for the supplied error code; if this is TCPERR_SOCKET,
|
|
// then the function will try to retrieve the last error from the C library
|
|
// or OpenSSL library
|
|
const char *cp3000_error_string(cp3000_device_t, int error_code);
|
|
|
|
#endif /* __CP3000_H */
|