////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2001-2023 Alexey Kuryakin daqgroup@mail.ru under MIT license //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// This file is part of the CRW-DAQ project by DaqGroup - component CRWLIB.   //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Purpose:                                                                   //
// DIM interface for Object Pascal (Delphi 5.0 & FPC tested).                 //
// DIM is Distributed Information Manager by CERN,                            //
//     see http://dim.web.cern.ch/dim/                                        //
// DIM is CERN product under GNU GPL for distributed realtime DAQ systems.    //
// DIM included in CRW32 "as is", I wrote only interface for Object Pascal.   //
// DIM is multiplatform: Windows, Linux, Unix etc.                            //
// DNS is Distributed Name Server.                                            //
// DIS is a DIM server.                                                       //
// DIC is a DIM client.                                                       //
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// History:                                                                   //
// 20040703 - creation & tests                                                //
// 20040707 - first tested release                                            //
// 20050616 - scheduler_class, priority etc                                   //
// 20190213 - update to dim20; use TDimLong type (tags); add DIM/DIS/DIC.     //
// 20230605 - Modified for FPC (A.K.)                                         //
////////////////////////////////////////////////////////////////////////////////

unit _crw_dim; // Distributed Information Manager interface

{$I _crw_sysdef}

{$IFDEF FPC}{$mode Delphi}{$ENDIF}{$H+}

 // Define the DIM_STATIC parameter to use static DLL linking.
 // When using static  linking, EXE file will depend from DLL.
 // When using dynamic linking - call LoadDimLibrary on start,
 // and use ValidDimLibrary to check library is really loaded.
 // If ValidDimLibrary return false, any call of DIM functions
 // will raise general violation exception (nil address call).

{-$DEFINE DIM_STATIC}

interface

uses
 _crw_sharemem, // NB: THIS UNIT MUST BE FIRST !!!
 {$IFDEF UNIX} cthreads, dl, {$ENDIF}
 {$IFDEF WINDOWS} windows, {$ENDIF}
 sysutils, classes,
 _crw_alloc;

 ////////////////////////////////////////////
 // DIM general constants, derived from dim.h
 ////////////////////////////////////////////
const
 DNS_TASK           = 'DIM_DNS';    // Name server task
 DNS_PORT           = 2505;         // Name server port, if DIM_DNS_PORT not defined
 START_PORT_RANGE   = 5100;         // Lowest  port to use by DIM servers
 STOP_PORT_RANGE    = 10000;        // Highest port to use by DIM servers
 MAX_NODE_NAME      = 40;           // Max size of node names
 MAX_TASK_NAME      = 40;           // Max size of task names
 MAX_NAME           = 132;          // Max size of format/service names

 ///////////////////////////////////////////////
 // DIM service types, derived from dim_common.h
 ///////////////////////////////////////////////
const
 ONCE_ONLY          = $01;          // Execute service once
 TIMED              = $02;          // Update service by timer
 MONITORED          = $04;          // Update service when changed (server take care)
 COMMAND            = $08;
 DIM_DELETE         = $10;
 MONIT_ONLY         = $20;
 UPDATE             = $40;
 TIMED_ONLY         = $80;
 MONIT_FIRST        = $100;
 MAX_TYPE_DEF       = $100;
 STAMPED            = $1000;
 
 ///////////////////////
 // DIM Error Severities
 ///////////////////////
const
 es_DIM_INFO        = 0;            // No error(s), just information
 es_DIM_WARNING     = 1;            // Warning, not error yet
 es_DIM_ERROR       = 2;            // Error found (recoverable)
 es_DIM_FATAL       = 3;            // Fatal error (unrecoverable)
 
 //////////////////
 // DIM Error Codes
 //////////////////
const
 ec_DIMDNSUNDEF     = $1;           // DIM_DNS_NODE undefined           FATAL
 ec_DIMDNSREFUS     = $2;           // DIM_DNS refuses connection       FATAL
 ec_DIMDNSDUPLC     = $3;           // Service already exists in DNS    FATAL
 ec_DIMDNSEXIT      = $4;           // DNS requests server to EXIT      FATAL
 ec_DIMDNSTMOUT     = $5;           // Server failed sending Watchdog   WARNING
 ec_DIMSVCDUPLC     = $10;          // Service already exists in Server ERROR
 ec_DIMSVCFORMT     = $11;          // Bad format string for service    ERROR
 ec_DIMSVCINVAL     = $12;          // Service ID invalid               ERROR
 ec_DIMSVCTOOLG     = $13;          // Service name too long            ERROR
 ec_DIMTCPRDERR     = $20;          // TCP/IP read error                ERROR
 ec_DIMTCPWRRTY     = $21;          // TCP/IP write   error - Retrying  WARNING
 ec_DIMTCPWRTMO     = $22;          // TCP/IP write error - Disconnect  ERROR
 ec_DIMTCPLNERR     = $23;          // TCP/IP listen error              ERROR
 ec_DIMTCPOPERR     = $24;          // TCP/IP open server error         ERROR
 ec_DIMTCPCNERR     = $25;          // TCP/IP connection error          ERROR
 ec_DIMTCPCNEST     = $26;          // TCP/IP connection established    INFO
 ec_DIMDNSCNERR     = $30;          // Connection to DNS failed         ERROR
 ec_DIMDNSCNEST     = $31;          // Connection to DNS established    INFO

type                                // dim_long is type uses to store tag values
 TDimLong           = PtrInt;       // => integer type with same size as Pointer

 ///////////////////////////////////////////////////////////////////////
 // User callback routines to be called from DIM core to make all needs.
 // Note that all DIM routines uses 'cdecl' call convention.
 // TDis_User_Routine   : server callback to provide service data.
 // TDis_Cmnd_Routine   : server callback to execute command received from client.
 // TDis_Exit_Handler   : server callback to handle client or server exit.
 // TDic_User_Routine   : client callback to accept received service data.
 // TDic_Cmnd_Routine   : client callback to notify sent command result.
 // TDtq_User_Routine   : timeout callback to notify timeout expired.
 // TDis_Error_Handler  : server callback to handle errors.
 // TDic_Error_Handler  : client callback to handle errors.
 // TDim_Thread_Routine : callback routine for user thread.
 // tag                 : uses to identify service/command.
 // buff                : buffer to get/put service/command data.
 // size                : buffer size.
 // ret_code            : sent function result.
 // severity            : error class - info/warning/error/fatal
 // error_code          : error code to identify error
 // error_message       : error message to explain what's happened
 ///////////////////////////////////////////////////////////////////////
type
 TDis_User_Routine   = procedure(var tag:TDimLong; var buff:Pointer; var size:Integer; var first:Integer); cdecl;
 TDis_Cmnd_Routine   = procedure(var tag:TDimLong; buff:Pointer; var size:Integer); cdecl;
 TDis_Exit_Handler   = procedure(var code:Integer); cdecl;
 TDic_User_Routine   = procedure(var tag:TDimLong; buff:Pointer; var size:Integer); cdecl;
 TDic_Cmnd_Routine   = procedure(var tag:TDimLong; var ret_code:Integer); cdecl;
 TDtq_User_Routine   = procedure(tag:TDimLong); cdecl;
 TDis_Error_Handler  = procedure(severity:Integer; error_code:Integer; error_message:PChar); cdecl;
 TDic_Error_Handler  = procedure(severity:Integer; error_code:Integer; error_message:PChar); cdecl;
 TDim_Thread_Routine = procedure(tag:TDimLong); cdecl;

