This version of the guide corresponds with ADCH++ versions 2.9.x and later.

1. Introduction

ADCH++ is a hub server software for the ADC network. It implements the ADC protocol. The core application is very simple, but extensible using plugins. Among the standard plugins there is a scripting plugin that allows hub owners to further customize the hub using the Lua scripting language. The core is also exposed as a Python and a Ruby module, thus it is possible to use it within a Python or Ruby application.

2. Preface

This guide is intended for novice or expert users. It focuses on various scripting interfaces, advanced hub security, compiling and running ADCH++ in service mode, as well as troubleshooting and bug reporting.

3. Advanced hub security

This part shows how to achieve spam, badword or badsearch protection as well as how to protect the hub’s normal operation from malicious or accidental flooding or misuse.

Important The prepackaged LUA scripts should be properly loaded to get the functionality described in this chapter.

3.1. Automatic spam, badword and badsearch protection: working with the banre commands

+banxxxre commands are very powerful tools for getting rid of unwanted text showing in mainchat or private message as well as for blocking searches containing keywords which treated malicious. These commands use LUA pattern matching method which is similar to the popular regular expressions. Usage of the commands to detect the unwanted content requires knowledge of how to construct a regular expression like filter.

Tip For basic information about regular expressions visit:

A quick tutorial about LUA patterns, their usage and differences to regular expressions is avalilable at Wowpedia.

Table 1. List of +banre commands
Command Purpose

+banmsgre [action] <chat-reg-exp> [reason] [expiration]

Block chatmessages that match the given LUA pattern

+bannickre [action] <nick-reg-exp> [reason] [expiration]

Block nicks that match the given LUA pattern

+banschre [action] <search-reg-exp> [reason] [expiration]

Block searches that match the given LUA pattern

Using the +banre commands the LUA pattern must be specified within < and > brackets. The action parameter is optional, you can skip it to achieve a simple block or set it to -1 to permanetly ban the user; any other positive number means how many minutes you want to tempban the user for. The expiration parameter is also optional, it defines when this particular rule expires (in minutes). Skipping [expiraton] results a permanent rule while specifying 0 allows you to remove this banre rule.

Important Removing a banre rule does NOT automatically remove the already (temp)banned users!
Example: Banre Command Example
+banmsgre 100 <www> unwanted spam

3.2. Setting up limits rules

Using basic rules you can specify a few parameters the hub members should meet to use your hub. These rules provided by the clients with their periodic info data.

Table 2. List of basic limits setting variables
Setting Purpose


Maximum number of hubs allowed, 0 = disabled


Maximum hub/slots ratio allowed, 0 = disabled


Maximum number of characters allowed per chat message, 0 = no limit


Maximum nickname length allowed, 0 = no limit


Maximum share size allowed in bytes, 0 = disabled


Maximum number of shared files allowed in bytes, 0 = disabled


Maximum amount of opened upload slots allowed, 0 = disabled


Minimum hub/slots ratio required, 0 = disabled


Minimum share size required in bytes, 0 = disabled


Minimum number of shared files required in bytes, 0 = disabled


Minimum amount of opened upload slots required, 0 = disabled

You can set the limiting rules using the +cfgli command:

Example: setting minimum share size to 1Mb
+cfgli minsharesize 1000000

The limiting function is disabled by default, you can enable or disable the function globally using the

+cfgli li_limitstats


Table 3. Using the global limits enable/disable setting
Setting Purpose


Globaly enable/disable the limiting function, 0 = for limits enforcing only, 1 = limits enforcing and logging to a file on disk, -1 = function disabled completly

Tip Other settings values and logs are kept even if you globally disable the limiting function.

There are more advanced limiting possibilities, using those you can regulate user parameters like nick length, maximum length of search strings or require special ADC client features. You can get all the available limit rules settings, their description and current values using the

+help cfgli


