200 lines
8.0 KiB
OpenEdge ABL
200 lines
8.0 KiB
OpenEdge ABL
#ifndef ASCON_I
|
|
#define ASCON_I
|
|
|
|
#include <sys/time.h>
|
|
#include "ascon.h"
|
|
#include "dynstring.h"
|
|
|
|
/** \file
|
|
* \brief Asynchronous connection handling for devices controlled over tcp-ip
|
|
* connections. Interface for the implementation of custom protocols.
|
|
*
|
|
* For the implementation of a custom protocol, you have to implement
|
|
* the handler function and the init function, declare the protocol
|
|
* of type AsconProtocol and call AsconInsertProtocol on startup.
|
|
* The handler and init functions are normally a wrapper around AsconStdHandler
|
|
* and AsconStdInit
|
|
*
|
|
* The functions with fd as the first argument are utility functions with
|
|
* may be used in handler wrapper functions.
|
|
* On error, the return value may be one of the defined macros ASCON_xxx,
|
|
* and errno will give more details about the error.
|
|
*/
|
|
|
|
/**
|
|
* The state of the connection.
|
|
*/
|
|
typedef enum {
|
|
AsconNotConnected, /**< unconnected, not to be connected automatically */
|
|
AsconConnectStart, /**< after initialisation or after AsconFailed */
|
|
AsconConnecting, /**< after AsconConnectStart or AsconConnecting */
|
|
AsconConnectDone, /**< after AsconConnecting */
|
|
AsconWriteStart, /**< set by the AsconWrite function */
|
|
AsconWriting, /**< after AsconWriteStart or AsconWriting */
|
|
AsconWriteDone, /**< after AsconWriting */
|
|
AsconReadStart, /**< after AsconWriteDone */
|
|
AsconReading, /**< after AsconReadStart or AsconReading */
|
|
AsconReadDone, /**< after AsconReading */
|
|
AsconReadDoneReconnect, /**< after AsconReading, read success, but need to reconnect */
|
|
AsconIdle, /**< after AsconWriteDone, AsconReadDone, AsconTimeout, AsconIdle */
|
|
AsconFailed, /**< after any state */
|
|
AsconTimeout, /**< after AsconReading */
|
|
AsconMaxState /**< number of states */
|
|
} AsconState;
|
|
|
|
/** \brief the task handler function prototype
|
|
*
|
|
* custom handlers must have this prototype
|
|
*/
|
|
typedef int (* AsconHandler)(Ascon *connection);
|
|
|
|
/** Ascon struct
|
|
* all fields are public, allowing access by handler wrappers
|
|
* the fields marked with (std) are used by the standard handler
|
|
* they may get other meanings in a custom handler
|
|
*/
|
|
struct Ascon {
|
|
AsconState state; /**< the current state */
|
|
int fd; /**< socket */
|
|
int conState; /**< 1: connection refused, 0: else */
|
|
int readState; /**< (std) last char was CR */
|
|
pDynString rdBuffer; /**< read buffer */
|
|
pDynString wrBuffer; /**< write buffer */
|
|
int wrPos; /**< write buffer position */
|
|
double timeout; /**< read timeout (sec) */
|
|
char *sendTerminator; /**< terminator for sending messages */
|
|
char *replyTerminator; /**< (std) terminator list for reply. NULL is the special case CR, LF or CR/LF */
|
|
char *hostport; /**< host:port to connect */
|
|
char ip[16]; /**< the ip address (dotted numbers) */
|
|
pDynString errmsg; /**< error message */
|
|
double start; /**< unix time when read was started */
|
|
int noResponse; /**< no response expected */
|
|
int responseValid; /**< a valid response is ready */
|
|
AsconHandler handler; /**< handler function */
|
|
double reconnectInterval; /**< reconnect interval */
|
|
double lastReconnect; /**< last reconnect try */
|
|
char lastChar; /**< last char read */
|
|
char *separator; /**< (std) separator for multiline responses */
|
|
int lineCount; /**< number of lines expected (counting down) */
|
|
int compositeTerminator; /**< the terminator contains several chars */
|
|
void *private; /**< private data of protocol */
|
|
void (*killPrivate)(void *); /**< kill function for private */
|
|
};
|
|
|
|
#define ASCON_SELECT_ERROR -1
|
|
#define ASCON_RECV_ERROR -2
|
|
#define ASCON_SEND_ERROR -3
|
|
#define ASCON_DISCONNECTED -4
|
|
|
|
/** \brief the basic handler routine.
|
|
* \param a the connection
|
|
* \return when the state before the call was not AsconReading, the return
|
|
* value should be 1
|
|
* when the state was AsconReading, a 1 indicates that a character was read
|
|
* and the character is stored in the lastChar field. A 0 indicates
|
|
* that no character was read. And this 0 has to be given, otherwise AsconTask
|
|
* goes into an endless loop till timeout is hit!
|
|
*
|
|
*
|
|
* In most cases a custom handler may be a wrapper around AsconBaseHandler
|
|
* or around AsconStdHandler
|
|
*/
|
|
int AsconBaseHandler(Ascon *a);
|
|
|
|
/** \brief the standard handler routine.
|
|
* \param a the connection
|
|
* \return see AsconBaseHandler
|
|
*
|
|
* features: see description of AsconStdInit
|
|
*/
|
|
int AsconStdHandler(Ascon *a);
|
|
|
|
/** \brief initialize a standard connection
|
|
* \param a the connection
|
|
* \param con A connection to print errors too.
|
|
* \param argc number of arguments
|
|
* \param argv arguments ("<host>:<port>" [sendTerminator] [timeout] [replyTerminators] [separator])
|
|
* sendTerminator is a character or string sent at the end of a command
|
|
* timeout is in seconds
|
|
* replyTerminators is a string, meant as a list of terminator characters
|
|
* if no replyTerminator is given, or if it is empty, CR, LF or CR/LF all are detected
|
|
* as terminators. If the terminator is CR, LF or CR/LF, it is removed from the result,
|
|
* all other terminators are kept in the result.
|
|
* is the first and the last character are single quotes (') is is treated as a composite
|
|
* terminator and not as a list of single character terminators
|
|
* separator is used for multiline responses. If this parameter
|
|
* is given (and not empty) a command may be followed by a line count in curly brackets,
|
|
* indicating that a multiline response is expected. All the lines of the response are
|
|
* then returned, separated with "separator"
|
|
*
|
|
* In many cases a custom init function may be a wrapper around AsconStdInit
|
|
*/
|
|
int AsconStdInit(Ascon *a, SConnection *con, int argc, char *argv[]);
|
|
|
|
/** The Ascon Protocol
|
|
*/
|
|
typedef struct AsconProtocol {
|
|
struct AsconProtocol *next;
|
|
char *name;
|
|
AsconHandler handler;
|
|
int (*init)(Ascon *s, SConnection *con, int argc, char *argv[]);
|
|
} AsconProtocol;
|
|
|
|
/** \brief Insert a new protocol into the protocol list
|
|
* protocol the protocol (must be allocated by the caller, may be statically)
|
|
*/
|
|
void AsconInsertProtocol(AsconProtocol *protocol);
|
|
|
|
/** \brief close the connection and free internal used memory
|
|
* \param a the connection to be closed
|
|
* remark: the connection struct itself has to be freed manually
|
|
*/
|
|
void AsconClose(Ascon *a);
|
|
|
|
/** \brief swallow garbage (utility function)
|
|
* \param fd the socket
|
|
* \return >=0: number of chars swallowed, else error
|
|
*/
|
|
int AsconReadGarbage(int fd);
|
|
|
|
/** \brief check if a connection has succeded (utility function)
|
|
* \param fd the socket
|
|
* \return 1: connection succesful, 0: connection in progress, <0: error
|
|
*/
|
|
int AsconConnectSuccess(int fd);
|
|
|
|
/** \brief read one character, if available (utility function)
|
|
* \param fd the socket
|
|
* \param chr the result
|
|
* \return 1: succes, 0: no data available, <0: error
|
|
*/
|
|
int AsconReadChar(int fd, char *chr);
|
|
|
|
/** \brief non blocking write (utility function)
|
|
* \param fd the socket
|
|
* \param data the data (not nul-terminated, may contain nul)
|
|
* \param length the length of the data
|
|
* \return >0: number of written chars,0: write not yet possible, <0: error
|
|
*/
|
|
int AsconWriteChars(int fd, char *data, int length);
|
|
|
|
/** \brief store an error
|
|
* \param a The asynchronous I/O structure to store the
|
|
* error with
|
|
* \param msg The error message
|
|
* \param errorno The error number or 0 for a custom error
|
|
*/
|
|
void AsconError(Ascon *a, char *msg, int errorno);
|
|
|
|
int AsconInterpreteArgs(int argc, char *argv[],
|
|
int parc, char *parn[], char *pars[]);
|
|
|
|
|
|
/**
|
|
* Treat hex strings as terminators right. Note that this
|
|
* is limited to single character terminators.
|
|
*/
|
|
void AsconCheckTerminators(Ascon *a);
|
|
|
|
#endif
|