type // Buffers for DIM format/service names
 TDimNameBuffer = packed array[0..MAX_NAME-1] of Char;   // For names
 TDimPathBuffer = packed array[0..MAX_NAME*2-1] of Char; // For file names etc

 ///////////////////////////////////////////////////////////////////////////////
 // Note that all dim.dll routines uses 'cdecl' call convention.
 // Note that all dimStd.dll routines uses 'stdcall' call convention.
 // To use dimStd.dll instead of dim.dll, change all 'cdecl' to 'stdcall'.
 ///////////////////////////////////////////////////////////////////////////////

 /////////////////////////////////////
 // DIM common API, derived from dim.h
 /////////////////////////////////////

{$IFDEF DIM_STATIC}

 //
 // Hash function uses for hash table indexing.
 //
function  HashFunction(name:PChar; max:Integer):Integer; cdecl;

 //
 // Get host node name.
 // That is environment variable DIM_HOST_NODE or local host name.
 // Result : 1=Ok, 0=fail.
 //
function  get_node_name(NodeName:PChar):Integer; cdecl;

 //
 // Get DNS port number.
 // That is environment variable DIM_DNS_PORT or standard port DNS_PORT.
 //
function  get_dns_port_number:Integer; cdecl;

 //
 // Get DNS node name from environment.
 // That is environment variable DIM_DNS_NODE.
 // It's better to use dim_get_dns_node instead.
 // Result : 1=Ok, 0=fail.
 //
function  get_dns_node_name(NodeName:PChar):Integer; cdecl;

 //
 // Get list of DNS accepted domains from environment.
 // That is environment variable DIM_DNS_ACCEPTED_DOMAINS.
 // Result : 1=Ok, 0=fail.
 //
function  get_dns_accepted_domains(Domains:PChar):Integer; cdecl;

 //
 // Get list of DNS accepted nodes from environment.
 // That is environment variable DIM_DNS_ACCEPTED_NODES.
 // Result : 1=Ok, 0=fail.
 //
function get_dns_accepted_nodes(nodes:PChar):Integer; cdecl;

 ////////////////////////////////////////////
 // DIM common API, derived from dim_common.h
 ////////////////////////////////////////////

 //
 // Sleep until given time 'secs' (in seconds) elapsed.
 // Result : always 0.
 //
function  dtq_sleep(secs:Integer):Integer; cdecl;

 //
 // Start timeout request.
 // secs : timeout in seconds.
 // rout : user routine to be called when timeout interval elapsed.
 // tag  : uses to identify timeout request.
 //
procedure dtq_start_timer(secs:Integer; rout:TDtq_User_Routine; tag:TDimLong); cdecl;

 //
 // Stop (cancel) timeout request.
 // tag    : identifier of timeout request.
 // Result : time, in seconds, remains to timeout or -1 if timeout occured.
 //
function  dtq_stop_timer(tag:TDimLong):Integer; cdecl;

 //
 // Internal DIM routines.
 //
procedure dim_init; cdecl;
procedure dim_no_threads; cdecl;
procedure dna_set_test_write(conn_id:Integer; time:Integer); cdecl;
procedure dna_rem_test_write(conn_id:Integer); cdecl;

 //
 // dim_get/set_scheduler_class - get/set process priority class.
 // pclass   : -1/0/1/2=IDLE/NORMAL/HIGH/REALTIME
 // threadId : 1/2/3=Main/IO/Timer
 // prio     : -3/-2-1/0/1/2/3=IDLE/LOWEST/LOWER/NORMAL/HIGHER/HIGHEST/TIMECRITICAL
 // Returns 1/0=Ok/fail.
 //
function dim_set_scheduler_class(pclass:Integer):Integer; cdecl;
function dim_get_scheduler_class(var pclass:Integer):Integer; cdecl;
function dim_set_priority(threadId:Integer; prio:Integer):Integer; cdecl;
function dim_get_priority(threadId:Integer; var prio:Integer):Integer; cdecl;

 //
 // Get/set DIM_DNS_NODE, DIM_DNS_PORT. Buffer Node must be >= 40 chars. Returns 1/0=Ok/fail.
 //
function  dim_set_dns_node(Node:PChar):Integer; cdecl;
function  dim_get_dns_node(Node:PChar):Integer; cdecl;
function  dim_set_dns_port(port:Integer):Integer; cdecl;
function  dim_get_dns_port:Integer; cdecl;

 //
 // Internal DIM routines.
 //
procedure dic_set_debug_on; cdecl;
procedure dic_set_debug_off; cdecl;
procedure dim_print_date_time; cdecl;
procedure dim_set_write_timeout(secs:Integer); cdecl;
function  dim_get_write_timeout:Integer; cdecl;
procedure dim_usleep(t:Cardinal); cdecl;
function  dim_wait:Integer; cdecl;
{$IFDEF WINDOWS} procedure dim_pause; cdecl; {$ENDIF WINDOWS}
{$IFDEF WINDOWS} procedure dim_wake_up; cdecl; {$ENDIF WINDOWS}
procedure dim_lock; cdecl;
procedure dim_unlock; cdecl;
{$IFDEF WINDOWS} procedure dim_sleep(t:Cardinal); cdecl; {$ENDIF WINDOWS}
{$IFDEF WINDOWS} procedure dim_win_usleep(t:Cardinal); cdecl; {$ENDIF WINDOWS}
function  dim_start_thread(UserRoutine:TDim_Thread_Routine; tag:TDimLong):TDimLong; cdecl;
function  dic_set_dns_node(node:PChar):Integer; cdecl;
function  dic_get_dns_node(node:PChar):Integer; cdecl;
function  dic_set_dns_port(port:Integer):Integer; cdecl;
function  dic_get_dns_port:Integer; cdecl;
function  dis_set_dns_node(node:PChar):Integer; cdecl;
function  dis_get_dns_node(node:PChar):Integer; cdecl;
function  dis_set_dns_port(port:Integer):Integer; cdecl;
function  dis_get_dns_port:Integer; cdecl;
procedure dim_stop; cdecl;
function  dim_stop_thread(tid:TDimLong):Integer; cdecl;
function  dis_add_dns(node:PChar; port:Integer):TDimLong; cdecl;
function  dic_add_dns(node:PChar; port:Integer):TDimLong; cdecl;
function  dim_get_env_var(env_var:PChar; value:PChar; value_size:Integer):Integer; cdecl;
function  dim_set_write_buffer_size(bytes:Integer):Integer; cdecl;
function  dim_get_write_buffer_size:Integer; cdecl;
function  dim_set_read_buffer_size(bytes:Integer):Integer; cdecl;
function  dim_get_read_buffer_size:Integer; cdecl;
procedure dis_set_debug_on; cdecl;
procedure dis_set_debug_off; cdecl;
procedure dim_set_keepalive_timeout(secs:Integer); cdecl;
function  dim_get_keepalive_timeout:Integer; cdecl;
procedure dim_set_listen_backlog(size:Integer); cdecl;
function  dim_get_listen_backlog:Integer; cdecl;

 /////////////////////////////////////
 // DIM Server API, derived from dis.h
 /////////////////////////////////////

 //
 // Start serving client requests.
 // TaskName : server identifier, uses by client to access services.
 // Result   : 1 = Ok, 0 = fails.
 //
function  dis_start_serving(TaskName:PChar):Integer; cdecl;

 //
 // Stop serving, remove all DIM services.
 //
