libmqmsgque 9.0
Loading...
Searching...
No Matches
libmqmsgque

The C Application-Server Project.

SYNOPSIS

The libmqmsgque package is the implementation of the Programming-Language-Micro-Kernel into the target-language C.

link: -Lpath -lmqmsgque or automake: LDADD = libmqmsgque.la

The libmqmsgque package is a composition of multiple classes defining the Programming-Language-Micro-Kernel:

object description
Mq the namespace with all libmqmsgque specific definitions
MqAttribute(…) the interface to access the package specific attribute
MqClassAttribute(…) the interface to access the class specific attribute
MqClassAttribute(Instance,…) the interface to access the instance specific attribute

To access all features without Mq prefix use:

#include "msgque_mq.h"

Using the libmqmsgque package.
Using the libmqmsgque package …
With automake/libtool the libmqmsgque library needs to be linked with the executable/library, this is done with:

‍LDADD = path/to/libmqmsgque.la

or

‍mylib_la_LIBADD = path/to/libmqmsgque.la

Example from acmds/Makefile.am using libmkkernel.la and libmqmsgque.la:
atool_SOURCES = atool.c ajoin.c acut.c asort.c asplit.c optionL.c optionL.h
atool_CFLAGS = -Wconversion -Werror -Wstrict-prototypes $(libmqmsgque_CPPFLAGS)
atool_LDFLAGS = $(UBSAN) -no-undefined
atool_LDADD = $(libmqmsgque_shared_LIBADD)
Using automake/libtool the MkKernel library have to be linked with the executable/library, this is done with:

‍LDADD = path/to/libmkkernel.la

or

‍mylib_la_LIBADD = path/to/libmkkernel.la

Example from acmds/Makefile.am using libmkkernel.la and libmqmsgque.la:
atool_SOURCES = atool.c ajoin.c acut.c asort.c asplit.c optionL.c optionL.h
atool_CFLAGS = -Wconversion -Werror -Wstrict-prototypes $(libmqmsgque_CPPFLAGS)
atool_LDFLAGS = $(UBSAN) -no-undefined
atool_LDADD = $(libmqmsgque_shared_LIBADD)

INDEX

BASICS
Philosophy , ConfigFile
CLASS
MqMsgque PACKAGE , MqContextC , MqDumpC , MqFactoryC
CONTEXT
Class, Config, Link, Service, Send, Read, Route, Proxy, Slave, Storage, High, CallEnv, Error, Log
MISC
InstStor, Filter, Examples

INTRODUCTION

C-API: MQ_C_API - namespace for the LibMqMsgque "C"-API

The MqMsgque project is an infrastructure that allows multiple package-items to be linked together to act as one application.

PHILOSOPHY

The MqMsgque project is an infrastructure that allows multiple package-items to be linked together to act as one application.
To link, you need to distribute the work from one package-item to another package-item and wait for an answer or not.

Philosophy
Write Once → Run Everywhere

The package-item can be a thread, a separate local process that is started by fork or spawn, or even a network of multiple services on multiple hosts.

The package-item can be written in any language that is supported by the Programming-Language-Micro-Kernel support.
It even supports running multiple programming languages in a single piece of software.
Supported Languages are: (C,C++,C#,VB.NET,Java,Python,Ruby,Perl,PHP,Tcl or GO)

Strategy
It takes 4 years to write a programming-language, but it only takes 4 weeks to insert a micro-kernel.

The package-item is connected to one another via a pipe or a socket and is based on packages which are sent from one package-item to another package-item and back.

Conclusion
The MqMsgque project is used to manage a network of multiple package-items using an API that is available in all major programming-languages.

PROGRAMMING

The MqMsgque library is responsible for:

  • establishing and managing the package-items, local or remote
  • establishing and managing the connections between package-items
  • establishing and managing the routing between package-items
  • sending and receiving the package data, calling up a service
  • reading and writing data from or into a data-package
  • setup and maintain event-handling and scheduling
  • interception, distribution and processing of error messages

The LibMsgque library is separted into three programming-layers:

  1. The foundation-layer, used by the MqMsgque library programmer
  2. The kernel-layer, used by the Programming-Language-Micro-Kernel programmer
  3. The implementation-layer, used by the target-language programmer
foundation-layer
The foundation-layer implement the libmqmsgque library and is also responsible for the quality-target of the entire project.
  • establishing and managing the package-items
  • establishing and managing the connections
  • memory-management and garbage-collection
  • error-handling
  • logging and debugging
  • written in plain C
kernel-layer
The kernel-layer implement the Programming-Language-Micro-Kernel and is also responsible to generate and maintain the target-language-API source-code.
  • implementation of the managed-object technology
  • implementation of the token-stream-compiler technology
  • written in plain C, TCL and the target-language-API
implementation-layer
The implementation-layer is the API used by the target-language-programmer.
  • written in plain target-programming-language (C,C++,C#,VB.NET,Java,Python,Ruby,Perl,PHP,Tcl or GO)
Target
!! This documentation describe the implementation-layer and target the C programmer. !!

CONFIG FILE

C-API: MqConfigS::cfg - add libconfig configuration file …

introduction

A config-file is used to add configuration-values to a libmqmsgque-application using a structured text-file.

supported
By default command-line-options; filter-pipline and slave-worker-setup is supported.

A service-callback and "programming" is not supported. To "programm and modify" something use a scripting language like tcl or python.

goal
The goal is to give the user of a compiled application the ability to provide a single place for common-configuration-values.

technology

libconfig is used to parse a config-file using the application … --config fileName … option.

syntax
The config-file syntax is defined at: http://hyperrealm.github.io/libconfig/libconfig_manual.html

The following restrictions apply to the --config option.

  1. The config-file is parsed when the --config option is parsed
  2. An application is identfied in the config-file by groupname : { ... } ( ":" or "=" is allowd )
  3. The groupname is the return from ClassIdentGet using hint from --ident-from prefix|factory
  4. The groupname is modified with the --name string, --prefix string or --ident-from prefix|factory naming-options
  5. The order of option-parsing is the order on the command-line
    MyClient … --XXX … --config YYY … --ZZZ …
    order MyClient : XXX < YYY < ZZZ
  6. For a pipe the config-file from the client is added to the end of the server-options :
    MyClient --AAA … --config BBB --CCC … @ Filter3 --name otto --DDD … @ MyServer --EEE …
    application groupname option-parsing-order
    MyClient MyClient AAA < BBB < CCC
    Filter3 otto DDD < BBB
    MyServer MyServer EEE < BBB
    This is required because the --name or --prefix option from DDD or EEE change the group read from the config-file
  7. attention! on a client or a non-pipe server it is a difference if the naming-option is set before or after the --config option
  8. All options set after the --config option overwrite the options from the config-file
  9. The filter ( groupname : { … filter : [ … ] } ) config-file-option define the server to start in a pipe and have to be an array of strings starting with the application-executable OR the factory-identifer

examples

1. Example from MyClient.config filter-pipeline with last server start in debug mode

# commandline OLD: MyClient @ Filter3 @ MyServer --debug 1
# commandline NEW: MyClient --config MyClient.config
version = "1.0" ; // string : version of the configuration file reader
default = "MyClient" ; // string : if the 'class' is unknown use 'default'
MyClient:
{
config:
{
# name = "myName" ; // string : displayname name of the 'context' (default: executable basename)
# identFrom = "prefix" ; // list : select how to identify the application from remote: 'prefix' or 'factory' (default: prefix)
# prefix = "" ; // string : set the 1'part of the visible displayname (default: "" = FactoryName)
# postfix = "" ; // string : set the 2'part of the visible displayname (default: "" = ConnectionName)
# string = false ; // bool : (default: no)
# startAs = "default" ; // string : from list (ref… MqStartE): default, spawn, thread, fork (default: default)
# daemon = "MyServer.pid" ; // string : file for PID
# timeout = 90 ; // int : user defined timeout to terminate a blocking function call (default: 90 sec)
# storage = "#memdb#" ; // string : storage file for the database: #memdb#, #tmpdb# or filename (default: #memdb#)
# runtime = { // struct (ref… MkRuntimeS) : runtime configuration (global)
# debug = 1 ; // int : set the debug-level, Valid values are 0 <= debug <= 9 using 0 for "no" and 9 for "max". (default: 0)
# silent = false ; // bool : write (no) or don't write (yes) any message to stdout or stderr (default: no)
# logfile = "stderr" ; // string : append to logfile, valid values are: stderr, stdout or a filename (default: stderr)
# };
# io = { // struct (ref… MqIoComE) : what kind of socket interface to use? (default: pipe)
# buffersize = 4096 // int : io buffersize (default: 4096)
# pkgsize = 10240 // int : io pkgsize (default: 10 * 1024)
# pipe = true; // struct (ref… MqIoPipeConfigS) → ONLY client (default: true)
# init = false; // struct (ref… MqIoInitConfigS) → ONLY server (default: false)
# tcp = { // struct (ref… MqIoTcpConfigS)
# port = "7777" ; // string : port number or well known port name
# host = "localhost" ; // string : hostname / interfacename
# myport = "1111" ; // string : client MY port number or well known port name
# myhost = "localhost" ; // string : client MY hostname / interfacename
# };
# uds = { // struct (ref… MqIoUdsConfigS)
# file = "filename" ; // string : name of a uds-socket-file (default: null)
# }
# };
};
# start executable "Filter3" in a "@" pipe and change application-name (groupname) to "otto"
filter = [ "Filter3", "--name", "otto" ] ; // array of string : filter pipeline name of "server"
};
# config section for "Filter3" start in the "pipe"
otto = {
filter = [ "MyServer" ] ;
}
# final "MyServer" set option "debug" to "1"
MyServer = {
config: { runtime: {debug = 1} }
# 'config.runtime.debug = 1' is NOT supported.
}

2. Example from libconfig.test filter-pipeline with last server connect by tcp/ip

# OLD: MyClient @ Filter3 @ --tcp --port $PORT
# NEW: MyClient --config configFile
version: 1.0
default = "MyClient"
MyClient: {
filter: [ "Filter3" ]
}
Filter3: {
filter: [ "--tcp", "--port", "$PORT" ]
}

MqMsgque PACKAGE

MqMsgque ENUM

enum MqIdentEidentify the application using prefix (default) or factory
IdentE_FromIntreturn the MqIdentE from integer …
IdentE_ToIntreturn the MqIdentE as integer …
IdentE_ToStringreturn the MqIdentE as string …
enum MqSlaveEpredefined slave-id for well known slaves …
SlaveE_FromIntreturn the MqSlaveE from integer …
SlaveE_ToIntreturn the MqSlaveE as integer …
SlaveE_ToStringreturn the MqSlaveE as string …
enum MqStartEUser preferences on HOWTO start a new entity.
StartE_FromIntreturn the MqStartE from integer …
StartE_ToIntreturn the MqStartE as integer …
StartE_ToStringreturn the MqStartE as string …
enum MqStatusIsEFInformation about how the context was created.
StatusIsEF_FromIntreturn the MqStatusIsEF from integer …
StatusIsEF_ToIntreturn the MqStatusIsEF as integer …
StatusIsEF_ToStringreturn the MqStatusIsEF as string …
enum MqWaitOnEventEwait for an event? …
WaitOnEventE_FromIntreturn the MqWaitOnEventE from integer …
WaitOnEventE_ToIntreturn the MqWaitOnEventE as integer …
WaitOnEventE_ToString

return the MqWaitOnEventE as string …

MqMsgque HELP

Helpwrite libmqmsgque specific user-help to stderr
HelpMsgque

return a page with the usage of all libmqmsgque specific options

MqMsgque INIT

InitGetArg0get the process startup-prefix argument
InitResetArg0Reset the process-startup-prefix argument to an empty list …
InitSetArg0set the process startup-prefix argument to bfl
InitSetArg0VAset the process startup-prefix to a args
InitSetArg0VAL

set the process startup-prefix to var_list

MqMsgque ITEM

MqMsgque MAIN

MqMsgque SETUP

Cleanupcleanup libmqmsgque internal memory …
Setup

setup libmqmsgque internal memory …

MqMsgque DETAIL

C-API: MqMsgque_C_API - The package is the toplevel structure of the Programming-Language-Micro-Kernel

The libmqmsgque package is loaded with:

link: -Lpath -lmqmsgque or automake: LDADD = libmqmsgque.la

and is a composition of one or more package-item and exact one package-main.

The libmqmsgque package add the following classes into MkObjectC_C_API :

Object C-Short Description
MqContextS MQ_CTX The MqContextC object known as ctx or context is the main data structure and application-handle
MqDumpS MQ_DMP The MqDumpC object known as dmp or dump is used to export a libmqmsgque data package as binary
MqFactoryS MQ_FCT The MqFactoryC object known as fct or factory is used to provide an interface to create one or more new MqContextC

The libmqmsgque package add the following types into MkObjectC_C_API :

ABSTRACT: MkTypeSTT (TypeTypeType = type of a TypeType)
|
|- ABSTRACT: MqCtxTypeC_TT (TypeType = type of a Type)
|  |
|  |- MqContextC_T
|
|- ABSTRACT: MkDefTypeSTT (TypeType = type of a Type)
   |
   |- MqFactoryST, MqDumpST

MqMsgque ENUM

C-API: MqMsgque_Enum_C_API - C-API: Internal - Enum definition - libmqmsgque enum definition …

A enum in the Programming-Language-Micro-Kernel is a enum-data-type and 3 enum-access-attributes

  1. ENUM_ToString → return the string-value from the enum-value
  2. ENUM_ToInt → return the integer-value from the enum-value
  3. ENUM_FromInt → create an enum-value from an integer-value.

The enum-data-type and the 3 enum-access-attributes are defined in all target-languages (C,C++,C#,VB.NET,Java,Python,Ruby,Perl,PHP,Tcl or GO).

enum MqIdentE

TOP

identify the application using prefix (default) or factory … → API: MqIdentE

enum MqIdentE {
};
MqIdentE
identify the application using prefix (default) or factory …
Definition msgque_mq.h:707
@ MQ_IDENT_FACTORY
value from MqFactoryS::originalIdent
Definition msgque_mq.h:709
@ MQ_IDENT_PREFIX
value from MqConfigS::prefix
Definition msgque_mq.h:708
See also
ConfigGetIdentFrom, ConfigSetIdentFrom, IdentE_ToString

(static) enum MkErrorE MqIdentE_FromInt(MK_INT value, enum MqIdentE* value_out)

TOP

return the MqIdentE from integer … → API: MqIdentE_FromInt

(static) MK_INT MqIdentE_ToInt(enum MqIdentE value)

TOP

return the MqIdentE as integer … → API: MqIdentE_ToInt

(static) MK_STRN MqIdentE_ToString(enum MqIdentE value)

TOP

return the MqIdentE as string … → API: MqIdentE_ToString


enum MqSlaveE

TOP

predefined slave-id for well known slaves … → API: MqSlaveE

__parser__(enum-accept-integer=int32)
enum MqSlaveE {
MQ_SLAVE_MAX = 1024,
};
MqSlaveE
predefined slave-id for well known slaves …
Definition msgque_mq.h:1577
@ MQ_SLAVE_OTHER
internal: on the master-ctx get the slave-ctx and on the slave-ctx get the master-ctx
Definition msgque_mq.h:1581
@ MQ_SLAVE_FILTER
internal: the filter-slave-id, (on a master get the filter-slave)
Definition msgque_mq.h:1579
@ MQ_SLAVE_USER
internal: start of user-defined-slave-id
Definition msgque_mq.h:1582
@ MQ_SLAVE_MASTER
internal: the master-slave-id, (on a slave get the master)
Definition msgque_mq.h:1580
@ MQ_SLAVE_LOOPBACK
internal: the loopback-slave-id, (call my own services)
Definition msgque_mq.h:1578
@ MQ_SLAVE_MAX
internal: the maximum slave-id …
Definition msgque_mq.h:1586
#define __parser__(...)
See also
ServiceProxy, SlaveWorker, SlaveCreate, SlaveDelete, SlaveCheck, SlaveGet, SlaveGetProxy

(static) enum MkErrorE MqSlaveE_FromInt(MK_INT value, enum MqSlaveE* value_out)

TOP

return the MqSlaveE from integer … → API: MqSlaveE_FromInt

(static) MK_INT MqSlaveE_ToInt(enum MqSlaveE value)

TOP

return the MqSlaveE as integer … → API: MqSlaveE_ToInt

(static) MK_STRN MqSlaveE_ToString(enum MqSlaveE value)

TOP

return the MqSlaveE as string … → API: MqSlaveE_ToString


enum MqStartE

TOP

User preferences on HOWTO start a new entity. → API: MqStartE

enum MqStartE {
};
MqStartE
User preferences on HOWTO start a new entity.
Definition msgque_mq.h:1353
@ MQ_START_SPAWN
create entity as spawn process
Definition msgque_mq.h:1357
@ MQ_START_DEFAULT
use application-context default entity creation
Definition msgque_mq.h:1354
@ MQ_START_THREAD
create entity as thread
Definition msgque_mq.h:1356
@ MQ_START_FORK
create entity as fork
Definition msgque_mq.h:1355
See also
ConfigSetStartAs, ConfigCheckStartAs, ConfigGetStartAs, StartE_ToString

(static) enum MkErrorE MqStartE_FromInt(MK_INT value, enum MqStartE* value_out)

TOP

return the MqStartE from integer … → API: MqStartE_FromInt

(static) MK_INT MqStartE_ToInt(enum MqStartE value)

TOP

return the MqStartE as integer … → API: MqStartE_ToInt

(static) MK_STRN MqStartE_ToString(enum MqStartE value)

TOP

return the MqStartE as string … → API: MqStartE_ToString


enum MqStatusIsEF

TOP

Information about how the context was created. → API: MqStatusIsEF

__parser__(enum-is-flag)
};
MqStatusIsEF
Information about how the context was created.
Definition msgque_mq.h:1394
@ MQ_STATUS_IS_FORK
context is created as a fork
Definition msgque_mq.h:1398
@ MQ_STATUS_IS_DUP
context is created as a duplicate of an other context
Definition msgque_mq.h:1396
@ MQ_STATUS_IS_THREAD
context is created as a thread
Definition msgque_mq.h:1397
@ MQ_STATUS_IS_INITIAL
context is the first context
Definition msgque_mq.h:1395
@ MQ_STATUS_IS_SPAWN
context is created as a spawn
Definition msgque_mq.h:1399
See also
ConfigGetStatusIs, StatusIsEF_ToString

(static) enum MkErrorE MqStatusIsEF_FromInt(MK_INT value, enum MqStatusIsEF* value_out)

TOP

return the MqStatusIsEF from integer … → API: MqStatusIsEF_FromInt

(static) MK_INT MqStatusIsEF_ToInt(enum MqStatusIsEF value)

TOP

return the MqStatusIsEF as integer … → API: MqStatusIsEF_ToInt

(static) MK_STRN MqStatusIsEF_ToString(enum MqStatusIsEF value)

TOP

return the MqStatusIsEF as string … → API: MqStatusIsEF_ToString


enum MqWaitOnEventE

TOP

wait for an event? … → API: MqWaitOnEventE

};
MqWaitOnEventE
wait for an event? …
Definition msgque_mq.h:1509
@ MQ_WAIT_ONCE
Wait maximum timeout seconds for one new event, doesn't matter which context the event belongs to or ...
Definition msgque_mq.h:1524
@ MQ_WAIT_OWN
Wait maximum timeout seconds for one new event that belongs to the current context or raise an timeou...
Definition msgque_mq.h:1531
@ MQ_WAIT_NO
Check for one event but do not wait …
Definition msgque_mq.h:1514
@ MQ_WAIT_FOREVER
Wait maximum timeout seconds for an event or raise an timeout-error …
Definition msgque_mq.h:1539
See also
ProcessEvent

(static) enum MkErrorE MqWaitOnEventE_FromInt(MK_INT value, enum MqWaitOnEventE* value_out)

TOP

return the MqWaitOnEventE from integer … → API: MqWaitOnEventE_FromInt

(static) MK_INT MqWaitOnEventE_ToInt(enum MqWaitOnEventE value)

TOP

return the MqWaitOnEventE as integer … → API: MqWaitOnEventE_ToInt

(static) MK_STRN MqWaitOnEventE_ToString(enum MqWaitOnEventE value)

TOP

return the MqWaitOnEventE as string … → API: MqWaitOnEventE_ToString

MqMsgque HELP

C-API: MqMsgque_Help_C_API - access to a qualified help-message

(static) MK_STR MqHelp(MK_STRN tool)

TOP

write libmqmsgque specific user-help to stderr → API: MqHelp

Parameters
toolthe name of the tool (e.g. argv[0]) or NULL.
Returns
the help messages as string

If tool != NULL, the function will display a header like:

 tool [ARGUMENT]... syntax:
   aclient [OPTION]... @ tool [OPTION]... @...

on the help page.

(static) MK_STR MqHelpMsgque(void)

TOP

return a page with the usage of all libmqmsgque specific options → API: MqHelpMsgque

MqMsgque INIT

C-API: MqMsgque_Init_C_API - initialize the MqContextC startup and/or external-object-link

(static) MK_BFL MqInitGetArg0(void)

TOP

get the process startup-prefix argument → API: MqInitGetArg0

Returns
a pointer to the initialization buffer (Only C-API)
Attention
if not set return a NULL pointer

(static) MK_BFL MqInitResetArg0(void)

TOP

Reset the process-startup-prefix argument to an empty list … → API: MqInitResetArg0

The startup-prefix have to be the name of the executable, found in the PATH environment variable, and additional arguments like the script name or the required startup options. The startup-prefix is used for two different purpose:

  • To start a new entity using the MqStartAs "--spawn" command-line option.
  • To replace the command-line-argument "... @ SELF ..." with "... @ startup-prefix ..." at LinkCreate.

Every use of this function will free the data of the previous startup-prefix. By default the startup-prefix is set during application startup by libmqmsgque and have not to be initialized again.

Example from server.c initialize the startup-prefix with the data read from service-args

static enum MkErrorE
Ot_INIT ( MQ_CALLBACK_SERVICE_CALL_ARGS )
{
  MqInitSetArg0 (MqReadALL_e (mqctx));
error:
  return MqSendRETURN (mqctx);
}
See also
InitSetArg0 InitGetArg0

(static) void MqInitSetArg0(MK_BAC bfl)

TOP

set the process startup-prefix argument to bfl → API: MqInitSetArg0

The startup-prefix is the argument(s) required to start the application… this is minimal the binary-path for binaries (same as as used on command-line) or the interpreter+scriptFile for scripts.

Parameters
[in]bflthe object will be merged into the startup-prefix, afterwords the bfl is empty and can be deleted

(static) void MqInitSetArg0VA(MK_STRN arg0, ... args)

TOP

set the process startup-prefix to a args → API: MqInitSetArg0VA

Attention
… the C-Api requires a NULL item on end to signal… end-of-list

(static) void MqInitSetArg0VAL(MK_STRN arg0, va_list var_list)

TOP

set the process startup-prefix to var_list → API: MqInitSetArg0VAL

MqMsgque ITEM

C-API: MqMsgque_Item_C_API - The package-item is a class-object and must use the MqContextC as the base-class.

  1. One package-item has all the code and services required to define one application-feature.
  2. An application-feature can be a database or a gui-frontend or just an internal logic-interface.
  3. Multiple package-items define an application with each package-item assigned to one specific factory-item.

A factory-item is created with:

(constructor) MQ_FCT MqFactoryAdd(MK_OBJN error, MqFactoryCTorF createCallF, MK_CCP constructor, MqFactoryDataFreeF createDataFreeF, MqFactoryDataCopyF createDataCopyF, MqFactoryDTorF deleteCallF, MK_CCP destructor, MqFactoryDataFreeF deleteDataFreeF, MqFactoryDataCopyF deleteDataCopyF, MK_STRN ident)

Example from perfserver.c Create a factory-item from the "perfserver" package-item

  // create "PerfServer" factory… and make it to the default.
  MqFactoryDefault( MqFactoryAdd_2(PerfServerFactory, "perfserver"));

Read more about the usage of the factory-item at: MqFactoryC.

MqMsgque MAIN

C-API: MqMsgque_Main_C_API - The package-main is a single piece of code evaluated only once at application startup.

Example from MyServer.c The package-main configure the factory and start the server.

#include "common.h"

// service to serve all incoming requests for token "HLWO"
static enum MkErrorE MyFirstService ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MqSendSTART_E (mqctx);
  MqSendV_E (mqctx, "%s World", MqReadC_e(mqctx));
error:
  return MqSendRETURN(mqctx);
}

// define a service as link between the token "HLWO" and the callback "MyFirstService"
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  return MqServiceCreate(mqctx,"HLWO", MyFirstService, NULL, NULL, NULL);
}

// package-item
enum MkErrorE
MyServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  MQ_CTX const mqctx = *contextP = MqContextCreate(NULL,tmpl);
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
  return MK_OK;
}

// package-main
int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // setup commandline arguments for later use

  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // create "MyServer" factory… and make it to the default.
  MqFactoryDefault(
    MqFactoryAdd(MK_ERROR_PANIC, MyServerFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "MyServer")
  );
  // inspect commandline-argument for the "factory" to choose… and create a object
  MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);

  // start listen for incoming call's
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}

MqMsgque SETUP

C-API: MqMsgque_Setup_C_API - Setup und Cleanup the libmqmsgque

For details about Setup and Cleanup usage refer to MkKernel_Setup_C_API

(static) void MqCleanup(void)

TOP

cleanup libmqmsgque internal memory … → API: MqCleanup

MkCleanup can only be called once and will be ignored if not called in the same thread as MqSetup. after a call to MqSetup the call to MkCleanup is possible again.

Attention
during cleanup objects will be deleted too -> the language interpreter have to be active

(static) void MqSetup(void)

TOP

setup libmqmsgque internal memory … → API: MqSetup

MqSetup can only be called once, additional call's will be ignored until a MqCleanup is called.


MqContextC

SUPER: MkObjectC, TOP

MqContextC DETAIL

MqContextC CLASS APIaccess data related to the type of the object…
MqContextC CONFIG APIvarious function to 'get' configuration-data from a MqContextC
MqContextC ENV APIprotect and restore the service-environment…
MqContextC ERROR APImove and copy an error in a MqContextC
MqContextC HIGH APIUser friendly replacement for the MqContextC_SendApi_C_API and the MqContextC_ReadApi_C_API
MqContextC LINK APIsetup and manage a client-server-link
MqContextC LOG APIlog output to string or MkLogFileC
MqContextC MISC APIvarious functions to work on a MqContextC
MqContextC PROXY APIcopy data from the read-data-package of the sourceCtx to the send-data-package of the targetCtx
MqContextC READ APIread a single-data-item outof a read-data-package
MqContextC ROUTE APIsetup and manage a routing-link
MqContextC SEND APIappend a native PRIMITIVE TYPE value to the send-data-package. …
MqContextC SERVICE APIcreate and manage a service …
MqContextC SLAVE APIcreate and manage a slave context …
MqContextC STORAGE API

setup and manage a storage used to persist data-packages

MqContextC INTROSPECTION

Instancesget head-instance from linked-list of MqContextS type …
Nextget next instance from linked-list of MqContextS type
Prev

get previous instance from linked-list of MqContextS type

MqContextC TOR

Createcreate and initialize the MqContextC ...
FromHandle
Delete

Destructor - delete a MqContextC instance …

MqContextC DETAIL

C-API: MqContextC_C_API - The MqContextC object known as ctx or context is the main data structure and application-handle

The context is the package-item with the required features and created by the implementation-layer-programmer. The context can be a client or a server.

HOWTO client-context

The client-context-creation is triggerd by the software-workflow on demand. The client is calling the LinkCreate to create a connection to the server using the connection-arguments to specify the target.

The life-cycle of a client is:

ContextCreate create and initialize the MqContextC ...
LinkCreate make ctx to a parent-context and setup a new client-server-link
SendTT append a native PRIMITIVE TYPE value to the send-data-package. …
ReadTT read a PRIMITIVE TYPE from the read-data-package
LinkDelete close the client-server-link
ContextDelete Destructor - delete a MqContextC instance …
Exit delete the context and exit the current process or thread …

HOWTO server-context

The server-context-creation is always triggerd by the LinkCreate command of the client. The server is usually using a factory-constructor to call the ContextCreate and finally to call the ContextDelete.
The server-context is fully under control of the client.

The life-cycle of a server is:

