关于AllJoyn不多做介绍,请看官网:www.alljoyn.org/

0. 问题来源:

应用程序要使用AllJoyn库,就必须启动deamon。

目前有两种方式:

  • 使用standalone形式,单独启动alljoyn-daemon进程。
  • 使用bundled daemon形式,应用程序在连接AllJoyn时自己启动该deamon。

AllJoyn的开发者解释如下:https://www.alljoyn.org/forums/developers/building-embedded-linux-system

The decision to use standalone or bundled daemon is made runtime but there is also an additional component that specifies whether an AllJoyn library supports bundled daemon at all. This the BD variable that we use when we build AllJoyn using scons.

More specifically, the check to choose which daemon is always made in the same manner irrespective of whether we have a standalone daemon or bundled daemon. The only thing BD signifies during build is whether the library will actually include code to run bundled daemon.

An AllJoyn application will always see is there is a standalone daemon running. If yes it will connect to that daemon else it will try and use the bundled daemon which may or may not be a part of the library depending on whether you said BD=on or off.

bundled daemon形式不需要单独启动进程,比较方便。因此就来研究如何使用该种方式。

1. 从入口看起:

BusAttachment::Connect()
{
#ifdef _WIN32
const char* connectArgs = "tcp:addr=127.0.0.1,port=9956";
#else
const char* connectArgs = "unix:abstract=alljoyn";
#endif
return Connect(connectArgs);
}

很明显,针对windows使用tcp transport,其他平台使用“unix:abstract=alljoyn“transport。

然后调用内部函数BusAttachment::Connect(const char* connectSpec)进行连接。

2. BusAttachment::Connect(const char* connectSpec)函数,重点如下:

...
this->connectSpec = connectSpec;
status = TryConnect(connectSpec);
/*
* Try using the null transport to connect to a bundled daemon if there is one
*/
if (status != ER_OK && !isDaemon) {
printf("TryConnect() failed.\n"); qcc::String bundledConnectSpec = "null:";
if (bundledConnectSpec != connectSpec) {
status = TryConnect(bundledConnectSpec.c_str());
if (ER_OK == status) {
this->connectSpec = bundledConnectSpec;
}
}
}
...

首先尝试连接指定的"unix:abstract=alljoyn";

如果连接失败就尝试连接名为”null:”的transport(对应的类是NullTransport )------该transport 即使用bundled daemon

3. 再看BusAttachment::TryConnect(const char* connectSpec)函数,重点如下:

...
/* Get or create transport for connection */
Transport* trans = busInternal->transportList.GetTransport(connectSpec);
if (trans) {
SessionOpts emptyOpts;
status = trans->Connect(connectSpec, emptyOpts, tempEp);
...
}
...

从busInternal中获取指定的transport,再进行连接。
那么busInternal是如何存储transport的呢?

4. 看busInternal的初始化过程:

BusAttachment::Internal::Internal(const char* appName,
BusAttachment& bus,
TransportFactoryContainer& factories,
Router* router,
bool allowRemoteMessages,
const char* listenAddresses,
uint32_t concurrency) :
application(appName ? appName : "unknown"),
bus(bus),
listenersLock(),
listeners(),
m_ioDispatch("iodisp", 16),
transportList(bus, factories, &m_ioDispatch, concurrency),
keyStore(application),
authManager(keyStore),
globalGuid(qcc::GUID128()),
msgSerial(1),
router(router ? router : new ClientRouter),
localEndpoint(transportList.GetLocalTransport()->GetLocalEndpoint()),
allowRemoteMessages(allowRemoteMessages),
listenAddresses(listenAddresses ? listenAddresses : ""),
stopLock(),
stopCount(0)
{
...
}

可以看到,这里是通过TransportFactoryContainer(一组transport factory)对象来初始化所支持的transport list。

5.

QStatus TransportList::Start(const String& transportSpecs)
{
...
for (uint32_t i = 0; i < m_factories.Size(); ++i) {
TransportFactoryBase* factory = m_factories.Get(i);
if (factory->GetType() == ttype && factory->IsDefault() == false) {
transportList.push_back(factory->Create(bus));
}
}
...
}

可以看到,这里根据每个transport factory来创建对应的transport,并添加到transportList.中。

所以问题的关键在于:TransportFactoryContainer是如何初始化的呢(由transport factory 来决定支持的transport list)?

6. 再回过头来看BusAttachment的构造函数:

BusAttachment::BusAttachment(const char* applicationName, bool allowRemoteMessages, uint32_t concurrency) :
isStarted(false),
isStopping(false),
concurrency(concurrency),
busInternal(new Internal(applicationName, *this, clientTransportsContainer, NULL, allowRemoteMessages, NULL, concurrency)),
joinObj(this)
{
...
}