procedure dis_stop_serving; cdecl;

 //
 // Get from command queue next command requested by client.
 // Uses if UserRoutine=nil when dis_add_cmnd called.
 // Tag    : command identifier.
 // Buff   : buffer where command is to be copied to.
 // Size   : on input, buffer size; on output, received command size.
 // Result : 0 = no waiting commands, 1 = Ok, -1 = buffer size to small.
 //
function  dis_get_next_cmnd(var Tag:TDimLong; Buff:Pointer; var Size:Integer):Integer; cdecl;

 //
 // Get current client name as PID@hostname.
 // To be called inside TDis_User_Routine/TDis_Cmnd_Routine.
 // Name   :  buffer to copy client name to, at least 81 chars.
 // Result :  client connection ID or 0.
 //
function  dis_get_client(Name:PChar):Integer; cdecl;

 //
 // Get current client connection ID.
 // To be called inside TDis_User_Routine/TDis_Cmnd_Routine.
 // Result : Current connection ID.
 //
function  dis_get_conn_id:Integer; cdecl;

 //
 // Add new service to service list.
 // ServiceName : name to identify service.
 // ServiceType : describe service structure, like I:2;D:2;C.
 // ServiceAddr : points to service buffer or nil if uses UserRoutine.
 // ServiceSize : size of ServiceAddr buffer or 0 if uses UserRoutine.
 // UserRoutine : user routine to handle client requests.
 // Tag         : uses to identify service.
 // Returns     : Nonzero service ID if Ok or 0 if fails.
 //
function  dis_add_service(ServiceName:PChar; ServiceType:PChar;
                          ServiceAddr:Pointer; ServiceSize:Integer;
                          UserRoutine:TDis_User_Routine; Tag:TDimLong):Cardinal; cdecl;

 //
 // Add new command to server command list.
 // ServiceName : name to identify command.
 // ServiceType : describe command structure, like I:2;D:2;C.
 // UserRoutine : user routine to handle client commands.
 // Tag         : uses to identify service.
 // Returns     : Nonzero service ID if Ok or 0 if fails.
 //
function  dis_add_cmnd(ServiceName:PChar; ServiceType:PChar;
                       UserRoutine:TDis_Cmnd_Routine;
                       Tag:TDimLong):Cardinal; cdecl;
 //
 // Setup user routine to be called after client exit.
 // Client must declare Integer coomand service TASK/SET_EXIT_HANDLER
 // with some 'tag' value to identify client. UserRoutine will be called at
 // server side with 'tag' argument, when client exited. Client code like:
 // int id=123; sprintf(str,"%s/SET_EXIT_HANDLER",TaskName); dic_cmnd_service(str, &id, 4);
 //
procedure  dis_add_client_exit_handler(UserRoutine:TDis_Exit_Handler); cdecl;

 //
 // Set user routine to be called after client with given connection ID exit.
 // To get connection ID, use dis_get_conn_id, available inside UserRoutine.
 // Client may do nothing, code uses to identify reason, it should be <> 0.
 //
procedure  dis_set_client_exit_handler(ConnId:Integer; code:Integer); cdecl;

 //
 // Setup server user routine to be called when client call TASK/EXIT command.
 // For example, client wants to kill server. Server may die or not, as wish.
 //
procedure dis_add_exit_handler(UserRoutine:TDis_Exit_Handler); cdecl;

 //
 // Add an error handler to this server.
 //
procedure dis_add_error_handler(handler:TDis_Error_Handler); cdecl;

 //
 // ???
 //
procedure dis_report_service(ServiceName:PChar); cdecl;

 //
 // Update service with given ServiceID, send service data to notify clients.
 // ServiceID : service identifier returned by dis_add_service.
 // Result    : 1=Ok, 0=fails.
 //
function  dis_update_service(ServiceId:Cardinal):Integer; cdecl;

 //
 // Remove service with given ServiceID.
 // ServiceID : service identifier returned by dis_add_service.
 // Result    : 1=Ok, 0=fails.
 //
function  dis_remove_service(ServiceId:Cardinal):Integer; cdecl;

 //
 // Send service to clients. It's better to use dis_update_service instead.
 // ServiceID : service identifier returned by dis_add_service.
 // Buff,Size : Buffer where service placed and size of buffer.
 //
procedure dis_send_service(ServiceId:Cardinal; Buff:Pointer; Size:Integer); cdecl;

 //
 // Set packet size. Usually packet size grows dinamically, if packet size insufficient.
 // Size   : New packet size.
 // Result : 1=Ok, 0=fails.
 //
function  dis_set_buffer_size(Size:Integer):Integer; cdecl;
 //
 // Set quality for given ServiceId.
 //
procedure dis_set_quality(ServiceId:Cardinal; Quality:Integer); cdecl;

 //
 // Set time stamp for given ServiceId.
 //
procedure dis_set_timestamp(ServiceId:Cardinal; secs:Integer; millisecs:Integer); cdecl;

 //
 // Selective service update for given clients.
 // ServiceID      : service identifier returned by dis_add_service.
 // client_id_list : integer array of clients, terminated by 0.
 // Result         : 1=Ok, 0=fails.
 //
function  dis_selective_update_service(ServiceId:Cardinal; var client_id_list:Integer):Integer; cdecl;

 //
 // Disable padding by data size.
 //
procedure dis_disable_padding; cdecl;

 //
 // Get timeout for given service & client.
 //
function  dis_get_timeout(ServiceId:Cardinal; ClientId:Integer):Integer; cdecl;

 //
 // Gets the names of DIM services that have an error.
 // To be called inside TDis_Error_Handler to find out, which service(s) have an error.
 // Returns a list of services, that originated the error.
 //
function dis_get_error_services:PChar; cdecl;

 //
 // Gets the services of a DIM client, which has subscribed to this DIM server.
 // To be called inside TDis_User_Routime when service data is updated.
 //
function dis_get_client_services(conn_id:Integer):PChar; cdecl;

 //
 // Functions for multiple DNS. Similar, but uses dns_id from dis_add_dns/dic_add_dns.
 //
function  dis_start_serving_dns(dns_id:TDimLong; task_name:PChar):Integer; cdecl;
procedure dis_stop_serving_dns(dns_id:TDimLong); cdecl;
function  dis_add_service_dns(dns_id:TDimLong; ServiceName:PChar; ServiceType:PChar;
                          ServiceAddr:Pointer; ServiceSize:Integer;
                          UserRoutine:TDis_User_Routine; Tag:TDimLong):Cardinal; cdecl;
function  dis_add_cmnd_dns(dns_id:TDimLong; ServiceName:PChar; ServiceType:PChar;
                       UserRoutine:TDis_Cmnd_Routine; Tag:TDimLong):Cardinal; cdecl;

 //
 // Get number of clients connected to the service.
 //
function dis_get_n_clients(ServiceId:Cardinal):Integer; cdecl;

 //
 // Get time stamp of a service.
 //
function dis_get_timestamp(ServiceId:Cardinal; var secs:Integer; var millisecs:Integer):Integer; cdecl;

 /////////////////////////////////////
 // DIM client API, derived from dic.h
 /////////////////////////////////////

 //
 // Start information service of different kind (stamped, unstamped, command,
 // command with callback notification), provided by server.
 // ServiceName : name of service.
 // req_type    : service tipe, ONCE_ONLY,TIMED,MONITORED
 // req_timeout : timeout in seconds.
 // ServiceAddr : Service buffer address or nil if uses UserRoutine.
 // ServiceSize : Service buffer size    or 0   if uses UserRoutine.
 // UserRoutine : User routine to handle service data or nil if uses ServiceAddr.
 // CmndRoutine : User routine to notify if command was sent properly or not.
 // tag         : service identifier.
 // fill_addr   : buffer returned if unsuccess IO.
 // fill_size   : previous buffer size.
 // Result      : ServiceID or 0 if service unaccessible.
 //