SETUPdefine a class and add the setup/cleanup code
IServerSetup define the server-setup-interface (callback) used on startup …
ServiceCreate create a link between a service-token and a service-callback
IServerCleanup define the server-cleanup-interface (callback) used on cleanup …
ServiceDelete delete a service. …
STARTUPdefine the factory and start the listener
FactoryAdd add a new MqFactoryC identified by factory-identifier and defined by factory-constructor
FactoryNew create a new MqContextC from a MqFactoryC
LinkCreate make ctx to a parent-context and setup a new client-server-link
ProcessEvent enter the event-loop and wait for an incoming service-request. …
WORKprocess the service-calls and exit on end
ReadTT read a PRIMITIVE TYPE from the read-data-package
SendTT append a native PRIMITIVE TYPE value to the send-data-package. …
Exit delete the context and exit the current process or thread …

MqContextS CTOR and DTOR

command alias
(constructor) MQ_CTX MqContextCreate(MK_TYP type, MQ_CTX tmpl) no
void MqContextDelete(MQ_CTX ctx) no

MqContextC CLASS API

NAVI: TOP , up

ClassFactoryGetget the MqFactoryC used by the MqContextC
ClassFactorySetlink the MqContextC to a new MqFactoryC
ClassIdentGetget the application-identification
ClassIdentSetlink the MqContextC to a new MqFactoryC identified by ident
ClassOriginalIdentGet

get the MqFactoryS::originalIdent from the MqContextC

MqContextC CLASS API DETAILS

C-API: MqContextC_Class_C_API - access data related to the type of the object…

The type of an object is related to the MqFactoryC. The factory decide which class a new created object has. The factory has two identifiers:

The relevance of the MqContextC CLASS API based type system, provided by MqFactoryC, decreased with the rise of the MANAGED OBJECT technology.
The MqContextC CLASS API based type system has more influence for target-languages without reflection, like C or C++.
The factory is something like a constructor but only support the application-context MqContextC .
The MqContextC ROUTE API using the ClassIdentGet from MqFactoryC to identify an application from remote.

MQ_FCT MqClassFactoryGet(MQ_CTXN ctx)

TOP

get the MqFactoryC used by the MqContextC → API: MqClassFactoryGet

Parameters
[in]ctxthe MqContextC to extract the MqFactoryC from
Returns
the MqFactoryC

enum MkErrorE MqClassFactorySet(MQ_CTX ctx, MQ_FCT item)

TOP

link the MqContextC to a new MqFactoryC → API: MqClassFactorySet_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextC to be linked with the MqFactoryC
[in]itemthe MqFactoryC to link with
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MK_STRN MqClassIdentGet(MQ_CTXN ctx)

TOP

get the application-identification … → API: MqClassIdentGet

Parameters
[in]ctxthe MqContextC to extract the ident from
Returns
the identifer or an empty string if ident was not set

An application has TWO possible names:

  1. The name from the context the application was configured with.
  2. The name from the factory the application was created with.

The --ident-from prefix|factory value decide which on is used.

The application-identification is defined by MqConfigS::identFrom :

MqFactoryS::originalIdentif ident == MQ_IDENT_FACTORY
MqConfigS::prefixif ident == MQ_IDENT_PREFIX (default)

The MqFactoryS::originalIdent is the official name of the MqFactoryC and is defined by the application-programmer with FactoryAdd or FactoryDup2.

The MqConfigS::prefix is the official name of the MqContextC that startet first, usually the server-name, and is set by the application-user with --prefix string at startup or with the ConfigSetPrefix at setup.

When the server starts, the ClassIdentGet value is send from the server to the client and the client initializes the MqLinkS::targetIdent with this value. This value identifes the server from remote and is used by the MqContextC ROUTE API to select which server receive the routing-package.

The client usually get the factory and the idenfication from the: FactoryInitial.

Example: Change the factory-identifier of FactoryInitial to the value "TestClient" with:

C# MqFactoryC.Get("initial").Dup2("TestClient").Initial()
TCL [[tclmsgque::MqFactoryC Get "initial"] Dup2 "TestClient"] Initial
Attention
After link-startup the MqLinkS::targetIdent will no longer changed.
The string is owned by libmqmsgque -> do not free !!

enum MkErrorE MqClassIdentSet(MQ_CTX ctx, MK_STRN ident)

TOP

link the MqContextC to a new MqFactoryC identified by ident → API: MqClassIdentSet_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextC to set the ident
[in]identthe MqFactoryS::originalIdent to link with
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
this function does not replace the ident of the current factory linked to context… this function replace the entire factory with a new factory identified by name. if the factory is not found or the link is already connected… an error is retured.

MK_STRN MqClassOriginalIdentGet(MQ_CTXN ctx)

TOP

get the MqFactoryS::originalIdent from the MqContextC → API: MqClassOriginalIdentGet

Parameters
[in]ctxthe MqContextC to extract the original-ident from
Returns
the identifer or an empty string if no factory is available
Attention
the string is owned by libmqmsgque -> do not free !!

MqContextC CONFIG API

NAVI: TOP , up

MqContextC CONFIG API GET

ConfigGetBuffersizeget the minimum of the read/send buffersize of the socket
ConfigGetIdentFromget the MqConfigS::identFrom
ConfigGetIoPipereturn the MqIoPipeConfigS
ConfigGetIoTcpget the configuration-data of the tcp-client-server-link
ConfigGetIoTcpLget the configuration-data of the tcp-client-server-link as MkBufferListC
ConfigGetIoUdsreturn the MqIoUdsConfigS
ConfigGetIsParentdoes the context object is a parent ? An objext is a parent id the MqConfigS::parent attribute is NULL
ConfigGetIsServerdoes the context object is a server ?
ConfigGetIsStringdoes the context object is using the string-mode ?
ConfigGetNameget the name of the context object
ConfigGetPkgsizeget the maximun size of a BDY package
ConfigGetPostfixget the MqConfigS::postfix
ConfigGetPrefixget the MqConfigS::prefix
ConfigGetStartAsreturn the MqConfigS::startAs value
ConfigGetStatusIsreturn the MqContextS::statusIs value
ConfigGetStorageget the storage of the context object
ConfigGetTimeoutget the timeout value of the context object
ConfigSetConfigFile

set the config-file and parse for well-known config-items

MqContextC CONFIG API INTERFACE

ConfigSetBgErrorset the MqSetupS::BgError
ConfigSetEventset the MqSetupS::Event
ConfigSetServerCleanupset the MqSetupS::ServerCleanup
ConfigSetServerSetup

set the MqSetupS::ServerSetup

MqContextC CONFIG API MISC

ConfigReset

clean the MqContextS::config data

MqContextC CONFIG API SET

ConfigCheckStartAscheck if MqConfigS::startAs can be set to data
ConfigSetAllDebugset the MkRuntimeS::debug value
ConfigSetBuffersizeset the MqIoConfigS::buffersize value
ConfigSetDaemonstart the server-context as daemon …
ConfigSetIdentFromset the MqConfigS::identFrom value
ConfigSetIgnoreExitset the MqSetupS::ignoreExit value
ConfigSetIoPipeset the pipe configuration data …
ConfigSetIoTcpconfigure a context to use a tcp-client-server-link
ConfigSetIoTcpLconfigure a context to use a tcp-client-server-link
ConfigSetIoUdsconfigure a context to use a uds-client-server-link
ConfigSetIsServerset the MqSetupS::isServer value
ConfigSetIsStringset the MqConfigS::native value 'S'string or 'L'owEndian or 'B'igEndian
ConfigSetNameset the MqConfigS::dispname value and cleanup old value
ConfigSetPkgsizeset the MqIoConfigS::pkgsize value
ConfigSetPostfixset the client-part (2) of the application-identifer MqConfigS::dispname
ConfigSetPrefixset the server-part (1) of the application-identifer MqConfigS::dispname
ConfigSetStartAsset the MqConfigS::startAs value
ConfigSetStartAsStringset the MqConfigS::startAs value using string default, thread, fork or spawn
ConfigSetStorageset the Storage value and cleanup old value
ConfigSetTimeout

set the MqIoConfigS::timeout value

MqContextC CONFIG API DETAILS

C-API: MqContextC_Config_C_API - various functions to 'config' a MqContextC

The configuration is done persistent using config-api functions or on link-setup using command-line-arguments.

Options API
Naming Options
--config fileName, --name string, --prefix string, --postfix string, --ident-from prefix|factory
Startup Options
--tcp --host string --port int --myhost string --myport int, --uds --file fileName, --pipe, --thread --spawn --fork, --daemon pidfile
Runtime Options
--logfile fileName, --silent, --debug
Misc Options
--buffersize int, --pkgsize int, --timeout int, --string
Interface API
interface: void MqConfigSetServerSetup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)
interface: void MqConfigSetServerCleanup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)
interface: void MqConfigSetBgError(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)
interface: void MqConfigSetEvent(MQ_CTX ctx, MqServiceCallbackF fEvent, MK_CBP data, MqDataFreeF fFree, MqDataCopyF fCopy)
Function API

CONFIG OPTION DETAILS

CONFIG NAMING OPTIONS DETAILS

--config fileName

set: enum MkErrorE MqConfigSetConfigFile(MQ_CTX ctx, MK_STRN filename)

add libconfig configuration file …

introduction

A config-file is used to add configuration-values to a libmqmsgque-application using a structured text-file.

supported
By default command-line-options; filter-pipline and slave-worker-setup is supported.

A service-callback and "programming" is not supported. To "programm and modify" something use a scripting language like tcl or python.

goal
The goal is to give the user of a compiled application the ability to provide a single place for common-configuration-values.

technology

libconfig is used to parse a config-file using the application … --config fileName … option.

syntax
The config-file syntax is defined at: http://hyperrealm.github.io/libconfig/libconfig_manual.html

The following restrictions apply to the --config option.

  1. The config-file is parsed when the --config option is parsed
  2. An application is identfied in the config-file by groupname : { ... } ( ":" or "=" is allowd )
  3. The groupname is the return from ClassIdentGet using hint from --ident-from prefix|factory
  4. The groupname is modified with the --name string, --prefix string or --ident-from prefix|factory naming-options
  5. The order of option-parsing is the order on the command-line
    MyClient … --XXX … --config YYY … --ZZZ …
    order MyClient : XXX < YYY < ZZZ
  6. For a pipe the config-file from the client is added to the end of the server-options :
    MyClient --AAA … --config BBB --CCC … @ Filter3 --name otto --DDD … @ MyServer --EEE …
    application groupname option-parsing-order
    MyClient MyClient AAA < BBB < CCC
    Filter3 otto DDD < BBB
    MyServer MyServer EEE < BBB
    This is required because the --name or --prefix option from DDD or EEE change the group read from the config-file
  7. attention! on a client or a non-pipe server it is a difference if the naming-option is set before or after the --config option
  8. All options set after the --config option overwrite the options from the config-file
  9. The filter ( groupname : { … filter : [ … ] } ) config-file-option define the server to start in a pipe and have to be an array of strings starting with the application-executable OR the factory-identifer

examples

1. Example from MyClient.config filter-pipeline with last server start in debug mode

# commandline OLD: MyClient @ Filter3 @ MyServer --debug 1
# commandline NEW: MyClient --config MyClient.config
version = "1.0" ; // string : version of the configuration file reader
default = "MyClient" ; // string : if the 'class' is unknown use 'default'
MyClient:
{
config:
{
# name = "myName" ; // string : displayname name of the 'context' (default: executable basename)
# identFrom = "prefix" ; // list : select how to identify the application from remote: 'prefix' or 'factory' (default: prefix)
# prefix = "" ; // string : set the 1'part of the visible displayname (default: "" = FactoryName)
# postfix = "" ; // string : set the 2'part of the visible displayname (default: "" = ConnectionName)
# string = false ; // bool : (default: no)
# startAs = "default" ; // string : from list (ref… MqStartE): default, spawn, thread, fork (default: default)
# daemon = "MyServer.pid" ; // string : file for PID
# timeout = 90 ; // int : user defined timeout to terminate a blocking function call (default: 90 sec)
# storage = "#memdb#" ; // string : storage file for the database: #memdb#, #tmpdb# or filename (default: #memdb#)
# runtime = { // struct (ref… MkRuntimeS) : runtime configuration (global)
# debug = 1 ; // int : set the debug-level, Valid values are 0 <= debug <= 9 using 0 for "no" and 9 for "max". (default: 0)
# silent = false ; // bool : write (no) or don't write (yes) any message to stdout or stderr (default: no)
# logfile = "stderr" ; // string : append to logfile, valid values are: stderr, stdout or a filename (default: stderr)
# };
# io = { // struct (ref… MqIoComE) : what kind of socket interface to use? (default: pipe)
# buffersize = 4096 // int : io buffersize (default: 4096)
# pkgsize = 10240 // int : io pkgsize (default: 10 * 1024)
# pipe = true; // struct (ref… MqIoPipeConfigS) → ONLY client (default: true)
# init = false; // struct (ref… MqIoInitConfigS) → ONLY server (default: false)
# tcp = { // struct (ref… MqIoTcpConfigS)
# port = "7777" ; // string : port number or well known port name
# host = "localhost" ; // string : hostname / interfacename
# myport = "1111" ; // string : client MY port number or well known port name
# myhost = "localhost" ; // string : client MY hostname / interfacename
# };
# uds = { // struct (ref… MqIoUdsConfigS)
# file = "filename" ; // string : name of a uds-socket-file (default: null)
# }
# };
};
# start executable "Filter3" in a "@" pipe and change application-name (groupname) to "otto"
filter = [ "Filter3", "--name", "otto" ] ; // array of string : filter pipeline name of "server"
};
# config section for "Filter3" start in the "pipe"
otto = {
filter = [ "MyServer" ] ;
}
# final "MyServer" set option "debug" to "1"
MyServer = {
config: { runtime: {debug = 1} }
# 'config.runtime.debug = 1' is NOT supported.
}

2. Example from libconfig.test filter-pipeline with last server connect by tcp/ip

# OLD: MyClient @ Filter3 @ --tcp --port $PORT
# NEW: MyClient --config configFile
version: 1.0
default = "MyClient"
MyClient: {
filter: [ "Filter3" ]
}
Filter3: {
filter: [ "--tcp", "--port", "$PORT" ]
}

--name string

attribute: MqConfigS::dispname, getter: MqConfigGetName, setter: MqConfigSetName

set the display-name of the context

The display-name is used as:

- A prefix in the local debug/error/log output:

  • C> (dispname) [2009-01-12:16-22-27] [4-0-sIoCheckArg]: option: io->com = PIPE

The dispname is initialized with:

Example:
use MqConfigS::prefix and MqConfigS::postfix to set the MqConfigS::dispname :
  • prefix postfix dispname
    client -1-1 client-1-1
Attention
~ the memory of MqConfigS::dispname is owned by libmqmsgque -> do not free.
~ if the dispname is NOT set the value is initialized from MqConfigS::prefix
~ to initialize the dispname by yourself use: void MqConfigSetName(MQ_CTX ctx, MK_STRN data) or --name string
~ if the --name string is explicitly set, then --prefix string and --postfix string have no effect

--prefix string

attribute: MqConfigS::prefix, getter: MqConfigGetPrefix, setter: MqConfigSetPrefix

set the server-part (1) of the application-identifer MqConfigS::dispname

The prefix is used for:

  1. MqConfigS::dispname initialization
  2. application-identifer if --ident-from prefix|factory is set to prefix (default)
  3. groupname in --config fileName is used as application-identifer

The prefix is initialize with:

  1. the basename of the executable if NO factory is used
  2. the MqFactoryS::originalIdent
  3. the void MqConfigSetPrefix(MQ_CTX ctx, MK_STRN data) or the void MqConfigSetName(MQ_CTX ctx, MK_STRN data) function
  4. the --name string OR the --prefix string option
Attention
if the --name string is explicitly set, then --prefix string and --postfix string have no effect

--postfix string

attribute: MqConfigS::postfix, getter: MqConfigGetPostfix, setter: MqConfigSetPostfix

set the client-part (2) of the application-identifer MqConfigS::dispname

The postfix is used for:

  1. MqConfigS::dispname initialization

The postfix is initialize with:

  1. an empty string
  2. the void MqConfigSetPostfix(MQ_CTX ctx, MK_STRN data) function
  3. the client postfix at server-startup
  4. the --postfix string option
Attention
if the --name string is explicitly set, then --prefix string and --postfix string have no effect

--storage fileName

attribute: MqConfigS::storage, getter: MqConfigGetStorage, setter: MqConfigSetStorage

--ident-from prefix|factory

attribute: MqConfigS::identFrom, getter: MqConfigGetIdentFrom, setter: MqConfigSetIdentFrom

select how to identify the application from remote …

An application has TWO possible names:

  1. The name from the context the application was configured with.
  2. The name from the factory the application was created with.

The --ident-from prefix|factory value decide which on is used.

The application-identification is defined by MqConfigS::identFrom :

MqFactoryS::originalIdentif ident == MQ_IDENT_FACTORY
MqConfigS::prefixif ident == MQ_IDENT_PREFIX (default)

The MqFactoryS::originalIdent is the official name of the MqFactoryC and is defined by the application-programmer with FactoryAdd or FactoryDup2.

The MqConfigS::prefix is the official name of the MqContextC that startet first, usually the server-name, and is set by the application-user with --prefix string at startup or with the ConfigSetPrefix at setup.

When the server starts, the ClassIdentGet value is send from the server to the client and the client initializes the MqLinkS::targetIdent with this value. This value identifes the server from remote and is used by the MqContextC ROUTE API to select which server receive the routing-package.

The client usually get the factory and the idenfication from the: FactoryInitial.

Example: Change the factory-identifier of FactoryInitial to the value "TestClient" with:

C# MqFactoryC.Get("initial").Dup2("TestClient").Initial()
TCL [[tclmsgque::MqFactoryC Get "initial"] Dup2 "TestClient"] Initial
Attention
After link-startup the MqLinkS::targetIdent will no longer changed.

CONFIG STARTUP OPTIONS DETAILS

--tcp --host string --port int --myhost string --myport int

attribute: MqIoTcpConfigS, getter: MqConfigGetIoTcp, setter: MqConfigSetIoTcp

configure a context to use a tcp-client-server-link

Parameters
[in]hostclient: name of the remote interface (default: localhost)
server: name of the local interface (default: listen on all interfaces)
[in]portclient: name of the remote port
server: name of the local port
[in]myhostclient: name of the local interface
[in]myportclient: name of the local port

--uds --file fileName

attribute: MqIoUdsConfigS, getter: MqConfigGetIoUds, setter: MqConfigSetIoUds

configure a context to use a uds-client-server-link