If a user tries to breach any set rule (either when he/she is logged in or at login time) an action will be taken. For most kind of rules you can specify the action (disconnect or redirect) and also the maximum count or count/interval to be reached to make the re-attempts treated as flooding. In this case the user will be punished according the flood protection settings (described later).

You can use the following commands to specify the action and counts:

Table 4. List of limit counts and action settings
Setting Purpose


Global expire time for all enabled limit rules in minutes, it must be greater than zero. This time specifies how long the count of limit breaches will be kept for an user. If no more problems occour within the specified time interval the counts will be reset.


Global maximum count of attempts allowed for all limit rules, 0 = disabled. If the number of attempts reach this value within li_exptime then action will be taken.


Global maximum rate in counts/hour for all enabled limit rules, 0 = disabled. If the number of attempts reach this value then action will be taken immediately.


All users with level greater than this will be excluded from the limit rules like slots/hubs/sharesize, use -1 to disable. You can use this setting in conjunction with li_minlevel to apply the limit rules to certain userslevels while exclude higher and lower levels (e.g. unregistered users and operators).


Minimum user level to apply the sharing limit rules like slots/hubs/sharesize, 0 means all users will be checked. You can use this setting in conjunction with minsearchlevel and mindownloadlevel settings to block low user levels but allow them to login without complying the rules.


Specifies the action when the sharing limit rules like slots/hubs/sharesize is breached. Set a redirect address for redirecting, if you want the user simply disconnected then leave this setting blank. This setting does not effect some of the limits counts (like maxnicklength or search related limits), those are immediately added to the flood protection counts.

Tip You can use both li_maxcount and li_maxrate at the same time: the specified action (li_redirect) will happen whatever value reached first.

Every single limit setting has its own expiration and rate setting to be able to fine tune the action behaviour of the individual rules. Expiration or rate settings for an individual limit rule will always override the global settings (li_exptime and li_maxrate). The syntax of the name of the settings follows a pattern: you add _exp and _rate to the name of each limit rule setting to get the name of their corresponding individual expiration and rate settings:

Example: alter individual limits rate and expiration settings
+cfgli maxslots 10
+cfgli maxslots_exp 60
+cfgli maxslots_rate 5

+cfgli minschlength 3
+cfgli minschlength_exp 30
+cfgli minschlength_rate 10

To see all the current limits rules settings values in a grouped table format use the



3.3. Flood protection

The access.guard.lua script provides an advanced flood protection for your hub. The function is globally disabled by default but the various settings are filled with optimal parameters to start with. If you want to fine tune the flood protection you can do so as every parameter is highly configurable.

You can enable or disable the function globally using the

+cfgfl fl_commandstats


Table 5. Using the global flood protection enable/disable setting
Setting Purpose


Globaly enable/disable the flood protection function, 0 = for flood protection only, 1 = flood protection and logging to a file on disk, -1 = function disabled completly

Tip Other settings values and logs are kept even if you globally disable the flood protection function.

You can list the available individual flood protection settings using the

+help cfgfl


Important Be careful with the settings as wrong values can easily render your hub unusable.

Flooding attempts can be punished with widely configurable automatic response actions with step by step severity. Besides classic flooding methods, these actions can also be triggered by the repeatedly breached limit rules (see the previous chapter). The available actions are disconnect, temporary ban and full ban. These actions can happen only in this order, step by step, starting with warning(s) sent to the user and so on. The step by step manner means that a flooder will always be warned (at least once) then kicked, time banned and at last - if the flooding attepmts don’t stop - the final solution is the permanent ban. This way of action steps from warning to severe punishment allows the accidental flooder to "cool down" and retry the command/operation in an acceptable normal way. You can configure how many punishment actions should occour from one kind to step over the next one. If you set one flood protection action type’s count to zero then neither that action nor the following one in the row will ever happen. You can use the following +cfgfl settings to configure them:

Table 6. List of flood action control settings
Setting Purpose


Global expire time for all flood settings in minutes, it must be greater than zero. This time specifies how long the count of detected flood attempts will be kept for a particualr user. If no more problems occour within the specified time interval the counts will be reset.