function  dic_info_service(ServiceName:PChar; req_type:Integer; req_timeout:Integer;
                           ServiceAddr:Pointer; ServiceSize:Integer;
                           UserRoutine:TDic_User_Routine; tag:TDimLong;
                           fill_addr:Pointer; fill_size:Integer):Cardinal; cdecl;
function  dic_info_service_stamped(ServiceName:PChar; req_type:Integer; req_timeout:Integer;
                                   ServiceAddr:Pointer; ServiceSize:Integer;
                                   UserRoutine:TDic_User_Routine; tag:TDimLong;
                                   fill_addr:Pointer; fill_size:Integer):Cardinal; cdecl;
function  dic_cmnd_callback(ServiceName:PChar; ServiceAddr:Pointer; ServiceSize:Integer;
                            CmndRoutine:TDic_Cmnd_Routine; tag:TDimLong):Integer; cdecl;
function  dic_cmnd_service(ServiceName:PChar; ServiceAddr:Pointer; ServiceSize:Integer):Integer; cdecl;

 //
 // Change service buffer address and size.
 //
procedure dic_change_address(ServiceId:Cardinal; ServiceAddr:Pointer; ServiceSize:Integer); cdecl;

 //
 // Release service given by ServiceID.
 //
procedure dic_release_service(ServiceId:Cardinal); cdecl;

 //
 // Get client ID in pid@node form, like 123@lxplus.cern.ch.
 // Name   : buffer to write client ID.
 // Result : always 1.
 //
function  dic_get_id(Name:PChar):Integer; cdecl;

 //
 // Get quality for given ServiceId.
 // If ServiceId=0, get quality for current service (uses in user routines).
 // Result : quality or -1 if invalid service.
 //
function  dic_get_quality(ServiceId:Cardinal):Integer; cdecl;

 //
 // Get time stamp for given ServiceId.
 // Result : -1=fails, 0=no-stamped service, 1=Ok.
 //
function  dic_get_timestamp(ServiceId:Cardinal; var secs:Integer; var milisecs:Integer):Integer; cdecl;

 //
 // Get format for given ServiceId.
 // If ServiceId=0, get format for current service (uses in user routines).
 // Result : format char or nil if invalid service.
 //
function  dic_get_format(ServiceId:Cardinal):PChar; cdecl;

 //
 // Disable data size padding.
 //
procedure dic_disable_padding; cdecl;

 //
 // Close DNS connection.
 //
procedure  dic_close_dns; cdecl;

 //
 // Add an error handler to this client.
 //
procedure dic_add_error_handler(handler:TDic_Error_Handler); cdecl;

 //
 // Returns a list of services, that originated the error.
 // To be called inside TDic_Error_Handler to find out, which service(s) have an error.
 //
function dic_get_error_services:PChar; cdecl;

 //
 // Gets the services of a DIM server to which the client has subscribed.
 // To be called inside TDic_User_Routine when service data is being received from a server.
 // Its purpose is to get a list of all services, to which this DIM client has subscribed.
 // The list contains only the services of the specified server.
 //
function dic_get_server_services(conn_id:Integer):PChar; cdecl;

 //
 // Gets the identification of the current DIM server.
 // To be called inside TDic_User_Routine when service data is being received from a server.
 // Returns the server_id, in terms of its connection id, or 0 if no server is currently being handled.
 // It obtains the name of the DIM server in the format "DIMSERVERNAME@nodename".
 //
function dic_get_server(name:PChar):Integer; cdecl;

 //
 // Gets the connection ID of the current DIM server.
 // To be called inside TDic_User_Routine when service data is being received from a server.
 // Its purpose is to obtain the conn_id that is required by other routines.
 //
function dic_get_conn_id:Integer; cdecl;

 //
 // Undocumented.
 // Stop DIM client connections and threads.
 //
procedure dic_stop; cdecl;

 //
 // Undocumented.
 // To be called inside TDic_User_Routine when service data is being received from a server.
 // Returns the server_id, in terms of its connection id, or 0 if no server is currently being handled.
 // It obtains the PID of the DIM server.
 //
function dic_get_server_pid(var pid:Integer):Integer; cdecl;

{$ELSE  DIM_STATIC}

var HashFunction: function (name:PChar; max:Integer):Integer; cdecl;
var get_node_name: function (NodeName:PChar):Integer; cdecl;
var get_dns_port_number: function :Integer; cdecl;
var get_dns_node_name: function (NodeName:PChar):Integer; cdecl;
var get_dns_accepted_domains: function (Domains:PChar):Integer; cdecl;
var get_dns_accepted_nodes: function (nodes:PChar):Integer; cdecl;
var dtq_sleep: function (secs:Integer):Integer; cdecl;
var dtq_start_timer: procedure (secs:Integer; rout:TDtq_User_Routine; tag:TDimLong); cdecl;
var dtq_stop_timer: function (tag:TDimLong):Integer; cdecl;
var dim_init: procedure ; cdecl;
var dim_no_threads: procedure ; cdecl;
var dna_set_test_write: procedure (conn_id:Integer; time:Integer); cdecl;
var dna_rem_test_write: procedure (conn_id:Integer); cdecl;
var dim_set_scheduler_class: function (pclass:Integer):Integer; cdecl;
var dim_get_scheduler_class: function (var pclass:Integer):Integer; cdecl;
var dim_set_priority: function (threadId:Integer; prio:Integer):Integer; cdecl;
var dim_get_priority: function (threadId:Integer; var prio:Integer):Integer; cdecl;
var dim_set_dns_node: function (Node:PChar):Integer; cdecl;
var dim_get_dns_node: function (Node:PChar):Integer; cdecl;
var dim_set_dns_port: function (port:Integer):Integer; cdecl;
var dim_get_dns_port: function :Integer; cdecl;
var dic_set_debug_on: procedure ; cdecl;
var dic_set_debug_off: procedure ; cdecl;
var dim_print_date_time: procedure ; cdecl;
var dim_set_write_timeout: procedure (secs:Integer); cdecl;
var dim_get_write_timeout: function :Integer; cdecl;
var dim_usleep: procedure (t:Cardinal); cdecl;
var dim_wait: function :Integer; cdecl;
{$IFDEF WINDOWS} var dim_pause: procedure ; cdecl; {$ENDIF WINDOWS}
{$IFDEF WINDOWS} var dim_wake_up: procedure ; cdecl; {$ENDIF WINDOWS}
var dim_lock: procedure ; cdecl;
var dim_unlock: procedure ; cdecl;
{$IFDEF WINDOWS} var dim_sleep: procedure (t:Cardinal); cdecl; {$ENDIF WINDOWS}
{$IFDEF WINDOWS} var dim_win_usleep: procedure (t:Cardinal); cdecl; {$ENDIF WINDOWS}
var dim_start_thread: function (UserRoutine:TDim_Thread_Routine; tag:TDimLong):TDimLong; cdecl;
var dic_set_dns_node: function (node:PChar):Integer; cdecl;
var dic_get_dns_node: function (node:PChar):Integer; cdecl;
var dic_set_dns_port: function (port:Integer):Integer; cdecl;
var dic_get_dns_port: function :Integer; cdecl;
var dis_set_dns_node: function (node:PChar):Integer; cdecl;
var dis_get_dns_node: function (node:PChar):Integer; cdecl;
var dis_set_dns_port: function (port:Integer):Integer; cdecl;
var dis_get_dns_port: function :Integer; cdecl;
var dim_stop: procedure ; cdecl;
var dim_stop_thread: function (tid:TDimLong):Integer; cdecl;
var dis_add_dns: function (node:PChar; port:Integer):TDimLong; cdecl;
var dic_add_dns: function (node:PChar; port:Integer):TDimLong; cdecl;
var dim_get_env_var: function (env_var:PChar; value:PChar; value_size:Integer):Integer; cdecl;
var dim_set_write_buffer_size: function (bytes:Integer):Integer; cdecl;
var dim_get_write_buffer_size: function :Integer; cdecl;
var dim_set_read_buffer_size: function (bytes:Integer):Integer; cdecl;
var dim_get_read_buffer_size: function :Integer; cdecl;
var dis_set_debug_on: procedure ; cdecl;
var dis_set_debug_off: procedure ; cdecl;
var dim_set_keepalive_timeout: procedure (secs:Integer); cdecl;
var dim_get_keepalive_timeout: function :Integer; cdecl;
var dim_set_listen_backlog: procedure (size:Integer); cdecl;
var dim_get_listen_backlog: function :Integer; cdecl;
var dis_start_serving: function (TaskName:PChar):Integer; cdecl;
var dis_stop_serving: procedure ; cdecl;
var dis_get_next_cmnd: function (var Tag:TDimLong; Buff:Pointer; var Size:Integer):Integer; cdecl;
var dis_get_client: function (Name:PChar):Integer; cdecl;
var dis_get_conn_id: function :Integer; cdecl;
var dis_add_service: function (ServiceName:PChar; ServiceType:PChar;
                          ServiceAddr:Pointer; ServiceSize:Integer;
                          UserRoutine:TDis_User_Routine; Tag:TDimLong):Cardinal; cdecl;