The uds-socket (http://en.wikipedia.org/wiki/Unix_domain_socket) is usually 50% faster than a local tcp communication but only available on UNIX.

Parameters
[in]filename of a uds-socket-file (default: NULL)

--pipe

attribute: MqIoPipeConfigS, getter: MqConfigGetIoPipe, setter: MqConfigSetIoPipe

configure a context to use a pipe-client-server-link

The socket option is special because it is used only for internal purpose to submit the socket from the client to the server started as pipe by the client.

Parameters
[in]hdlthe file-descriptor-number (default: not set)

--thread --spawn --fork

attribute: MqConfigS::startAs, getter: MqConfigGetStartAs, setter: MqConfigSetStartAs

create a new application-context as thread, spawn or fork …

A new application-context is created if:

  • a tcp-uds-server listen on socket and get a connection-request from a client.
    This require: MqFactoryC and IServerSetup .
  • a filter-context create a new filter-object
  • a server-context create a new worker-context using SlaveWorker
  • a server-context start a new client-server-link using SELF as executable-name using LinkCreate

The allowed integer values for MqConfigS::startAs are:

(default: do not create a new application-context)

--daemon pidfile

set: enum MkErrorE MqConfigSetDaemon(MQ_CTX ctx, MK_STRN pidfile)

This option is not available for libmqmsgque.

CONFIG RUNTIME OPTIONS DETAILS

--logfile fileName

attribute: MkRuntimeS::logfile, getter: MkRuntimeGetLogfile, setter: MkRuntimeSetLogfile

--silent

attribute: MkRuntimeS::isSilent, getter: MkRuntimeGetIsSilent, setter: MkRuntimeSetIsSilent

--debug

attribute: MkRuntimeS::debug, getter: MkRuntimeGetDebug, setter: MkRuntimeSetDebug

CONFIG MISC OPTIONS DETAILS

--buffersize int

attribute: MqIoConfigS::buffersize, getter: MqConfigGetBuffersize, setter: MqConfigSetBuffersize

set the OS specific value for the socket-operation-buffer (default: OS specific)

--pkgsize int

attribute: MqIoConfigS::pkgsize, getter: MqConfigGetPkgsize, setter: MqConfigSetPkgsize

set maximum package size (default: 10 KiB)

--timeout int

attribute: MqIoConfigS::timeout, getter: MqConfigGetTimeout, setter: MqConfigSetTimeout

user defined timeout to terminate a blocking function call (default: 90 sec)

--string

attribute: MqConfigS::native, getter: MqConfigGetIsString, setter: MqConfigSetIsString

CONFIG INTERFACE API

interface: void MqConfigSetServerSetup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

define the server-setup-interface (callback) used on startup …

This interface is used to configure a new server-context-link, like a constructor, and is called at the end of LinkCreate or LinkCreateChild. This interface is called for every new incoming connection request and is used to define context specific services using ServiceCreate or to initialize context-specific variables. As side-effect this interface set MqSetupS::isServer to MK_YES.

Read more about how to define a callback at MqContextC_ServiceApi_Callback.

interface: void MqConfigSetServerCleanup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

define the server-cleanup-interface (callback) used on cleanup …

This interface is used to cleanup an old server-context-link, like a destructor, and is called at the beginning of LinkDelete to free context-specific variables. As side-effect this interface set MqSetupS::isServer to MK_YES.

Read more about how to define a callback at MqContextC_ServiceApi_Callback.

interface: void MqConfigSetBgError(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

define the background-error-interface

A background error is an error without a link to an application-context and happen if an SendEND call fails or if an other asynchronous task fails. if the interface is not defined the error is printed to stderr and the application continue to work. if the interface is defined the context is set to error and the callback is called to process this error. Inside the callback the error is available using ErrorGetNum and ErrorGetText and can be cleared using ErrorReset.

Read more about how to define a callback at MqContextC_ServiceApi_Callback.

interface: void MqConfigSetEvent(MQ_CTX ctx, MqServiceCallbackF fEvent, MK_CBP data, MqDataFreeF fFree, MqDataCopyF fCopy)

Create a link to the calling tool event-handling queue …

Event-Handling is used to process tasks in the background to give the tool-user the feeling of a non-blocking application. For example Tcl using the event-handling to update the Tk user-interface while the application is waiting for data. The event handling function is called on idle-time and is designed for a very short function execution time. Do only one action per function call. This function will be called with a ~10000 usec interval to guarantee a parallel like execution.

Attention
1. The Event-Handler is used to start background processing during idel-time.
2. If MqSetupS::ignoreExit is set… and the process/thread is already on shutdown… the process/thread will continue to work as long as background tasks are available.
3. The process will only exit if all Event-Handler return ErrorSetCONTINUE to signal that no other background tasks are available.
example: example/LANG/Filter4.EXT

Read more about how to define a callback at MqContextC_ServiceApi_Callback.

MqContextC CONFIG API GET

C-API: MqContextC_ConfigApi_Get_C_API - various function to 'get' configuration-data from a MqContextC

MK_INT MqConfigGetBuffersize(MQ_CTXN ctx)

TOP

get the minimum of the read/send buffersize of the socket → API: MqConfigGetBuffersize

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.buffersize(R/S) value

enum MqIdentE MqConfigGetIdentFrom(MQ_CTX ctx)

TOP

get the MqConfigS::identFrom → API: MqConfigGetIdentFrom

Parameters
[in]ctxthe MqContextS instance to work on
Returns
prefix or factory

MQ_SOCK_HDL MqConfigGetIoPipe(MQ_CTX ctx)

TOP

return the MqIoPipeConfigS → API: MqConfigGetIoPipe

Parameters
[in]ctxthe MqContextS instance to work on

enum MkErrorE MqConfigGetIoTcp(MQ_CTX ctx, MK_STRN* host_out, MK_STRN* port_out, MK_STRN* myhost_out, MK_STRN* myport_out)

TOP

get the configuration-data of the tcp-client-server-link … → API: MqConfigGetIoTcp

Parameters
[in]ctxthe MqContextS instance to work on
[out]host_outclient: name of the remote interface (default: localhost)
server: name of the local interface (default: listen on all interfaces)
[out]port_outclient: name of the remote port
server: name of the local port
[out]myhost_outclient: name of the local interface
[out]myport_outclient: name of the local port
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
  • if the config-value is not defined… the out-value will be set to NULL
  • if the the out-value is NULL… nothing will be done

enum MkErrorE MqConfigGetIoTcpL(MQ_CTX ctx, MK_BFL* vals_out)

TOP

get the configuration-data of the tcp-client-server-link as MkBufferListC … → API: MqConfigGetIoTcpL

host
clientname of the remote interface (default: localhost)
servername of the local interface (default: listen on all interfaces
port
clientname of the remote port
servername of the local port
myhostname of the local interface
myportname of the local port
Parameters
[in]ctxthe MqContextS instance to work on
[out]vals_outthe contain host, port, myhost and myport data
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
the vals_out is owned by libmqmsgque ... do not free !

MK_STRN MqConfigGetIoUds(MQ_CTXN ctx)

TOP

return the MqIoUdsConfigS → API: MqConfigGetIoUds

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.io.uds.file value

MK_BOOL MqConfigGetIsParent(MQ_CTX ctx)

TOP

does the context object is a parent ? An objext is a parent id the MqConfigS::parent attribute is NULL → API: MqConfigGetIsParent

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the (ctx->config.parent == NULL) value

MK_BOOL MqConfigGetIsServer(MQ_CTX ctx)

TOP

does the context object is a server ? → API: MqConfigGetIsServer

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the (ctx->setup.isServer == true) value

MK_BOOL MqConfigGetIsString(MQ_CTX ctx)

TOP

does the context object is using the string-mode ? → API: MqConfigGetIsString

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the (ctx->config.native == 'S') value

MK_STRN MqConfigGetName(MQ_CTXN ctx)

TOP

get the name of the context object → API: MqConfigGetName

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.name value
Attention
the string is owned by libmqmsgque -> do not free !!

MK_INT MqConfigGetPkgsize(MQ_CTXN ctx)

TOP

get the maximun size of a BDY package → API: MqConfigGetPkgsize

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.pkgsize(R/S) value

MK_STRN MqConfigGetPostfix(MQ_CTXN ctx)

TOP

get the MqConfigS::postfix → API: MqConfigGetPostfix

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the value requested
Attention
the string is owned by libmqmsgque -> do not free !!

MK_STRN MqConfigGetPrefix(MQ_CTXN ctx)

TOP

get the MqConfigS::prefix → API: MqConfigGetPrefix

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the value requested
Attention
the string is owned by libmqmsgque -> do not free !!

enum MqStartE MqConfigGetStartAs(MQ_CTX ctx)

TOP

return the MqConfigS::startAs value → API: MqConfigGetStartAs

enum MqStatusIsEF MqConfigGetStatusIs(MQ_CTX ctx)

TOP

return the MqContextS::statusIs value → API: MqConfigGetStatusIs

MK_STRN MqConfigGetStorage(MQ_CTXN ctx)

TOP

get the storage of the context object → API: MqConfigGetStorage

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.storage value
Attention
the string is owned by libmqmsgque -> do not free !!

MK_TIME_T MqConfigGetTimeout(MQ_CTXN ctx)

TOP

get the timeout value of the context object → API: MqConfigGetTimeout

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the context.config.timeout value

enum MkErrorE MqConfigSetConfigFile(MQ_CTX ctx, MK_STRN filename)

TOP

set the config-file and parse for well-known config-items → API: MqConfigSetConfigFile_RT

Read more at MqConfigS::cfg

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]filenamename of the config-file for input
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC CONFIG API INTERFACE

C-API: MqContextC_ConfigApi_Get_C_API - various function to 'get' configuration-data from a MqContextC

void MqConfigSetBgError(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

TOP

set the MqSetupS::BgError → API: MqConfigSetBgError_RT

void MqConfigSetEvent(MQ_CTX ctx, MqServiceCallbackF fEvent, MK_CBP data, MqDataFreeF fFree, MqDataCopyF fCopy)

TOP

set the MqSetupS::Event → API: MqConfigSetEvent_RT

Attention

void MqConfigSetServerCleanup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

TOP

set the MqSetupS::ServerCleanup → API: MqConfigSetServerCleanup_RT

void MqConfigSetServerSetup(MQ_CTX ctx, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MqDataCopyF fCopy)

TOP

set the MqSetupS::ServerSetup → API: MqConfigSetServerSetup_RT

MqContextC CONFIG API MISC

C-API: MqContextC_ConfigApi_Get_C_API - various function to 'get' configuration-data from a MqContextC

void MqConfigReset(MQ_CTX ctx)

TOP

clean the MqContextS::config data → API: MqConfigReset_RT

MqContextC CONFIG API SET

C-API: MqContextC_ConfigApi_Get_C_API - various function to 'get' configuration-data from a MqContextC

MK_BOOL MqConfigCheckStartAs(MQ_CTX ctx, enum MqStartE data)

TOP

check if MqConfigS::startAs can be set to data → API: MqConfigCheckStartAs

enum MkErrorE MqConfigSetAllDebug(MQ_CTX ctx, MK_INT data)

TOP

set the MkRuntimeS::debug value → API: MqConfigSetAllDebug_RT

set all childs and all slaves and the link target parter… too

void MqConfigSetBuffersize(MQ_CTX ctx, MK_INT data)

TOP

set the MqIoConfigS::buffersize value → API: MqConfigSetBuffersize

enum MkErrorE MqConfigSetDaemon(MQ_CTX ctx, MK_STRN pidfile)

TOP

start the server-context as daemon … → API: MqConfigSetDaemon_RT

A daemon is a server-process without any link to the parent-process. A daemon-process has closed all default IO (e.g stdout, stdin, stderr) and forked into the background. (default: no daemon)

MK_RT_ARGS
MQ_CTX const ctx,
MK_STRN pidfile
) {
if (MQ_IS_SERVER(ctx)) {
if (MqContextCT_X(ctx)->ignoreFork == true) {
return MkErrorDbV_XS (MK_ERROR_OPTION_FORBIDDEN, "--daemon", "current");
} else {
MkErrorCheck (MkSysDaemonize(MkOBJ(ctx), pidfile));
}
} else {
return MkErrorDbV_XS (MK_ERROR_OPTION_FORBIDDEN, "--daemon", "client");
}
return MK_OK;
error:
return MkErrorStack_1X(ctx);
}
#define MkErrorStack_1X(...)
MkErrorE
MK_OK
const MK_STRB * MK_STRN
#define MkOBJ(x)
void MkRuntimeSetIsSilent(bool silent)
#define MK_RT_ATTR_HDL_CHECK(x)
#define MK_RT_ATTR_RUNTIME_CHECK_XN(x)
#define MqContextCT_X(instance)
cast from an instance into the specific-instance-type …
Definition msgque_mq.h:3865
#define MQ_IS_SERVER(ctx)
extract boolean information from context
Definition msgque_mq.h:2339
MQ_EXTERN enum MkErrorE MqConfigSetDaemon_RT(MK_RT const mkrt, MQ_CTX const ctx, MK_STRN pidfile)
start the server-context as daemon …
#define MkErrorCheck(err)
PUBLIC data structure for the libmqmsgque-specific-data
Definition msgque_mq.h:3804
Attention
this option require the fork system-call and is not compatible with threads.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]pidfilewrite the PID of the daemon into this file (default: NULL, do not start as daemon)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

void MqConfigSetIdentFrom(MQ_CTX ctx, enum MqIdentE data)

TOP

set the MqConfigS::identFrom value → API: MqConfigSetIdentFrom

void MqConfigSetIgnoreExit(MQ_CTX ctx, MK_BOOL data)

TOP

set the MqSetupS::ignoreExit value → API: MqConfigSetIgnoreExit

enum MkErrorE MqConfigSetIoPipe(MQ_CTX ctx, MQ_SOCK_HDL fh)

TOP

set the pipe configuration data … → API: MqConfigSetIoPipe_RT

This is configuration option is only useful for a (x)inetd setup to use the stdin (socket=0) as send/recv communication socket

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fhthe name of the known socket
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqConfigSetIoTcp(MQ_CTX ctx, MK_STRN host, MK_STRN port, MK_STRN myhost, MK_STRN myport)

TOP

configure a context to use a tcp-client-server-link … → API: MqConfigSetIoTcp_RT

Parameters
[in]hostclient: name of the remote interface (default: localhost)
server: name of the local interface (default: listen on all interfaces)
[in]portclient: name of the remote port
server: name of the local port
[in]myhostclient: name of the local interface
[in]myportclient: name of the local port
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqConfigSetIoTcpL(MQ_CTX ctx, MK_BFL vals)

TOP

configure a context to use a tcp-client-server-link … → API: MqConfigSetIoTcpL_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valsa list with host, port, myhost, myport
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqConfigSetIoUds(MQ_CTX ctx, MK_STRN file)

TOP

configure a context to use a uds-client-server-link … → API: MqConfigSetIoUds_RT

The uds-socket (http://en.wikipedia.org/wiki/Unix_domain_socket) is usually 50% faster than a local tcp communication but only available on UNIX.

Parameters
[in]filename of a uds-socket-file (default: NULL)
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

void MqConfigSetIsServer(MQ_CTX ctx, MK_BOOL data)

TOP

set the MqSetupS::isServer value → API: MqConfigSetIsServer

void MqConfigSetIsString(MQ_CTX ctx, MK_BOOL data)

TOP

set the MqConfigS::native value 'S'string or 'L'owEndian or 'B'igEndian → API: MqConfigSetIsString

Attention
only the client can set this option... the server get this option from the client and using this function is ignored.

void MqConfigSetName(MQ_CTX ctx, MK_STRN data)

TOP

set the MqConfigS::dispname value and cleanup old value → API: MqConfigSetName_RT

void MqConfigSetPkgsize(MQ_CTX ctx, MK_INT data)

TOP

set the MqIoConfigS::pkgsize value → API: MqConfigSetPkgsize

void MqConfigSetPostfix(MQ_CTX ctx, MK_STRN data)

TOP

set the client-part (2) of the application-identifer MqConfigS::dispname … → API: MqConfigSetPostfix_RT

The postfix is used for:

  1. MqConfigS::dispname initialization

The postfix is initialize with:

  1. an empty string
  2. the void MqConfigSetPostfix(MQ_CTX ctx, MK_STRN data) function
  3. the client postfix at server-startup
  4. the --postfix string option
Attention
if the --name string is explicitly set, then --prefix string and --postfix string have no effect

void MqConfigSetPrefix(MQ_CTX ctx, MK_STRN data)

TOP

set the server-part (1) of the application-identifer MqConfigS::dispname … → API: MqConfigSetPrefix_RT

The prefix is used for:

  1. MqConfigS::dispname initialization
  2. application-identifer if --ident-from prefix|factory is set to prefix (default)
  3. groupname in --config fileName is used as application-identifer

The prefix is initialize with:

  1. the basename of the executable if NO factory is used
  2. the MqFactoryS::originalIdent
  3. the void MqConfigSetPrefix(MQ_CTX ctx, MK_STRN data) or the void MqConfigSetName(MQ_CTX ctx, MK_STRN data) function
  4. the --name string OR the --prefix string option
Attention
if the --name string is explicitly set, then --prefix string and --postfix string have no effect

enum MkErrorE MqConfigSetStartAs(MQ_CTX ctx, enum MqStartE data)

TOP

set the MqConfigS::startAs value → API: MqConfigSetStartAs

enum MkErrorE MqConfigSetStartAsString(MQ_CTX ctx, MK_STRN data)

TOP

set the MqConfigS::startAs value using string default, thread, fork or spawn → API: MqConfigSetStartAsString

void MqConfigSetStorage(MQ_CTX ctx, MK_STRN data)

TOP

set the Storage value and cleanup old value → API: MqConfigSetStorage_RT

void MqConfigSetTimeout(MQ_CTX ctx, MK_TIME_T data)

TOP

set the MqIoConfigS::timeout value → API: MqConfigSetTimeout

MqContextC ENV API

NAVI: TOP , up

EnvProtectprotect the service-environment
EnvRestore

restore the service-environment

MqContextC ENV API DETAILS

C-API: MqContextC_Env_C_API - protect and restore the service-environment…

The "Env" style functions are used to secure the service-environment (defined in MqEnvS)
and is required.. under special conditions... to proper answer the original service call at the
end of the service-processing.
By default libmqmsgque guarantee the proper management of the environment on behalf of the user.
Under normal conditions the user don't need these functions.

The folllowing design-goals were defined:

  • normal condition...
    • Every libmqmsgque function does protect the original service-environment by default
    • esay goal to remember: come-in == come-out
  • special condition...
    • After loading the read-data-package...
    • the service-environment must be in the same condition as when the read-data-package was saved.

The two design-goals from above are in conflict and the both functions EnvProtect and EnvRestore are used to solve this conflict.

Example from server.c protect the environment and import from database

    // PROTECT the original service-call
    MqEnvProtect(mqctx);
    // OVERWRITE the original service-call with data from the database
    MqDumpImport(dump,mqctx);
    MK_BFL ret = MqReadALL_e(mqctx);
    // RESTORE the original service-call
    MqEnvRestore(mqctx);
    // ANSWER the original service-call
    MqSend_E(mqctx, "R", "L", ret);

void MqEnvProtect(MQ_CTX ctx)

TOP

protect the service-environment → API: MqEnvProtect_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on

void MqEnvRestore(MQ_CTX ctx)

TOP

restore the service-environment → API: MqEnvRestore

Parameters
[in]ctxthe MqContextS instance to work on

MqContextC ERROR API

NAVI: TOP , up

ErrorCopycopy a MkErrorS from the sourceCtx to the targetCtx
ErrorDEFAULThelper used to access ErrorDEFAULT from MqContextC
ErrorMove

move a MkErrorS from the sourceCtx to the targetCtx

MqContextC ERROR API DETAILS

C-API: MqContextC_Error_C_API - move and copy an error in a MqContextC

enum MkErrorE MqContextErrorCopy(MQ_CTXN targetCtx, MQ_CTXN sourceCtx)

TOP

copy a MkErrorS from the sourceCtx to the targetCtx … → API: MqContextErrorCopy_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
targetCtxthe MqContextC object and the target of the error
sourceCtxthe MqContextC object and the source of the error
Attention
~ by default… every error set in a slave is also set in the master.
~ by default… the error is only copied if sourceCtx and targetCtx are different.
~ by default… the error is not copied if targetCtx MqConfigS::master of sourceCtx.
~ by default… the copy only happen if sourceCtx has an error.
~ on copy… the error of sourceCtx will be reset.

MK_ERR MqContextErrorDEFAULT(MQ_CTXN fmtobj)

TOP

helper used to access ErrorDEFAULT from MqContextC → API: MqContextErrorDEFAULT

enum MkErrorE MqContextErrorMove(MQ_CTXN targetCtx, MQ_CTXN sourceCtx)

TOP

move a MkErrorS from the sourceCtx to the targetCtx … → API: MqContextErrorMove_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
targetCtxthe MqContextC object and the target of the error
sourceCtxthe MqContextC object and the source of the error and cleared
Attention
~ by default… every error set in a slave is also set in the master.
~ by default… the error is only copied if sourceCtx and targetCtx are different.
~ by default… the error is not copied if targetCtx MqConfigS::master of sourceCtx.
~ by default… the copy only happen if sourceCtx has an error.
~ on copy… the error of sourceCtx will be reset.

MqContextC HIGH API

NAVI: TOP , up

SendVL2

va_list version of MqSend …

MqContextC HIGH API DETAILS

C-API: MqContextC_High_C_API - User friendly replacement for the MqContextC_SendApi_C_API and the MqContextC_ReadApi_C_API

User Friendly mean, replacing many lines of code by a single line of code.
The basic idea is, to use a format-signature to identify the additional command-line-arguments (args…).

The pseudo syntax is:

MqSend( "CALL-SIGNATUR",call-args …,"TOKEN-SIGNATURE",send-args …,read-args …);
CALL-SIGNATUR = "[E|W|C|S|T|R|t|r]" or ?call-args?
E = MqSendEND ?t-arg = 0?
S = MqSendEND_AND_SUB, c-arg, ?t-arg = MK_TIMEOUT_DEFAULT?
t = expect timeout value as t-arg in call-arg
r = switch 'rpc-flag' on to enable 'rpc' style parsing of the TOKEN-SIGNATURE
call-args = ?c-arg?, ?i-arg?, ?t-arg?
?c-arg? = callback ... function, service
?i-arg? = ident ...... MQ_TOK service-identifer to receive the result
?t-arg? = timeout .... MK_TIME_T in seconds
TOKEN-SIGNATUR = "service-ident:send-signature@read-signature"
service-ident = MQ_TOK service identifier to call a remote service
send-signature = ?(…)? or multiple [Y|O|S|I|F|W|D|G|C|B|U|L] or […]
?(…)? = only as FIRST arg, only for MqSendEND_AND_TRANSACTION
Y = MqSendY
O = MqSendO
S = MqSendS
I = MqSendI
F = MqSendF
W = MqSendW
D = MqSendD
C = MqSendC
B = MqSendB
U = MqSendU
L = MqSendL
read-signature = multiple [Y|O|S|I|F|W|D|G|C|B|U|L] or . or * or […]
. = MqReadU
Y = MqReadY
O = MqReadO
S = MqReadS
I = MqReadI
F = MqReadF
W = MqReadW
D = MqReadD
C = MqReadC
B = MqReadB
U = MqReadU
L = MqReadL
MK_TIMEOUT_DEFAULT
time_t MK_TIME_T
MK_STRN MQ_TOK
a char[4+1] or hex[8+1] string used to unique identify a service …
Definition msgque_mq.h:5401
#define MqSendY(...)
#define MqSendF(...)
#define MqSendLONG(...)
#define MqSendD(...)
#define MqReadL_START(...)
#define MqSendI(...)
#define MqReadC(...)
#define MqReadB(...)
#define MqSendEND_AND_TRANSACTION(...)
#define MqReadY(...)
#define MqSendO(...)
#define MqReadO(...)
#define MqSendEND_AND_CALLBACK(...)
#define MqReadI(...)
#define MqReadLONG(...)
#define MqReadW(...)
#define MqReadF(...)
#define MqSendS(...)
#define MqReadL(...)
#define MqSendL_START(...)
#define MqSendEND_AND_SUB(...)
#define MqSendEND_AND_WAIT(...)
#define MqSendEND(...)
#define MqReadU(...)
#define MqSendT_END(...)
#define MqReadD(...)
#define MqSend(...)
#define MqSendU(...)
#define MqSendB(...)
#define MqReadALL(...)
#define MqSendC(...)
#define MqReadL_END(...)
#define MqSendL_END(...)
#define MqSendL(...)
#define MqSendT_START(...)
#define MqReadS(...)
#define MqSendW(...)
#define MqSendRETURN(...)

The following parts from the MqContextC_SendApi_C_API will be replaced by the MqContextC_High_C_API

API Function Usage
SendSTART -> start a service call or a answer
SendATOM -> write a single argument into the data-package
SendEND -> send the service-call to the receiver
ReadATOM -> read a single argument from the data-package
SendRETURN -> answer a service call

The replacement is defined by two parts, a High_CALL_SIGNATURE and a High_TOKEN_SIGNATURE. Both parts are strings and descripe a type or an action of a vararg argument.

Example: a typical code replacement in C looks like

MkErrorCheck( MqSend( ctx, "Wt", 15, "SUBI:IDC@D", 5, 6.3, "HALLO", &doubleVal ) );

and replaces the following commands...

MkErrorCheck( MqSendI( ctx, 5 ) );
MkErrorCheck( MqSendD( ctx, 6.3 ) );
MkErrorCheck( MqSendC( ctx, "HALLO" ) );
MkErrorCheck( MqSendEND_AND_WAIT( ctx, "SUBI", 15 ) );
MkErrorCheck( MqReadD( ctx, &doubleVal ) );
#define MqSendSTART(...)

High_CALL_SIGNATURE

The Call-Signature is a string of call-signature-char (CFC) starting with "E", "W", "C", "S" or "R" followed optional with "t"

CFC Required Reference call-args Default Usage
E yes once no yes SendEND
W yes once no no SendEND_AND_WAIT
C yes once function or service no SendEND_AND_CALLBACK
S yes once function or service no SendEND_AND_SUB
T yes once service-ident no SendEND_AND_TRANSACTION
R yes once no no SendRETURN
t no W,S,T seconds MK_TIMEOUT_USER set the TIMEOUT

High_TOKEN_SIGNATURE

  1. The token-signature has the usage "service-ident : send-signature @ read-signature" and is used to identify the target-service and the required arguments.
  2. The service-ident is identified by the MQ_TOK item followed by a [:] and the send-signature.
  3. The send-signature has one type-identifer for every send-argument. The send-argument is identified by a arg-signature-char (ASC) and is defined in MkTypeE.
  4. The MkTypeE is used in the MkBufferU and descripe the type of a vararg argument or action.
ASC MkTypeE Usage Number of arguments required
Y MK_BYT MkBufferAtomU.Y 1
O MK_BOL MkBufferAtomU.O 1
S MK_SRT MkBufferAtomU.S 1
I MK_INT MkBufferAtomU.I 1
F MK_FLT MkBufferAtomU.F 1
W MK_WID MkBufferAtomU.W 1
D MK_DBL MkBufferAtomU.D 1
G MK_LONG 32bit=I, 64bit=W 1
B MK_BIN MkBufferU.B 2 -> MK_BIN pointer and MK_SIZE len
C MK_STR MkBufferU.C 1
U MK_BUF MkBufferC . 1 -> typeless Buffer able to hold every kind of data
L MK_BFL MkBufferListC . 1 -> list of MkBufferC .
. MK_BUF MkBufferC . 1 -> READ ONLY - like 'U' but return the Buffer-Value and not the MkBufferC .
* MK_BFL MkBufferListC . 1 -> READ ONLY - like 'L' but collect ALL remaining data as ONE MkBufferListC .
[ SendL_START 0 -> Start of List
] SendL_END 0 -> End of List
( SendT_START 0 -> Start of Transaction Object, only as FIRST parameter
) SendT_END 0 -> End of Transaction Object, only ONE supported
: END of SERVICE-IDENT * -> next SEND_SIGNATURE
@ END of SEND-SIGN. * -> next READ-SIGNATURE

Example from server.c in a service-call send the server-configuratien back to the client

static enum MkErrorE
Ot_CNFG ( MQ_CALLBACK_SERVICE_CALL_ARGS )
{
  MqSendSTART_E (mqctx);

  MqSendO_E (mqctx,MqConfigGetIsServer(mqctx));
  MqSendO_E (mqctx,MqLinkIsParent(mqctx));
  MqSendO_E (mqctx,MqSlaveIs(mqctx));
  MqSendO_E (mqctx,MqConfigGetIsString(mqctx));
  MqSendO_E (mqctx,MkRuntimeGetIsSilent());
  MqSendO_E (mqctx,MqLinkIsConnected(mqctx));

  MqSendC_E (mqctx,MqConfigGetName(mqctx));
  MqSendI_E (mqctx,MkRuntimeGetDebug());
  MqSendI_E (mqctx,(MK_INT)MqLinkGetCtxId(mqctx));
  MqSendC_E (mqctx,MqServiceGetToken(mqctx));

error:
  return MqSendRETURN (mqctx);
}

enum MkErrorE MqSendVL2(MQ_CTX ctx, MK_STRN cstr, va_list var_list)

TOP

va_list version of MqSend … → API: MqSendVL2_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]cstrthe doc_mq_c_High_CALL_SIGNATURE
[in]var_lista variable argument list object
See also
Send

MqContextC INTROSPECTION

C-API: MqContextC_Introspection_C_API - Get information about all instances created by class

(static) MQ_CTX MqContextInstances(void)

TOP

get head-instance from linked-list of MqContextS type … → API: MqContextInstances

The head-instance is the last instance created.

MQ_CTX MqContextNext(MQ_CTX ctx)

TOP

get next instance from linked-list of MqContextS type → API: MqContextNext

MQ_CTX MqContextPrev(MQ_CTX ctx)

TOP

get previous instance from linked-list of MqContextS type → API: MqContextPrev

MqContextC LINK API

NAVI: TOP , up

LinkConnectre-connect a client-server-link after a server crash or a network downtime …
LinkCreatemake ctx to a parent-context and setup a new client-server-link
LinkCreateChildmake a context to a child-context on-top of an existing parent-client-server-link
LinkDeleteclose the client-server-link
LinkGetCtxIdget an identifier which is unique per parent-or-child-context
LinkGetParentget the parent-context from a client/server link …
LinkGetTargetIdentget the ident of the link-target
LinkIsConnectedis the context connected? …
LinkIsParentis the context a parent-context? …
LinkShutdown

shutdown the communication with a server

MqContextC LINK API DETAILS

C-API: MqContextC_Link_C_API - setup and manage a client-server-link

The client-server-link connect two context, a client-parent-context and a server-parent-context. The link can be local (connect two context on the same host) or can be remote (connect two context on different hosts). On-Top the parent-context multiple child-context are allowed.

  !on remote host!                                  !on local host!

      server1---------x                     x----------server2
         |            |                     |             |
         |     child-context-1       child-context-2      |
         |            |                     |             |                      server
 parent-context-1-----x                     x-----parent-context-2
         |                                                |
 (MqConfigS::server)                 (example: MqConfigS::server --fork --uds … --file …)
         |                                                |
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
         |                                                |
      (--tcp)                                  (--pipe, --uds, --tcp)
         |                                                |
 parent-context-1-----x                     x-----parent-context-2
         |            |                     |             |                      client
         |     child-context-1       child-context-2      |
         |            |                     |             |
         x------------x--------client-------x-------------x

                           !on local host!

Definition of a "client-context"

  • every new client-parent-context create a new client-server-link and perform the connect system-call.
  • every new client-server-link start a new server-object and creating a new server-parent-context
  • every deletion of the client-parent-context stop the previous started server-object and delete the server-parent-context
  • the client-context get all the error/warning/info messages from the server-context

Definition of a "server-context"

  • every new server-parent-context is created by request from the client-parent-context:
  • in remote mode every new server-parent-context wait for a tcp or uds connection request using the accept system-call.
client --tcp --host REMOTE_HOST --port REMOTE_PORT ... or
client --uds --file MYFILE ...\endverbatim
  • in local mode new server-parent-context is started by the client-parent-context as pipe:
    client @ server

Definition of a "parent-context"

  • the parent is the first context created and is created with LinkCreate
  • every new parent-context on the client create a new communication to a server.
  • every new parent-context on the client connect to a new parent-context on the server
  • every new parent-context on the server is using a new server-object
  • the parent-context control the socket communication interface

Definition of a "child-context"

  • the child-context is the second or more context and is created with LinkCreateChild.
  • every new child-context on the client create a new child-context on the server.
  • every new child-context is totally independent from the parent-context setup and is able to serve its own services.
  • the child-context is using the parent-context as a tunnel.
  • the parent of a child-context can be a parent-context or an other child-context. A tree like structure is created.
  • the child-context is using the communication interface from the parent-context.
  • if a context is deleted (parent or child) the depending context (parent or child) is deleted too.
  • if a context is deleted the depending context-tree is deleted too.

enum MkErrorE MqLinkConnect(MQ_CTX ctx)

TOP

re-connect a client-server-link after a server crash or a network downtime … → API: MqLinkConnect_RT

Do nothing if the client-server-link is already connected. This function is only useful in an event-function (IEvent) if the link-disconnect (ErrorIsEXIT) is ignored (ErrorReset). Read more from the: /example/c/Filter4.c example.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqLinkCreate(MQ_CTX ctx, MK_BAC args)

TOP

make ctx to a parent-context and setup a new client-server-link … → API: MqLinkCreate_RT

the argument args has the following restrictions:

command-line-arguments to configure the client-server-link including the @ item to add server-command-line-arguments.

The following special keywords, direct after the first @, are recognized:

  • factory-name -> a known factory previeous added with FactoryAdd)
  • SELF -> recognized as the initial-factory-name. (e.g. FactoryInitial)
    The startup from "@ SELF arg1…" will be "@ executable factory-name arg1…"
  • WORKER -> recognized as the own executable name.
    The startup from "@ WORKER arg1…" will be "@ executable arg1…"
    If the ctx is not the server-context… (e.g MqSetupS::isServer == true) the default-factory (e.g. FactoryDefault) will be used.

the executable will be taken from the doc_mq_c_MqMsgqueInit arguments.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]argscommand-line-arguments to configure the client-server-link
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqLinkCreateChild(MQ_CTX ctx, MQ_CTX parent, MK_BAC args)

TOP

make a context to a child-context on-top of an existing parent-client-server-link … → API: MqLinkCreateChild_RT

A child is using the same process or thread as the parent but a different namespace. With a different namespace a child is able to act on different services on the shared server.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]parentthe parent-context defined with LinkCreate
[in]argscommand-line-arguments to configure the client-server-link without the "@" item.
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

void MqLinkDelete(MQ_CTX ctx)

TOP

close the client-server-link … → API: MqLinkDelete_RT

On a client the context will be set to not-connected and the function LinkIsConnected will return MK_NO. On a server the context will be deleted but only if MqSetupS::ignoreExit is not set to MK_YES. If the link is already not-connected nothing will happen.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on

MK_NUM MqLinkGetCtxId(MQ_CTX ctx)

TOP

get an identifier which is unique per parent-or-child-context … → API: MqLinkGetCtxId

The context-identifier is a number and is used in the protocol to link a data-package to a context-pointer. This is necessary because the communication interface is shared between the parent-context and the child-context. This number is unique.

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the identifier as number

MQ_CTX MqLinkGetParent(MQ_CTX ctx)

TOP

get the parent-context from a client/server link … → API: MqLinkGetParent

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the parent-context or NULL if not a child-context

MK_STRN MqLinkGetTargetIdent(MQ_CTX ctx)

TOP

get the ident of the link-target … → API: MqLinkGetTargetIdent

This function is only useful if the link is up and running.

Parameters
[in]ctxthe MqContextS instance to work on
Returns
get the ident of the link-target or NULL if not connected

MK_BOOL MqLinkIsConnected(MQ_CTX ctx)

TOP

is the context connected? … → API: MqLinkIsConnected

A context is connected if the LinkCreate command was successful. A context is not connected if:

  • the context has just been created and not connected
  • the link was deleted with LinkDelete
Parameters
[in]ctxthe MqContextS instance to work on
Returns
a boolean value, MK_YES or MK_NO

MK_BOOL MqLinkIsParent(MQ_CTX ctx)

TOP

is the context a parent-context? … → API: MqLinkIsParent

A context is a parent-context if it was created with LinkCreate

Parameters
[in]ctxthe MqContextS instance to work on
Returns
a boolean value, MK_YES or MK_NO

enum MkErrorE MqLinkShutdown(MQ_CTX ctx)

TOP

shutdown the communication with a server → API: MqLinkShutdown_RT

The following tasks are performend:

  • shutdown all childs
  • shutdown all slaves
  • client send the shutdown-sequence to the server
  • server answer the shutdown-sequence from the client
  • if parantshutdown the communication infrastructure
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC LOG API

NAVI: TOP , up

Loglog the MqContextC
LogConfiglog the MqContextC part MqConfigS
LogEnvlog the MqContextC part MqEnvS
LogLinklog the MqContextC part MqLinkS
LogSetuplog the MqContextC part MqSetupS
LogShortlog the MqContextC with less info then ContextLog
LogTypelog the MqContextC part MkTypeS
LogParentOrChildis ctx a PARENT or a CHILD ? …
LogServerOrClient

is ctx a SERVER or a CLIENT ? …

MqContextC LOG API DETAILS

C-API: MqContextC_Log_C_API - log output to string or MkLogFileC

Logging is an important part of the debugging and validation task.

The logging target is set with RuntimeSetLogfile wich accepts a filename or the special token stdout or stderr.

Many logging functions have common parameters:

Parameters
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)

void MqContextLog(MQ_CTXN ctx, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC … → API: MqContextLog_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)
See also
MqContextC_C_API ContextLogShort

void MqContextLogConfig(MQ_CTXN ctx, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC part MqConfigS … → API: MqContextLogConfig_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)

void MqContextLogEnv(MQ_CTX ctx, MK_OBJ fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC part MqEnvS … → API: MqContextLogEnv_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)
See also
MqContextC_Env_C_API

void MqContextLogLink(MQ_CTXN ctx, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC part MqLinkS … → API: MqContextLogLink_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)

