/* ----------------------------------------------------------------------------
 *
 * Raima Database Manager
 *
 * Copyright (c) 2010 Raima Inc.,  All rights reserved.
 *
 * Use of this software, whether in source code format, or in executable,
 * binary object code form, is governed by the Raima LICENSE which
 * is fully described in the LICENSE.TXT file, included within this
 * distribution of files.
 *
 * ----------------------------------------------------------------------------
 */

/* transport.h - Contains definitions for the transport layer */
#ifndef TRANSPORT_H
#define TRANSPORT_H

#include "psp.h"

#ifdef __cplusplus
extern "C" {
#endif

#define RDM_STRINGIFY(data) #data
#define RDM_STRINGIFY2(data) RDM_STRINGIFY(data)

/* TFS defaults */
#define TFS_MAX_PORT            65533
#define TFS_MIN_PORT            1
#define TFS_SHM_PREFIX          "RDM_"
#define TFS_DEFAULT_URI         "tfs:///"
#define TFS_DEFAULT_PORT        21553
#define TFS_DEFAULT_PORT_STR    RDM_STRINGIFY2(TFS_DEFAULT_PORT)
#define TFS_DEFAULT_NAME        TFS_DEFAULT_PORT_STR
#define TFS_DEFAULT_NAME_STR    RDM_STRINGIFY2(TFS_DEFAULT_NAME)

/* The dbmirror port is 1 plus the tfs port */
#define MIRROR_PORT_OFFSET      1
#define MIRROR_NAME_EXTENSION   "_rep"
/*#define MIR_DEFAULT_PORT        (TFS_DEFAULT_PORT + MIRROR_PORT_OFFSET) */

#define SQL_PORT_OFFSET         2
#define SQL_NAME_EXTENSION      "_sql"
/*#define SQL_DEFAULT_PORT        (TFS_DEFAULT_PORT + SQL_PORT_OFFSET ) */

typedef struct {
    uint16_t    portIncrement;
    const char *extension;
} TFS_ANCHOR_OFFSET;

#define TFS_TRANSPORT_TCP            "tcp"
#define TFS_TRANSPORT_SHM            "shm"
#define TFS_TRANSPORT_NMP            "nmp"
#define TFS_TRANSPORT_UD             "ud"
#if defined(RDM_HAS_SHARED_MEMORY)
#define TFS_AVAILABLE_TRANSPORTS_STR RDM_STRINGIFY2(TFS_TRANSPORT_TCP) " and " RDM_STRINGIFY2(TFS_TRANSPORT_SHM)
#define TFS_DEFAULT_TRANSPORTS       "shm,tcp"
#else
#define TFS_AVAILABLE_TRANSPORTS_STR RDM_STRINGIFY2(TFS_TRANSPORT_TCP)
#define TFS_DEFAULT_TRANSPORTS       "tcp"
#endif
#define TFS_DEFAULT_TRANSPORTS_STR   RDM_STRINGIFY2(TFS_DEFAULT_TRANSPORTS)

typedef enum
{
    TX_NONE = 0x0000,
    TX_TCP  = 0x0001,
    TX_SHM  = 0x0002, /* not available on all platforms */
    TX_NMP  = 0x0004, /* not available on all platforms */
    TX_UD   = 0x0008, /* not available on all platforms */
    TX_UUID = 0x8000  /* internal */
} TX_CONN_TYPE;

#define TFS_MAX_CONN_TYPE 4

#if defined(RDM_HAS_SHARED_MEMORY)
/*lint -emacro(655,TX_DEFAULT_TYPE) */
#define TX_DEFAULT_TYPE (TX_TCP | TX_SHM)
#else
#define TX_DEFAULT_TYPE TX_TCP
#endif

#define TX_MAX_CONN_TYPE 4

typedef struct {
    const char *hostname;
    uint16_t    port;
    uint32_t    heartbeat;
} TX_TCP_CONN_INFO;

#if defined(RDM_HAS_SHARED_MEMORY)
typedef struct {
    const char *name;
    uint32_t    seq;
} TX_SHM_CONN_INFO;
#endif

#if defined(RDM_HAS_NAMED_PIPES)
typedef struct {
    const char *name;
    const char *node;
} TX_NMP_CONN_INFO;
#endif

#if defined(RDM_HAS_UNIX_DOMAIN_SOCKETS)
typedef struct {
    const char *name;
} TX_UD_CONN_INFO;
#endif

typedef struct {
    UUID_VAL uuid;
} TX_UUID_CONN_INFO;

typedef struct {
    TX_CONN_TYPE connType;
    union {
        TX_TCP_CONN_INFO  tcp;
#if defined(RDM_HAS_SHARED_MEMORY)
        TX_SHM_CONN_INFO  shm;
#endif
#if defined(RDM_HAS_NAMED_PIPES)
        TX_NMP_CONN_INFO  nmp;
#endif
#if defined(RDM_HAS_UNIX_DOMAIN_SOCKETS)
        TX_UD_CONN_INFO   ud;
#endif
        TX_UUID_CONN_INFO uuid;
    } info;
} TX_CONN_INFO;

typedef struct {
    uint32_t      num;
    TX_CONN_INFO *info;
    const char   *dbname;
    const char   *tfsspec;
} TX_CONN_CTX;

typedef const void *TX_CONNECTION;

typedef enum {
    SERVER_UNKNOWN,
    SERVER_TFSERVER,
    SERVER_DBMIRROR,
    SERVER_DBREP,
    SERVER_DBREPSQL,
    SERVER_RDMSQLSERVER
} TFS_SERVER_TYPE;

typedef struct {
    int32_t (*startup_fcn)(const char *, uint32_t);
    void    (*cleanup_fcn)(void);
    int32_t (*listen_fcn)(const TX_CONN_INFO *, TX_CONNECTION *, TFS_SERVER_TYPE, const char **);
    int32_t (*accept_fcn)(TX_CONNECTION, TX_CONNECTION *);
    int32_t (*connect_fcn)(const TX_CONN_INFO *, TX_CONNECTION *, int32_t);
    void    (*discon_fcn)(TX_CONNECTION);
    int32_t (*read_fcn)(TX_CONNECTION, void *, uint32_t, uint32_t *, uint32_t);
    int32_t (*write_fcn)(TX_CONNECTION, const void *, uint32_t);
    int32_t (*gethostname_fcn)(char *, int32_t);
    void    (*free_fcn)(TX_CONNECTION);
} TX_FCNS;

typedef struct {
    const char  *hostname;         /* TCP/IP hostname */
    uint16_t     port;             /* TCP/IP port */
    uint32_t     heartbeatTimeout; /* TCP/IP heartbeat timeout in seconds */
    const char  *name;             /* name (for non-TCP/IP connections) */
    TX_CONN_TYPE transportBitmap;  /* bitmap indicating which transports to use */
} TRANSPORT_PARAMS;

/*********************** TRANSPORT LAYER CONNECTIONS *******************/
typedef const void *TX_CONN;
typedef const void *TX_LIST;

RDM_EXPORT const TX_FCNS * EXTERNAL_FCN tl_getTcpFunctions(void);
RDM_EXPORT const TX_FCNS * EXTERNAL_FCN tl_getShmFunctions(void);
RDM_EXPORT const TX_FCNS * EXTERNAL_FCN tl_getNmpFunctions(void);
RDM_EXPORT const TX_FCNS * EXTERNAL_FCN tl_getUdFunctions(void);
RDM_EXPORT const TX_FCNS * EXTERNAL_FCN tl_getHbFunctions(void);

RDM_EXPORT int32_t     EXTERNAL_FCN tl_connect(const TX_CONN_CTX *, TX_CONN *);
RDM_EXPORT void        EXTERNAL_FCN tl_discon(TX_CONN);
RDM_EXPORT void        EXTERNAL_FCN tl_abort(TX_CONN);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_gethostname(TX_CONN, char *, int32_t);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_listen(const TX_CONN_INFO *, TFS_SERVER_TYPE, TX_LIST *);
RDM_EXPORT const char *EXTERNAL_FCN tl_listenMessage(TX_LIST);
RDM_EXPORT void        EXTERNAL_FCN tl_stoplisten(TX_LIST);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_accept(TX_LIST, TX_CONN *);

RDM_EXPORT int32_t     EXTERNAL_FCN tl_send(TX_CONN);
RDM_EXPORT void        EXTERNAL_FCN tl_beginReceive(TX_CONN);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_sendAndReceive(TX_CONN);

RDM_EXPORT const char  *EXTERNAL_FCN tl_transportList(TX_CONN_TYPE);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_validateTransports(const char *, TX_CONN_TYPE *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_createConnectionInfo(TFS_SERVER_TYPE, const TRANSPORT_PARAMS *, const TX_CONN_CTX **);
RDM_EXPORT TX_CONN_CTX *EXTERNAL_FCN tl_copyConnectionInfo(const TX_CONN_CTX *, PSP_MEMTAG);
RDM_EXPORT void         EXTERNAL_FCN tl_freeConnectionInfo(const TX_CONN_CTX *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_parseConnectionUri(TFS_SERVER_TYPE, const char *, const TX_CONN_CTX **, int16_t *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_compareConnectionInfo(const TX_CONN_INFO *, const TX_CONN_INFO *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_compareDatabase(const TX_CONN_CTX *, const TX_CONN_CTX *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_makeUris(const TX_CONN_CTX *, const char *, const char *const **, uint32_t *);
RDM_EXPORT void         EXTERNAL_FCN tl_freeUris(const char *const *, uint32_t);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_isUuidConnection(const TX_CONN_CTX *, UUID_VAL *);
RDM_EXPORT const char  *EXTERNAL_FCN tl_connDbName(const TX_CONN_CTX *);
RDM_EXPORT const char  *EXTERNAL_FCN tl_connTfsSpec(const TX_CONN_CTX *);
RDM_EXPORT const char  *EXTERNAL_FCN tl_connTcpHostname(const TX_CONN_CTX *);
RDM_EXPORT uint16_t     EXTERNAL_FCN tl_connTcpPort(const TX_CONN_CTX *);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_createUri(const char *, const char *, const char **);
RDM_EXPORT int32_t      EXTERNAL_FCN tl_uriInformation(const char *, int32_t *, TX_CONN_TYPE *);

RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamChar(TX_CONN, char);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamInt16(TX_CONN, int16_t);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamInt32(TX_CONN, int32_t);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamInt64(TX_CONN, int64_t);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamFloat32(TX_CONN, float);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamFloat64(TX_CONN, double);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamString(TX_CONN, const char *);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamStringWithLength(TX_CONN, const char *);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamBytes(TX_CONN, const void *, size_t);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamUser(TX_CONN, TX_USER);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putParamUUID(TX_CONN, const UUID_VAL *);
RDM_EXPORT int32_t     EXTERNAL_FCN tl_putDirect(TX_CONN, const void *, size_t);

#define tl_putParamFcnID(c, f)    tl_putParamBytes((c), (f), sizeof(f) - 1)
#define tl_putParamFile(c, f)     tl_putParamBytes((c), &(f), sizeof(f))
#define tl_putParamDb(c, d)       tl_putParamBytes((c), &(d), sizeof(d))
#define tl_putParamCurrentUser(c) tl_putParamUser(c, (TX_USER) 0)
#define tl_putParamIni(c, i)      tl_putParamBytes((c), &(i), sizeof(i))
#define tl_putParamTxID(c, t)     tl_putParamUInt64((c), (uint64_t) (t))

#define tl_putParamUInt8(c, u8)   tl_putParamChar((c), (char) (u8))
#define tl_putParamUInt16(c, u16) tl_putParamInt16((c), (int16_t) (u16))
#define tl_putParamUInt32(c, u32) tl_putParamInt32((c), (int32_t) (u32))
#define tl_putParamUInt64(c, u64) tl_putParamInt64((c), (int64_t) (u64))

RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamChar(PSP_INPUTBUFF, char *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamInt8(PSP_INPUTBUFF, int8_t *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamInt16(PSP_INPUTBUFF, int16_t *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamInt32(PSP_INPUTBUFF, int32_t *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamInt64(PSP_INPUTBUFF, int64_t *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamFloat32(PSP_INPUTBUFF, float *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamFloat64(PSP_INPUTBUFF, double *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamString(PSP_INPUTBUFF, char **);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamStringWithLength(PSP_INPUTBUFF, char *, size_t);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamBytes(PSP_INPUTBUFF, void *, size_t);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamUser(TX_CONN, TX_USER *);
RDM_EXPORT int32_t EXTERNAL_FCN tl_getParamUUID(TX_CONN, UUID_VAL *);

#define tl_getParamFile(c, f)     tl_getParamBytes((c), (f), sizeof(*(f)))
#define tl_getParamDb(c, d)       tl_getParamBytes((c), (d), sizeof(*(d)))
#define tl_getParamIni(c, i)      tl_getParamBytes((c), (i), sizeof(*(i)))
#define tl_getParamCurrentUser(c) tl_getParamUser(c, (TX_USER *) 0)
#define tl_getParamTxID(c, t)     tl_getParamUInt64((c), (uint64_t *) (t))

#define tl_getParamUInt8(c,  u8)  tl_getParamInt8((c),  ((int8_t *)  (u8)))
#define tl_getParamUInt16(c, u16) tl_getParamInt16((c), ((int16_t *) (u16)))
#define tl_getParamUInt32(c, u32) tl_getParamInt32((c), ((int32_t *) (u32)))
#define tl_getParamUInt64(c, u64) tl_getParamInt64((c), ((int64_t *) (u64)))

RDM_EXPORT int32_t EXTERNAL_FCN tl_parsePortNumber(const char *str, uint16_t *port);


#ifdef __cplusplus
}
#endif

#endif