var dis_add_cmnd: function (ServiceName:PChar; ServiceType:PChar;
                       UserRoutine:TDis_Cmnd_Routine;
                       Tag:TDimLong):Cardinal; cdecl;
var dis_add_client_exit_handler: procedure (UserRoutine:TDis_Exit_Handler); cdecl;
var dis_set_client_exit_handler: procedure (ConnId:Integer; code:Integer); cdecl;
var dis_add_exit_handler: procedure (UserRoutine:TDis_Exit_Handler); cdecl;
var dis_add_error_handler: procedure (handler:TDis_Error_Handler); cdecl;
var dis_report_service: procedure (ServiceName:PChar); cdecl;
var dis_update_service: function (ServiceId:Cardinal):Integer; cdecl;
var dis_remove_service: function (ServiceId:Cardinal):Integer; cdecl;
var dis_send_service: procedure (ServiceId:Cardinal; Buff:Pointer; Size:Integer); cdecl;
var dis_set_buffer_size: function (Size:Integer):Integer; cdecl;
var dis_set_quality: procedure (ServiceId:Cardinal; Quality:Integer); cdecl;
var dis_set_timestamp: procedure (ServiceId:Cardinal; secs:Integer; millisecs:Integer); cdecl;
var dis_selective_update_service: function (ServiceId:Cardinal; var client_id_list:Integer):Integer; cdecl;
var dis_disable_padding: procedure ; cdecl;
var dis_get_timeout: function (ServiceId:Cardinal; ClientId:Integer):Integer; cdecl;
var dis_get_error_services: function :PChar; cdecl;
var dis_get_client_services: function (conn_id:Integer):PChar; cdecl;
var dis_start_serving_dns: function (dns_id:TDimLong; task_name:PChar):Integer; cdecl;
var dis_stop_serving_dns: procedure (dns_id:TDimLong); cdecl;
var dis_add_service_dns: function (dns_id:TDimLong; ServiceName:PChar; ServiceType:PChar;
                          ServiceAddr:Pointer; ServiceSize:Integer;
                          UserRoutine:TDis_User_Routine; Tag:TDimLong):Cardinal; cdecl;
var dis_add_cmnd_dns: function (dns_id:TDimLong; ServiceName:PChar; ServiceType:PChar;
                       UserRoutine:TDis_Cmnd_Routine; Tag:TDimLong):Cardinal; cdecl;
var dis_get_n_clients: function (ServiceId:Cardinal):Integer; cdecl;
var dis_get_timestamp: function (ServiceId:Cardinal; var secs:Integer; var millisecs:Integer):Integer; cdecl;
var dic_info_service: function (ServiceName:PChar; req_type:Integer; req_timeout:Integer;
                           ServiceAddr:Pointer; ServiceSize:Integer;
                           UserRoutine:TDic_User_Routine; tag:TDimLong;
                           fill_addr:Pointer; fill_size:Integer):Cardinal; cdecl;
var dic_info_service_stamped: function (ServiceName:PChar; req_type:Integer; req_timeout:Integer;
                                   ServiceAddr:Pointer; ServiceSize:Integer;
                                   UserRoutine:TDic_User_Routine; tag:TDimLong;
                                   fill_addr:Pointer; fill_size:Integer):Cardinal; cdecl;
var dic_cmnd_callback: function (ServiceName:PChar; ServiceAddr:Pointer; ServiceSize:Integer;
                            CmndRoutine:TDic_Cmnd_Routine; tag:TDimLong):Integer; cdecl;
var dic_cmnd_service: function (ServiceName:PChar; ServiceAddr:Pointer; ServiceSize:Integer):Integer; cdecl;
var dic_change_address: procedure (ServiceId:Cardinal; ServiceAddr:Pointer; ServiceSize:Integer); cdecl;
var dic_release_service: procedure (ServiceId:Cardinal); cdecl;
var dic_get_id: function (Name:PChar):Integer; cdecl;
var dic_get_quality: function (ServiceId:Cardinal):Integer; cdecl;
var dic_get_timestamp: function (ServiceId:Cardinal; var secs:Integer; var milisecs:Integer):Integer; cdecl;
var dic_get_format: function (ServiceId:Cardinal):PChar; cdecl;
var dic_disable_padding: procedure ; cdecl;
var dic_close_dns: procedure ; cdecl;
var dic_add_error_handler: procedure (handler:TDic_Error_Handler); cdecl;
var dic_get_error_services: function :PChar; cdecl;
var dic_get_server_services: function (conn_id:Integer):PChar; cdecl;
var dic_get_server: function (name:PChar):Integer; cdecl;
var dic_get_conn_id: function :Integer; cdecl;
var dic_stop: procedure ; cdecl;
var dic_get_server_pid: function(var pid:Integer):Integer; cdecl;

{$ENDIF DIM_STATIC}

 /////////////////////////
 // Addon utility routines
 /////////////////////////

 //
 // Name of severity: INFO/WARNING/ERROR/FATAL/UNKNOWN
 //
function dim_severity_name(severity:Integer):PChar; cdecl;

 //////////////////////////////
 // Service to load DIM library
 //////////////////////////////
function  ValidDimLibrary:Boolean; inline; // Check status
function  LoadDimLibrary(const FileName:String=''):Boolean;
procedure FreeDimLibrary; // Do not use this call directly
function  DimLibraryName:String; // dim, dim.dll, libdim.so