void MqContextLogSetup(MQ_CTXN ctx, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC part MqSetupS … → API: MqContextLogSetup_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)

void MqContextLogShort(MQ_CTXN ctx, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl, MK_STRN label)

TOP

log the MqContextC with less info then ContextLog … → API: MqContextLogShort_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]labela string to identify a task or object
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)
See also
MqContextC_C_API ContextLog

void MqContextLogType(MQ_CTX ctx, MK_OBJ fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqContextC part MkTypeS … → API: MqContextLogType_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)
See also
MqContextC_C_API ContextLog

MK_STRN MqLogParentOrChild(MQ_CTXN ctx)

TOP

is ctx a PARENT or a CHILD ? … → API: MqLogParentOrChild

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the string PARENT or CHILD

MK_STRN MqLogServerOrClient(MQ_CTXN ctx)

TOP

is ctx a SERVER or a CLIENT ? … → API: MqLogServerOrClient

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the string SERVER or CLIENT

MqContextC MISC API

NAVI: TOP , up

GetBufferget the MqContextS::ctxbuf object
ToStringtoString slot of MqContextC
Exitdelete the context and exit the current process or thread …
GetRootget the Root (toplevel initial context)
ProcessEvent

enter the event-loop and wait for an incoming service-request. …

MqContextC MISC API DETAILS

C-API: MqContextC_Misc_C_API - various functions to work on a MqContextC

MK_BUF MqContextGetBuffer(MQ_CTX ctx)

TOP

get the MqContextS::ctxbuf object → API: MqContextGetBuffer_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
the context->ctxbuf object
Attention
The memory of the out-value belongs to the called LibMqMsgque function and therefore never becomes NULL. For details on the out-value, see: MkKernel_Storage_C_API.

MK_STRN MqContextToString(MQ_CTXN ctx)

TOP

toString slot of MqContextC … → API: MqContextToString_RT

void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline)

TOP

delete the context and exit the current process or thread … → API: MqExit_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]callfilethe name of the file the call take place (e.g. FILE)
[in]calllinethe number of the line the call take place (e.g. LINE)

To delete an application is a difficult task because the link-target have to be informed. This information is send as shutdown-event and finally as socket-exit after application-exit. This library tries to perform this two steps even if the default exit function is called. This is no problem because the second step (socket-exit) is enough to signal a link-down. It is not secure to depend only on socket-exit for application exit because sometimes the sockets stop working or the link-target does not get a socket-exit. For example the pipe-link on windows. The client can not exit and create a socket-exit error on the server because the server is still running without receiving a shutdown-event. A second argument for using the void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline) function is, that it can be used for process and thread exit. A thread, started by libmqmsgque, does exit but the process continue to work. To make it short use void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline) to exit your application.

The following steps are performed:

Attention
It is a bad practice to call void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline) from inside a service.

potential problems

  1. If you call void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline) on a service in a c++ (p)thread on linux … an SIGABRT ist raised… ??? this problem is related with the "internal thread cleanup"… call ErrorSetEXIT to exit from a service handle

MQ_CTX MqGetRoot(MQ_CTX ctx)

TOP

get the Root (toplevel initial context) → API: MqGetRoot

enum MkErrorE MqProcessEvent(MQ_CTX ctx, enum MqWaitOnEventE wait, MK_TIME_T timeout)

TOP

enter the event-loop and wait for an incoming service-request. … → API: MqProcessEvent_RT

This function is used to enter the event-loop and start listen on open file-handles and to call IEvent on idle.
This function is mostly used on a server to enter the event-loop and wait for an incoming service request or on a client/server with all functions which exchange data like MqContextC SEND API, LinkConnect etc.

Attention
Be aware that the read-data-package is only valid until the event-loop is entered. During event-loop new data may be available for the ctx and the read-data-package will be overwritten.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]waitthe operation-mode used to define the behaviour, possible values are:
MQ_WAIT_NO 0

Check for one event but do not wait …

If an event is available process the event, but only one. If no event is available return with MK_CONTINUE. This is the default.

MQ_WAIT_ONCE 1

Wait maximum timeout seconds for one new event, doesn't matter which context the event belongs to or raise an timeout-error


attention: During serving an event and this event uses the MqContextC SEND API or an other ProcessEvent … an additional event could be served as well.


error: An asynchronous error (_ERR) always belong to the parent-context of the socket connection

  • if bgerror is set.. the current context will be return with MK_OK
  • if bgerror is not set the return will be MK_ERROR and an error is raised
MQ_WAIT_OWN 2

Wait maximum timeout seconds for one new event that belongs to the current context or raise an timeout-error


error: An asynchronous error (_ERR) always belong to the parent-context of the socket connection

  • if bgerror is set.. the current context will not return and continue to work
  • if bgerror is not set the return will be MK_ERROR and an error is raised
MQ_WAIT_FOREVER 3

Wait maximum timeout seconds for an event or raise an timeout-error

  • If an event was found process the event.
  • If an event was not found, raise a timeout-error. After the event was processed continue to listen for a the new event.

This function will only come back on error or on exit.

[in]timeoutin seconds until a timeout-error is raised, possible values are:
integer >0 use this value as number of seconds.
MK_TIMEOUT_DEFAULT -1 MK_TIMEOUT_USER for MQ_WAIT_ONCE or MK_TIMEOUT_MAX for MQ_WAIT_FOREVER. default,
MK_TIMEOUT_USER -2
MK_TIMEOUT_MAX -3
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC PROXY API

NAVI: TOP , up

ProxyForwardsend the entire read-data-package-data to the link-target
ProxyItem

Copy a single-data-item from the sourceCtx to the targetCtx.

MqContextC PROXY API DETAILS

C-API: MqContextC_Proxy_C_API - copy data from the read-data-package of the sourceCtx to the send-data-package of the targetCtx

The proxy-feature is used in a filter-setup to process-and-forward incoming data.

See also
MqDumpC

Example: A typical proxy-setup in pseudo C++ code

void myService () {
MqContextC *ftr = SlaveGetFilter(); // get the "slave" with id "1" (the filter)
...
ftr->SendSTART(); // start the FORWARD
while (ReadItemExists()) { // read ALL data from the ORIGINAL service-call
ProxyItem(ftr); // forward a SINGEL item from "this" to "ftr"
}
...
ftr->SendEND_AND_WAIT("MYTK"); // send the data.package to "ftr"
...
SendSTART(); // start the ANSWER
while (ftr->ReadItemExists()) { // read ALL data from the "MYTK" service-call
ftr->ProxyItem(this); // forward a SINGEL item from "ftr" to "this"
}
SendRETURN(); // answer the ORIGINAL service call
}

enum MkErrorE MqProxyForward(MQ_CTX sourceCtx, MQ_CTX targetCtx, MQ_DMP dump, MK_TIME_T timeout)

TOP

send the entire read-data-package-data to the link-target … → API: MqProxyForward_RT

The goal of this function is to link two context, typically a master and a slave (filter). This function is typically used in a service or and event callback to send the entire package and wait for the answer.

Example of a typical usage in pseudo c++

void myService () {
MqContextC *ftr = SlaveGetFilter(); // get the "slave" with id "1" (the filter)
...
ProxyForward(ftr); // forward AND send the entire ENTIRE package from "this" to "ftr"
...
SendRETURN(); // answer the ORIGINAL service call
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]sourceCtxthe source of the copy
[in,out]targetCtxthe target of the copy
[in]dumpif not NULL, the value is the source of the copy, dump is the return from DumpExport,
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT=MK_TIMEOUT_USER)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
ProxyItem ServiceProxy ServiceProxyCtx

enum MkErrorE MqProxyItem(MQ_CTX sourceCtx, MQ_CTX targetCtx)

TOP

Copy a single-data-item from the sourceCtx to the targetCtx. → API: MqProxyItem_RT

copy data from the read-data-package of the sourceCtx to the send-data-package of the targetCtx

The proxy-feature is used in a filter-setup to process-and-forward incoming data.

See also
MqDumpC

Example: A typical proxy-setup in pseudo C++ code

void myService () {
MqContextC *ftr = SlaveGetFilter(); // get the "slave" with id "1" (the filter)
...
ftr->SendSTART(); // start the FORWARD
while (ReadItemExists()) { // read ALL data from the ORIGINAL service-call
ProxyItem(ftr); // forward a SINGEL item from "this" to "ftr"
}
...
ftr->SendEND_AND_WAIT("MYTK"); // send the data.package to "ftr"
...
SendSTART(); // start the ANSWER
while (ftr->ReadItemExists()) { // read ALL data from the "MYTK" service-call
ftr->ProxyItem(this); // forward a SINGEL item from "ftr" to "this"
}
SendRETURN(); // answer the ORIGINAL service call
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]sourceCtxthe source of the copy
[in,out]targetCtxthe target of the copy
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
ProxyForward ServiceProxy ServiceProxyCtx

MqContextC READ API

NAVI: TOP , up

MqContextC READ API ATOM

ReadALLget a temporary MkBufferListC from all data in the read-data-package
ReadLISTget all arguments as native list …
ReadLONGread the long native object from the read-data-package
ReadNEXTget the next argument as native object …
ReadTT

read a PRIMITIVE TYPE from the read-data-package

MqContextC READ API BLOCK

ReadL_ENDfinish to extract a list-items from the read-data-package. …
ReadL_STARTstart to extract a list-items from the read-data-package. …
ReadT_ENDfinish to extract a longterm-transaction-item from the read-data-package. …
ReadT_START

start to extract a longterm-transaction-item from the read-data-package. …

MqContextC READ API MISC

ReadGetNextTypeget the type (MkTypeE) of the next Item in the read-data-buffer or "0" if not available
ReadGetNumItemsget the number of items left in the read-data-package
ReadItemExistscheck if an item exists in the read-data-package
ReadUndo

undo the last MqContextC READ API function call …

MqContextC READ API DETAILS

C-API: MqContextC_ReadApi_C_API - extract data from an incoming read-data-package. …

A data-package is read in two different scenarios:

  • on a server to serve an incoming service-call from the client
  • on a client to process the return-data from a previous service-call

Reading data is a passive-task and the opposite of sending data, which is an active-task. Passive means that the reading process is triggered by an incoming-data-package and not by the software workflow or by the user.
There is a read function and some help functions for each basic type defined in MkBufferS .

Read-Safe
Each service-call has a private read-data-package. This means that during a service-call that is in progress, another service-call can be served without damaging the read-data-package of the current service-call.
Type-Safe
A data-item in a read-data-package is type safe, this mean that every read of a data-item have to match the data-type of the previous write. One exception is available, the cast from and to the string data-type (TYPE=C) is allowed.

Example from server.c read-safety: Make a nested service-call

static enum MkErrorE
Ot_CSV1 ( MQ_CALLBACK_SERVICE_CALL_ARGS )
{
  // read the input-data from the CSV1-service-call
  // client → server
  MK_INT retI, inI = MqReadI_e(mqctx) + 1;

  // call the CSV2-service at the client, wait 10sec for timeout
  // server → client → server
  MqSend_E(mqctx, "Wt", 10, "CSV2:I@I", inI, &retI);

  // answer the CSV1-service-call with the result from the CSV2-service-call
  // server → client
error:
  return MqSend(mqctx, "R", "I", retI+1);
}

MqContextC READ API ATOM

C-API: MqContextC_ReadApi_Atom_C_API - read a single-data-item outof a read-data-package

enum MkErrorE MqReadALL(MQ_CTX ctx, MK_BFL* val_inout)

TOP

get a temporary MkBufferListC from all data in the read-data-package … → API: MqReadALL_RT

If the val_inout is NULL than a temporary MkBufferListC is returned. If the val_inout is not NULL than the memory of the val_inout is reused.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]val_inoutthe MkBufferListC - the storage of the input is reused
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
ReadL
Attention
The memory of the out-value belongs to the called LibMqMsgque function and therefore never becomes NULL. For details on the out-value, see: MkKernel_Storage_C_API.

enum MkErrorE MqReadLIST(MQ_CTX ctx, MK_NAT_LIST* val_out)

TOP

get all arguments as native list … → API: MqReadLIST_RT

Example from server.tcl start a WORKER using all arguments from the service-call.

my SlaveWorker $id "WORKER" {*}[my ReadLIST] --name wk-cl-$id @ --name wk-sv-$id
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]val_outthe native list as return
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
ReadL ReadNEXT

enum MkErrorE MqReadLONG(MQ_CTX ctx, MK_LONG* val_out)

TOP

read the long native object from the read-data-package → API: MqReadLONG_RT

on 64bit use a ReadW and on 32bit use a ReadI

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]val_outthe native long object to read
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
this is NON portable

enum MkErrorE MqReadNEXT(MQ_CTX ctx, MK_NAT_OBJECT* val_out)

TOP

get the next argument as native object … → API: MqReadNEXT_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]val_outthe native object as return
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
ReadLIST ReadU

enum MkErrorE MqReadTT(MQ_CTX ctx, MK_BYT* val_out)

The ReadTT provide a single function for every PRIMITIVE TYPE

returncommand

C-API :

enum MkErrorE MqReadB(MQ_CTX ctx, MkBinaryR* val_out)MqReadB_RT
enum MkErrorE MqReadC(MQ_CTX ctx, MK_STRN* val_out)MqReadC_RT
enum MkErrorE MqReadD(MQ_CTX ctx, MK_DBL* val_out)MqReadD_RT
enum MkErrorE MqReadF(MQ_CTX ctx, MK_FLT* val_out)MqReadF_RT
enum MkErrorE MqReadI(MQ_CTX ctx, MK_INT* val_out)MqReadI_RT
enum MkErrorE MqReadL(MQ_CTX ctx, MK_BFL* val_out)MqReadL_RT
enum MkErrorE MqReadO(MQ_CTX ctx, MK_BOL* val_out)MqReadO_RT
enum MkErrorE MqReadS(MQ_CTX ctx, MK_SRT* val_out)MqReadS_RT
enum MkErrorE MqReadU(MQ_CTX ctx, MK_BUF* val_out)MqReadU_RT
enum MkErrorE MqReadW(MQ_CTX ctx, MK_WID* val_out)MqReadW_RT
enum MkErrorE MqReadY(MQ_CTX ctx, MK_BYT* val_out)

MqReadY_RT

read a PRIMITIVE TYPE from the read-data-package

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]val_outthe value to read
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC READ API BLOCK

C-API: MqContextC_ReadApi_Atom_C_API - read a single-data-item outof a read-data-package

enum MkErrorE MqReadL_END(MQ_CTX ctx)

TOP

finish to extract a list-items from the read-data-package. … → API: MqReadL_END_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqReadL_START(MQ_CTX ctx, MK_BUF buf)

TOP

start to extract a list-items from the read-data-package. … → API: MqReadL_START_RT

Initialize the read with the current body-item or an optional MkBufferC. This command requires a final enum MkErrorE MqReadL_END(MQ_CTX ctx) to finish the read.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]bufan optional MkBufferC as result from a previous RDocNsA{ReadU} call or NULL to use the next item from the read-data-package.
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqReadT_END(MQ_CTX ctx)

TOP

finish to extract a longterm-transaction-item from the read-data-package. … → API: MqReadT_END_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqReadT_START(MQ_CTX ctx)

TOP

start to extract a longterm-transaction-item from the read-data-package. … → API: MqReadT_START_RT

Initialize the read with the current-item or an optional MkBufferC. The current-item have to be the first item in the read-data-package. This command requires a final enum MkErrorE MqReadL_END(MQ_CTX ctx) to finish the read.

Example from server.c read the results from a service-call with transaction-support

static enum MkErrorE Ot_TRN2 ( MQ_CALLBACK_SERVICE_CALL_ARGS )
{
  struct ServerCtxS *srvctx = (struct ServerCtxS*) mqctx;
  MqReadT_START_E (mqctx);
  MqReadI_E (mqctx, &srvctx->i);
  MqReadT_END_E (mqctx);
  MqReadI_E (mqctx, &srvctx->j);

  return MK_OK;
error:
  return MkErrorStack_1X (mqctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC READ API MISC

C-API: MqContextC_ReadApi_Atom_C_API - read a single-data-item outof a read-data-package

enum MkTypeE MqReadGetNextType(MQ_CTX ctx)

TOP

get the type (MkTypeE) of the next Item in the read-data-buffer or "0" if not available → API: MqReadGetNextType

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the type

MK_NUM MqReadGetNumItems(MQ_CTX ctx)

TOP

get the number of items left in the read-data-package … → API: MqReadGetNumItems

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the number of items as integer

MK_BOOL MqReadItemExists(MQ_CTX ctx)

TOP

check if an item exists in the read-data-package … → API: MqReadItemExists

Parameters
[in]ctxthe MqContextS instance to work on
Returns
boolean, MK_YES or MK_NO

enum MkErrorE MqReadUndo(MQ_CTX ctx)

TOP

undo the last MqContextC READ API function call … → API: MqReadUndo_RT

Put the internal position-pointer to the start of the last read body-item. The next read function call will extract the same item again. Only one undo level is supported.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC ROUTE API

NAVI: TOP , up

RouteCreatecreate/delete a routing-link between context an a service using route
RouteDeletedelete a routing-link created with RouteCreate
RouteGetPathreturn the absolut route-connection-string up to the current ctx
RouteGetTreecreate an overview about all available routing-target and services …
RouteResolvereturn a list of all context belonging to ident
RouteTraverse

traverse a tree down and call service if available.

MqContextC ROUTE API DETAILS

C-API: MqContextC_Route_C_API - setup and manage a routing-link

A routing-link is the connection of two context, the route-source and the route-target, with a unspecifiend number of hub-context in between using a specific service-token.

A single context is identified by the context-identifier as returned by ClassIdentGet.

A routing-link can be created using Service-Level-Routing or Package-Level-Routing.

  • The Service-Level-Routing is using a round-robin-proxy-service on the hub-context to forward an incoming package to the routing-target.
  • The Package-Level-Routing is using a routing-database to route the data on the package-level without a service involved.

The difference between Service-Level-Routing and Package-Level-Routing is the public versa private behaviour.

  • The Service-Level-Routing route EVERY package send to the hub-context using the service-token to the routing-target, this behaviour is called public.
  • The Package-Level-Routing route ONLY the package(s) from the creator (owner) of the route, this behaviour is called private.

Summary:

TCP/IP layer model

The TCP/IP model define the following layers (from: https://www.geeksforgeeks.org/tcp-ip-model/) :

Network Access Layer
This layer corresponds to the combination of Data Link Layer and Physical Layer of the OSI model. It looks out for hardware addressing and the protocols present in this layer allows for the physical transmission of data.
Internet Layer
This layer parallels the functions of OSI’s Network layer. It defines the protocols which are responsible for logical transmission of data over the entire network
The main protocols residing at this layer are :
  1. IP – stands for Internet Protocol and it is responsible for delivering packages from the source host to the destination host by looking at the IP addresses in the package headers. IP has 2 versions: IPv4 and IPv6. IPv4 is the one that most of the websites are using currently. But IPv6 is growing as the number of IPv4 addresses are limited in number when compared to the number of users.
  2. ICMP – stands for Internet Control Message Protocol. It is encapsulated within IP datagrams and is responsible for providing hosts with information about network problems.
  3. ARP – stands for Address Resolution Protocol. Its job is to find the hardware address of a host from a known IP address. ARP has several types: Reverse ARP, Proxy ARP, Gratuitous ARP and Inverse ARP.
Host-to-Host Layer
This layer is analogous to the transport layer of the OSI model. It is responsible for end-to-end communication and error-free delivery of data. It shields the upper-layer applications from the complexities of data.
The two main protocols present in this layer are :
  1. Transmission Control Protocol (TCP) – It is known to provide reliable and error-free communication between end systems. It performs sequencing and segmentation of data. It also has acknowledgment feature and controls the flow of the data through flow control mechanism. It is a very effective protocol but has a lot of overhead due to such features. Increased overhead leads to increased cost.
  2. User Datagram Protocol (UDP) – On the other hand does not provide any such features. It is the go-to protocol if your application does not require reliable transport as it is very cost-effective. Unlike TCP, which is connection-oriented protocol, UDP is connectionless.
Application Layer
This layer performs the functions of top three layers of the OSI model: Application, Presentation and Session Layer. It is responsible for node-to-node communication and controls user-interface specifications. Some of the protocols present in this layer are: HTTP, HTTPS, FTP, TFTP, Telnet, SSH, SMTP, SNMP, NTP, DNS, DHCP, NFS, X Window, LPD. Have a look at Protocols in Application Layer for some information about these protocols.
Protocols other than those present in the linked article are :
  1. HTTP and HTTPS – HTTP stands for Hypertext transfer protocol. It is used by the World Wide Web to manage communications between web browsers and servers. HTTPS stands for HTTP-Secure. It is a combination of HTTP with SSL(Secure Socket Layer). It is efficient in cases where the browser need to fill out forms, sign in, authenticate and carry out bank transactions.
  2. SSH – SSH stands for Secure Shell. It is a terminal emulations software similar to Telnet. The reason SSH is more preferred is because of its ability to maintain the encrypted connection. It sets up a secure session over a TCP/IP connection.
  3. NTP – NTP stands for Network Time Protocol. It is used to synchronize the clocks on our computer to one standard time source. It is very useful in situations like bank transactions. Assume the following situation without the presence of NTP. Suppose you carry out a transaction, where your computer reads the time at 2:30 PM while the server records it at 2:28 PM. The server can crash very badly if it’s out of sync.

LibMqMsgque layer model

The libmqmsgque layer model is an extension to the TCP/IP layer model.

TCP/IP Application Layer
This layer is used for the libmqmsgque protocol - The protocol is the "language" of the libmqmsgque
library. The layer is defined as protocol-message-format and as protocol-flow-format.
  1. protocol-message-format - Example from msgque_protocoll_mq.h this is the "syntax" of the protocol.
    struct HdrS {
    MK_STRB ID[4] ;
    MK_STRB native ;
    MK_STRB charA ;
    union HdrIU ctxId ;
    MK_STRB charS ;
    union HdrIU bdySize ;
    MK_STRB charO ;
    MK_STRB tok[HDR_TOK_LEN] ;
    MK_STRB charT ;
    union HdrIU transSId ;
    MK_STRB charR ;
    union HdrIU routeId ;
    MK_STRB charC ;
    MK_STRB hs ;
    MK_STRB charE ;
    MK_STRB tt ;
    MK_STRB charF ;
    };
    struct BdyS {
    MK_STRB ID[4] ;
    //MK_STRB charN ; ///< <TT>size: 1 .............. -> total: 4 .. -> character .. -> "+"</TT>
    union HdrIU numItems;
    MK_STRB charE ;
    };
    struct LtrS {
    MK_STRB ID[4] ;
    //MK_STRB charN ; ///< <TT>size: 1 .............. -> total: 4 .. -> character .. -> "+"</TT>
    MK_BINB ltrP[HDR_ID_SIZE] ;
    MK_STRB charE ;
    };
    #define LTR_SIZE (3 + 1 + HDR_ID_SIZE + 1)
    struct RouS {
    MK_STRB ID[4] ;
    //MK_STRB charN ; ///< <TT>size: 1 .............. -> total: 4 .. -> character .. -> "+"</TT>
    MK_BINB rouP[HDR_ID_SIZE] ;
    MK_STRB charE ;
    };
    #define ROU_SIZE (3 + 1 + HDR_ID_SIZE + 1)
    struct PackageS {
    struct HdrS hdr ;
    struct BdyS bdy ;
    };
    char MK_STRB
    unsigned char MK_BINB
  2. protocol-flow-format - this is the "grammatic" of the protocol.
LibMqMsgque Service Layer

This layer provide the MqContextC-ServiceApi ontop of the Application Layer.

The master-slave-link is used to create a mesh of nodes defined by different parent-context. The master control the slave.

The master-slave-link is used to perform the following tasks:

  • report error messages from the slave-context to the master-context
  • to create a slave-child-context if a master-child-context is created
  • to delete a slave-context if a master-context is deleted

In difference to the client-server-link the master-slave-link connect two independent parent-context in the same process or thread (e.g. node). This leads to the restriction that only the master-context can be a server-context because only one server-context per node is possible.

   node-0   |           node-1/2        |   node-3/4/5
===================================================================

| <- client/server link -> | <- client/server link -> |

             | <-- master/slave link --> |

                           |- client1-0 -|- server3 ...
             |-  server1  -|
             |             |- client1-1 -|- server4 ...
  client0-0 -|
             |-  server2  -|- client1-2 -|- server5 ...

Definition of the "master-context"

  • the master-context is a parent-context without a child-context available.
  • the master-context is a client-context or a server-context.
  • the link between the master-context and the slave-context is done using SlaveWorker or SlaveCreate

Definition of the "slave-context"

  • the slave-context is a parent-context without a child-context available.
  • the slave-context is a client-context.
  • the slave-context lifetime is controlled by the master-context.
  • the slave-context report all error-messages to the master-context.
  • the slave-context is identified by a unique-slave-id starting with 0.
  • a special form of a slave-context is a worker-context

Definition of the "worker-context"

  • the worker-context is a slave-context using the image of the master-context self.
  • the master-context can be a server-context or a client-context.
  • the worker-context is created using SlaveWorker
  • the worker-context is identified by a unique-slave-id starting with 0.

Definition of the "slave-id"

  • the slave-id is defined at enum MqSlaveE
  • a slave is identified in his master-context by a slave-id
  • the slave-id work like a defined well-known-port-number in /etc/services
  • the slave-id is an integer value with valid values > 0
  • it is a good practice to plan the usage of your slave-id(s)
  • slave
    slave-id value definition
    MQ_SLAVE_MAX 1024 internal: the maximum slave-id … .
    MQ_SLAVE_USER 10 internal: start of user-defined-slave-id .
    MQ_SLAVE_LOOPBACK 0 internal: the loopback-slave-id, (call my own services) .
    MQ_SLAVE_FILTER 1 internal: the filter-slave-id, (on a master get the filter-slave) .
    MQ_SLAVE_MASTER 1 internal: the master-slave-id, (on a slave get the master) .
    MQ_SLAVE_OTHER 1 internal: on the master-ctx get the slave-ctx and on the slave-ctx get the master-ctx .
  • range
    range definition
    0 <= slave-id < MQ_SLAVE_MAX range of valid slave-id's
    0 <= slave-id < MQ_SLAVE_USER internale usage
    MQ_SLAVE_USER <= slave-id < MQ_SLAVE_MAX external usage

Definition of the "LOOPBACK" (0) slave

  •    client   |           server            |
    ===========================================
    
    | <--- client/server --->  | <-- loop --> |
    
                | <------ master/slave -----> |
    
      client -- | -- server -- | -- client -- #
                       ==             ==      #
                     server -- | -- client -- #
  • the loopback has always the slave-id = 0 .
  • the loopback has the same class as the parent, if reflection is not available the FactoryInitial is used.
  • the loopback is used to call a service on the same process or thread.
  • the loopback is a special filter without an additional process or thread to be started.
  • the loopback is only internal accessible
  • the service called by the loopback need the same attention as the service called by the filter, the context of the service is the loopback-context.
  • the loopback can call ServiceCreate to create a new link between a service-token and a service-method, by default all services from the master-context (the owner of the loopback) are also accessible by the loopback.
  • in the service use SlaveGetMaster to get the master-context from the loopback-context.
  • Example from MyLoopServer.c create a new loop-server
    #include "common.h"
    
    // [MyLoopServerC_Define]
    typedef struct MyLoopServerS {
      struct MqContextS mqctx;    ///< link to the \libmqmsgque object
      #define mydata_size 30
      char mydata[mydata_size];   ///< define the "mydata" attribute
    } MyLoopServerC;  
    // [MyLoopServerC_Define]
    
    // the MyLoopServerC class-type
    static MkThreadLocal MK_TYP MyLoopServerCTT = NULL;
    
    // service to serve all EXTERNAL requests for token "HLWO"
    static enum MkErrorE HLWO_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // get the "loopback" context
      MQ_CTX loop = MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK);
      // call the LOOP service on the SAME server
      MqSend_E(loop,"W","LOOP");
      // answer HLWO with string-return from LOOP
      MqSend_E(mqctx, "R", "C", MqReadC_e(loop));
      return MK_OK;
    error:
      return MqSendRETURN(mqctx);
    }
    