All users with level greater of this setting will be affected by the flood protecting rules, -1 = disabled


Global maximum rate in counts/minute for all enabled flood protection rules, 0 = disabled. If the number of attempts reach this value then the next punishing action in a row will be taken immediately.


Maximum amount of hammering warnings before the user is disconnected, 0 = disabled


Maximum amount of kicks occoured before the user is tempbanned, 0 = disabled


Maximum amount of tempbans before user is permanently banned, 0 = disabled


Sets how many minutes a user will be tempbanned after reaching the maxkicks value, 0 = disabled

The reaction for the different kind of flooding attempts can be fine tuned with tons of parameters available in +help cfgfl. Similar to the limits settings, every flood type can have its own individual expiration and rate settings to provide maximum flexibility.

It’s possible to check how the punishing actions hit the users. There’s a log of kick and tempban events that kept for several days and can be displayed with the following commands:


You can configure how long do you want to keep the log of the kick and tempban events with the

+cfg fl_logexptime n

setting where n is the log expire time in days for both logs.

3.4. Tracing users

Above the basic current information the core provides about an online user (+info <nick/CID> command) it’s possible to keep track of registered and unregistered users' activity in the hub for a given period of time (last n days). You can identify users logging on with different clients, using different nicks or arriving from various IP addresses.

The tracing function is disabled by default, you can enable or disable it globally using the

+cfgen en_entitystats


Table 7. Using the global tracing enable/disable setting
Setting Purpose


Globaly enable/disable the tracing function, 0 = for entity logging only, 1 = entity logging to a log file as well, -1 = function disabled completly

You can specify how long you want to trace different type of users. To see what configuration options available for enable/disable tracing individual users (entities) use the

+help cfgen


You can get the trace information for any stored entity (user) by one of its three possible indentifiers using the following commands:

Table 8. List of entity tracing commands
Command Purpose


traces the entity’s last info and history by CID (aliases: +tracebycid)


traces the entity’s last info and history by IP address (aliases: +tracebyip)


traces the entity’s last info and history by nick (aliases: +tracebyni)


shows the current info for all entities that match either Nick, IP or CID

Example trace
        Entity                                  CID: NMEW4RRISS2RUQPU3XMK5WNGJLXSPNKSVSMPEKY
        IP:                                     180.196.324.211
        Nick:                                   user
        Client:                                 StrgDC++ 2.42
        User Level:                             2
        Changed Nick, IP, AP or Level:          0 times
        Logins:                                 16 times
        Last Logon:                             0 days, 12 hours, 26 minutes and 30 seconds ago
        Total Time Online:                      4 days, 4 hours, 0 minutes and 45 seconds
        Last Updated Nick, IP, AP or Level:     8 days, 23 hours, 51 minutes and 12 seconds ago
        Entity Regged by:                       Admin
        Entity Created:                         8 days, 23 hours, 51 minutes and 12 seconds ago
        Entity Expires:                         in 59 days, 23 hours, 53 minutes and 48 seconds
Tip Settings values and logs are kept even if you globally disable the entity tracing function.

3.5. Displaying extended hub statistics

If the acces.guard script is running it’s possible to obtain highly detailed statistics about the ADC commands used in the hub. This is an useful addition to the basic information the hub core provides with the +info command. To see the extended hub commands usage statistics use the



Tip All statistics, traces and logs are saved so in case of a clean hub restart, shutdown or scripts reload these data is kept between sessions.

4. PtokaX API2 bridge for ADCH++

It’s possible to create or use existing PtokaX API2 LUA scripts in your hub using the ADCHPP-PtokaX bridge script. The bridge is separately maintained and available to download at its home page. Before you go on make sure you read the documentation (README.txt) provided in the ADCHPP-PtokaX package.

Caution To avoid problems make sure you use the revision of PtokaX bridge script corresponding to the ADCH++ version you run.

An example folder structure of a correctly installed ADCHPP-PtokaX bridge script and some native PtokaX scripts:

Directory of c:\users\username\adchpp\Scripts

2010-05-27  18:01    <DIR>          .
2010-05-27  18:01    <DIR>          ..
2010-05-03  22:58            58 383 access.lua
2010-05-03  22:58            18 483 access.bans.lua
2010-05-03  22:58             8 242
2010-05-03  22:58             9 385 access.guard.lua
2010-05-03  22:58            18 343 access.op.lua
2010-05-26  17:26            33 141 adchpp-ptokax.lua
2010-05-03  22:58             2 653 autil.lua
2010-05-03  22:58             3 699 example.lua
2010-05-03  22:58             3 003 history.lua
2010-05-03  22:58            15 808 json.lua
2010-05-03  22:58               742 motd.lua
2010-05-27  18:01    <DIR>          px
               8 File(s)        117 544 bytes

 Directory of c:\users\username\adchpp\Scripts\px

2010-05-27  18:01    <DIR>          .
2010-05-27  18:01    <DIR>          ..
2010-05-26  19:14             4 652 px_lastip.lua
2010-05-26  18:06            15 158 px_record.lua
2010-05-26  18:02             3 935 px_tagcheck.lua
2007-12-23  12:51            13 312 px_tophubbers.lua
2010-05-26  17:50             5 918 px_topshare.lua
               5 File(s)         62 491 bytes

You can configure the PtokaX scripts using the user commands provided by the bridge script (ADCH++-PtokaX submenu in the hub context menu of your ADC client). The usage is pretty straightforward eg. when you select Add a script you will be asked where to load the scripts from. The default location is the Scripts folder so if you have the scripts in a subdirectory like in the example above then you can simply load them by specifying their relative path like (px/example_script.lua).

The bridge script will create a file named adchpp-ptokax.txt in the Config directory of the ADCH++ installation. This file lists the path of the currently added PtokaX scripts. You can edit the file to add multiple scripts in one go like in the following example (your structure may differ):


Some of the PtokaX scripts (like FreshStuff or Feedwatch) may require LUA filesystem or socket library. Since version 2.9.0 the ADCH++ repository contains these libraries and the Windows binary distributions include the compiled libraries as .dll’s.

Caution Sometimes the libraries (.dll’s in Windows) have to be copied to the appropriate place when a PtokaX scripts search for them in esoteric paths (for example lv/libs for Leviathan). You can get more information from the README file that comes with ADCHPP-PtokaX package.

This is the example of how the Freshstuff script should be correctly configured. Add the script as you would normally do with any scripts. The rest of the directory contents should look like this:

Directory of c:\users\username\adchpp\Scripts\px

2010-05-27  18:08    <DIR>          .
2010-05-27  18:08    <DIR>          ..
2010-05-26  18:31    <DIR>          freshstuff
2010-05-26  18:14             1 815 freshstuff.lua
2010-05-26  19:16            19 516 px_feedwatch.lua
2010-05-26  19:14             4 652 px_lastip.lua
2010-05-26  18:06            15 158 px_record.lua
2010-05-26  18:02             3 935 px_tagcheck.lua
2007-12-23  12:51            13 312 px_tophubbers.lua
2010-05-26  17:50             5 918 px_topshare.lua
               7 File(s)         64 306 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff

2010-05-26  18:31    <DIR>          .
2010-05-26  18:31    <DIR>          ..
2010-05-26  18:14    <DIR>          components
2010-05-26  18:14    <DIR>          config
2010-05-26  18:15    <DIR>          data
2010-05-26  18:14    <DIR>          docs
2010-05-26  18:14            24 155 kernel.lua
2010-05-26  18:42    <DIR>          lib
2010-05-26  18:14            12 010 ptokax.lua
2010-05-26  18:14             5 775 tables.lua
               3 File(s)         41 940 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff\components

2010-05-26  18:14    <DIR>          .
2010-05-26  18:14    <DIR>          ..
2010-05-26  18:14             3 503 extras.lua
2010-05-26  18:14            14 072 requester.lua
               2 File(s)         17 575 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff\config