原来是BusAttachment在构造对象时初始化了Internal对象, 参数TransportFactoryContainer就是clientTransportsContainer

7. 继续跟踪clientTransportsContainer:

/*
* Transport factory container for transports this bus attachment uses to communicate with the daemon.
*/
static class ClientTransportFactoryContainer : public TransportFactoryContainer {
public:
ClientTransportFactoryContainer() : transportInit(0) { } void Init()
{
/*
* Registration of transport factories is a one time operation.
*/
if (IncrementAndFetch(&transportInit) == 1) {
if (ClientTransport::IsAvailable()) {
Add(new TransportFactory<ClientTransport>(ClientTransport::TransportName, true));
}
if (NullTransport::IsAvailable()) {
Add(new TransportFactory<NullTransport>(NullTransport::TransportName, true));
}
} else {
DecrementAndFetch(&transportInit);
}
} private:
volatile int32_t transportInit;
} clientTransportsContainer;

可以看到这是一个静态类,在初始化时检查是否支持NullTransport,如果支持就将它添加到TransportFactoryContainer中,在start时就会创建对应的transport 对象,供connect进行连接。

所以,现在问题的关键在于:NullTransport::IsAvailable()是否返回true。

8. 跟踪NullTransport::IsAvailable()函数:

/**
* The null transport is only available if the application has been linked with bundled daemon
* support. Check if the null transport is available.
*
* @return Returns true if the null transport is available.
*/
static bool IsAvailable() { return daemonLauncher != NULL; } 该函数通过检查daemonLauncher 变量是否为空,来决定是否支持NullTransport。其声明如下:
class NullTransport : public Transport {
private:
...
static DaemonLauncher* daemonLauncher; /**< The daemon launcher if there is bundled daemon present */
};

初始化:

DaemonLauncher* NullTransport::daemonLauncher;

可知:daemonLauncher变量默认为空,即默认是不支持NullTransport的。

9. 检查整个工程代码,发现为其赋值的代码如下:

BundledDaemon::BundledDaemon() : transportsInitialized(false), stopping(false), ajBus(NULL), ajBusController(NULL)
{
NullTransport::RegisterDaemonLauncher(this);
}
void NullTransport::RegisterDaemonLauncher(DaemonLauncher* launcher)
{
daemonLauncher = launcher;
}

说明:只有在声明BundledDaemon对象的情况下daemonLauncher才不为空,才能支持NullTransport(即Bundled Daemon 模式)。

10. 查看文件daemon/bundled/BundledDaemon.cc230行,发现已声明BundledDaemon 的静态对象

static BundledDaemon bundledDaemon;

这是不是意味着,只需要连接该文件就可以声明BundledDaemon 对象, daemonLauncher才不为空,进而支持NullTransport(即Bundled Daemon 模式)?

以AllJoyn自带的chat做实验,位于:alljoyn-3.3.0-src/build/linux/x86-64/debug/dist/samples/chat

修改Makefile的连接选项,发现只需要按如下顺序添加连接选项:

LIBS = -lalljoyn ../../lib/BundledDaemon.o -lajdaemon -lstdc++ -lcrypto -lpthread –lrt

程序就会自动启用Bundled Daemon,而不需要手动启动alljoyn-daemon进程

$ ./chat -s a
BusAttachment started.
RegisterBusObject succeeded.
0.063 ****** ERROR NETWORK external Socket.cc:249 | Connecting (sockfd = 15) to @alljoyn : 111 - Connection refused: ER_OS_ERROR
0.063 ****** ERROR ALLJOYN external posix/ClientTransport.cc:258 | ClientTransport(): socket Connect(15, @alljoyn) failed: ER_OS_ERROR
Using BundledDaemon
AllJoyn Daemon GUID = 8216a0fc60832b5f50c2111527f89fc1 (2MWyW3hV)
StartListen: tcp:r4addr=0.0.0.0,r4port=0
StartListen: ice:
Connect to ‘null:’ succeeded-----------------------------已经连上NullTransport

  

最终结论:

应用程序如果想使用Bundled Daemon,只需要在连接选项中添加如下库即可(不可改变连接库顺序):

-lalljoyn ../../lib/BundledDaemon.o -lajdaemon

  

  

  