    // service to serve all INTERNAL requests for token "LOOP
    static enum MkErrorE LOOP_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // get the "master" context 
      MyLoopServerC* master = (MyLoopServerC*)MqSlaveGetMaster(mqctx);
      // answer LOOP with data from MASTER->mydata attribute
      return MqSend(mqctx, "R", "C", master->mydata);
    }
    
    // define a service as link between the token "HLWO" and the callback "HLWO_srv"
    static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // EXTERNAL: link the "HLWO" service with "HLWO_srv"
      MqServiceCreate_E(mqctx, "HLWO", HLWO_srv, NULL, NULL, NULL);
      // INTERNAL: link the "LOOP" service with "LOOP_srv"
      MqServiceCreate_E(MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK), "LOOP", LOOP_srv, NULL, NULL, NULL);
      return MK_OK;
    error:
      return MkErrorStack_1X(mqctx);
    }
    
    // [MyLoopServerC_Create]
    enum MkErrorE
    MyLoopServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
    { 
      // create new instance using the MyLoopServerCTT class-type
      MQ_CTX const mqctx = *contextP = MqContextCreate(MyLoopServerCTT,tmpl);
    
      // initialize the new context
      MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
    
      // cast the libmqmsgque-context into the MyLoopServerC-context
      MyLoopServerC* mqctxC = (MyLoopServerC*)mqctx;
    
      // initialize the "mydata" attribute
      strncpy(mqctxC->mydata,"Hello World",mydata_size);
      mqctxC->mydata[mydata_size-1] = '\0';
    
      return MK_OK;
    }
    // [MyLoopServerC_Create]
    
    int main (int argc, MK_STRN argv[]) 
    {
      MqRtSetup_NULL;
    
      // [MyLoopServerC_Init]
      // initialize the MyLoopServer class-type with existing MqContextC_TT class-type
      MyLoopServerCTT = MkTypeDup2(MqContextC_TT,"MyLoopServerC");
      MyLoopServerCTT->objsize = sizeof(struct MyLoopServerS);
      // [MyLoopServerC_Init]
    
      // setup commandline arguments for later use
      MK_BFL largv = MkBufferListCreateVC(argc, argv);
      MQ_CTX mqctx = NULL;
    
      // create "MyLoopServer" factory… and make it to the default.
      MqFactoryDefault(MqFactoryAdd_2(MyLoopServerFactory,"MyLoopServer"));
      // inspect commandline-argument for the "factory" to choose… and create a object
      MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);
    
      // start listen for incoming call's
      MqLinkCreate_E (mqctx, largv);
      MqCheckForLeftOverArguments_E (mqctx, largv);
      MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
    error:
      MkBufferListDelete(largv);
      MqExit_1(mqctx);
    }
    

Performance analyse

The performance-test is created with:
  • pipe
    • Nhi1Exec perfclient.c --parent --wrk ? @ perfserver.c
  • spawn, fork, thread
    • Nhi1Exec -r=uds perfserver.c --spawn|fork|thread
    • Nhi1Exec -r=uds perfclient.c --parent --wrk ?
  • the number of workers are set with the –wrk option
  • the cpu is a xeon with 4/8
  • the performance is calculated as worker-context-created / time-in-sec with a ~2sec (default) measurement period.
performance-test code:
  • The test-setup is done as:
      perfclient                                worker                            perfserver
      ==========                                ======                            ==========
      |
      |- loop --wrk x
        |- MqSlaveWorker(...)               ->  worker[1] 
        |- MqSend(worker[1],"E","STR0..")   ->  PerfWorker_SRT0(...)
                                                |- loop endless
                                                  |- MqContextCreate(...)
                                                  |- MqLinkCreate(...)      <->   MqContextCreate(...)
                                                  |- MqContextDelete(...)   <->   MqContextDelete(...)
      |- sleep x sec
      |- loop --wrk x
        |- MqSend(worker[1],"C"..,"END0")   ->  PerfWorker_END0(...)
        |                                       |- stop loop
        |- "callback" - add number to all   <-  |- return #context 
performance-test results:
  • results generated using the debug environment
    setup –wrk # worker-context performance info
    pipe 1 2500 1000 the pipe start a new worker-context with spawn
    spawn 1 2500 <1000 same as pipe but use network-protocoll
    fork 1 3800 4000 the fork is faster than spawn
    thread 1 16500 9000 the thread is faster than fork
    pipe 4 8000 4500 the worker scale linear up to number of processors
    spawn 4 7600 <4500 -
    fork 4 23200 11500 -
    thread 4 55500 27500 -
    pipe 8 10000 5500 the additional scaling up to the max hyper-threading does not really help
    spawn 8 9100 <5500 -
    fork 8 23200 11500 -
    thread 8 55500 27500 -

example (C++ syntax)

Route-Connection-String

A client-server connection is defined with the route-connection-string as a composition of "identifier" and is build like a UNIX directory tree with the initial client as root.

Example: GUI/Data Frontend

*
|-header
|-GUI-|
frontend-| |-footer
|
|-DB
*

With --ident-from prefix|factory the identifier is defined as prefix-identifier or factory-identifer.

A route-connection-string is the path between TWO locations in the tree using the UNIX syntax:

short syntax direction
dot . current-context
double-dot .. previous-context
slash / root-context (the client)
"string" xxx next-context with name xxx

path between "DB" and "header"

  • relative: ctx.RouteCreate("../GUI/header",service)
  • absolute: ctx.RouteCreate("/frontend/GUI/header",service)

path between "footer" and "DB"

  • relative: ctx.RouteCreate("../../DB",service)
  • absolute: ctx.RouteCreate("/frontend/DB",service)

path between "frontend" and "footer"

  • relative: ctx.RouteCreate("GUI/footer",service)
  • absolute: ctx.RouteCreate("/frontend/GUI/footer",service)

Service-Layer-Routing

The LibMqMsgque-Service-Layer-Routing create proxy-services (ServiceProxyRoundRobin ...) between frontend and footer. (example c++)

// 1. on "frontend" create a route to the service "MYSV" on the "footer" passing "GUI"
DOING: frontendCtx.RouteCreate("GUI/footer", "MYSV");
// 2. on "frontend" call the route using the "loopback" slave
DOING: frontendCtx.SlaveGet(MQ_SLAVE_LOOPBACK).Send("W", "MYSV:..@..", ..);
// 3. on "frontend/GUI" proxy "footer"
INTERNAL: frontendCtx.ServiceProxyRoundRobin("MYSV", GUICtx);
INTERNAL: GUICtx.ServiceProxyRoundRobin("MYSV", footerCtx);
// 4. on "footer" call the service "MYSV"
SETUP: footerCtx.ServiceCreate("MYSV", ...);

The RouteCreate will take the following action:

  1. create a round-robin-proxy on frontend and on GUI using service MYSV
  2. check if service MYSV is available on footer

Attention:

  1. With the proxy on frontend/GUI no other service with the name MYSV on frontend/GUI is possible and every service-call to frontend or GUI using the service MYSV will be redirected to the service MYSV on footer.
  2. The live-time of the Service-Layer-Routing is up to the next RouteDelete call using the same arguments. If the proxy-to-footer becomes invalid on a the GUI-context the routing-link will be recreated.
  3. The RouteCreate can be used multiple times with the same Route-Connection-String and service-token and overwrite=true to guarantee that a route is available.

Package-Layer-Routing

...

enum MkErrorE MqRouteCreate(MQ_CTX ctx, MK_STRN route, MK_STRN service, MK_BOOL overwrite)

TOP

create/delete a routing-link between context an a service using route → API: MqRouteCreate_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]routethe absolute or relative path to the target-context, if NULL or '\0' the current context is returned.
[in]servicethe service token on the target context
[in]overwriteif overwrite=false an error is raised if the service already exists.
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
RouteCreate, RouteDelete

enum MkErrorE MqRouteDelete(MQ_CTX ctx, MK_STRN route, MK_STRN service, MK_BOOL overwrite)

TOP

delete a routing-link created with RouteCreate → API: MqRouteDelete_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]routethe absolute or relative path to the target-context, if NULL or '\0' the current context is returned.
[in]servicethe service token on the target context
[in]overwriteif overwrite=false an error is raised if the service already exists.
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
RouteCreate, RouteDelete

enum MkErrorE MqRouteGetPath(MQ_CTX ctx, MK_STRN* path_out)

TOP

return the absolut route-connection-string up to the current ctx … → API: MqRouteGetPath_RT

The absolut route-connection-string is the route starting at root (e.g. "/").

Attention
~ The path_out returned is owned by the loopback-slave -> do not free.
~ The path_out returned is only valid until the next call to the loopback-slave.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]path_outthe return path or NULL on error
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
RouteGetTree

enum MkErrorE MqRouteGetTree(MQ_CTX ctx, MK_BFL* treeP_out)

TOP

create an overview about all available routing-target and services … → API: MqRouteGetTree_RT

The data returned is a list of "ROUTE|IDENT|SERVICE,..." string items.

Example from MyWorker.c get the "Tree" as service

    void TREE () {
      Send("R", "L", RouteGetTree());
    }

Example from tests/route2.test -> route2-1-0

  • Get a list of all services on all servers reachable by test-context.
 /cl-0/sv-0/svWO2-11/svWO3-11|svWO3-11-0-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-11|svWO3-11-1-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-11|svWO3-11-2-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-12|svWO3-12-0-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-12|svWO3-12-1-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-12|svWO3-12-2-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11|svWO2-11-0-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11|svWO2-11-1-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11|svWO2-11-2-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-11|svWO3-11-0-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-11|svWO3-11-1-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-11|svWO3-11-2-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-12|svWO3-12-0-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-12|svWO3-12-1-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12/svWO3-12|svWO3-12-2-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12|svWO2-12-0-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12|svWO2-12-1-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-12|svWO2-12-2-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0|sv-0-0-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0|sv-0-1-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0|sv-0-2-2|FOID,HLWO,HLWS,PATH,TREE
 /cl-0|cl-0-0-2|HLWO,HLWS
 /cl-0|cl-0-1-2|HLWO,HLWS
 /cl-0|cl-0-2-2|HLWO,HLWS
 /cl-0/sv-0/svWO2-11/svWO3-11|svWO3-11-0-2|FINL,FOID,HLWO,HLWS,PATH,TREE
 /cl-0/sv-0/svWO2-11/svWO3-11|svWO3-11-1-2|FINL,FOID,HLWO,HLWS,PATH,TREE

The following information is available:

  • root is cl-0
  • multiple other clients, parallel to cl-0, are reachable: cl-0-....
  • multiple servers involved: sv...
  • multiple services reachable: FINL,FOID,HLWO,HLWS,PATH,TREE
Attention
~ The list-object returned is owned by RouteGetTree and is only valid until the next call to RouteGetTree.
~ On error the list-object will be empty.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]treeP_outthe tree-object with the results…
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
RouteGetPath

MQ_CTX_A MqRouteResolve(MQ_CTX ctx, MK_STRN ident, MK_NUM retnum)

TOP

return a list of all context belonging to ident … → API: MqRouteResolve_RT

This api-proc is used to return all context with MqLinkS::targetIdent == ident .

In addition the following special ident are recognized:

  • EMPTY or NULL or DOT=. or ClassIdentGet -> The loopback-slave
  • DOUBLE-DOT=.. -> On the server the server-context and on the slave the master-context

Example from server.c in a service call return all connected targets

    MK_STRN rmtIdent = MqReadC_e (mqctx);
    for (MQ_CTX* ret=MqRouteResolve(mqctx,rmtIdent,-1).data; *ret != NULL; ret++) {
      MqSendC_E (mqctx, MqLinkGetTargetIdent(*ret));
    }
Attention
1. The memory of the out-value belongs to the called LibMqMsgque function and therefore never becomes NULL. For details on the out-value, see: MkKernel_Storage_C_API.
2. The maximun number of items in the return-array is MQ_ROUTE_CTX_MAX .
3. (C-API) The last item in the return-array is always a NULL.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]identThe identifer to search the context for
[in]retnumThe maximum number-of-items accepted in the result-array, if <0 than MQ_ROUTE_CTX_MAX is used.
Returns
An array of MqContextC, the last item is a NULL.

enum MkErrorE MqRouteTraverse(MQ_CTX ctx, MK_STRN service, MK_BAC args)

TOP

traverse a tree down and call service if available. → API: MqRouteTraverse_RT

This is an Tool to be used to do maintenance work, sometimes services are changed (e.g RouteCreate) or an internal status need to be reset.

Attention
The service is called using the loopback-slave, be aware to call SlaveGetMaster first to get the master-context.

Example from Filter4.c calling a service from a loopback-slave

static enum MkErrorE WRIT ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MK_STRN str;
  struct FilterCtxS *ctx = (struct FilterCtxS *) MqSlaveGetMaster(mqctx);
  MqReadC_E (mqctx, &str);
  fprintf(ctx->FH, "%s\n", str);
  fflush(ctx->FH);
error:
  return MqSendRETURN(mqctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]servicethe service token to be called
[in]argscommand-line-arguments passed as arguments to the service call

MqContextC SEND API

NAVI: TOP , up

MqContextC SEND API ATOM

SendLONGsend the long native object to the send-data-package
SendL_FLATappend a MkBufferListC object as flat list of items to the send-data-package object …
SendVappend a vararg string to the send-data-package object …
SendVLappend a vararg string as va_list to the send-data-package object …
SendTT

append a native PRIMITIVE TYPE value to the send-data-package. …

MqContextC SEND API BASICS

SendENDfinish the send-data-block and call synchronous/asynchronous a remote-service
SendEND_AND_CALLBACKfinish the send-data-block, call the remote service, do not-wait for the result but expect the result on a callback
SendEND_AND_SUBfinish the send-data-block, call the remote service, do wait for the result and expect multiple sub-results on a callback
SendEND_AND_TRANSACTIONfinish the send-data-block, call the remote service to do a longterm-transaction-call
SendEND_AND_WAITfinish the send-data-block, call the remote service and wait for result…
SendSTARTinitialize the send-data-package. …
SendSYNC

The is used to garantee that all pending asynchronous-service-call are processed. …

MqContextC SEND API BLOCK

SendL_ENDfinish to append an embedded body-list-item to the send-data-package. …
SendL_STARTstart to append an embedded body-list-item to the send-data-package. …
SendT_ENDclosed a longterm-transaction-item
SendT_START

open a longterm-transaction-item

MqContextC SEND API RETURN

SendERRORsend the data from the MkErrorC to the link target . …
SendRETURNfinish the send-data-block on the server and optional return the results. …
Send_SUB_RETURN

return Sub-Data-Blocks required by SendEND_AND_SUB

MqContextC SEND API DETAILS

C-API: MqContextC_SendApi_C_API - construct an outgoing send-data-package

A data-package is send in two different scenarios:

  1. on a client to call a service on the server
  2. on a server to answer a service call from the client

Sending data is an active task and the opposite of reading data, which is a passive task. Active means that the send process is triggered by the software workflow or by the user.
For each basic type defined in MkBufferS, there is a send function and some help functions.

Send-Safe
Sending data is an atomic task and must not be interrupted between SendSTART and SendEND. The MqContextC HIGH API is uninterruptible by design.
Basic rule: process first and send all data last.

If timeout != 0 is used, the application enters the event loop and waits in the current process or thread for timeout seconds until the service call is finished.
While waiting for a result, the application can continue to work on other events that are in the same or in a different process or thread.

Recursion-Safe
If another-service-call arrives while waiting for a response from a previous-service-call, the previous-service-call will NOT end until processing of the other-service-call is complete.

Example-1: a service call, send and read a data-package

On a client: perform a service call

send the service-call SendSTARTSendTT... → SendEND_AND_WAIT
read the result packageReadTT... → ...

on a server: answer a service call

read the service-call ReadTT... → ...
send the result packageSendSTARTSendTT... → SendRETURN

Important in the code from above is the last command SendEND_AND_WAIT because this is just one of five possibilities:

command synchron database result
SendEND no no no
SendEND_AND_WAIT yes no single return data
SendEND_AND_SUB yes no multiple return data
SendEND_AND_CALLBACK no no single return data
SendEND_AND_TRANSACTION no yes two return data

To send a data-package is one task, to send it to the right receiver is an other one. The right receiver is identified using the token parameter argument. This parameter have to be a 4 character string. You'll probably ask "why 4?" the answer is that this string should be "human" readable and easy to "compare". As solution this string is mapped to a 4 byte integer used to find the proper key/value entry in the service-hash-table on the server. (in short: to search an integer is much faster as to search a string)

Example-2: (in C) At the client, calling the service and wait for an answer

...
enum MkErrorE MyServiceCall(MQ_CTX const ctx) {
// ... do some work
MqSendSTART_E(ctx); // init the Send-Buffer object
MqSendI_E(ctx,int_value); // 1. argument: a MK_INT value
MqSendC_E(ctx,"num:01"); // 2. argument: a MK_STRN value
MqSendB_E(ctx,mypicture,size); // 3. argument: a MK_BIN picture of size length
MqSendEND_AND_WAIT_E(ctx,"SRV1",60); // call service "SRV1" and wait max 60sec for the results
// ... get the results
MK_INT retI = MqReadI_e(ctx); // expect ONE integer as result
// ... do some work
return MK_OK;
error: // default error-handler
return MkErrorStack_1X(ctx); // on error, build up the error-stack
}
#define MqSendC_E(...)
#define MqSendSTART_E(...)
#define MqSendI_E(...)
#define MqSendEND_AND_WAIT_E(...)
#define MqSendB_E(...)

... or using the MqContextC HIGH API

...
enum MkErrorE MyServiceCall(MQ_CTX const ctx) {
// ... do some work
MqSend_E(ctx, "W", "SRV1:ICB", int_value, "num:01", mypicture, size);
// ... get the results
MK_INT retI = MqReadI_e(ctx); // expect ONE integer as result
// ... do some work
return MK_OK;
error: // default error-handler
return MkErrorStack_1X(ctx); // on error, build up the error-stack
}

Example-3: (in C) At the server, answer the service call

...
static MkErrorE SRV1(MQ_CTX const ctx, MK_PTR data) { // the name "SRV1" can be free chosen
// ... do some work
MK_INT myInt = MqReadI_e(ctx); // read a MK_INT value
MK_STRN myStr = MqReadC_e(ctx); // read a MK_STR value
MK_BUF myPic = MqReadU_e(ctx); // read a MkBuffer64S object to store the picture data
// ... do some work
MqSendSTART_E(ctx); // init the Send-Buffer object
MqSendI_E(ctx,int_ret); // return argument: a MK_INT value
error: // something is wrong, error back
return MqSendRETURN(ctx); // send the package as an answer of a previous service-call
}
MK_PTRB * MK_PTR
#define MqReadC_e(...)
#define MqReadU_e(...)

... or using the MqContextC HIGH API

...
static MkErrorE SRV1(MQ_CTX const ctx, MK_PTR data) { // the name "SRV1" can be free chosen
// ... do some work
MK_INT myInt = MqReadI_e(ctx); // read a MK_INT value
MK_STRN myStr = MqReadC_e(ctx); // read a MK_STR value
MK_BUF myPic = MqReadU_e(ctx); // read a MkBuffer64S object to store the picture data
// ... do some work
error:
return MqSend(ctx, "R", "I", int_ret); // send the package as an answer of a previous service-call
}

MqContextC SEND API ATOM

C-API: MqContextC_SendApi_Atom_C_API - append a native PRIMITIVE TYPE value to the send-data-package. …

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe value to appending
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendLONG(MQ_CTX ctx, MK_LONG val)

TOP

send the long native object to the send-data-package → API: MqSendLONG_RT

on 64bit use a SendW and on 32bit use a SendI

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe native long object to send
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
this is NON portable
See also
ReadLONG

enum MkErrorE MqSendL_FLAT(MQ_CTX ctx, MK_BFL val)

TOP

append a MkBufferListC object as flat list of items to the send-data-package object … → API: MqSendL_FLAT_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe pointer to an MkBufferListC object to send
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
SendL

enum MkErrorE MqSendV(MQ_CTX ctx, MK_FST printfmt, ... args)

TOP

append a vararg string to the send-data-package object … → API: MqSendV_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]printfmtis a c-string used as printf like format string

enum MkErrorE MqSendVL(MQ_CTX ctx, MK_FST printfmt, va_list var_list)

TOP

append a vararg string as va_list to the send-data-package object … → API: MqSendVL_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]printfmtis a c-string used as printf like format string
[in]var_lista variable argument list object

enum MkErrorE MqSendTT(MQ_CTX ctx, MK_BYT val)

The SendTT provide a single function for every PRIMITIVE TYPE

returncommand

C-API :

enum MkErrorE MqSendB(MQ_CTX ctx, MkBinaryR val)MqSendB_RT
enum MkErrorE MqSendC(MQ_CTX ctx, MK_STRN val)MqSendC_RT
enum MkErrorE MqSendD(MQ_CTX ctx, MK_DBL val)MqSendD_RT
enum MkErrorE MqSendF(MQ_CTX ctx, MK_FLT val)MqSendF_RT
enum MkErrorE MqSendI(MQ_CTX ctx, MK_INT val)MqSendI_RT
enum MkErrorE MqSendL(MQ_CTX ctx, MK_BFL val)MqSendL_RT
enum MkErrorE MqSendO(MQ_CTX ctx, MK_BOL val)MqSendO_RT
enum MkErrorE MqSendS(MQ_CTX ctx, MK_SRT val)MqSendS_RT
enum MkErrorE MqSendU(MQ_CTX ctx, MK_BUF val)MqSendU_RT
enum MkErrorE MqSendW(MQ_CTX ctx, MK_WID val)MqSendW_RT
enum MkErrorE MqSendY(MQ_CTX ctx, MK_BYT val)

MqSendY_RT

append a native PRIMITIVE TYPE value to the send-data-package. …

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe value to appending
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC SEND API BASICS

C-API: MqContextC_SendApi_Atom_C_API - append a native PRIMITIVE TYPE value to the send-data-package. …

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe value to appending
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendEND(MQ_CTX ctx, MQ_TOK token, MK_TIME_T timeout)

TOP

finish the send-data-block and call synchronous/asynchronous a remote-service … → API: MqSendEND_RT

calling a remote service and wait timeout seconds for an result. If timeout == 0 it is an asynchronous-service-call and if the timeout > 0 it is a synchronous-service-call.

service-call blocking timeout
synchronous yes timeout > 0
asynchronous no timeout == 0

blocking mean waiting max timeout seconds to finishing the service-call:

  • If the service-call is finished in less than timeout seconds… the results are available and can be processed.
  • If the service-call is NOT finished in timeout seconds… an timeout-error is created and the transaction will be canceled.

If an error was raised on the server during the service-processing… the following error-handling will be available

  1. on a synchronous-service-call the error will be the result of the service-call
  2. on a asynchronous-service-call with callback the error will be the result of the callback
  3. on a asynchronous-service-call without callback the error will be send asynchronous from the server to the client . On the client the error will be raised on the NEXT event-handlng-command or as background-error if the MqSetupS::BgError function was defined.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT=0)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
SendSYNC

enum MkErrorE MqSendEND_AND_CALLBACK(MQ_CTX ctx, MQ_TOK token, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MK_TIME_T timeout)

TOP

finish the send-data-block, call the remote service, do not-wait for the result but expect the result on a callback … → API: MqSendEND_AND_CALLBACK_RT

This function will never block and return immediately. Usually multiple SendEND_AND_CALLBACK are send and finally multiple ProcessEvent are called to wait for the results.

Example from route_mq.c (C) call a service using a callback

int i;
int flag[MQ_ROUTE_CTX_MAX] = {0};
// call for a "routing" setup/check using all rrctx from "rr->list" in parallel.
// -> use "flag" to check if a callback was called.
for (i=0; i<rr->num; i++) {
MQ_CTX rrctx = rr->list[i];
MqSendSTART_E(rrctx);
MqSendC_E(rrctx,routeCUR);
MqSendC_E(rrctx,service);
MqSendO_E(rrctx,isCreate);
MqSendO_E(rrctx,overwrite);
if (MkErrorCheckI(MqSendEND_AND_CALLBACK(rrctx,"_ROU",sRouteTool_CB,&flag[i],NULL,MK_TIMEOUT_DEFAULT))) {
pContextErrorCopy ( ctx,rrctx);
goto error;
}
}
// wait to finish all "calls" from obove - using "flag" to check if wait is still required.
for (i=0; i<rr->num; i++) {
MQ_CTX rrctx = rr->list[i];
while (flag[i] == 0) { // just be shure the CB is still "open=0"
if (MkErrorCheckI(MqProcessEvent(rrctx, MQ_WAIT_OWN, MK_TIMEOUT_DEFAULT))) {
pContextErrorCopy ( ctx,rrctx);
goto error;
}
}
}
#define MQ_ROUTE_CTX_MAX
maximum number of context-items in the return-array from RouteResolve …
Definition msgque_mq.h:5182
#define MqSendO_E(...)
#define MkErrorCheckI(err)

Be aware of the followig limitatitions if multiple SendEND_AND_CALLBACK are called with different ctx:

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]fCallthe function to process the service-call results
[in]callbacka user defined additional data-argument for the callback function (C-API only)
[in]fFreethe function to free the data-argument after use (C-API only)
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT= 0)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
(C-Only) if data is using memory from the local-call-frame (current proc) than the call-back is only valid if the return is at the local-call-frame -> leaving the local-call-frame create a core-dump in "pTransSetResultCB" on return !!

enum MkErrorE MqSendEND_AND_SUB(MQ_CTX ctx, MQ_TOK token, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MK_TIME_T timeout)

TOP

finish the send-data-block, call the remote service, do wait for the result and expect multiple sub-results on a callback … → API: MqSendEND_AND_SUB_RT

The goal of this service-call is, to split a big data-block into multiple pieces. A typical solution would be a database-application doing a select and sending EVERY row as a enum MkErrorE MqSend_SUB_RETURN(MQ_CTX ctx). At the end ONE final and EMPTY enum MkErrorE MqSendRETURN(MQ_CTX ctx) is used to delete the open transaction and finish the service call.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]fCallthe function to process the service-call results
[in]callbacka user defined additional data-argument for the callback function (C-API only)
[in]fFreethe function to free the data-argument after use (C-API only)
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT=MK_TIMEOUT_USER)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
By default the callback for the last item (enum MkErrorE MqSendRETURN(MQ_CTX ctx)) will only called if the package has an item or and an error… if the package is empty only the transaction will be closed.
See also
SendEND_AND_WAIT SendEND_AND_CALLBACK Send_SUB_RETURN SendRETURN

enum MkErrorE MqSendEND_AND_TRANSACTION(MQ_CTX ctx, MQ_TOK token, MQ_TOK callback, MK_TIME_T timeout)

TOP

finish the send-data-block, call the remote service to do a longterm-transaction-call … → API: MqSendEND_AND_TRANSACTION_RT

A longterm-transaction is a service-call with guaranteed delivery. guaranteed mean that the transaction is using the MqContextC STORAGE API to keep every step persistent being able to recover a step if something unexpected happen.

To link the result with the calling-environment a private transaction-item is used to save the calling-environment to the local-storage. If the local-storage is persistent, the calling-environment will even survive an application restart.
If the result from the public service-call arrives, the transaction-item will be extracted from the result and the private calling-environment will be initialized from the local-storage.

To create a persistent-transaction the MqContextC STORAGE API have to be setup as persistent. By default, an in-memory MqContextC STORAGE API is used.

The longterm-transaction-call has TWO results…

  • the FIRST result is a acknowledge that the longterm-transaction was stored in the remote database
  • the SECOND result is the result of the service-call

In difference to SendEND_AND_WAIT and SendEND_AND_CALLBACK a longterm-transaction-call have to survive an application restart. To achieve this goal… two features have to be available to process the results:

  • a transaction-callback as a service created with ServiceCreate
  • a transaction-item as a environment created with SendT_STARTSendT_END and stored into an internal database.

transaction-item

The transaction-item is the entry-id from the local internal database and is the public handle of the private data. If the transaction-item-private-data should be persistent (survive an application restart) the internal database have to be persistent using the Storage option.
The transaction-item-private-data requires a SendT_STARTSendT_END at the beginning of the send-data-package.
The list of data-items in the transaction-item-private-data have to be provided by the programmer and is used to initialise the environment in the callback (for example an external database-entry-id).
In the transaction-callback the transaction-item-private-data have to be extracted with ReadT_STARTReadT_END at the beginning of the read-data-package.

transaction-callback

The transaction-callback have to be a MqContextC_ServiceApi_Identifer defined with ServiceCreate in the application setup code (like IServerSetup) and have to be available after an application restart.

If an error is raised on the server during the database-insert the function will return this error immediately. During waiting for the return the event-loop is used to process other events. Use IEvent to add your tasks into the event loop.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]callbackthe MqContextC_ServiceApi_Identifer of the MqContextC_ServiceApi_Callback
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT=MK_TIMEOUT_USER)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