2010-05-26  18:14    <DIR>          .
2010-05-26  18:14    <DIR>          ..
2010-05-26  18:14               987 extras.lua
2010-05-26  18:14             3 182 main.lua
2010-05-26  18:14               374 requester.lua
               3 File(s)          4 543 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff\data

2010-05-26  18:15    <DIR>          .
2010-05-26  18:15    <DIR>          ..
2010-05-26  18:15               125 categories.dat
               1 File(s)            125 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff\docs

2010-05-26  18:14    <DIR>          .
2010-05-26  18:14    <DIR>          ..
2010-05-26  18:14             1 471 customprofile.txt
2010-05-26  18:14             4 350 development.txt
2010-05-26  18:14               201 INSTALL.txt
2010-05-26  18:14            16 755 license.txt
2010-05-26  18:14               735 README.txt
2010-05-26  18:14               644 TODO.txt
               6 File(s)         24 156 bytes

 Directory of c:\users\username\adchpp\Scripts\px\freshstuff\lib

2010-05-26  18:42    <DIR>          .
2010-05-26  18:42    <DIR>          ..
2010-05-13  16:14            13 824 lfs.dll
2010-05-13  16:14               616 lfs.dll.manifest
2010-05-26  18:14           138 240 PXLFS.dll
2010-05-26  18:14           262 144 PXLFS.tds
               4 File(s)        414 824 bytes

5. Scripting Interface and examples

ADCH++ core is exposed to various scripting languages that either has direct access to the core or can use it as a plugin.

5.1. LUA Interface

By default ADCH++ comes with prepackaged LUA scripts to handle the basic hub functions. These scripts themselves are very good examples of how to use the ADCH++ LUA API. You can also use following examlpe file to learn the basics:

-- This is an example script that scripters might want to use as a basis for their work. It
-- documents the bare minimum needed to make an Lua script interface with ADCH++.

-- For more detailed information, peeking into other, more evolved (but less documented) example
-- scripts as well as the Doxygen documentation of ADCH++ <> would
-- be a good idea.

-- Generally, to reach member "bar" of the class "foo" of ADCH++, one has to use: adchpp.foo_bar.
-- Examples: adchpp.Util_getCfgPath(), adchpp.AdcCommand_CMD_MSG, adchpp.Entity_STATE_NORMAL...

-- Feel free to use <> or <> if you need help.

-- When multiple scripts are loaded within the same global Lua engine, they can access each other's
-- public exports. It is therefore a convention to run each script in its own module.
-- Global Lua functions can still be accessed via _G, but we alias it to "base" for conveniance.
-- Global functions can then be called as such: base.print('blah'), base.pcall(protected_func)...
local base = _G

module('example') -- Give each module a unique name so they don't clash.

-- Import the ADCH++ Lua DLL (luadchpp.dll).
local adchpp = base.luadchpp

-- Import various base sets of Lua methods. Only import those you need for your specific module.
local io = base.require('io')
local math = base.require('math')
local os = base.require('os')
local string = base.require('string')
local table = base.require('table')

-- Import some utilitary Lua Scripts; these don't need to be explicitly loaded by ADCH++ (eg if
-- using the adchppd daemon, they don't need to be referenced in Scripts.xml).
local autil = base.require('autil')
local json = base.require('json')

-- Cache pointers to some managers of ADCH++ that we frequently use.
local cm = adchpp.getCM() -- ClientManager
local pm = adchpp.getPM() -- PluginManager

-- Listeners to connect to ADCH++. Define one unique identifier for each listener (i chose to call
-- them example_1, example_2 and so on) to make sure the variable holding the listener doesn't get
-- collected by Lua's garbage collector until the program is over.