var // Internal DIM data, please don't change
 DimLibrary : record       // DIM library data
  Valid     : Boolean;     // Library status
  libHandle : TLibHandle;  // Library handle
  numLoaded : Integer;     // Num functions loaded
  numFailed : Integer;     // Num functions failed
  Report    : ShortString; // Report result on Load
 end = ( Valid:false; libHandle:0; numLoaded:0; numFailed:0; Report:'' );

implementation

const // Expected number of functions loaded
  ExpectedNumLoaded = 102 {$IFDEF WINDOWS} + 4 {$ENDIF};

{$IFDEF DIM_STATIC}

const // The Name of DIM library
 DimDll = {$IFDEF WINDOWS} 'dim.dll' {$ELSE} 'dim' {$ENDIF};

function  HashFunction;                 external DimDll name 'HashFunction';
function  get_node_name;                external DimDll name 'get_node_name';
function  get_dns_port_number;          external DimDll name 'get_dns_port_number';
function  get_dns_node_name;            external DimDll name 'get_dns_node_name';
function  get_dns_accepted_domains;     external DimDll name 'get_dns_accepted_domains';
function  get_dns_accepted_nodes;       external DimDll name 'get_dns_accepted_nodes';
function  dtq_sleep;                    external DimDll name 'dtq_sleep';
procedure dtq_start_timer;              external DimDll name 'dtq_start_timer';
function  dtq_stop_timer;               external DimDll name 'dtq_stop_timer';
procedure dim_init;                     external DimDll name 'dim_init';
procedure dim_no_threads;               external DimDll name 'dim_no_threads';
procedure dna_set_test_write;           external DimDll name 'dna_set_test_write';
procedure dna_rem_test_write;           external DimDll name 'dna_rem_test_write';
function  dim_set_scheduler_class;      external DimDll name 'dim_set_scheduler_class';
function  dim_get_scheduler_class;      external DimDll name 'dim_get_scheduler_class';
function  dim_set_priority;             external DimDll name 'dim_set_priority';
function  dim_get_priority;             external DimDll name 'dim_get_priority';
function  dim_set_dns_node;             external DimDll name 'dim_set_dns_node';
function  dim_get_dns_node;             external DimDll name 'dim_get_dns_node';
function  dim_set_dns_port;             external DimDll name 'dim_set_dns_port';
function  dim_get_dns_port;             external DimDll name 'dim_get_dns_port';
procedure dic_set_debug_on;             external DimDll name 'dic_set_debug_on';
procedure dic_set_debug_off;            external DimDll name 'dic_set_debug_off';
procedure dim_print_date_time;          external DimDll name 'dim_print_date_time';
procedure dim_set_write_timeout;        external DimDll name 'dim_set_write_timeout';
function  dim_get_write_timeout;        external DimDll name 'dim_get_write_timeout';
procedure dim_usleep;                   external DimDll name 'dim_usleep';
function  dim_wait;                     external DimDll name 'dim_wait';
{$IFDEF WINDOWS} procedure dim_pause;   external DimDll name 'dim_pause';   {$ENDIF WINDOWS}
{$IFDEF WINDOWS} procedure dim_wake_up; external DimDll name 'dim_wake_up'; {$ENDIF WINDOWS}
procedure dim_lock;                     external DimDll name 'dim_lock';
procedure dim_unlock;                   external DimDll name 'dim_unlock';
{$IFDEF WINDOWS} procedure dim_sleep;   external DimDll name 'dim_sleep';         {$ENDIF WINDOWS}
{$IFDEF WINDOWS} procedure dim_win_usleep; external DimDll name 'dim_win_usleep'; {$ENDIF WINDOWS}
function  dim_start_thread;             external DimDll name 'dim_start_thread';
function  dic_set_dns_node;             external DimDll name 'dic_set_dns_node';
function  dic_get_dns_node;             external DimDll name 'dic_get_dns_node';
function  dic_set_dns_port;             external DimDll name 'dic_set_dns_port';
function  dic_get_dns_port;             external DimDll name 'dic_get_dns_port';
function  dis_set_dns_node;             external DimDll name 'dis_set_dns_node';
function  dis_get_dns_node;             external DimDll name 'dis_get_dns_node';
function  dis_set_dns_port;             external DimDll name 'dis_set_dns_port';
function  dis_get_dns_port;             external DimDll name 'dis_get_dns_port';
procedure dim_stop;                     external DimDll name 'dim_stop';
function  dim_stop_thread;              external DimDll name 'dim_stop_thread';
function  dis_add_dns;                  external DimDll name 'dis_add_dns';
function  dic_add_dns;                  external DimDll name 'dic_add_dns';
function  dim_get_env_var;              external DimDll name 'dim_get_env_var';
function  dim_set_write_buffer_size;    external DimDll name 'dim_set_write_buffer_size';
function  dim_get_write_buffer_size;    external DimDll name 'dim_get_write_buffer_size';
function  dim_set_read_buffer_size;     external DimDll name 'dim_set_read_buffer_size';
function  dim_get_read_buffer_size;     external DimDll name 'dim_get_read_buffer_size';
procedure dis_set_debug_on;             external DimDll name 'dis_set_debug_on';
procedure dis_set_debug_off;            external DimDll name 'dis_set_debug_off';
procedure dim_set_keepalive_timeout;    external DimDll name 'dim_set_keepalive_timeout';
function  dim_get_keepalive_timeout;    external DimDll name 'dim_get_keepalive_timeout';
procedure dim_set_listen_backlog;       external DimDll name 'dim_set_listen_backlog';
function  dim_get_listen_backlog;       external DimDll name 'dim_get_listen_backlog';
function  dis_start_serving;            external DimDll name 'dis_start_serving_';
procedure dis_stop_serving;             external DimDll name 'dis_stop_serving_';
function  dis_get_next_cmnd;            external DimDll name 'dis_get_next_cmnd_';
function  dis_get_client;               external DimDll name 'dis_get_client_';
function  dis_get_conn_id;              external DimDll name 'dis_get_conn_id';
function  dis_add_service;              external DimDll name 'dis_add_service_';
function  dis_add_cmnd;                 external DimDll name 'dis_add_cmnd_';
procedure dis_add_client_exit_handler;  external DimDll name 'dis_add_client_exit_handler_';
procedure dis_set_client_exit_handler;  external DimDll name 'dis_set_client_exit_handler_';
procedure dis_add_exit_handler;         external DimDll name 'dis_add_exit_handler_';
procedure dis_add_error_handler;        external DimDll name 'dis_add_error_handler';
procedure dis_report_service;           external DimDll name 'dis_report_service_';
function  dis_update_service;           external DimDll name 'dis_update_service_';
function  dis_remove_service;           external DimDll name 'dis_remove_service_';
procedure dis_send_service;             external DimDll name 'dis_send_service_';
function  dis_set_buffer_size;          external DimDll name 'dis_set_buffer_size';
procedure dis_set_quality;              external DimDll name 'dis_set_quality_';
procedure dis_set_timestamp;            external DimDll name 'dis_set_timestamp_';
function  dis_selective_update_service; external DimDll name 'dis_selective_update_service_';
procedure dis_disable_padding;          external DimDll name 'dis_disable_padding';
function  dis_get_timeout;              external DimDll name 'dis_get_timeout';
function  dis_get_error_services;       external DimDll name 'dis_get_error_services';
function  dis_get_client_services;      external DimDll name 'dis_get_client_services';
function  dis_start_serving_dns;        external DimDll name 'dis_start_serving_dns';
procedure dis_stop_serving_dns;         external DimDll name 'dis_stop_serving_dns';
function  dis_add_service_dns;          external DimDll name 'dis_add_service_dns';
function  dis_add_cmnd_dns;             external DimDll name 'dis_add_cmnd_dns';
function  dis_get_n_clients;            external DimDll name 'dis_get_n_clients';
function  dis_get_timestamp;            external DimDll name 'dis_get_timestamp_';
function  dic_info_service;             external DimDll name 'dic_info_service_';
function  dic_info_service_stamped;     external DimDll name 'dic_info_service_stamped_';
function  dic_cmnd_callback;            external DimDll name 'dic_cmnd_callback_';
function  dic_cmnd_service;             external DimDll name 'dic_cmnd_service_';
procedure dic_change_address;           external DimDll name 'dic_change_address_';
procedure dic_release_service;          external DimDll name 'dic_release_service_';
function  dic_get_id;                   external DimDll name 'dic_get_id_';
function  dic_get_quality;              external DimDll name 'dic_get_quality_';
function  dic_get_timestamp;            external DimDll name 'dic_get_timestamp_';
function  dic_get_format;               external DimDll name 'dic_get_format_';
procedure dic_disable_padding;          external DimDll name 'dic_disable_padding';
procedure dic_close_dns;                external DimDll name 'dic_close_dns';
procedure dic_add_error_handler;        external DimDll name 'dic_add_error_handler';
function  dic_get_error_services;       external DimDll name 'dic_get_error_services';
function  dic_get_server_services;      external DimDll name 'dic_get_server_services';
function  dic_get_server;               external DimDll name 'dic_get_server';
function  dic_get_conn_id;              external DimDll name 'dic_get_conn_id';
procedure dic_stop;                     external DimDll name 'dic_stop';
function  dic_get_server_pid;           external DimDll name 'dic_get_server_pid';