Example from MyTransaction.c make a logterm-transaction-call using the LOW and the HIGH api

#include "msgque_mq.h"

static enum MkErrorE callback( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MqReadT_START_E(mqctx);
  MK_STRN myPrivateHandle = MqReadC_e(mqctx);
  MqReadT_END(mqctx);
  MK_INT myServiceResult = MqReadI_e(mqctx);

  fprintf(stdout,"myPrivateHandle=%s, myServiceResult=%d\n", myPrivateHandle, myServiceResult);
  fflush(stdout);

error:
  return MkErrorStack_E(mqctx);
}

int main (int argc, MK_STRN argv[]) 
{
  MkRtSetup_NULL;

  MQ_CTX ctx = MqContextCreate(NULL,NULL);

  MqConfigSetName(ctx, "MyTransaction");

  // setup commandline arguments used for parsing
  MK_BFL args = MkBufferListCreateVC(argc, argv);

  // check if the '--token' option is available, default "SRVC"
  MK_STRN token = MkBufferListCheckOptionC_e(args, "--token", "SRVC", true);

  // connect to the server
  MqLinkCreate_E(ctx, args);

  // register callback
  MqServiceCreate_E(ctx, "CLB1", callback, NULL, NULL, NULL);
   
  // send block using the LOW-Api
  MqSendSTART_E(ctx);
  MqSendT_START_E(ctx);
  MqSendC_E(ctx, "Privat_Data_1");
  MqSendT_END_E(ctx);
  MqSendI_E(ctx, 11111);
  MqSendEND_AND_TRANSACTION_E(ctx, token, "CLB1", MK_TIMEOUT_DEFAULT);
   
  // send block using the HIGN-Api -> same as above, but shorter
  char buffer[30];
  sprintf(buffer, "%s:(C)I",token);
  MqSend_E(ctx, "T", "CLB1", buffer, "Privat_Data_2", 22222);
   
  // now we wait for exact ONE result of the "ctx"
  MqProcessEvent_E(ctx, MQ_WAIT_OWN, MK_TIMEOUT_DEFAULT);

error:
  MkBufferListDelete(args);
  // delete the context using the libmqmsgque APPLICATION-DTOR function "MqExit_1"
  MqExit_1(ctx);
}

enum MkErrorE MqSendEND_AND_WAIT(MQ_CTX ctx, MQ_TOK token, MK_TIME_T timeout)

TOP

finish the send-data-block, call the remote service and wait for result… → API: MqSendEND_AND_WAIT_RT

If an error is raised on the server during the service-processing the function will return this error immediately. During waiting for the return the event-loop is used to process other events. Use IEvent to add your tasks into the event loop.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]timeoutin seconds until a timeout-error is raised (possible values like ProcessEvent) (MK_TIMEOUT_DEFAULT=MK_TIMEOUT_USER)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendSTART(MQ_CTX ctx)

TOP

initialize the send-data-package. … → API: MqSendSTART_RT

This function have to be the first statement in a send-data-block. If the socket is closed or down the connection is established with a LinkConnect. Be aware that during LinkConnect the event loop is entered and your read-data-package may become invalid.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendSYNC(MQ_CTX ctx)

TOP

The is used to garantee that all pending asynchronous-service-call are processed. … → API: MqSendSYNC_RT

The asynchronous-service-call is defined at: MqContextC_Service_C_API.

In a mass sending of an asynchronous-sevice-request:

for (int i=0; i<1000; i++} {
MqSend(mqctx,"E","B",data(i));
}
MqSendSYNC(mqctx);
#define MqSendSYNC(...)

The last SendSYNC garantee the all previous asynchronous-service-calls are finished.

MqContextC SEND API BLOCK

C-API: MqContextC_SendApi_Atom_C_API - append a native PRIMITIVE TYPE value to the send-data-package. …

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe value to appending
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendL_END(MQ_CTX ctx)

TOP

finish to append an embedded body-list-item to the send-data-package. … → API: MqSendL_END_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendL_START(MQ_CTX ctx)

TOP

start to append an embedded body-list-item to the send-data-package. … → API: MqSendL_START_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Example:
: create a body-list-item
MqSendL_START(send); // start a list-item
MqSendI(send,myInt); // first list-sub-item
MqSendC(send,"myString"); // second list- sub-item
// ... do additional MqSend?
MqSendL_END(send); // finish a list-item

enum MkErrorE MqSendT_END(MQ_CTX ctx)

TOP

closed a longterm-transaction-item … → API: MqSendT_END_RT

finish a setup-block started with SendT_START. read more at SendEND_AND_TRANSACTION.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendT_START(MQ_CTX ctx)

TOP

open a longterm-transaction-item … → API: MqSendT_START_RT

Every longterm-transaction-item have to be closed with SendT_END. Between SendT_START and SendT_END, a non specified number of other items can be added. These items are saved in a local database (in-memory or file-based) and the rowid is send as transaction-id to the link-target. By Default only the in-memory-database is used. To switch to a file-based database use the StorageOpen function.

Example from server.c make a service-call with transaction-support

static enum MkErrorE
Ot_TRNS ( MQ_CALLBACK_SERVICE_CALL_ARGS )
{
  struct ServerCtxS *srvctx = (struct ServerCtxS*) mqctx;
  MK_INT i;

  MqSendSTART_E (mqctx);
  MqSendT_START_E (mqctx);
  MqSendI_E (mqctx, 9876);
  MqSendT_END_E (mqctx);
  MqReadI_E (mqctx, &i);
  MqSendI_E (mqctx, i);

  MqSendEND_AND_TRANSACTION_E (mqctx, "ECOI", "TRN2", MK_TIMEOUT_USER);

  MqProcessEvent_E (mqctx, MQ_WAIT_ONCE, 10);

  MqSendSTART_E (mqctx);
  MqSendI_E (mqctx, srvctx->i);
  MqSendI_E (mqctx, srvctx->j);
error:
  return MqSendRETURN (mqctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC SEND API RETURN

C-API: MqContextC_SendApi_Atom_C_API - append a native PRIMITIVE TYPE value to the send-data-package. …

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]valthe value to appending
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendERROR(MQ_CTX ctx)

TOP

send the data from the MkErrorC to the link target . … → API: MqSendERROR_RT

If an error is available the error-number and the error-text is send to the link target. After send the error is reset. This function only raise an error if the sending self fails.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSendRETURN(MQ_CTX ctx)

TOP

finish the send-data-block on the server and optional return the results. … → API: MqSendRETURN_RT

Every service-handler have to use this function at the end to return the results or the error. If an error is returned the local MkErrorC is reset. The following behaviour is used:

  • if a shortterm transaction is ongoing this function return the data or the error to the link target
  • if the answer does not return any data no previous SendSTART is required.
  • if no transaction is ongoing this function does just return. If an error is available report an asynchronous error to the link target.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqSend_SUB_RETURN(MQ_CTX ctx)

TOP

return Sub-Data-Blocks required by SendEND_AND_SUB … → API: MqSend_SUB_RETURN_RT

Every service-handler CAN use this function at the end of a data block if the caller used SendEND_AND_SUB to initiate the service call. SendEND_AND_SUB will block until ithe final enum MkErrorE MqSendRETURN(MQ_CTX ctx) was send.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC SERVICE API

NAVI: TOP , up

ServiceCheckTokenin an ongoing-service-call compare the MqContextC_ServiceApi_Identifer with token on equity …
ServiceCreatecreate a link between a service-token and a service-callback
ServiceDeletedelete a service. …
ServiceGetTokenget the MqContextC_ServiceApi_Identifer from an ongoing-service-call
ServiceIsTransactioncheck if the ongoing-service-call belongs to a transaction …
ServiceProxycreate a service to link a master-context with a slave-context. …
ServiceProxyCtxsame as ServiceProxy but use an MqContextC as input.
ServiceProxyCtxExistscheck if service who belongs to token is a proxy-service
ServiceProxyRoundRobincreate a proxy-service using Round-Robin as load-balancer …
ServiceStorage

setup a service listen on a MqContextC_ServiceApi_Identifer and save all read-data-package into the STORAGE

MqContextC SERVICE API DETAILS

C-API: MqContextC_Service_C_API - create and manage a service …

To provide a service is the main purpose of a server and the main-purpose of a client/server connection is to call a service and to process the result.
A service can be defined on the server or on the client. On the server a service can be initial setup with IServerSetup method and finally cleanup with IServerCleanup.

‍A service is created with the ServiceCreate and deleted with the ServiceDelete.

A service can be created and deleted during the entire life-cycle of the server or the client. If the server/client-context is deleted all services of the are deleted also.

‍A ServiceDelete is not required.

Creating or deleting a service is like granting or revoking the right to access a single feature.

eventloop

To receive a data-package on a service the event-loop have to be active. The event-loop ia always active on an synchronous-service-call . On a server the event-loop is started with ProcessEvent at startup.
synchronous-service-call
A synchronous-service-call always block and enter the event-loop to wait for an answer
asynchronous-service-call
A asynchronous-service-call always return immediately and the possible result is received on a callback

callback

A callback is the function called by a service and required to receive data from remote.
A callback is created with ServiceCreate or is part of the service-call.
A callback can be a service-identifer or a service-callback.
service-call with callback
SendEND_AND_CALLBACK, SendEND_AND_SUB, SendEND_AND_TRANSACTION
service-call without callback
SendEND, SendEND_AND_WAIT

Example from MyServer.c define the service SRV1 on the server-link-setup

#include "common.h"

// service to serve all incoming requests for token "HLWO"
static enum MkErrorE MyFirstService ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MqSendSTART_E (mqctx);
  MqSendV_E (mqctx, "%s World", MqReadC_e(mqctx));
error:
  return MqSendRETURN(mqctx);
}

// define a service as link between the token "HLWO" and the callback "MyFirstService"
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  return MqServiceCreate(mqctx,"HLWO", MyFirstService, NULL, NULL, NULL);
}

// package-item
enum MkErrorE
MyServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  MQ_CTX const mqctx = *contextP = MqContextCreate(NULL,tmpl);
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
  return MK_OK;
}

// package-main
int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // setup commandline arguments for later use

  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // create "MyServer" factory… and make it to the default.
  MqFactoryDefault(
    MqFactoryAdd(MK_ERROR_PANIC, MyServerFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "MyServer")
  );
  // inspect commandline-argument for the "factory" to choose… and create a object
  MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);

  // start listen for incoming call's
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}

MK_BOOL MqServiceCheckToken(MQ_CTX ctx, MQ_TOK token)

TOP

in an ongoing-service-call compare the MqContextC_ServiceApi_Identifer with token on equity … → API: MqServiceCheckToken

Parameters
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
Returns
a boolean value, MK_YES or MK_NO

enum MkErrorE MqServiceCreate(MQ_CTX ctx, MQ_TOK token, MqServiceCallbackF fCall, MK_CBP callback, MqDataFreeF fFree, MkMarkF fMark)

TOP

create a link between a service-token and a service-callback … → API: MqServiceCreate_RT

The servive-token (e.g. MqContextC_ServiceApi_Identifer) have to be unique but the service-callback (e.g. MqServiceCallbackF) not. If a service-callback is not unique than this is called an alias, use MQ_TOK MqServiceGetToken(MQ_CTX ctx) to get the current token for an incoming-service-call.

The service-callback have to be callable by the server and/or by the child and/or the slave context. A static-callback is a good choice to achive this goal.

The filter, a slave-context, is setup with the initial factory using the initial-class (MqContextC) usually different from the server-class (MyServer…). The filter need the service-callback, usually shared with the server, to report a filter-message to the server.
To distinguish the server and the filter the following functions are used
(all function cann be called as either server or filter context):

Example from Filter6.c setup the services for server and filter

  MqServiceCreate_E   (mqctx, "LOGF", LOGF, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "EXIT", EXIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "SOEX", SOEX, NULL, NULL, NULL);
  MqServiceStorage_E  (mqctx, "PRNT");
  MqServiceStorage_E  (mqctx, "PRN2");
  MqServiceCreate_E   (mqctx, "+ALL", FiIn, NULL, NULL, NULL);
  MqServiceCreate_E   (ftr,   "WRIT", WRIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "WRIT", WRIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "CLTI", CLTI, NULL, NULL, NULL);
  MqServiceProxy_E    (ftr,   "WRT2", MQ_SLAVE_MASTER);
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]fCallthe C-function to process the incoming service-request (C-API only)
[in]callbackthe user defined callback as data-argument for the C-function fCall
[in]fFreethe function to free the data-argument after use (C-API only)
[in]fMarkthe function to mark the data-argument during garbage-collection (C-API only)
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
the link-setup (LinkCreate or LinkCreateChild) have to done before using this function

enum MkErrorE MqServiceDelete(MQ_CTX ctx, MQ_TOK token)

TOP

delete a service. … → API: MqServiceDelete_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MQ_TOK MqServiceGetToken(MQ_CTX ctx)

TOP

get the MqContextC_ServiceApi_Identifer from an ongoing-service-call … → API: MqServiceGetToken

This function is needed on the server to process a service-request defined as +ALL or as an alias to extract the current MqContextC_ServiceApi_Identifer.

Parameters
[in]ctxthe MqContextS instance to work on
Returns
the MqContextC_ServiceApi_Identifer

MK_BOOL MqServiceIsTransaction(MQ_CTX ctx)

TOP

check if the ongoing-service-call belongs to a transaction … → API: MqServiceIsTransaction

A service-call can be with-transaction (return MK_YES if the package was send with SendEND_AND_WAIT or SendEND_AND_CALLBACK) or can be without-transaction (return MK_NO if the package was send with SendEND)

Parameters
[in]ctxthe MqContextS instance to work on
Returns
a boolean value, MK_YES or MK_NO

enum MkErrorE MqServiceProxy(MQ_CTX ctx, MQ_TOK token, MQ_SLAVE_ID id)

TOP

create a service to link a master-context with a slave-context. … → API: MqServiceProxy_RT

This function is used to create a proxy-service to forward the body-data from the read-data-package of the master to the send-data-package of the slave. The data is not changed. This function support the reverse-operation also. If the ctx is a master-context than the data is send to slave identified by id. If the ctx is a slave-context than the data is send to the master of the slave.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]idthe SlaveId to unique identify the master/slave link
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqServiceProxyCtx(MQ_CTX ctx, MQ_TOK token, MQ_CTX target)

TOP

same as ServiceProxy but use an MqContextC as input. → API: MqServiceProxyCtx_RT

See also
ServiceProxy

MK_BOOL MqServiceProxyCtxExists(MQ_CTX ctx, MQ_TOK token, MQ_CTX target)

TOP

check if service who belongs to token is a proxy-service → API: MqServiceProxyCtxExists

This is used for route (RouteDelete) to identify the service-usage

See also
ServiceProxy

enum MkErrorE MqServiceProxyRoundRobin(MQ_CTX ctx, MQ_TOK token, MK_STRN ident)

TOP

create a proxy-service using Round-Robin as load-balancer … → API: MqServiceProxyRoundRobin_RT

This function is used to create a proxy-service to forward the body-data from the read-data-package of the master-context to the send-data-package of the slave-context. The data is not changed. This function support the reverse-operation also. If the ctx is a master-context than the data is send to one of the slave-context identified by ident. If the ctx is a slave-context than the data is send to the master-context of the slave.

The Round-Robin-Load-Balancer is only used for the direction from the master-context to the slave-context if the name-resolution return multiple target-context for the single ident.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
[in]identthe targetIdent used to select a list slave-Context for the Round-Robin
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqServiceStorage(MQ_CTX ctx, MQ_TOK token)

TOP

setup a service listen on a MqContextC_ServiceApi_Identifer and save all read-data-package into the STORAGE … → API: MqServiceStorage_RT

In a shortterm-transaction-synchronous-service-call the service will return an empty data package. In a longterm-transaction-synchronous-service-call the data will return as normal.

Example from Filter6.c using ServiceStorage to store all packages from service PRNT and PRN2 into database

  MqServiceCreate_E   (mqctx, "LOGF", LOGF, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "EXIT", EXIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "SOEX", SOEX, NULL, NULL, NULL);
  MqServiceStorage_E  (mqctx, "PRNT");
  MqServiceStorage_E  (mqctx, "PRN2");
  MqServiceCreate_E   (mqctx, "+ALL", FiIn, NULL, NULL, NULL);
  MqServiceCreate_E   (ftr,   "WRIT", WRIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "WRIT", WRIT, NULL, NULL, NULL);
  MqServiceCreate_E   (mqctx, "CLTI", CLTI, NULL, NULL, NULL);
  MqServiceProxy_E    (ftr,   "WRT2", MQ_SLAVE_MASTER);
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]tokenthe MqContextC SERVICE API to identify the service
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MqContextC SLAVE API

NAVI: TOP , up

SlaveCheckcheck if slave-id is valid
SlaveCreatecreate a master/slave link between the master-parent-context and the slave-parent-context …
SlaveDeleteDelete a slave object from a master/slave link identified by id. …
SlaveGetget the slave-context from a master-context
SlaveGetFilterget the filter-ctx or the master-ctx
SlaveGetMasteropposite function of SlaveGetFilter
SlaveGetProxyon slave return the master and on master return the slave identified by id.
SlaveIsis the context a slave-context ? …
SlaveWorker

create a master/slave link using the image of the ctx object self. …

MqContextC SLAVE API DETAILS

C-API: MqContextC_SlaveApi_C_API - create and manage a slave context …

The master-slave-link is used to create a mesh of nodes defined by different parent-context. The master control the slave.

The master-slave-link is used to perform the following tasks:

  • report error messages from the slave-context to the master-context
  • to create a slave-child-context if a master-child-context is created
  • to delete a slave-context if a master-context is deleted

In difference to the client-server-link the master-slave-link connect two independent parent-context in the same process or thread (e.g. node). This leads to the restriction that only the master-context can be a server-context because only one server-context per node is possible.

   node-0   |           node-1/2        |   node-3/4/5
===================================================================

| <- client/server link -> | <- client/server link -> |

             | <-- master/slave link --> |

                           |- client1-0 -|- server3 ...
             |-  server1  -|
             |             |- client1-1 -|- server4 ...
  client0-0 -|
             |-  server2  -|- client1-2 -|- server5 ...

Definition of the "master-context"

  • the master-context is a parent-context without a child-context available.
  • the master-context is a client-context or a server-context.
  • the link between the master-context and the slave-context is done using SlaveWorker or SlaveCreate

Definition of the "slave-context"

  • the slave-context is a parent-context without a child-context available.
  • the slave-context is a client-context.
  • the slave-context lifetime is controlled by the master-context.
  • the slave-context report all error-messages to the master-context.
  • the slave-context is identified by a unique-slave-id starting with 0.
  • a special form of a slave-context is a worker-context

Definition of the "worker-context"

  • the worker-context is a slave-context using the image of the master-context self.
  • the master-context can be a server-context or a client-context.
  • the worker-context is created using SlaveWorker
  • the worker-context is identified by a unique-slave-id starting with 0.

Definition of the "slave-id"

  • the slave-id is defined at enum MqSlaveE
  • a slave is identified in his master-context by a slave-id
  • the slave-id work like a defined well-known-port-number in /etc/services
  • the slave-id is an integer value with valid values > 0
  • it is a good practice to plan the usage of your slave-id(s)
  • slave
    slave-id value definition
    MQ_SLAVE_MAX 1024 internal: the maximum slave-id … .
    MQ_SLAVE_USER 10 internal: start of user-defined-slave-id .
    MQ_SLAVE_LOOPBACK 0 internal: the loopback-slave-id, (call my own services) .
    MQ_SLAVE_FILTER 1 internal: the filter-slave-id, (on a master get the filter-slave) .
    MQ_SLAVE_MASTER 1 internal: the master-slave-id, (on a slave get the master) .
    MQ_SLAVE_OTHER 1 internal: on the master-ctx get the slave-ctx and on the slave-ctx get the master-ctx .
  • range
    range definition
    0 <= slave-id < MQ_SLAVE_MAX range of valid slave-id's
    0 <= slave-id < MQ_SLAVE_USER internale usage
    MQ_SLAVE_USER <= slave-id < MQ_SLAVE_MAX external usage

Definition of the "LOOPBACK" (0) slave

  •    client   |           server            |
    ===========================================
    
    | <--- client/server --->  | <-- loop --> |
    
                | <------ master/slave -----> |
    
      client -- | -- server -- | -- client -- #
                       ==             ==      #
                     server -- | -- client -- #
  • the loopback has always the slave-id = 0 .
  • the loopback has the same class as the parent, if reflection is not available the FactoryInitial is used.
  • the loopback is used to call a service on the same process or thread.
  • the loopback is a special filter without an additional process or thread to be started.
  • the loopback is only internal accessible
  • the service called by the loopback need the same attention as the service called by the filter, the context of the service is the loopback-context.
  • the loopback can call ServiceCreate to create a new link between a service-token and a service-method, by default all services from the master-context (the owner of the loopback) are also accessible by the loopback.
  • in the service use SlaveGetMaster to get the master-context from the loopback-context.
  • Example from MyLoopServer.c create a new loop-server
    #include "common.h"
    
    // [MyLoopServerC_Define]
    typedef struct MyLoopServerS {
      struct MqContextS mqctx;    ///< link to the \libmqmsgque object
      #define mydata_size 30
      char mydata[mydata_size];   ///< define the "mydata" attribute
    } MyLoopServerC;  
    // [MyLoopServerC_Define]
    
    // the MyLoopServerC class-type
    static MkThreadLocal MK_TYP MyLoopServerCTT = NULL;
    
    // service to serve all EXTERNAL requests for token "HLWO"
    static enum MkErrorE HLWO_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // get the "loopback" context
      MQ_CTX loop = MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK);
      // call the LOOP service on the SAME server
      MqSend_E(loop,"W","LOOP");
      // answer HLWO with string-return from LOOP
      MqSend_E(mqctx, "R", "C", MqReadC_e(loop));
      return MK_OK;
    error:
      return MqSendRETURN(mqctx);
    }
    
    // service to serve all INTERNAL requests for token "LOOP
    static enum MkErrorE LOOP_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // get the "master" context 
      MyLoopServerC* master = (MyLoopServerC*)MqSlaveGetMaster(mqctx);
      // answer LOOP with data from MASTER->mydata attribute
      return MqSend(mqctx, "R", "C", master->mydata);
    }
    
    // define a service as link between the token "HLWO" and the callback "HLWO_srv"
    static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
      // EXTERNAL: link the "HLWO" service with "HLWO_srv"
      MqServiceCreate_E(mqctx, "HLWO", HLWO_srv, NULL, NULL, NULL);
      // INTERNAL: link the "LOOP" service with "LOOP_srv"
      MqServiceCreate_E(MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK), "LOOP", LOOP_srv, NULL, NULL, NULL);
      return MK_OK;
    error:
      return MkErrorStack_1X(mqctx);
    }
    
    // [MyLoopServerC_Create]
    enum MkErrorE
    MyLoopServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
    { 
      // create new instance using the MyLoopServerCTT class-type
      MQ_CTX const mqctx = *contextP = MqContextCreate(MyLoopServerCTT,tmpl);
    
      // initialize the new context
      MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
    
      // cast the libmqmsgque-context into the MyLoopServerC-context
      MyLoopServerC* mqctxC = (MyLoopServerC*)mqctx;
    
      // initialize the "mydata" attribute
      strncpy(mqctxC->mydata,"Hello World",mydata_size);
      mqctxC->mydata[mydata_size-1] = '\0';
    
      return MK_OK;
    }
    // [MyLoopServerC_Create]
    
    int main (int argc, MK_STRN argv[]) 
    {
      MqRtSetup_NULL;
    
      // [MyLoopServerC_Init]
      // initialize the MyLoopServer class-type with existing MqContextC_TT class-type
      MyLoopServerCTT = MkTypeDup2(MqContextC_TT,"MyLoopServerC");
      MyLoopServerCTT->objsize = sizeof(struct MyLoopServerS);
      // [MyLoopServerC_Init]
    
      // setup commandline arguments for later use
      MK_BFL largv = MkBufferListCreateVC(argc, argv);
      MQ_CTX mqctx = NULL;
    
      // create "MyLoopServer" factory… and make it to the default.
      MqFactoryDefault(MqFactoryAdd_2(MyLoopServerFactory,"MyLoopServer"));
      // inspect commandline-argument for the "factory" to choose… and create a object
      MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);
    
      // start listen for incoming call's
      MqLinkCreate_E (mqctx, largv);
      MqCheckForLeftOverArguments_E (mqctx, largv);
      MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
    error:
      MkBufferListDelete(largv);
      MqExit_1(mqctx);
    }
    

Performance analyse

The performance-test is created with:
  • pipe
    • Nhi1Exec perfclient.c --parent --wrk ? @ perfserver.c
  • spawn, fork, thread
    • Nhi1Exec -r=uds perfserver.c --spawn|fork|thread
    • Nhi1Exec -r=uds perfclient.c --parent --wrk ?
  • the number of workers are set with the –wrk option
  • the cpu is a xeon with 4/8
  • the performance is calculated as worker-context-created / time-in-sec with a ~2sec (default) measurement period.
performance-test code:
  • The test-setup is done as:
      perfclient                                worker                            perfserver
      ==========                                ======                            ==========
      |
      |- loop --wrk x
        |- MqSlaveWorker(...)               ->  worker[1] 
        |- MqSend(worker[1],"E","STR0..")   ->  PerfWorker_SRT0(...)
                                                |- loop endless
                                                  |- MqContextCreate(...)
                                                  |- MqLinkCreate(...)      <->   MqContextCreate(...)
                                                  |- MqContextDelete(...)   <->   MqContextDelete(...)
      |- sleep x sec
      |- loop --wrk x
        |- MqSend(worker[1],"C"..,"END0")   ->  PerfWorker_END0(...)
        |                                       |- stop loop
        |- "callback" - add number to all   <-  |- return #context 
performance-test results:
  • results generated using the debug environment
    setup –wrk # worker-context performance info
    pipe 1 2500 1000 the pipe start a new worker-context with spawn
    spawn 1 2500 <1000 same as pipe but use network-protocoll
    fork 1 3800 4000 the fork is faster than spawn
    thread 1 16500 9000 the thread is faster than fork
    pipe 4 8000 4500 the worker scale linear up to number of processors
    spawn 4 7600 <4500 -
    fork 4 23200 11500 -
    thread 4 55500 27500 -
    pipe 8 10000 5500 the additional scaling up to the max hyper-threading does not really help
    spawn 8 9100 <5500 -
    fork 8 23200 11500 -
    thread 8 55500 27500 -

MK_BOOL MqSlaveCheck(MQ_CTXN ctx, MQ_SLAVE_ID id)

TOP

check if slave-id is valid → API: MqSlaveCheck

Parameters
[in]ctxthe master-context as PARENT or CHILD
[in]idthe SlaveId to unique identify the master/slave link
Returns
boolean true = valid or false = invalid

enum MkErrorE MqSlaveCreate(MQ_CTX ctx, MQ_SLAVE_ID id, MQ_CTX slave)

TOP

create a master/slave link between the master-parent-context and the slave-parent-context … → API: MqSlaveCreate_RT

The slave-context have to be a sub-class of MqContextC and is owned by the master-context. Owned mean that no other external references should be used.
The slave-context will be deleted if the master-context is deleted and the slave-context will create a child-context if the master-context create a child context.

Example from server.cs with reflection support... only the class is required :

Client clt = new Client();
clt.LinkCreate(ConfigGetStartAs());
SlaveCreate (id, clt);

Example from server.cc without reflection support... the factory is required :

MqFactoryCT<Client>::Add("client");

and the factory is used to create the object :

Client *clt = MqFactoryCT<Client>::Get("client")->New();
clt->LinkCreate(ConfigGetStartAs());
SlaveCreate (id, clt);
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe master context object as PARENT without a CHILD
[in]idthe SlaveId to unique identify the master/slave link
[in]slavethe slave context object as CLIENT-PARENT without a CHILD
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
SlaveGet

enum MkErrorE MqSlaveDelete(MQ_CTX ctx, MQ_SLAVE_ID id)

TOP

Delete a slave object from a master/slave link identified by id. … → API: MqSlaveDelete_RT

By default the slave-context object will be deleted if the master-context is deleted. Use this function to delete the parent-slave-context explicit and brake the master/slave link. If id is invalid nothing will happen. It is an error to delete a child-slave-context.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe master context object as PARENT without a CHILD
[in]idthe SlaveId to unique identify the master/slave link
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
it is still possible to delete a child-slave-context using LinkDelete but this will break the internal master/slave order.