-- ClientManager::signalConnected: called when an Entity entity has just connected.
example_1 = cm:signalConnected():connect(function(entity)
        -- Process signalConnected here.

-- ClientManager::signalReady: called when an Entity entity is now ready for read / write
-- operations (TLS handshake completed).
example_2 = cm:signalReady():connect(function(entity)
        -- Process signalReady here.

-- ClientManager::signalReceive: called when an AdcCommand cmd is received from Entity entity.
example_3 = cm:signalReceive():connect(function(entity, cmd, ok)
        local res = (function(entity, cmd, ok)
                -- Skip messages that have been handled and deemed as discardable by others.
                if not ok then
                        return ok
                -- Process signalReceive here.
                -- Return true to let the command be dispatched, false to block it.
        end)(entity, cmd, ok)
        if not res then
        return res

-- ClientManager::signalState: called after the state of an online Entity entity has changed.
example_4 = cm:signalState():connect(function(entity)
        -- Process signalState here.

-- ClientManager::signalDisconnected: called after an Entity entity has disconnected.
example_5 = cm:signalDisconnected():connect(function(entity)
        -- Process signalDisconnected here.

-- PluginManager::getCommandSignal(string): called when a +command managed by another plugin is
-- being executed.
example_6 = pm:getCommandSignal("blah"):connect(function(entity, list, ok)
        -- Skip messages that have been handled and deemed as discardable by others.
        if not ok then
                return ok
        -- Process getCommandSignal here.
        -- Return true to let the command be executed, false to block it.

The complete list of of the ADCH++ LUA API functions are available both in the Docs folder in the ADCH++ repository or at the ADCH++ home page.

5.2. Ruby Interface

Example file using the Ruby interface:


puts "Loading module..."

require 'rbadchpp'

a = Rbadchpp

config_path = File.expand_path("../etc/") + '/'
puts "Configuration path is #{config_path}..."

core = a::Core.create(config_path)

sil =
si = a::ServerInfo.create()
si.port= 2780

cm = core.get_client_manager()

print "."
counter = 0
connected = cm.signal_connected().connect( { counter = counter + 1 })
disconnected = cm.signal_disconnected().connect( { counter = counter - 1 })
cb = core.add_timed_job(1000, { puts counter })

trap("INT") { core.shutdown() }

puts "Shutting down..."

disconnected = nil
connected = nil
puts cb

cb = nil

core = nil

5.3. Python Interface

Example file using the Python interface:

import sys,os

import pyadchpp as a

from Helpers import *
from Hub import *

hub = Hub()
op = Profile('op', hub)
vip = Profile('vip', hub)

profiles = dict([(, x) for x in (op, vip)])

users = [User(profile=op, nick='arnetheduck', password='test')]

nicks = dict([(x.nick, x) for x in users if x.nick])
cids = dict([(x.cid, x) for x in users if x.cid])

configPath = os.path.abspath('../etc/') + os.sep
core = a.Core.create(configPath)

def findUser(nick, cid):
        print "looking for", nick, cid
        if nick in nicks:
                return nicks[nick].password
        if cid in cids:
                return cids[cid].password

        return None

def handler(signum, frame):

def run():
    print "Starting"
    sil = a.TServerInfoList(1)
    si = a.ServerInfo.create()
    si.port = 2780
    sil[0] = si
    pw = PasswordHandler(core, findUser, None, None)
    iv = InfVerifier(core, None, None)
    print "."
    import signal
    signal.signal(signal.SIGINT, handler)

        import plugins
    except Exception as e:
        print "\n\nFATAL: Can't start ADCH++: %s\n" % e

if __name__ == '__main__':

core = None

6. ADCH++ command line parameters

The following command line parameters are available:

Example: Command usage
Usage: adchpp [[-c <configdir>] [-d]] | [-v] | [-h]
  • -c Specifies the path of configuration directory (default: .\config)

  • -d Deamon service (Linux only)

  • -p <pid-file> Writes process pid to <pid-file> (Linux only)

  • -i <service name> Installs a service instance. The name specifies the name the instance will have in the services list (Windows only)

  • -u <service name> Uninstalls a service instance. (Windows only)

  • -v Prints version number

  • -h Shows the usage help message

Table 9. Examples


adchppd -c /home/test/adchpp/bin/config/


adchppd -d


adchppd -p


adchppd.exe -c c:/users/test/adchpp/bin/config/


adchppd.exe -i adchpp

7. Running ADCH++ as a service module

Installing ADCH++ as a service requires to be run in an elevated state in Windows 7 or Vista as UAC will interfere with the process if its not executed as an administrator.

This is how it looks in case of problems:

ADCH++ elevation fails

You elevate adchpp.exe in Windows 7/Vista in the following way:

  • Right click on the application’s icon

  • Choose Properties

  • Go to Compatibility tab

ADCH++ elevation howto

  • Check the Run this program as an administrator box. Click OK.

  • Now execute the command adchpp -i <servicename> (example: adchpp.exe -i myserver) in your adchpp folder. If you omit the service name it will use "adchpp" as the service name by default.

  • Grant the application access if you have UAC enabled

To verify that your ADCH++ service is correctly installed under the name you specified go to Control Panel\System and Security\Administrative Tools or simply run the services.msc command from a Windows prompt.

ADCH++ Services

To check if your adchpp service is running start the "services" application in administrative tools:

ADCH++ verify service

Tip You can set up to automatically restart the hub service in case of a crash using the Recovery settings in the service properties.

8. Issues and problems

Like any other software ADCH++ can have flaws or bugs, can preform weird or contain unwanted features. It’s important to make the developers aware of such problems. If you want to help improving ADCH++ you can give feedback to the developers about found bugs, helping them to recreate and fix the problems. Many times, to be able to help solving issues, you must run a debug build of ADCH++. If you cannot compile ADCH++ in debug mode you can download nightly debug builds from the DCBase Builds Archive.

8.1. Crashes and getting backtrace logs

In the case of a crash you can help the development by reporting the bug to the official bug tracker.

To be able to analyze and solve a crash problem the developers need the following information:

  • As many details as you can provide about your system including the version of ADCH++ used, OS version, etc.

  • If you know how to reproduce the bug, specify a procedure that developers can follow to re-create the same bug.

  • Provide a crash/backtrace log and attach it to your bug report.

8.1.1. Getting backtrace log from a GCC/MinGW compiled debug build

For getting the crash log you need to use a debugger software called GDB (GNU Debugger). GDB.exe is downloadable directly from

  • Copy the debugger program (GDB.exe) to your ADCH++ program folder

  • Open a Windows Command prompt in the ADCH++ program folder (Start Menu, Run…, type cmd and navigate to the program folder). You will get the debugging output to this command window.

  • In the Command prompt type :

 gdb adchppd.exe
  • When you get the debugger prompt type : r (then press <enter>).

  • This will start ADCH++, now wait for the crash (or force the crash if you know the steps how to do so)

  • When it crashes get the backtrace information by typing to the debugger prompt :

 bt full
  • Press <enter> so the backtrace will be generated and printed to the debug console.

  • Mark and copy the output from the command window (easiest way : right-click to the window header, from the menu choose Edit, Select All).

  • Paste the output to a new text file.

  • Then type : q (and press <enter>) to exit the debugger, this will close ADCH++ as well.

Tip It’s the backtrace itself what may contain the most useful information so you can remove the best part of the large debug printout from the beginning of the text file. The important part is in the end, starting 10-15 lines >before< the issued bt full command and onwards. Also its wise to check if the text file you about to attach doesn’t contain any information that breaks yours or other’s privacy (IP addresses, nicks, etc…)
Tip The above procedure is for Windows but you must be able to get backtraces under Linux in a similar way

8.1.2. Getting backtrace log from a build compiled with Microsoft Visual C++

You should have Microsoft Visual C++ installed and you have to use a debug build of ADCH++ compiled with MSVC. MSVC should already be registered as a JIT debugger on your system. When a crash occurs, just click "debug" on the standard crash dialog and your debugger will handle unwinding the stack, opening the correct file and showing the offending line and instructions.

8.2. LUA errors

It’s possible that you get errors from the running LUA scripts as well. They will show up in the console window of ADCH++ while its running. Example:

access.lua:491: attempt to concatenate global 'reason' (a nil value)
stack traceback:
access.lua:491: in function 'dump_banned'
access.lua:579: in function <access.lua:496>
(tail call): ?
access.lua:1652: in function <access.lua:1651>

If you get errors from the core LUA scripts packaged with ADCH++, please report them to the official bug tracker at Launchpad:

Tip In case of other scripts, its best to report the errors to their respective authors if they’re indentifyable

9. Extension Support

The current version of ADCH++ supports the following ADC protocol extensions:

BLOM - this extension that allows hub software to create a map (bloom filter) of the shared files on the hub, but with minimal effort, e.g. the hub doesn’t keep a list of files, but a filter that never produces false negatives but only possible false positives. This can potentially save bandwidth and effort on the client side.
UCMD - User commands are used to send hub-specific commands to the client which provide useful shortcuts for the user.
ADCS - ADCS is an extension that has the goal of adding the TLS/SSL layer just over the TCP layer and beneath the application layer (where ADC runs). This way, the ADC protocol remains unchanged while the connections are encrypted.
PING - This extension can be supported by both clients and hubs, and when present, if hub supports it, it must send additional information to the client.
FO - If a hub goes down, the client’s only option is to keep re-trying the last known hub address. This extension will add a list of failover hub addresses, field FO, that the client can try to connect to, if the main hub address fail.

10. Compiling ADCH++

These are the minimum versions of tools required to compile ADCH++:

10.1. Building ADCH++

To build ADCH++ from source you have to:

  • Install SWIG and ensure it’s in your PATH

  • Install Python and ensure it’s in your PATH

  • Install SCons and ensure it’s in your PATH

  • Windows with MinGW: Install MinGW and ensure it’s in your PATH

  • Linux: Install GCC and appropriate header files, in particular, these packages spring to mind:

    • gcc-c++

    • libstdc++-devel

    • redhat: readline-devel, debian: libreadline-dev sys-libs/readline

  • Clang: Build with scons tools=clang. Make sure you modify tools/ according to your configuration.

  • Clang Static Analyzer: Build with scons tools=clang-analyzer. Have a look at tools/ to tweak options passed to scan-build. Since the Clang Static Analyzer uses Clang, follow the above instructions for Clang configuration as well.

  • To compile with support for secure connections, you need OpenSSL:

    • Windows: compile it yourself (or ask someone to do it) and put it in the "openssl" directory. append a d to debug libs and put x64 / ia64 libs into openssl/lib/x64 / openssl/lib/ia64 respectively.

    • Linux: if you don’t have it already, get the openssl-devel/libssl-dev package

  • In the source folder, type "scons -h" to see additional compile options

  • Type "scons" to create a debug build. "scons mode=release" will create a release build (see examples below).

10.1.1. Building ADCH++ with MinGW

To build a debug version use: scons

To build a release version use: scons mode=release

10.1.2. Building ADCH++ with MSVC

To build a x86 debug version use: scons tools=default

To build a x86 release version use: scons tools=default mode=release

To build a x64 debug version use: scons tools=default arch=x64

To build a x64 release version use: scons tools=default mode=release arch=x64

10.1.3. Building documentation

To generate html documentation use: scons docs=1

11. Patches and contributions

The author do accept patches in general for every part of the application, but in order to avoid future licensing issues, you’re asked to give the author the copyright over any submitted code. Make sure that the code doesn’t break support for any of the platforms supported and that it looks more or less like the rest of the code (indent, names etc). Patches should be sent to the dcplusplus-devel mailing list or to the official bug tracker at Launchpad. Please use unified patches against latest bzr trunk (ie. bzr diff) and supply a description of what the patch does.

12. Appendix

This document is published under GNU FDL

Copyright © 2010-2013 Jacek Sieka

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is available at