AllJoyn Bundled Daemon 使用方式研究的更多相关文章

  1. Tomcat以Daemon的方式启动(CentOS6&7)

    1 前言 一直以来都觉得Tomcat以root身份运行非常不安全,故研究Tomcat如何以普通用户身份运行,以下是参考网络上的一些配置实现Tomcat以daemon方式运行于CentOS 6& ...

  2. Docker Daemon 连接方式详解

    前言 在 Docker 常用详解指令 一文中粗粗提了一下, Docker 是分为客户端和服务端两部分的, 本文将介绍客户端是如何连接服务端的. 连接方式 1. UNIX域套接字 默认就是这种方式, 会 ...

  3. Docker客户端连接Docker Daemon的方式

    Docker为C/S架构,服务端为docker daemon,客户端为docker.service,支持本地unix socket域套接字通信与远程socket通信. 默认为本地unix socket ...

  4. Windows下非PE方式载荷投递方式研究

    0. 引言 0x1:载荷是什么?在整个入侵过程中起到什么作用? 载荷的作用在整个入侵链路的作用起到纽带的作用,它借助于目标系统提供的某些功能:组件:执行环境,将攻击者的传递的恶意payload包裹起来 ...

  5. UDP打洞、P2P组网方式研究

    catalogue . NAT概念 . P2P概念 . UDP打洞 . P2P DEMO . ZeroNet P2P 1. NAT概念 在STUN协议中,根据内部终端的地址(LocalIP:Local ...

  6. 恶意软件/BOT/C2隐蔽上线方式研究

    catalogue . 传统木马上线方式 . 新型木马上线方式 . QQ昵称上线 . QQ空间资料上线 . 第三方域名上线 . UDP/TCP二阶段混合上线 . Gmail CNC . NetBot两 ...

  7. DedeCMS顽固木马后门专杀工具V2.0实现方式研究

    catalog . 安装及使用方式 . 检查DEDECMS是否为最新版本 . 检查默认安装(install)目录是否存在 . 检查默认后台目录(dede)是否存在 . 检查DedeCMS会员中心是否关 ...

  8. linux标准daemon编写方式

    daemon定义 运行在后台的程序,通常不需要与用户进行交互的. 任何父进程id是0的通常是kernel进程,作为系统启动的一部分,除了init是用户态的命令. 规则 第一件事情是调用umask设置文 ...

  9. IPC$概念及入侵方式研究

    catalogue . 什么是IPC$ . IPC$攻击方式 . 漏洞检测与防御措施 1. 什么是IPC$ IPC$(空会话连接)是windows系统内置的一个功能模块,它的作用有很多(包括域帐号枚举 ...

随机推荐

  1. SharePoint咨询师之路:备份和恢复系列二 - 备份服务器场

    本系列包括: 备份服务器场和配置 备份web和服务应用程序 备份内容数据库 备份网站集 备份自定义项 根据“SharePoint咨询师之路:备份和恢复系列--制定备份计划”我们制定了一下备份计划如下: ...

  2. 第三百二十六天 how can I 坚持

    今天元宵节啊,晚上去蓝色港湾看了看灯光节,快冻死了,人倒是挺多. 其他没啥了. 还有晚上吃了几个元宵. 好像冻感冒了,有点头晕. 睡觉.

  3. 第二百零四天 how can i 坚持

    我应该不会看错吧.最近媒体热炒小米衰落了,有必要那么大张旗鼓的报道吗?小米.华为,坚决看好小米.感觉华为品牌有些杂乱,在走三星的老路,小米有些苹果的影子,但是,多了个互联网.互联网... 未来孰优孰劣 ...

  4. 【全面完美方案】iPhone 4S WiFi变灰 DIY修复方式

    这是我在一位台湾网友usaretama发表的一篇帖子中看到的,原帖我发表在维维网 如果你有WiFi开关变灰不能切换.WiFi遇到搜不到AP或搜到了连不上,那您就要注意这篇了. 家人的 iPhone 4 ...

  5. [iOS微博项目 - 2.4] - 重新安排app启动步骤

    github: https://github.com/hellovoidworld/HVWWeibo   A.app启动步骤 1.加入了授权步骤之后,最先要判断app内是否已经登陆了账号 2.在程序启 ...

  6. class list

    class list(object): """ list() -> new empty list list(iterable) -> new list ini ...

  7. Python基础 练习题

    DAY .1 1.使用while循环输出 1 2 3 4 5 6     8 9 10 n = 1 while n < 11: if n == 7: pass else: print(n) n ...

  8. StructLayout特性

    StructLayout特性          公共语言运行库利用 StructLayoutAttribute控制类或结构的数据字段在托管内存中的物理布局,即类或结构需要按某种方式排列.如果要将类传递 ...

  9. Max retries exceeded with url

    78 Traceback (most recent call last):   File "thread072413.py", line 163, in <module> ...

  10. My集合框架第五弹 最小堆

    二叉堆(以最小堆为例),其具有结构性质和堆序性质结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N            而且该结构可以很容易的使用数 ...