enum MkErrorE MqSlaveGet(MQ_CTX ctx, MQ_SLAVE_ID id, MQ_CTX* ctx_out)

TOP

get the slave-context from a master-context … → API: MqSlaveGet_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe master-context as PARENT or CHILD
[in]idthe SlaveId to unique identify the master/slave link
[out]ctx_outthe slave-context or NULL on error
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
an error is raised if id is not valid or ctx is not a master-context.

enum MkErrorE MqSlaveGetFilter(MQ_CTX ctx, MQ_CTX* ctx_out)

TOP

get the filter-ctx or the master-ctx … → API: MqSlaveGetFilter_RT

The functions SlaveGetFilter, SlaveGetMaster and SlaveGetProxy have the same purpose. A filter-pipeline has two ctx, one on the left and one on the right. The left-ctx is linked with the master-ctx and the right-ctx is linked to the slave-ctx. This function return the ctx wanted or an error if NOT available. The search is done using the following order:

  1. return ctx if ctx is the wanted ctx
  2. return master-ctx or filter-ctx
  3. return a "context not available" error
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]ctx_outthe ctx or NULL on error
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

MQ_CTX MqSlaveGetMaster(MQ_CTX ctx)

TOP

opposite function of SlaveGetFilter → API: MqSlaveGetMaster

Attention
if no master is available, a NULL is returned

enum MkErrorE MqSlaveGetProxy(MQ_CTX ctx, MQ_SLAVE_ID id, MQ_CTX* ctx_out)

TOP

on slave return the master and on master return the slave identified by id. → API: MqSlaveGetProxy_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe master or slave-context as PARENT or CHILD
[in]idthe SlaveId to unique identify the master/slave link
[out]ctx_outthe other-context or NULL on error
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
an error is raised if id is not valid

MK_BOOL MqSlaveIs(MQ_CTXN ctx)

TOP

is the context a slave-context ? … → API: MqSlaveIs

Parameters
[in]ctxthe MqContextS instance to work on
Returns
a boolean value, MK_YES or MK_NO

enum MkErrorE MqSlaveWorker(MQ_CTX ctx, MQ_SLAVE_ID id, MK_STRN fct, MK_BAC args)

TOP

create a master/slave link using the image of the ctx object self. … → API: MqSlaveWorker_RT

The slave-context is started as an independent process or thread based on the StartAs argument.
The start of a "worker" can be done at:

  • context-creation in the Factory or the class-constructor
  • link-creation in the IServerSetup method
  • service-call in the client-service-request (starting worker one-the-fly)

Example from server.c create a worker in a service-callback reading arguments from the service

MK_BFL argv = NULL;
argv = MqReadALL_e (master);
MkBufferListAppendC(argv, "--name");
MkBufferListAppendV(argv, "wk-cl-%d", master_id);
MkBufferListAppendC(argv, "@");
MkBufferListAppendC(argv, "--name");
MkBufferListAppendV(argv, "wk-sv-%d", master_id);
MqSlaveWorker_E (master, master_id, factory, argv);
error:
return MqContextErrorCopy(errorctx,master);
#define MkBufferListAppendC(...)
#define MkBufferListAppendV(...)
#define MkRtSetup_NULL
#define MqSlaveWorker_E(...)
#define MqReadALL_e(...)
#define MqContextErrorCopy(...)
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe master context object as PARENT without a CHILD
[in]idthe SlaveId to unique identify the master/slave link
[in]fctthe MqFactoryS::originalIdent or NULL or '\0' or "WORKER".
if ident is NULL or '\0' or WORKER the factory of ctx will be used
if ident is MqFactoryS::originalIdent the factory defined will be used
[in]argscommand-line arguments passed to the worker-client or the worker-server. all arguments prior the first @ token are added to the worker-client and the other arguments to the worker-server.
example: --debug 5 --name hello @ --name myserver
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
~ A slave-worker can only be crated in a parent-context.
~ The args MkBufferListC is comsumed by the SlaveWorker and is EPMTY afterwords.

MqContextC STORAGE API

NAVI: TOP , up

StorageCloseclose the storage. …
StorageCountcount the number of storage-rows
StorageDecrRefdecrease the internal refCount lock of the database-entry
StorageDeletedelete the storage-row identified by the transLIdP_inout
StorageErrCntincrement and return the database row-error-count for the row defined with transLId
StorageExportexport the read-data-package into the STORAGE
StorageImportimport the storage-package into the read-data-package
StorageIncrRefincrease the internal refCount lock of the database-entry
StorageLoglog the storage the status of the open transactions
StorageOpenswitch to a file-based-transaction-database
StorageResolve

extract the context->link.protect.rmtTransLId entry from the database

MqContextC STORAGE API DETAILS

C-API: MqContextC_StorageApi_C_API - setup and manage a storage used to persist data-packages

The storage is divided into: INTERNAL and EXTERNAL storage. Only the read-data-package can be stored or dumped into the storage.

The read-data-package is saved into the storage using:

ServiceStorage setup a service listen on a MqContextC_ServiceApi_Identifer and save all read-data-package into the STORAGE
StorageExport export the read-data-package into the STORAGE

The read-data-package is restored from the storage using:

StorageImport import the storage-package into the read-data-package
ProxyForward send the entire read-data-package-data to the link-target
All this usually happen in an Event Handler

Some important facts of the storage-feature:

  • The internal-storage depends on SQLite.
  • The package-storage can be used to save all kind of package-data.
  • The longterm-transaction-package-data is allways saved into storage.
  • By default only an in-memory storage is in use, but this can be changed with StorageOpen or Storage
  • An entire service-call can be saved with ServiceStorage

The following internal storages are supported:

default
The default-storage is set with the configuration parameter --storage fileName and defaults to "#memdb#". If a package have to be saved into the storage and the storage is not open the default-storage id used. The open will always be performed. If an explicit storage is required the default can be changed or a storage can explicit be opened with StorageOpen. Keep in mind that the default-storage is a per-context configuration but only one storage per process or thread is currently supported.
memdb
This is the default storage and can be set explicitly with StorageOpen using the "#memdb#" parameter.
tmpdb
This storage is like an in-memory-storage but export data to the TEMPORARY filesystem if the application run out of memory. This storage can explicit be set with StorageOpen with the parameter "#tmpdb#".
filedb
This storage always work on files. Only this storage is persistent and can explicit be set with StorageOpen with the storageFile parameter.

Performance analyse:

  • The performance is tested with: Nhi1Exec perfclient.c --all --storage VALUE @ perfserver.c.
  • The parameter VALUE is set to #memdb#, #tmpdb# or a filedb file.
  • If –storage is not set the filedb database is used together with an internal file-name.
database performance host crash application crash info
memdb 30.000 data lost data lost non persistent
tempdb < 30.000 data lost data lost uses memory and/or temporary file
filedb (mem) 10.000 data lost data safe in memory filesystem
filedb (disc) 50 data safe data safe disc-speed is the key factor

enum MkErrorE MqStorageClose(MQ_CTX ctx)

TOP

close the storage. … → API: MqStorageClose_RT

the next storage request will open the storage again with the location from Storage

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqStorageCount(MQ_CTX ctx, MQ_LTR* cnt_out)

TOP

count the number of storage-rows … → API: MqStorageCount_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]cnt_outnumber of rows, OLL if nothing is available
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqStorageDecrRef(MQ_CTX ctx, MQ_LTR transLId)

TOP

decrease the internal refCount lock of the database-entry → API: MqStorageDecrRef_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]transLIdstorage-id … return from StorageImport
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
StorageImport, StorageIncrRef

enum MkErrorE MqStorageDelete(MQ_CTX ctx, MQ_LTR* transLIdP_inout)

TOP

delete the storage-row identified by the transLIdP_inout … → API: MqStorageDelete_RT

The transLIdP_inout is the value returned by a previous StorageImport. If transLIdP_inout is NULL than OLL is used. StorageImport and StorageDelete work together link an transaction and every successfull transcation have to delete the transLIdP_inout out of the storage. After sucessfull delete the transLIdP_inout is set to 0LL, on error the initial value is unchanged.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in,out]transLIdP_inoutpointer to storage-id to delete, will be 0LL on success
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqStorageErrCnt(MQ_CTX ctx, MQ_LTR transLId, MK_INT* cnt_out)

TOP

increment and return the database row-error-count for the row defined with transLId → API: MqStorageErrCnt_RT

The storage is typical used in the following workflow:

<----- AT CALLING CLIENT ----->|<----- AT RECEIVING SERVER ----->
                               |
    *setup transaction         |
    make service-request      -->    *start service-handler
                               |     save request into storage
    wait for confirmation     <--    confirm data receiving
                               |     *stop service-handler

  ====================  enter event loop  =====================

                               |     *start event-handler
                               |     load reqest from storage
                               |     process data
    *start transaction        <--    send result-data
    process result-data        |     *stop event-handler
    *stop transaction          |

Example Filter6 - store incoming packages into storage

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]transLIdstorage-id … return from StorageImport
[out]cnt_outthe new value or -1 on error
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqStorageExport(MQ_CTX ctx, MQ_LTR* ltid_out)

TOP

export the read-data-package into the STORAGE … → API: MqStorageExport_RT

The export include all data required to setup a read-data-package later again. After import with StorageImport the read-data-package and the environment will be set as it was on StorageExport

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]ltid_outif ltid_out != NULL return the storage-id
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
DumpExport, StorageImport

enum MkErrorE MqStorageImport(MQ_CTX ctx, MQ_LTR* transLIdP_inout)

TOP

import the storage-package into the read-data-package … → API: MqStorageImport_RT

Select the read-data-package from the database using the transLIdP. Only a package with refCount = 0 will be selected.
After selection the refCount is incremented and the next call to StorageImport using the same transLId will fail.
StorageImport is used together with StorageDelete or StorageDecrRef to delete the selected package from database or to undo the select.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in,out]transLIdP_inoutstorage-id or NULL or 0 … return from StorageExport
*transLIdP > 0 return the read-data-package identified with the storage-id.
*transLIdP == 0 return the top-most (FIFO) read-data-package and set the transLIdP to the storage-id.
*transLIdP < 0 return an error
transLIdP == NULL like transLIdP == 0
*transLIdP invalid like transLIdP < 0
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
Read ProcessEvent for the dependency with the event-loop.
There is no guarantee that a package will be read FIFO.
In principle, the first free package (refCount=0) with the smallest transLId is read.
However, if the package hangs in subsequent processing and the refCount is not reset or the package is not deleted, then the package remains locked and a subsequent call to StorageImport will read the next free package.
  • This approach protects a server or router from blocking after an unpredictable failure.
See also
DumpExport, StorageExport, StorageDelete, StorageDecrRef, StorageIncrRef

enum MkErrorE MqStorageIncrRef(MQ_CTX ctx, MQ_LTR transLId)

TOP

increase the internal refCount lock of the database-entry → API: MqStorageIncrRef_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]transLIdstorage-id … return from StorageImport
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
StorageImport, StorageDecrRef

enum MkErrorE MqStorageLog(MQ_CTX ctx, MK_STRN callfunc)

TOP

log the storage the status of the open transactions → API: MqStorageLog_RT

enum MkErrorE MqStorageOpen(MQ_CTX ctx, MK_STRN storageFile)

TOP

switch to a file-based-transaction-database … → API: MqStorageOpen_RT

the value can also be set using the --storage commandline option.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[in]storageFilethe file used to create the transaction-database. Allowed values are:
  1. "#memdb#" for a in-memory-database (default)
  2. "#tmpdb#" for a temporary-database-file
  3. filename for a persistent-database-file
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR

enum MkErrorE MqStorageResolve(MQ_CTX ctx, MQ_CTX* otherCtxP_out, MQ_LTR* otherLIdP_out)

TOP

extract the context->link.protect.rmtTransLId entry from the database → API: MqStorageResolve_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
[out]otherCtxP_outthe ctx of the resolve
[out]otherLIdP_outthe transLId of the resolve

MqContextC TOR

C-API: MqContextC_TOR_C_API - various functions to create, initialize and destroy a MqContextC

(constructor) MQ_CTX MqContextCreate(MK_TYP type, MQ_CTX tmpl)

TOP

create and initialize the MqContextC ... → API: MqContextCreate_RT

This function is used to create a single new context… primary on the client. to create multiple new context on a server… a MqFactoryC is used.

The new instance belongs to the caller and may have to be released if necessary. A manual release using ContextDelete is always possible, but the instance can no longer be used afterwards.

Example from MyClient.c create a context using the static libmqmsgque CTOR

#include "debug_mq.h"
#include "msgque_mq.h"

int main (int argc, MK_STRN argv[]) 
{
  MkRtSetup_NULL;
  struct MkBufferListS * largv = MkBufferListCreateVC(argc, argv);
  // create a context using the static libmqmsgque CTOR function "MqContextCreate"
  MQ_CTX ctx = MqContextCreate(NULL,NULL);
  MqConfigSetName(ctx, "MyClient");
  MqLinkCreate_E (ctx, largv);
  MqCheckForLeftOverArguments_E (ctx, largv);
  MqSend_E (ctx, "W", "HLWO:C", "Hello");
  fprintf(stdout,"%s\n", MqReadC_e (ctx));
  fflush(stdout);

error:
  MkBufferListDelete(largv);
  // delete the context using the libmqmsgque APPLICATION-DTOR function "MqExit_1"
  MqExit_1(ctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]typetype type of the object like MqContextC_T or a new type created with TypeDup2. (default: NULL, reuse the MkTypeSTT from tmpl or use MqContextC_T if tmpl = NULL)
[in]tmplan other context-data-structure used as template to initialize the configuration data. This template is used for a child to get the configuration data from the parent. (default: NULL, create an initial context)
Returns
The newly created MqContextC instance, the instance is owned by the caller
See also
void MqContextDelete(MQ_CTX ctx), void MqExit(MQ_CTX ctx, MK_STRN callfunc, MK_STRN callfile, MK_INT callline)

(static) MQ_CTX MqContextFromHandle(MK_LONG exporthdl)

TOP

→ API: MqContextFromHandle

void MqContextDelete(MQ_CTX ctx)

TOP

Destructor - delete a MqContextC instance … → API: MqContextDelete_RT

Shutdown the client-server-link, free the memory and set the ctx to NULL. The context can not be reused.

Example from MyClient2.c delete a application-context using the libmqmsgque DTOR

#include "common.h"
int main (int argc, MK_STRN argv[])
{
struct MkBufferListS * largv = MkBufferListCreateVC(argc, argv);
// create a context using the libmqmsgque CTOR function "MqContextCreate"
MQ_CTX ctx = MqContextCreate(NULL,NULL);
MqConfigSetName(ctx, "MyClient");
MqLinkCreate_E (ctx, largv);
MqSend_E (ctx, "W", "HLWO");
fprintf(stdout,"%s\n", MqReadC_e (ctx));
fflush(stdout);
error:
// delete context using the libmqmsgque DTOR function "MqContextDelete"
}
#define MkBufferListCreateVC(...)
#define MqConfigSetName(...)
#define MqCheckForLeftOverArguments_E(...)
#define MqLinkCreate_E(...)
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe MqContextS instance to work on
See also
ContextCreate

INSTANCE STORAGE API

SUPER: MqContextC, TOP

libmqmsgque is using a class-attribute as instance-storage.

To create a new instance-storage 3 steps are reqired:

Step 1. - Define new class-type "MyLoopServerC" with attribute "mydata"

typedef struct MyLoopServerS {
  struct MqContextS mqctx;    ///< link to the \libmqmsgque object
  #define mydata_size 30
  char mydata[mydata_size];   ///< define the "mydata" attribute
} MyLoopServerC;  

Step 2. - Initialize the class-type "MyLoopServerCTT" with base-class "MyContextSTT"

  // initialize the MyLoopServer class-type with existing MqContextC_TT class-type
  MyLoopServerCTT = MkTypeDup2(MqContextC_TT,"MyLoopServerC");
  MyLoopServerCTT->objsize = sizeof(struct MyLoopServerS);

Step 3. - Create a new instance from class-type "MyLoopServerCTT" using "MqContextCreate"

enum MkErrorE
MyLoopServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  // create new instance using the MyLoopServerCTT class-type
  MQ_CTX const mqctx = *contextP = MqContextCreate(MyLoopServerCTT,tmpl);

  // initialize the new context
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);

  // cast the libmqmsgque-context into the MyLoopServerC-context
  MyLoopServerC* mqctxC = (MyLoopServerC*)mqctx;

  // initialize the "mydata" attribute
  strncpy(mqctxC->mydata,"Hello World",mydata_size);
  mqctxC->mydata[mydata_size-1] = '\0';

  return MK_OK;
}
See also
MkObjectC ContextCreate

Example from MyLoopServer.c create and access class-attribute mydata as instance-storage

#include "common.h"

// [MyLoopServerC_Define]
typedef struct MyLoopServerS {
  struct MqContextS mqctx;    ///< link to the \libmqmsgque object
  #define mydata_size 30
  char mydata[mydata_size];   ///< define the "mydata" attribute
} MyLoopServerC;  
// [MyLoopServerC_Define]

// the MyLoopServerC class-type
static MkThreadLocal MK_TYP MyLoopServerCTT = NULL;

// service to serve all EXTERNAL requests for token "HLWO"
static enum MkErrorE HLWO_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // get the "loopback" context
  MQ_CTX loop = MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK);
  // call the LOOP service on the SAME server
  MqSend_E(loop,"W","LOOP");
  // answer HLWO with string-return from LOOP
  MqSend_E(mqctx, "R", "C", MqReadC_e(loop));
  return MK_OK;
error:
  return MqSendRETURN(mqctx);
}

// service to serve all INTERNAL requests for token "LOOP
static enum MkErrorE LOOP_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // get the "master" context 
  MyLoopServerC* master = (MyLoopServerC*)MqSlaveGetMaster(mqctx);
  // answer LOOP with data from MASTER->mydata attribute
  return MqSend(mqctx, "R", "C", master->mydata);
}

// define a service as link between the token "HLWO" and the callback "HLWO_srv"
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // EXTERNAL: link the "HLWO" service with "HLWO_srv"
  MqServiceCreate_E(mqctx, "HLWO", HLWO_srv, NULL, NULL, NULL);
  // INTERNAL: link the "LOOP" service with "LOOP_srv"
  MqServiceCreate_E(MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK), "LOOP", LOOP_srv, NULL, NULL, NULL);
  return MK_OK;
error:
  return MkErrorStack_1X(mqctx);
}

// [MyLoopServerC_Create]
enum MkErrorE
MyLoopServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  // create new instance using the MyLoopServerCTT class-type
  MQ_CTX const mqctx = *contextP = MqContextCreate(MyLoopServerCTT,tmpl);

  // initialize the new context
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);

  // cast the libmqmsgque-context into the MyLoopServerC-context
  MyLoopServerC* mqctxC = (MyLoopServerC*)mqctx;

  // initialize the "mydata" attribute
  strncpy(mqctxC->mydata,"Hello World",mydata_size);
  mqctxC->mydata[mydata_size-1] = '\0';

  return MK_OK;
}
// [MyLoopServerC_Create]

int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // [MyLoopServerC_Init]
  // initialize the MyLoopServer class-type with existing MqContextC_TT class-type
  MyLoopServerCTT = MkTypeDup2(MqContextC_TT,"MyLoopServerC");
  MyLoopServerCTT->objsize = sizeof(struct MyLoopServerS);
  // [MyLoopServerC_Init]

  // setup commandline arguments for later use
  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // create "MyLoopServer" factory… and make it to the default.
  MqFactoryDefault(MqFactoryAdd_2(MyLoopServerFactory,"MyLoopServer"));
  // inspect commandline-argument for the "factory" to choose… and create a object
  MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);

  // start listen for incoming call's
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}

MqDumpC

SUPER: MkObjectC, TOP

MqDumpC INTROSPECTION

Instancesget head-instance from linked-list of MqDumpS type …
Nextget next instance from linked-list of MqDumpS type
Prev

get previous instance from linked-list of MqDumpS type

MqDumpC MISC

Loglog the MqDumpC
SizeGetreport the binary data size from an MqDumpS object
TokenGet

return the MqContextC_ServiceApi_Identifer

MqDumpC TOR

BinSetcreate an MqDumpS object from binary data
Errorexport the context->error into the dump-package
Exportcreate a MqDumpC as export of the ctx-read-data-package
FromHandle
BinGetexport the binary data from an MqDumpS object
DeleteDestructor - delete a MqDumpC instance …
Import

import the dump-package into the ctx-read-data-package

MqDumpC DETAIL

C-API: MqDumpC_C_API - The MqDumpC object known as dmp or dump is used to export a libmqmsgque data package as binary

The dump is used to exchange data with external counterparts such as a database or a user-specific infrastructure.

There are 3 different function that deal with a dump:

  1. The DumpExport export the read-data-package from the calling context to a dump.
  2. The DumpImport imports the dump into the read-data-package of the calling context. All MqContextC READ API functions can be used to read the data from the read-data-package.
  3. The ProxyForward imports the dump into the send-data-package of the calling context. All MqContextC SEND API functions can be used to write the data into the send-data-package
See also
MqContextC PROXY API

MqDumpC INTROSPECTION

C-API: MqDumpC_Introspection_C_API - Get information about all instances created by class

(static) MQ_DMP MqDumpInstances(void)

TOP

get head-instance from linked-list of MqDumpS type … → API: MqDumpInstances

The head-instance is the last instance created.

MQ_DMP MqDumpNext(MQ_DMP dmp)

TOP

get next instance from linked-list of MqDumpS type → API: MqDumpNext

MQ_DMP MqDumpPrev(MQ_DMP dmp)

TOP

get previous instance from linked-list of MqDumpS type → API: MqDumpPrev

MqDumpC MISC

C-API: MqDumpC_Misc_C_API - various functions to work on a MqDumpC

void MqDumpLog(MQ_DMP dmp, MK_OBJ fmtobj, MK_INT debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqDumpC … → API: MqDumpLog_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]dmpthe MqDumpS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)

MK_SIZE MqDumpSizeGet(MQ_DMPN dump)

TOP

report the binary data size from an MqDumpS object → API: MqDumpSizeGet

Parameters
[in]dumpthe source object
Returns
the size of the dump
MQ_DMPN const dump
) {
return dump->size;
}
long MK_SIZE
MQ_EXTERN MK_SIZE MqDumpSizeGet(MQ_DMPN const dump) MK_ATTR_HDL
report the binary data size from an MqDumpS object
#define MK_ATTR_HDL_CHECK(x)
The MqDumpC object known as dmp or dump is used to export a libmqmsgque data package as binary …
Definition msgque_mq.h:7935

MK_STRN MqDumpTokenGet(MQ_DMPN dump)

TOP

return the MqContextC_ServiceApi_Identifer … → API: MqDumpTokenGet

MQ_DMPN const dump
) {
return dump->hdr.tok;
}
MQ_EXTERN MK_STRN MqDumpTokenGet(MQ_DMPN const dump) MK_ATTR_HDL
return the MqContextC_ServiceApi_Identifer …

MqDumpC TOR

C-API: MqDumpC_TOR_C_API - various functions to create, initialize and destroy a MqDumpC

(constructor) enum MkErrorE MqDumpBinSet(MkBinaryR data, MQ_DMP* dmp_out)

TOP

create an MqDumpS object from binary data → API: MqDumpBinSet_RT

Check the MqDumpC_SIGNATURE and set the refCount to 0

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]datathe binary data
[out]dmp_outthe new MqDumpC
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
The MqDumpS object is an pointer object… this mean the original data is still required and must NOT be freed.
MK_RT_ARGS
MkBinaryR bin,
MQ_DMP *dmp_out
) {
assert(dmp_out!=NULL);
MQ_DMP dump = (MQ_DMP) bin.data;
if (!__MkCheckX(MqDumpC,dump)) {
return MkErrorDbV_2(MK_ERROR_PRINT,MK_ERROR_VALUE_INVALID, "signature", "MqDumpS");
} else {
MkOBJ_R(dump).refCount = 0;
}
*dmp_out = dump;
return MK_OK;
}
#define __MkCheckX(cls, x)
#define MkOBJ_R(x)
#define MkRtSetup_NULL_RT
struct MqDumpS * MQ_DMP
class-shortcut for struct MqDumpS *, all shortcut using the XX_YYY syntax (only for public API) …
Definition msgque_mq.h:541
MQ_EXTERN enum MkErrorE MqDumpBinSet_RT(MK_RT const mkrt, MkBinaryR data, MQ_DMP *dmp_out)
create an MqDumpS object from binary data

(constructor) enum MkErrorE MqDumpError(MQ_CTX error, MQ_DMP* dumpP_inout)

TOP

export the context->error into the dump-package … → API: MqDumpError_RT

The export include all data required to setup a read-data-package later again. After import with DumpImport the read-data-package and the environment will be set as it was on DumpExport The export can be saved into an external storage or be used in a network-tunnel (example: the agurad tool).

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]errorthe error-context to be exported into the dump-package-data
[in,out]dumpP_inoutthe dump-error-package-data to save
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
1. use remarks from DumpExport
2. DumpError using the send-data-package to create the dump-package.. to use the send-data-package afterwords a SendSTART is required
See also
StorageExport, DumpImport, DumpExport

(constructor) enum MkErrorE MqDumpExport(MQ_CTX ctx, MQ_DMP* dumpP_inout)

TOP

create a MqDumpC as export of the ctx-read-data-package … → API: MqDumpExport_RT

The new instance belongs to the caller and may have to be released if necessary. A manual release using DumpDelete is always possible, but the instance can no longer be used afterwards.

The export include all data required to setup a read-data-package again later. After import with DumpImport the read-data-package and the environment will be set as it was on DumpExport The export can be saved into an external storage or be used in a network-tunnel (example: the aguard tool).

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]ctxthe context to be exported into the dump-package-data
[in,out]dumpP_inoutreturns
Returns
The newly created MqDumpC instance, the instance is owned by the caller
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
See also
StorageExport, DumpImport, DumpError
Attention
1. The goal of this function is to create a dump to be loaded in the context later. If the context is not the original context… propably additional work is necessary.
2. The DumpExport is using realloc to allocate space. The value of *value should be initialized with either NULL or a result of a previous DumpExport or DumpError.
3. Garbage is detected using MqDumpC_SIGNATURE… there is a MINIMAL chance (1 to 4.294.967.295) that the gargabe is NOT detected… to be save… always initialize the dump.
4. If the dump was initialized with NULL or garbage … new memory will be allocated… If the dump memory will NOT be reused… free the memory with (6.)
5. If the dump was initialized with an previous dump … the memory will be reused… and extendet with realloc if required.
6.F ree the memory with DumpDelete.
7. On error… the dump is unchanged.
8. In case of TLS memory returned read more at MkKernel_Storage_C_API.

(static) MQ_DMP MqDumpFromHandle(MK_LONG exporthdl)

TOP

→ API: MqDumpFromHandle

MkBinaryR MqDumpBinGet(MQ_DMPN dump)

TOP

export the binary data from an MqDumpS object → API: MqDumpBinGet

Parameters
[in]dumpthe source object
Returns
The required MkBinaryR
Attention
The data still belongs to the MqDumpS object… do NOT free.
MQ_DMPN const dump
) {
return (MkBinaryR) {dump->size, (MK_BINN)dump};
}
MK_BINB const * MK_BINN
MQ_EXTERN MkBinaryR MqDumpBinGet(MQ_DMPN const dump) MK_ATTR_HDL
export the binary data from an MqDumpS object

void MqDumpDelete(MQ_DMP dmp)

TOP

Destructor - delete a MqDumpC instance … → API: MqDumpDelete_RT

See also
DumpExport DumpError

enum MkErrorE MqDumpImport(MQ_DMP dump, MQ_CTX ctx)

TOP

import the dump-package into the ctx-read-data-package … → API: MqDumpImport_RT

The dump is the result of a previous DumpExport function call. After the load an package is suitable for all kind of MqContextC READ API function. To just forward the package use the ProxyForward function.

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]dumpthe dump-package to be imported
[in]ctxthe context in wich the dump-package is imported
Returns
set the MkErrorC to the status MK_OK, MK_CONTINUE or MK_ERROR
Attention
~ The memory is dynamic-allocated and can be reused for the next DumpExport.
~ The memory of the out-value belongs to the called LibMqMsgque function and therefore never becomes NULL. For details on the out-value, see: MkKernel_Storage_C_API.
See also
StorageExport, DumpExport, DumpError