function LoadDimLibrary(const FileName:String=''):Boolean;
var libName:String;
begin
 DimLibrary.Valid:=true;
 DimLibrary.libHandle:=0;
 DimLibrary.numLoaded:=ExpectedNumLoaded;
 DimLibrary.numFailed:=0;
 libName:=Trim(FileName);
 if (libName='') then libName:=DimDll;
 DimLibrary.Report:=libName+': Success';
 Result:=DimLibrary.Valid;
end;

{$ELSE  DIM_STATIC}

const // The Name of DIM library
 DimDll = {$IFDEF WINDOWS} 'dim.dll' {$ELSE} 'libdim.so' {$ENDIF};

function LoadDimLibrary(const FileName:String=''):Boolean;
var lib:TLibHandle; numOk,numEr:Integer; libName:String;
 function DoGetProcAddress(ProcName:String):Pointer;
 begin
  if (lib=0)
  then Result:=nil
  else Result:=System.GetProcAddress(lib,ProcName);
  if (Result<>nil) then inc(numOk) else inc(numEr);
 end;
begin
 if DimLibrary.Valid then begin
  Result:=true; // Already done
  Exit;
 end;
 numOk:=0; numEr:=0;
 libName:=Trim(FileName);
 if (libName='') then libName:=DimDll;
 lib:=SafeLoadLibrary(libName);
 HashFunction                    := DoGetProcAddress( 'HashFunction' );
 get_node_name                   := DoGetProcAddress( 'get_node_name' );
 get_dns_port_number             := DoGetProcAddress( 'get_dns_port_number' );
 get_dns_node_name               := DoGetProcAddress( 'get_dns_node_name' );
 get_dns_accepted_domains        := DoGetProcAddress( 'get_dns_accepted_domains' );
 get_dns_accepted_nodes          := DoGetProcAddress( 'get_dns_accepted_nodes' );
 dtq_sleep                       := DoGetProcAddress( 'dtq_sleep' );
 dtq_start_timer                 := DoGetProcAddress( 'dtq_start_timer' );
 dtq_stop_timer                  := DoGetProcAddress( 'dtq_stop_timer' );
 dim_init                        := DoGetProcAddress( 'dim_init' );
 dim_no_threads                  := DoGetProcAddress( 'dim_no_threads' );
 dna_set_test_write              := DoGetProcAddress( 'dna_set_test_write' );
 dna_rem_test_write              := DoGetProcAddress( 'dna_rem_test_write' );
 dim_set_scheduler_class         := DoGetProcAddress( 'dim_set_scheduler_class' );
 dim_get_scheduler_class         := DoGetProcAddress( 'dim_get_scheduler_class' );
 dim_set_priority                := DoGetProcAddress( 'dim_set_priority' );
 dim_get_priority                := DoGetProcAddress( 'dim_get_priority' );
 dim_set_dns_node                := DoGetProcAddress( 'dim_set_dns_node' );
 dim_get_dns_node                := DoGetProcAddress( 'dim_get_dns_node' );
 dim_set_dns_port                := DoGetProcAddress( 'dim_set_dns_port' );
 dim_get_dns_port                := DoGetProcAddress( 'dim_get_dns_port' );
 dic_set_debug_on                := DoGetProcAddress( 'dic_set_debug_on' );
 dic_set_debug_off               := DoGetProcAddress( 'dic_set_debug_off' );
 dim_print_date_time             := DoGetProcAddress( 'dim_print_date_time' );
 dim_set_write_timeout           := DoGetProcAddress( 'dim_set_write_timeout' );
 dim_get_write_timeout           := DoGetProcAddress( 'dim_get_write_timeout' );
 dim_usleep                      := DoGetProcAddress( 'dim_usleep' );
 dim_wait                        := DoGetProcAddress( 'dim_wait' );
 {$IFDEF WINDOWS} dim_pause      := DoGetProcAddress( 'dim_pause' );   {$ENDIF WINDOWS}
 {$IFDEF WINDOWS} dim_wake_up    := DoGetProcAddress( 'dim_wake_up' ); {$ENDIF WINDOWS}
 dim_lock                        := DoGetProcAddress( 'dim_lock' );
 dim_unlock                      := DoGetProcAddress( 'dim_unlock' );
 {$IFDEF WINDOWS} dim_sleep      := DoGetProcAddress( 'dim_sleep' );      {$ENDIF WINDOWS}
 {$IFDEF WINDOWS} dim_win_usleep := DoGetProcAddress( 'dim_win_usleep' ); {$ENDIF WINDOWS}
 dim_start_thread                := DoGetProcAddress( 'dim_start_thread' );
 dic_set_dns_node                := DoGetProcAddress( 'dic_set_dns_node' );
 dic_get_dns_node                := DoGetProcAddress( 'dic_get_dns_node' );
 dic_set_dns_port                := DoGetProcAddress( 'dic_set_dns_port' );
 dic_get_dns_port                := DoGetProcAddress( 'dic_get_dns_port' );
 dis_set_dns_node                := DoGetProcAddress( 'dis_set_dns_node' );
 dis_get_dns_node                := DoGetProcAddress( 'dis_get_dns_node' );
 dis_set_dns_port                := DoGetProcAddress( 'dis_set_dns_port' );
 dis_get_dns_port                := DoGetProcAddress( 'dis_get_dns_port' );
 dim_stop                        := DoGetProcAddress( 'dim_stop' );
 dim_stop_thread                 := DoGetProcAddress( 'dim_stop_thread' );
 dis_add_dns                     := DoGetProcAddress( 'dis_add_dns' );
 dic_add_dns                     := DoGetProcAddress( 'dic_add_dns' );
 dim_get_env_var                 := DoGetProcAddress( 'dim_get_env_var' );
 dim_set_write_buffer_size       := DoGetProcAddress( 'dim_set_write_buffer_size' );
 dim_get_write_buffer_size       := DoGetProcAddress( 'dim_get_write_buffer_size' );
 dim_set_read_buffer_size        := DoGetProcAddress( 'dim_set_read_buffer_size' );
 dim_get_read_buffer_size        := DoGetProcAddress( 'dim_get_read_buffer_size' );
 dis_set_debug_on                := DoGetProcAddress( 'dis_set_debug_on' );
 dis_set_debug_off               := DoGetProcAddress( 'dis_set_debug_off' );
 dim_set_keepalive_timeout       := DoGetProcAddress( 'dim_set_keepalive_timeout' );
 dim_get_keepalive_timeout       := DoGetProcAddress( 'dim_get_keepalive_timeout' );
 dim_set_listen_backlog          := DoGetProcAddress( 'dim_set_listen_backlog' );
 dim_get_listen_backlog          := DoGetProcAddress( 'dim_get_listen_backlog' );
 dis_start_serving               := DoGetProcAddress( 'dis_start_serving_' );
 dis_stop_serving                := DoGetProcAddress( 'dis_stop_serving_' );
 dis_get_next_cmnd               := DoGetProcAddress( 'dis_get_next_cmnd_' );
 dis_get_client                  := DoGetProcAddress( 'dis_get_client_' );
 dis_get_conn_id                 := DoGetProcAddress( 'dis_get_conn_id' );
 dis_add_service                 := DoGetProcAddress( 'dis_add_service_' );
 dis_add_cmnd                    := DoGetProcAddress( 'dis_add_cmnd_' );
 dis_add_client_exit_handler     := DoGetProcAddress( 'dis_add_client_exit_handler_' );
 dis_set_client_exit_handler     := DoGetProcAddress( 'dis_set_client_exit_handler_' );
 dis_add_exit_handler            := DoGetProcAddress( 'dis_add_exit_handler_' );
 dis_add_error_handler           := DoGetProcAddress( 'dis_add_error_handler' );
 dis_report_service              := DoGetProcAddress( 'dis_report_service_' );
 dis_update_service              := DoGetProcAddress( 'dis_update_service_' );
 dis_remove_service              := DoGetProcAddress( 'dis_remove_service_' );
 dis_send_service                := DoGetProcAddress( 'dis_send_service_' );
 dis_set_buffer_size             := DoGetProcAddress( 'dis_set_buffer_size' );
 dis_set_quality                 := DoGetProcAddress( 'dis_set_quality_' );
 dis_set_timestamp               := DoGetProcAddress( 'dis_set_timestamp_' );
 dis_selective_update_service    := DoGetProcAddress( 'dis_selective_update_service_' );
 dis_disable_padding             := DoGetProcAddress( 'dis_disable_padding' );
 dis_get_timeout                 := DoGetProcAddress( 'dis_get_timeout' );
 dis_get_error_services          := DoGetProcAddress( 'dis_get_error_services' );
 dis_get_client_services         := DoGetProcAddress( 'dis_get_client_services' );
 dis_start_serving_dns           := DoGetProcAddress( 'dis_start_serving_dns' );
 dis_stop_serving_dns            := DoGetProcAddress( 'dis_stop_serving_dns' );
 dis_add_service_dns             := DoGetProcAddress( 'dis_add_service_dns' );
 dis_add_cmnd_dns                := DoGetProcAddress( 'dis_add_cmnd_dns' );
 dis_get_n_clients               := DoGetProcAddress( 'dis_get_n_clients' );
 dis_get_timestamp               := DoGetProcAddress( 'dis_get_timestamp_' );
 dic_info_service                := DoGetProcAddress( 'dic_info_service_' );
 dic_info_service_stamped        := DoGetProcAddress( 'dic_info_service_stamped_' );
 dic_cmnd_callback               := DoGetProcAddress( 'dic_cmnd_callback_' );
 dic_cmnd_service                := DoGetProcAddress( 'dic_cmnd_service_' );
 dic_change_address              := DoGetProcAddress( 'dic_change_address_' );
 dic_release_service             := DoGetProcAddress( 'dic_release_service_' );
 dic_get_id                      := DoGetProcAddress( 'dic_get_id_' );
 dic_get_quality                 := DoGetProcAddress( 'dic_get_quality_' );
 dic_get_timestamp               := DoGetProcAddress( 'dic_get_timestamp_' );
 dic_get_format                  := DoGetProcAddress( 'dic_get_format_' );
 dic_disable_padding             := DoGetProcAddress( 'dic_disable_padding' );
 dic_close_dns                   := DoGetProcAddress( 'dic_close_dns' );
 dic_add_error_handler           := DoGetProcAddress( 'dic_add_error_handler' );
 dic_get_error_services          := DoGetProcAddress( 'dic_get_error_services' );
 dic_get_server_services         := DoGetProcAddress( 'dic_get_server_services' );
 dic_get_server                  := DoGetProcAddress( 'dic_get_server' );
 dic_get_conn_id                 := DoGetProcAddress( 'dic_get_conn_id' );
 dic_stop                        := DoGetProcAddress( 'dic_stop' );
 dic_get_server_pid              := DoGetProcAddress( 'dic_get_server_pid' );
 DimLibrary.Valid:=(numOk=ExpectedNumLoaded) and (numEr=0);
 DimLibrary.libHandle:=lib;
 DimLibrary.numLoaded:=numOk;
 DimLibrary.numFailed:=numEr;
 if DimLibrary.Valid
 then DimLibrary.Report:=libName+': Success'
 else DimLibrary.Report:=libName+': Failure';
 {$IFDEF UNIX}
 if lib=0 then DimLibrary.Report:=StrPas(dlerror);
 {$ENDIF UNIX}
 Result:=DimLibrary.Valid;