MqFactoryC

SUPER: MkObjectC, TOP

MqFactoryC GET

Getreturn the MqFactoryC
GetCalledreturns the MqFactoryC identified by ident
GetCalledLreturns the MqFactoryC identified as first argument in the largs MkBufferListC
GetOriginalIdent

helper function to return MqFactoryS::originalIdent

MqFactoryC INTROSPECTION

Instancesget head-instance from linked-list of MqFactoryS type …
Nextget next instance from linked-list of MqFactoryS type
Prev

get previous instance from linked-list of MqFactoryS type

MqFactoryC MISC

DefaultIdentreturn the factory-identifier of the default MqFactoryC
InitialIdentreturn the factory-identifier of the initial MqFactoryC
LogAlllog all "factories" to stderr
Defaultset the default-attribute to the factory
Initialset the initial-attribut to fct
Loglog the MqFactoryC
New

create a new MqContextC from a MqFactoryC

MqFactoryC TOR

Addadd a new MqFactoryC identified by factory-identifier and defined by factory-constructor
FromHandle
DeleteDestructor - delete a MqFactoryC instance …
Dup2

create a duplicate of the singleton object MqFactoryC using a new factory-identifer

MqFactoryC DETAIL

C-API: MqFactoryC_C_API - The MqFactoryC object known as fct or factory is used to provide an interface to create one or more new MqContextC

The factory is an important part of the object management and has the following basic features:

  1. create/delete a MqContextC defined by a MqFactoryC
  2. infrastructure to host multiple MqFactoryC in a single executable
  3. provide an identifier used for factory-lookup and as an unique-application-name
  4. identification of a client and a server in an application-link

Without a factory only the pipe-feature without the child-feature is guaranteed to work. Other features may work, this depends of the "flexibility" of the programming-language.

The link between the MqFactoryS-identifier and the MqFactoryC is important for the future development of libmqmsgque. Message-Routing, Service-Location and Persistent-Transactions depend on this feature.

The relationship between the MqFactoryC and the MqContextC is the same as the relationship between a type (MqFactoryS) and an object (MqContextS) of a regular programming language. The MqFactoryC define the type of the server and the MqContextC define a single object of the server process or thread.

                                     Application
|-------------------------------------------------------------------------------------|
|--------------- physical host 1 -----------------------|------ physical host 2 ------|
|-------- process-1 --------|-------- process-2 --------|-- process-3 --|---- … ------|
 thread-1     thread-2…      thread-1…     thread-2…      thread-1…       thread-…
  factory-A     factory-X     factory-Y…    factory-Z…
   object-1     object-1   object-…    …
   object-2     object-2   …
   object-3     object-3
   …              …

A server has a single MqFactoryC object per thread or process but multiple MqFactoryC objects per application. Decreasing the size and the complexity of a MqContextC object will improve the server performance. In future more fields, defined in the MqSetupS attribute of the the MqContextC object, will move into MqFactoryC object.

MqFactoryC GET

C-API: MqFactoryC_Get_C_API - various functions to 'get' data out of a MqFactoryC

(static) MQ_FCT MqFactoryGet(MK_STRN ident)

TOP

return the MqFactoryC → API: MqFactoryGet

The ident is the factory-name used with FactoryAdd - usually the class-name.

The following ident are also supported:

"initial"belongs to the factory with FactoryInitial
"default" or ""belongs to the factory with FactoryDefault
Parameters
[in]identthe factory-identifier to search for
Returns
the MqFactoryC or NULL if ident was not found

(static) MQ_FCT MqFactoryGetCalled(MK_STRN ident)

TOP

returns the MqFactoryC identified by ident … → API: MqFactoryGetCalled

If multiple factories (FactoryAdd) are available the startup code have to choose which factory to use.
The selection is done by the factory-identifer and is taken from the ident or from the first argument of the commandline-arguments-list.

Parameters
[in]identthe factory-identifier or "" for the default MqFactoryC
Returns
the MqFactoryC or NULL if nothing was found
See also
FactoryGetCalledL

(static) MQ_FCT MqFactoryGetCalledL(MK_BFLN largs)

TOP

returns the MqFactoryC identified as first argument in the largs MkBufferListC … → API: MqFactoryGetCalledL_RT

Like FactoryGetCalled but the ident is taken from the MkBufferListC object that was created from the commandline-arguments-list.

Command-Line-Arguments-List
The Commandline-Argumentis-List begins with the first argument after the executable and/or the script file.
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]largsthe command-line-args or "" for the default MqFactoryC
Returns
the MqFactoryC or NULL if nothing was found
See also
FactoryGetCalled

MK_STRN MqFactoryGetOriginalIdent(MQ_FCTN fct)

TOP

helper function to return MqFactoryS::originalIdent → API: MqFactoryGetOriginalIdent

Attention
The MK_STRN returned belongs to libmqmsgque… do not free the data.

MqFactoryC INTROSPECTION

C-API: MqFactoryC_Introspection_C_API - Get information about all instances created by class

(static) MQ_FCT MqFactoryInstances(void)

TOP

get head-instance from linked-list of MqFactoryS type … → API: MqFactoryInstances

The head-instance is the last instance created.

MQ_FCT MqFactoryNext(MQ_FCT fct)

TOP

get next instance from linked-list of MqFactoryS type → API: MqFactoryNext

MQ_FCT MqFactoryPrev(MQ_FCT fct)

TOP

get previous instance from linked-list of MqFactoryS type → API: MqFactoryPrev

MqFactoryC MISC

C-API: MqFactoryC_Misc_C_API - various functions to work on a MqFactoryC

(static) MK_STRN MqFactoryDefaultIdent(void)

TOP

return the factory-identifier of the default MqFactoryC → API: MqFactoryDefaultIdent

(static) MK_STRN MqFactoryInitialIdent(void)

TOP

return the factory-identifier of the initial MqFactoryC → API: MqFactoryInitialIdent

(static) void MqFactoryLogAll(MK_STRN callfunc)

TOP

log all "factories" to stderr → API: MqFactoryLogAll_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)

MQ_FCT MqFactoryDefault(MQ_FCT fct)

TOP

set the default-attribute to the factory … → API: MqFactoryDefault

The default-factory is used to create an MqFactoryC if FactoryGetCalled was not able to find a specific factory object. This is designed for a scenario with multiple factories included into a single binary and the first commandline parameter after the executable name… (position 0=executable, position 1=factory-selector)… is not related to a factory-ident… added with FactoryAdd.

Parameters
[in]fctthe new default MqFactoryC
Returns
the input fct

Example: from example/c/server.cs

static void Main(string[] argv) {
var largv = new MkBufferListC(argv);
MqFactoryCT<Server>.Add("server").Default();
MqFactoryCT<Client>.Add("client");
// "ctx" get the "Default" factory "server" ... or ... the factory "client" ...
// if string "client" is on the FIRST position in "argv"
try {
ctx.LinkCreate(largv);
ctx.LogC("this is the log test\n",1,"test");
ctx.ProcessEvent(MqWaitOnEventE.FOREVER);
} catch (Exception ex) {
} finally {
ctx.Exit();
}
}
#define MqFactoryCT
instance-type as specific-instance-type for MqFactoryC in the target-programming-language (C,...
Definition msgque_mq.h:3071

MQ_FCT MqFactoryInitial(MQ_FCT fct)

TOP

set the initial-attribut to fct … → API: MqFactoryInitial

The factory with "Initial"-attribute is always used for an object that should only be created with the MqContextC base class, but for which no other factory has been specified.
Use this attribute with care because you are firmly linking a factory. In a programming language with class-support, such as C++ or C#, this class is used for every new MqContextC object.
Where "Reflection" is available, this attribute has less meaning since the class is primarily determined from the parent object by means of "Reflection".
The "Initial" attribute is otherwise used for the "Loopback" and the "Filter" capability.

Example from Filter4.c set Initial attribute to a Factory

int
main (
  const int argc,
  MK_STRN argv[]
)
{
  MqRtSetup_NULL;

  // new types are created per-runtime
  Filter4TT = MkTypeDup2(MqContextC_TT,"Filter4");
  Filter4TT->objsize = sizeof(struct FilterCtxS);

  // the parent-context
  MK_BFL args = MkBufferListCreateVC (argc, argv);

  // create the factory and set the "initial" attribute.
  // with "initial" set every new context get the "Filter4Factory" as factory.
  MqFactoryInitial(
    MqFactoryAdd(MK_ERROR_PANIC, Filter4Factory, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Filter4")
  );

  // instance created WITHOUT "MqFactoryNew" but "initial" from above garantee the right "factory-aware" setup.
  // WITHOUT "initial" from above there is NO link between the new instance and the "Filter4Factory".
  MQ_CTX mqctx = Filter4Create( MK_RT_CALL NULL);

  // create the link
  MqLinkCreate_E (mqctx, args);

  // start event-loop and wait forever
  MqProcessEvent_E (mqctx, MQ_WAIT_FOREVER, MK_TIMEOUT_USER);

  // finish and exit
error:
  MkBufferListDelete(args);
  MqExit_1 (mqctx);
}

Parameters
[in]fctthe new initial MqFactoryC
Returns
the input fct

void MqFactoryLog(MQ_FCTN fct, MK_OBJN fmtobj, MK_DBG debug, MK_STRN callfunc, MK_INT lvl)

TOP

log the MqFactoryC … → API: MqFactoryLog_RT

Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]fctthe MqFactoryS instance to work on
[in]fmtobjmanaged object used to format the log-message (default=NULL = use default format)
[in]debugthe debug level from MkRuntimeS::debug, use 0 <= debug <= 9 (default=0)
[in]callfunca user-defined postfix to identify the calling function or the environment (default=name-of-function)
[in]lvla user-defined prefix starting with "" for lvl=0 and increase with " " for lvl+1 (default=0)
See also
MqFactoryC

enum MkErrorE MqFactoryNew(MQ_FCT fct, MQ_CTX tmpl, MQ_CTX* val_out)

TOP

create a new MqContextC from a MqFactoryC … → API: MqFactoryNew_RT

this create only the initial-server-object… all other server-objects will be created on behalf of the client-request.

Example from MyServer.c create a new server context

#include "common.h"

// service to serve all incoming requests for token "HLWO"
static enum MkErrorE MyFirstService ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MqSendSTART_E (mqctx);
  MqSendV_E (mqctx, "%s World", MqReadC_e(mqctx));
error:
  return MqSendRETURN(mqctx);
}

// define a service as link between the token "HLWO" and the callback "MyFirstService"
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  return MqServiceCreate(mqctx,"HLWO", MyFirstService, NULL, NULL, NULL);
}

// package-item
enum MkErrorE
MyServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  MQ_CTX const mqctx = *contextP = MqContextCreate(NULL,tmpl);
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
  return MK_OK;
}

// package-main
int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // setup commandline arguments for later use

  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // create "MyServer" factory… and make it to the default.
  MqFactoryDefault(
    MqFactoryAdd(MK_ERROR_PANIC, MyServerFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "MyServer")
  );
  // inspect commandline-argument for the "factory" to choose… and create a object
  MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);

  // start listen for incoming call's
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]fcta MqFactoryC used to create a MqContextC
[in]tmpl(C-API only) template for context intialization
[out]val_outthe new context object as return or NULL on error
Returns
the new MqContextC or NULL on error
Attention
(C-API only)
the programmer have-to check the return value on NULL pointer
(non C-API only)
this is no hard constructor because the factory create the object and the self pointer is already available. ObjNew is used to extract the self pointer from the object

MqFactoryC TOR

C-API: MqFactoryC_TOR_C_API - various functions to create, initialize and destroy a MqFactoryC

(constructor) MQ_FCT MqFactoryAdd(MK_OBJN error, MqFactoryCTorF createCallF, MK_CCP constructor, MqFactoryDataFreeF createDataFreeF, MqFactoryDataCopyF createDataCopyF, MqFactoryDTorF deleteCallF, MK_CCP destructor, MqFactoryDataFreeF deleteDataFreeF, MqFactoryDataCopyF deleteDataCopyF, MK_STRN ident)

TOP

add a new MqFactoryC identified by factory-identifier and defined by factory-constructor … → API: MqFactoryAdd_RT

The factory is required to get all libmqmsgque features.

The constructor have to be a c-function.

Example from Filter5.c create a new context using factory F1; F2 or F3 read from the commandline

int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // create buffer-list of the application arguments
  MK_BFL largs = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // init the libmqmsgque global applications starter
  MqInitSetArg0VA(argv[0], NULL);

  // add factories
  MqFactoryAdd (MK_ERROR_PANIC, F1New, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "F1");
  MqFactoryAdd (MK_ERROR_PANIC, F2New, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "F2");
  MqFactoryAdd (MK_ERROR_PANIC, F3New, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "F3");

  // call factory using the !second! application argument,
  // first argument is the executable self
  MqFactoryNew_E (MqFactoryGetCalledL (largs), NULL, &mqctx);

  // configure and start the server
  MqLinkCreate_E (mqctx, largs);

  // report all arguments NOT consumed !!
  MqCheckForLeftOverArguments_E (mqctx, largs);

  // start event-loop and wait forever
  MqProcessEvent_E (mqctx, MQ_WAIT_FOREVER, MK_TIMEOUT_DEFAULT);

error:
  MkBufferListDelete(largs);
  MqExit_1(mqctx);
}
Parameters
[in]mkrtthe MkRuntimeS instance to work on - the runtime argument, used by MK_RT_CALL (C-only)
[in]error(C-API) flag to signal how to report an error. valid values are: MK_ERROR_PANIC, MK_ERROR_PRINT, MK_ERROR_IGNORE or an other MqContextC
[in]identthe factory-identifier, if NULL or EMPTY the class-name is used. The ident is the public identifier (name) of the factory and is used in logging-output (MqLog...) , name-resolution (MqFactoryGet...) and an first parameter in the executable-call: myserver ident ....
[in]createCallF(C-API) object constructor function
[in]constructorobject (class) constructor data
[in]createDataFreeF(C-API) object constructor data free function
[in]createDataCopyF(C-API) object copy-constructor data free function
[in]deleteCallF(C-API) object destructor function
[in]destructorobject (class) destructor data
[in]deleteDataFreeF(C-API) object destructor data free function
[in]deleteDataCopyF(C-API) object copy-constructor data free function
Returns
the new MqFactoryC or NULL on error
See also
FactoryTypeAdd

(static) MQ_FCT MqFactoryFromHandle(MK_LONG exporthdl)

TOP

→ API: MqFactoryFromHandle

void MqFactoryDelete(MQ_FCT fct)

TOP

Destructor - delete a MqFactoryC instance … → API: MqFactoryDelete_RT

This is more a "pseudo-delete" because a factory is always "inDuty". the reason is:

  1. A "context" has a MqSetupS::factory entry without a MkObjectS::refCount protection
  2. A MqFactoryDelete will modify the environment of a existing context's
  3. there are very "few" factories atAll
  4. factories are "shared" with threads… race-condition !!
  5. you can not "modify" a factory AFTER creation
See also
MqRefDecr_OP MqFactoryFree

(constructor) MQ_FCT MqFactoryDup2(MQ_FCTN fct, MK_STRN ident)

TOP

create a duplicate of the singleton object MqFactoryC using a new factory-identifer → API: MqFactoryDup2_RT


FILTER MODE

C-API: MqContextC_Filter_C_API - modify data using filter technology …

The filter mode is related to a special usage of the libmqmsgque software called a command pipeline. To define a filter create a server with:

Every filter has two context one belongs to the left command and one belongs to the right command:

 <-- left cmd --> <------- filter -------> <-- right cmd -->

                  <-- left --><- right -->
                  <- server -><- client ->
                  <- master -><- slave -->
                  <-context1-><-context2->

  ... command1   @         filter         @   command2 ...

The left context is created on application startup and the right context is created as slave of the left context.

  • if the @ argument is followed by an normal command (server) a local pipeline is created:
    client @ filter @ server
    
  • if the @ argument is followed by an option a non-local pipeline is created:
    <------------ host-1 -------------> <-- network --> <---------- host-2 ----------->
           <---- client arguments ---->                       <--- server arguments -->
                    <-- filter arg. -->
                      <--- options --->
    
    client @ filter @ --tcp --port 7777   ...........   server --tcp --port 7777 --fork
    

BI-DIRECTIONAL FILTER

A bi-directional filter allow a data-flow in both directions and is used in a classical client/server application:

    client ... <--> ... server

as a feature enhancement like a protocol-tunnelling:

    client @ mq2tunnel ... <--> ... tunnel2mq @ server

or to convert the protocol into an other protocol:

    client @ mq2soap ... <--> ... soap-server

To define a bi-directional filter a couple of commands provide support:

  • ServiceCreate
    • use the token +ALL to add a listener for all services. This feature is used for a tunnel to modify the body at all. (example: aguard)
  • ServiceProxy
    • use this function to link the left context with the right context identified with the slave-identifier id (default: 0). No data manipulation is performed.
  • SlaveGetFilter, SlaveGetMaster, SlaveGetProxy
    • in a filter service the current context is used to read the data. To send the data an other context, belonging to the other site of the communication, have to be used. This function return the context of the other site.
  • ServiceGetToken
    • if the token +ALL is used in ServiceCreate to add a generic service handler the current token is not known. This function return the current token.
  • ServiceIsTransaction
    • if the token +ALL is used in ServiceCreate to add a generic service handler the current transaction-status is not known. This function return the transaction-status as boolean with true (with-transaction) or false (without-transaction).
    • with-transaction: the package was send with SendEND_AND_WAIT or SendEND_AND_CALLBACK
    • without-transaction: the package was send with SendEND
  • DumpExport
    • read and return the read-data-package as MqDumpC. Use this dump to apply a transformation to the data, like encryption (example: aguard), or to save the body in a persistent storage for later use DumpImport.
  • DumpImport
    • load the MqDumpC into the read-data-package
  • ProxyForward
    • send the read-buffer or a MqDumpC, as returned by DumpExport, to the filter target.

ONE-DIRECTIONAL FILTER

A one-directional filter is a special form of a bi-directional filter and allow a data-flow from the left to the right.
This filter is well known from the unix shell to link different commands together:

    command1 | command2 | command3

A libmqmsgque command pipeline is created with the special character "@" instead of "|" :

    msgcmd1 @ msgcmd2 @ msgcmd3

To define a libmqmsgque filter... create a service handle with ServiceCreate or ServiceProxy ... using the token +FTR and +EOF

token description
+FTR required to act on filter data rows. Every filter input data is a list of filter data
rows and every row is a list of filter data columns. Every row is send to the following
filter-command as +FTR service request
+EOF required to act on End-Of-Filter data and is called after all +FTR data was send.
Sometimes the filter data can not be served as +FTR data (example: sorting of the
input rows need to read all rows before the data can be send to the next filter command)
and the+EOF token is used to continue send +FTR data rows.

and send every data item with SendEND_AND_WAIT .

PORTABILITY ISSUES

This library is actively developed and tested on x86_64 Linux (opensuse), older versions have also been successful tested on FreeBSD, WindowsXP/7, MacOSX and Solaris using x86_64, i686, ppc and sparc processor.


EXAMPLES

1. simple client/server application

  • The simple client/server application to provide the external "MMUL" service to multiplicate 2 double values
  • The client and the server application is using the low-level MqContextC SEND API and MqContextC READ API.

a) server to provide the "MMUL" service

Example from mulserver.c
#include "common.h"

static enum MkErrorE  MMUL( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MK_DBL d1,d2;
  MqSendSTART_E (mqctx);
  MqReadD_E (mqctx, &d1);
  MqReadD_E (mqctx, &d2);
  MqSendD_E (mqctx, d1*d2);
error:
  return MqSendRETURN(mqctx);
}
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  return MqServiceCreate(mqctx,"MMUL", MMUL, NULL, NULL, NULL);
}
static enum MkErrorE
MulServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  MQ_CTX const mqctx = *contextP = MqContextCreate(NULL,tmpl);
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);
  return MK_OK;
}
int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;
  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;
  MQ_FCT fct = MqFactoryAdd (MK_ERROR_PANIC,
                  MulServerFactory, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                  "mulserver"
               );
  MqFactoryNew_E (fct, NULL, &mqctx);
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}
Start mulserver using TCP port 7777 and spawn a new session for every incoming connection
> mulserver.c --tcp --port 7777 --spawn

b) client to call the "MMUL" service

Example from mulclient.c
#include "common.h"

int main (int argc, MK_STRN argv[]) 
{
  MkRtSetup_NULL;
  struct MkBufferListS * largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX ctx = MqContextCreate(NULL,NULL);
  MK_DBL d;
  MqConfigSetName (ctx, "MyMul");
  MqLinkCreate_E (ctx, largv);
  MqCheckForLeftOverArguments_E (ctx, largv);
  MqSendSTART_E (ctx);
  MqSendD_E (ctx,3.67);
  MqSendD_E (ctx,22.3);
  MqSendEND_AND_WAIT_E (ctx, "MMUL", 10);
  MqReadD_E (ctx, &d);
  fprintf(stdout,"%f\n", d);
  fflush(stdout);
error:
  MkBufferListDelete(largv);
  MqExit_1(ctx);
}
Use mulclient to connect to mulserver using TCP port 7777:
> mulclient.c --tcp --port 7777

2. advanced client/server application

  • The advanced client/server application to provide the external "HLWO" and the internal "LOOP" service.
  • The external "HLWO" service is calling the internal "LOOP" service.
  • The internal "LOOP" service is using a instance-attribute to return data.
  • The server is using the MqContextC HIGH API to simplify service-usage.

a) server to provide the "HLWO" service

Example from MyLoopServer.c
#include "common.h"

// [MyLoopServerC_Define]
typedef struct MyLoopServerS {
  struct MqContextS mqctx;    ///< link to the \libmqmsgque object
  #define mydata_size 30
  char mydata[mydata_size];   ///< define the "mydata" attribute
} MyLoopServerC;  
// [MyLoopServerC_Define]

// the MyLoopServerC class-type
static MkThreadLocal MK_TYP MyLoopServerCTT = NULL;

// service to serve all EXTERNAL requests for token "HLWO"
static enum MkErrorE HLWO_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // get the "loopback" context
  MQ_CTX loop = MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK);
  // call the LOOP service on the SAME server
  MqSend_E(loop,"W","LOOP");
  // answer HLWO with string-return from LOOP
  MqSend_E(mqctx, "R", "C", MqReadC_e(loop));
  return MK_OK;
error:
  return MqSendRETURN(mqctx);
}

// service to serve all INTERNAL requests for token "LOOP
static enum MkErrorE LOOP_srv ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // get the "master" context 
  MyLoopServerC* master = (MyLoopServerC*)MqSlaveGetMaster(mqctx);
  // answer LOOP with data from MASTER->mydata attribute
  return MqSend(mqctx, "R", "C", master->mydata);
}

// define a service as link between the token "HLWO" and the callback "HLWO_srv"
static enum MkErrorE ServerSetup ( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  // EXTERNAL: link the "HLWO" service with "HLWO_srv"
  MqServiceCreate_E(mqctx, "HLWO", HLWO_srv, NULL, NULL, NULL);
  // INTERNAL: link the "LOOP" service with "LOOP_srv"
  MqServiceCreate_E(MqSlaveGet_e(mqctx,MQ_SLAVE_LOOPBACK), "LOOP", LOOP_srv, NULL, NULL, NULL);
  return MK_OK;
error:
  return MkErrorStack_1X(mqctx);
}

// [MyLoopServerC_Create]
enum MkErrorE
MyLoopServerFactory ( MQ_CALLBACK_FACTORY_CTOR_ARGS )
{ 
  // create new instance using the MyLoopServerCTT class-type
  MQ_CTX const mqctx = *contextP = MqContextCreate(MyLoopServerCTT,tmpl);

  // initialize the new context
  MqConfigSetServerSetup (mqctx, ServerSetup, NULL, NULL, NULL);

  // cast the libmqmsgque-context into the MyLoopServerC-context
  MyLoopServerC* mqctxC = (MyLoopServerC*)mqctx;

  // initialize the "mydata" attribute
  strncpy(mqctxC->mydata,"Hello World",mydata_size);
  mqctxC->mydata[mydata_size-1] = '\0';

  return MK_OK;
}
// [MyLoopServerC_Create]

int main (int argc, MK_STRN argv[]) 
{
  MqRtSetup_NULL;

  // [MyLoopServerC_Init]
  // initialize the MyLoopServer class-type with existing MqContextC_TT class-type
  MyLoopServerCTT = MkTypeDup2(MqContextC_TT,"MyLoopServerC");
  MyLoopServerCTT->objsize = sizeof(struct MyLoopServerS);
  // [MyLoopServerC_Init]

  // setup commandline arguments for later use
  MK_BFL largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = NULL;

  // create "MyLoopServer" factory… and make it to the default.
  MqFactoryDefault(MqFactoryAdd_2(MyLoopServerFactory,"MyLoopServer"));
  // inspect commandline-argument for the "factory" to choose… and create a object
  MqFactoryNew_E (MqFactoryGetCalledL(largv), NULL, &mqctx);

  // start listen for incoming call's
  MqLinkCreate_E (mqctx, largv);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}
Start MyLoopServer using UDS file /var/loop-server.uds and thread a new session for every incoming connection
> MyLoopServer.c --uds --file /var/loop-server.uds --thread

b) client to call the "HLWO" service

Example from MyClient.c
#include "debug_mq.h"
#include "msgque_mq.h"

int main (int argc, MK_STRN argv[]) 
{
  MkRtSetup_NULL;
  struct MkBufferListS * largv = MkBufferListCreateVC(argc, argv);
  // create a context using the static libmqmsgque CTOR function "MqContextCreate"
  MQ_CTX ctx = MqContextCreate(NULL,NULL);
  MqConfigSetName(ctx, "MyClient");
  MqLinkCreate_E (ctx, largv);
  MqCheckForLeftOverArguments_E (ctx, largv);
  MqSend_E (ctx, "W", "HLWO:C", "Hello");
  fprintf(stdout,"%s\n", MqReadC_e (ctx));
  fflush(stdout);

error:
  MkBufferListDelete(largv);
  // delete the context using the libmqmsgque APPLICATION-DTOR function "MqExit_1"
  MqExit_1(ctx);
}
Use MyClient to connect to mulserver using UDS file /var/loop-server.uds:
> MyClient.c --uds --file /var/loop-server.uds

3. create a filter to wrap every column in a '<>' pair

Example from manfilter.c

#include "common.h"

static enum MkErrorE  FTR( MQ_CALLBACK_SERVICE_CALL_ARGS ) {
  MK_STRN str;
  MQ_CTX ftr;
  MqSlaveGetFilter_E (mqctx, &ftr);
  MqSendSTART_E (ftr);
  while (MqReadItemExists(mqctx)) {
    MqReadC_E (mqctx, &str);
    MkBufferSetV(MkBUF(&mqctx->ctxbuf),"<%s>", str);
    MqSendU_E (ftr, MkBUF(&mqctx->ctxbuf));
  }
  MqSendEND_AND_WAIT_E (ftr, "+FTR", MK_TIMEOUT_USER);
error:
  return MqSendRETURN (mqctx);
}
int main (int argc, MK_STRN argv[]) 
{
  MkRtSetup_NULL;
  struct MkBufferListS * largv = MkBufferListCreateVC(argc, argv);
  MQ_CTX mqctx = MqContextCreate(NULL,NULL);
  MqConfigSetName (mqctx, "ManFilter");
  MqConfigSetIsServer (mqctx, true);
  MqLinkCreate_E (mqctx, largv);
  MqServiceCreate_E (mqctx, "+FTR", FTR, NULL, NULL, NULL);
  MqServiceProxy_E (mqctx, "+EOF", MQ_SLAVE_FILTER);
  MqCheckForLeftOverArguments_E (mqctx, largv);
  MqProcessEvent_E (mqctx,MQ_WAIT_FOREVER,MK_TIMEOUT_DEFAULT);
error:
  MkBufferListDelete(largv);
  MqExit_1(mqctx);
}

Use manfilter in a libmqmsgque command pipeline:

> echo -e "1:2:3\na:b:c" | atool split -d : @ manfilter.c @ atool join -d :

SEE ALSO

libmqmsgque, ccmqmsgque, csmqmsgque, javamqmsgque, gomqmsgque, pymqmsgque, rbmqmsgque, tclmqmsgque, perlmqmsgque, phpmqmsgque

KEYWORDS

C, unix, socket, message, msgque