end;

{$ENDIF DIM_STATIC}

procedure FreeDimLibrary;
begin
 if (DimLibrary.libHandle<>0) then begin
  if DimLibrary.Valid then begin
   dis_stop_serving;
   dic_stop;
   dim_stop;
  end;
  FreeLibrary(DimLibrary.libHandle);
 end;
 DimLibrary.Valid:=false;
 DimLibrary.libHandle:=0;
 DimLibrary.numLoaded:=0;
 DimLibrary.numFailed:=0;
end;

function  ValidDimLibrary:Boolean;
begin
 Result:=DimLibrary.Valid;
end;

function dim_severity_name(severity:Integer):PChar; cdecl;
begin
 case severity of
  es_DIM_INFO    : Result:='INFO';
  es_DIM_WARNING : Result:='WARNING';
  es_DIM_ERROR   : Result:='ERROR';
  es_DIM_FATAL   : Result:='FATAL';
  else             Result:='UNKNOWN';
 end;
end;

function DimLibraryName:String;
begin
 Result:=DimDll;
end;

///////////////////////////////////////
// Unit initialization and finalization
///////////////////////////////////////

procedure Init_crw_dim;
begin
 LoadDimLibrary;
end;

procedure Free_crw_dim;
begin
 // FreeDimLibrary;
end;

initialization

 Init_crw_dim;

finalization

 Free_crw_dim;

end.

//////////////
// END OF FILE
//////////////

