Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Open sidebar
savoirfairelinux
jami-daemon
Commits
f062220c
Commit
f062220c
authored
Oct 23, 2016
by
Adrien Béraud
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nameservice: add name directory
Change-Id: I89c26b87c29d8c9dd541583f67dd13dbdc3ff37a Tuleap: #938
parent
7e42bf1e
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
661 additions
and
40 deletions
+661
-40
bin/Makefile.am
bin/Makefile.am
+4
-4
bin/dbus/cx.ring.Ring.ConfigurationManager.xml
bin/dbus/cx.ring.Ring.ConfigurationManager.xml
+112
-0
bin/dbus/dbusclient.cpp
bin/dbus/dbusclient.cpp
+2
-0
bin/dbus/dbusconfigurationmanager.cpp
bin/dbus/dbusconfigurationmanager.cpp
+18
-0
bin/dbus/dbusconfigurationmanager.h
bin/dbus/dbusconfigurationmanager.h
+3
-0
configure.ac
configure.ac
+12
-6
src/Makefile.am
src/Makefile.am
+2
-1
src/client/configurationmanager.cpp
src/client/configurationmanager.cpp
+46
-5
src/client/ring_signal.cpp
src/client/ring_signal.cpp
+2
-0
src/dring/account_const.h
src/dring/account_const.h
+5
-4
src/dring/call_const.h
src/dring/call_const.h
+1
-0
src/dring/configurationmanager_interface.h
src/dring/configurationmanager_interface.h
+12
-0
src/ringdht/Makefile.am
src/ringdht/Makefile.am
+6
-2
src/ringdht/namedirectory.cpp
src/ringdht/namedirectory.cpp
+261
-0
src/ringdht/namedirectory.h
src/ringdht/namedirectory.h
+61
-0
src/ringdht/ringaccount.cpp
src/ringdht/ringaccount.cpp
+98
-17
src/ringdht/ringaccount.h
src/ringdht/ringaccount.h
+16
-1
No files found.
bin/Makefile.am
View file @
f062220c
...
...
@@ -35,15 +35,15 @@ endif
if
RING_RESTCPP
SUBDIRS
=
restcpp
sbin_PROGRAMS
=
dring
sbin_PROGRAMS
=
rest
dring
dring_SOURCES
=
main.cpp
rest
dring_SOURCES
=
main.cpp
dring_CXXFLAGS
=
-g
\
rest
dring_CXXFLAGS
=
-g
\
-I
$(top_srcdir)
/src
\
-I
$(top_srcdir)
/src/dring
\
-DREST_API
\
-DTOP_BUILDDIR
=
\"
$$
(
cd
"
$(top_builddir)
"
;
pwd
)
\"
dring_LDADD
=
restcpp/libclient_rest.la
$(top_builddir)
/src/libring.la
rest
dring_LDADD
=
restcpp/libclient_rest.la
$(top_builddir)
/src/libring.la
endif
bin/dbus/cx.ring.Ring.ConfigurationManager.xml
View file @
f062220c
...
...
@@ -220,6 +220,118 @@
</arg>
</method>
<method
name=
"lookupName"
tp:name-for-bindings=
"lookupName"
>
<tp:docstring>
Performs name lookup with RingNS protocol for the specified account (if any) or using the default nameserver.
</tp:docstring>
<arg
type=
"s"
name=
"accountID"
direction=
"in"
>
The account to use. If empty, use the default RingNS server.
</arg>
<arg
type=
"s"
name=
"nameserverUri"
direction=
"in"
>
The name server URI to use, considered only if accountID is empty.
</arg>
<arg
type=
"s"
name=
"name"
direction=
"in"
>
</arg>
<arg
type=
"b"
name=
"success"
direction=
"out"
>
<tp:docstring>
True if the operation was initialized successfully. registeredNameFound will be trigered on completion.
</tp:docstring>
</arg>
</method>
<method
name=
"lookupAddress"
tp:name-for-bindings=
"lookupAddress"
>
<tp:docstring>
Performs address lookup with RingNS protocol for the specified account (if any) or using the default nameserver.
</tp:docstring>
<arg
type=
"s"
name=
"accountID"
direction=
"in"
>
The account to use. If empty, use the default RingNS server.
</arg>
<arg
type=
"s"
name=
"nameserverUri"
direction=
"in"
>
The name server URI to use, considered only if accountID is empty.
</arg>
<arg
type=
"s"
name=
"address"
direction=
"in"
>
<tp:docstring>
Address to lookup for. Must not include spaces.
</tp:docstring>
</arg>
<arg
type=
"b"
name=
"success"
direction=
"out"
>
<tp:docstring>
True if the operation was initialized successfully. registeredNameFound will be trigered on completion.
False in case of operation initialization error. registeredNameFound won't be called in that case.
</tp:docstring>
</arg>
</method>
<signal
name=
"registeredNameFound"
tp:name-for-bindings=
"registeredNameFound"
>
<tp:docstring>
Notify clients when a new registered address-name mapping is known.
If status is not success (0), requested field (name or address) is left empty.
</tp:docstring>
<arg
type=
"s"
name=
"accountID"
>
</arg>
<arg
type=
"i"
name=
"status"
>
<tp:docstring>
Status code: 0 for success
<ul>
<li>
SUCCESS = 0 everything went fine. Name/address pair was found.
</li>
<li>
INVALID_NAME = 1 provided name is not valid.
</li>
<li>
NOT_FOUND = 2 everything went fine. Name/address pair was not found.
</li>
<li>
ERROR = 3 An error happened
</li>
</ul>
</tp:docstring>
</arg>
<arg
type=
"s"
name=
"address"
>
</arg>
<arg
type=
"s"
name=
"name"
>
</arg>
</signal>
<method
name=
"registerName"
tp:name-for-bindings=
"registerName"
>
<tp:docstring>
Performs name registration with RingNS protocol for the specified account.
</tp:docstring>
<arg
type=
"s"
name=
"accountID"
direction=
"in"
>
</arg>
<arg
type=
"s"
name=
"password"
direction=
"in"
>
<tp:docstring>
Ring account main password.
</tp:docstring>
</arg>
<arg
type=
"s"
name=
"name"
direction=
"in"
>
<tp:docstring>
Name to register. Must be lower-case ASCII, digits or "-" or "_".
</tp:docstring>
</arg>
<arg
type=
"b"
name=
"success"
direction=
"out"
>
<tp:docstring>
True if the operation was initialized successfully. nameRegistrationEnded will be trigered on completion.
False in case of operation initialization error. nameRegistrationEnded won't be called in that case.
</tp:docstring>
</arg>
</method>
<signal
name=
"nameRegistrationEnded"
tp:name-for-bindings=
"nameRegistrationEnded"
>
<tp:docstring>
Notify clients when the registerName operation ended.
</tp:docstring>
<arg
type=
"s"
name=
"accountID"
>
</arg>
<arg
type=
"i"
name=
"status"
>
<tp:docstring>
Status code: 0 for success
<ul>
<li>
SUCCESS = 0 everything went fine. Name is now registered.
</li>
<li>
WRONG_PASSWORD = 1 registration failed: wrong password.
</li>
<li>
INVALID_NAME = 2 registration failed: invalid name.
</li>
<li>
ALREADY_TAKEN = 3 registration failed: name is already taken.
</li>
<li>
NETWORK_ERROR = 4 registration failed: network or server error.
</li>
</ul>
</tp:docstring>
</arg>
<arg
type=
"s"
name=
"name"
>
<tp:docstring>
The name that was attempted to register.
</tp:docstring>
</arg>
</signal>
<method
name=
"testAccountICEInitialization"
tp:name-for-bindings=
"testAccountICEInitialization"
>
<tp:docstring>
Test initializing an ICE transport with the current account configuration.
...
...
bin/dbus/dbusclient.cpp
View file @
f062220c
...
...
@@ -178,6 +178,8 @@ DBusClient::initLibrary(int flags)
exportable_callback
<
ConfigurationSignal
::
IncomingTrustRequest
>
(
bind
(
&
DBusConfigurationManager
::
incomingTrustRequest
,
confM
,
_1
,
_2
,
_3
,
_4
)),
exportable_callback
<
ConfigurationSignal
::
ExportOnRingEnded
>
(
bind
(
&
DBusConfigurationManager
::
exportOnRingEnded
,
confM
,
_1
,
_2
,
_3
)),
exportable_callback
<
ConfigurationSignal
::
KnownDevicesChanged
>
(
bind
(
&
DBusConfigurationManager
::
knownDevicesChanged
,
confM
,
_1
,
_2
)),
exportable_callback
<
ConfigurationSignal
::
NameRegistrationEnded
>
(
bind
(
&
DBusConfigurationManager
::
nameRegistrationEnded
,
confM
,
_1
,
_2
,
_3
)),
exportable_callback
<
ConfigurationSignal
::
RegisteredNameFound
>
(
bind
(
&
DBusConfigurationManager
::
registeredNameFound
,
confM
,
_1
,
_2
,
_3
,
_4
)),
exportable_callback
<
ConfigurationSignal
::
CertificatePinned
>
(
bind
(
&
DBusConfigurationManager
::
certificatePinned
,
confM
,
_1
)),
exportable_callback
<
ConfigurationSignal
::
CertificatePathPinned
>
(
bind
(
&
DBusConfigurationManager
::
certificatePathPinned
,
confM
,
_1
,
_2
)),
exportable_callback
<
ConfigurationSignal
::
CertificateExpired
>
(
bind
(
&
DBusConfigurationManager
::
certificateExpired
,
confM
,
_1
)),
...
...
bin/dbus/dbusconfigurationmanager.cpp
View file @
f062220c
...
...
@@ -86,6 +86,24 @@ DBusConfigurationManager::getKnownRingDevices(const std::string& accountID) -> d
return
DRing
::
getKnownRingDevices
(
accountID
);
}
auto
DBusConfigurationManager
::
lookupName
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
name
)
->
decltype
(
DRing
::
lookupName
(
account
,
nameserver
,
name
))
{
return
DRing
::
lookupName
(
account
,
nameserver
,
name
);
}
auto
DBusConfigurationManager
::
lookupAddress
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
address
)
->
decltype
(
DRing
::
lookupAddress
(
account
,
nameserver
,
address
))
{
return
DRing
::
lookupAddress
(
account
,
nameserver
,
address
);
}
auto
DBusConfigurationManager
::
registerName
(
const
std
::
string
&
account
,
const
std
::
string
&
password
,
const
std
::
string
&
name
)
->
decltype
(
DRing
::
registerName
(
account
,
password
,
name
))
{
return
DRing
::
registerName
(
account
,
password
,
name
);
}
void
DBusConfigurationManager
::
removeAccount
(
const
std
::
string
&
accountID
)
{
...
...
bin/dbus/dbusconfigurationmanager.h
View file @
f062220c
...
...
@@ -65,6 +65,9 @@ class DBusConfigurationManager :
std
::
string
addAccount
(
const
std
::
map
<
std
::
string
,
std
::
string
>&
details
);
bool
exportOnRing
(
const
std
::
string
&
accountID
,
const
std
::
string
&
password
);
std
::
map
<
std
::
string
,
std
::
string
>
getKnownRingDevices
(
const
std
::
string
&
accountID
);
bool
lookupName
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
name
);
bool
lookupAddress
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
address
);
bool
registerName
(
const
std
::
string
&
account
,
const
std
::
string
&
password
,
const
std
::
string
&
name
);
void
removeAccount
(
const
std
::
string
&
accoundID
);
std
::
vector
<
std
::
string
>
getAccountList
();
void
sendRegister
(
const
std
::
string
&
accoundID
,
const
bool
&
enable
);
...
...
configure.ac
View file @
f062220c
...
...
@@ -385,20 +385,26 @@ AS_IF([test "x$with_dbus" = "xyes"], [
AM_CONDITIONAL(RING_DBUS, true)],
AM_CONDITIONAL(RING_DBUS, false));
dnl Ring name service is default-enabled
AC_ARG_ENABLE([ringns], AS_HELP_STRING([--disable-ringns], [Enable Ring Name Service]))
AM_CONDITIONAL([RINGNS], test "x$enable_ringns" != "xno", [Define if you use the Ring Name Service])
AC_DEFINE_UNQUOTED([HAVE_RINGNS], `if test "x$enable_ringns" != "xno"; then echo 1; else echo 0; fi`, [Define if you use the Ring Name Service])
# Rest C++ with restbed
AC_ARG_WITH([restcpp],
AS_HELP_STRING([--with-restcpp], [enable rest support with C++]))
AS_IF([test "x$with_restcpp" = "xyes"],
[
PKG
_CHECK_
MODULES(RESTBED, lib
restbed,, AC_MSG_
WARN
([Missing restbed files]))
AS_IF([test
"x$enable_ringns" != "xno" || test
"x$with_restcpp" = "xyes"],
AC
_CHECK_
LIB(
restbed,
exit,
, AC_MSG_
ERROR
([Missing restbed files]))
);
AS_IF([test "x$with_restcpp" = "xyes"], [
AS_AC_EXPAND(SBINDIR, $sbindir)
AC_SUBST(SBINDIR)
AC_CONFIG_FILES([bin/restcpp/Makefile])
AM_CONDITIONAL(RING_RESTCPP, true)],
AM_CONDITIONAL(RING_RESTCPP, false));
AM_CONDITIONAL(RING_RESTCPP, true)
],
AM_CONDITIONAL(RING_RESTCPP, false)
);
dnl Check for libav
PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec development files]))
...
...
src/Makefile.am
View file @
f062220c
...
...
@@ -55,7 +55,8 @@ libring_la_LDFLAGS = \
@GNUTLS_LIBS@
\
@OPENDHT_LIBS@
\
@ZLIB_LIBS@
\
$(PCRE_LIBS)
$(PCRE_LIBS)
\
@LIBS@
if
HAVE_WIN32
libring_la_LDFLAGS
+=
-no-undefined
-avoid-version
...
...
src/client/configurationmanager.cpp
View file @
f062220c
...
...
@@ -61,6 +61,7 @@ namespace DRing {
constexpr
unsigned
CODECS_NOT_LOADED
=
0x1000
;
/** Codecs not found */
using
ring
::
SIPAccount
;
using
ring
::
RingAccount
;
using
ring
::
tls
::
TlsValidator
;
using
ring
::
tls
::
CertificateStore
;
using
ring
::
DeviceType
;
...
...
@@ -828,12 +829,52 @@ connectivityChanged()
RING_ERR
(
"UPnP context error: %s"
,
e
.
what
());
}
auto
account_list
=
ring
::
Manager
::
instance
().
getAccountList
();
for
(
auto
account_id
:
account_list
)
{
if
(
auto
account
=
ring
::
Manager
::
instance
().
getAccount
(
account_id
))
{
account
->
connectivityChanged
();
}
for
(
const
auto
&
account
:
ring
::
Manager
::
instance
().
getAllAccounts
())
{
account
->
connectivityChanged
();
}
}
bool
lookupName
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
name
)
{
#if HAVE_RINGNS
if
(
account
.
empty
())
{
ring
::
NameDirectory
::
instance
(
nameserver
).
lookupName
(
name
,
[
name
](
const
std
::
string
&
result
,
ring
::
NameDirectory
::
Response
response
)
{
ring
::
emitSignal
<
DRing
::
ConfigurationSignal
::
RegisteredNameFound
>
(
""
,
(
int
)
response
,
result
,
name
);
});
return
true
;
}
else
if
(
auto
acc
=
ring
::
Manager
::
instance
().
getAccount
<
RingAccount
>
(
account
))
{
acc
->
lookupName
(
name
);
return
true
;
}
#endif
return
false
;
}
bool
lookupAddress
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
address
)
{
#if HAVE_RINGNS
if
(
account
.
empty
())
{
ring
::
NameDirectory
::
instance
(
nameserver
).
lookupAddress
(
address
,
[
address
](
const
std
::
string
&
result
,
ring
::
NameDirectory
::
Response
response
)
{
ring
::
emitSignal
<
DRing
::
ConfigurationSignal
::
RegisteredNameFound
>
(
""
,
(
int
)
response
,
address
,
result
);
});
return
true
;
}
else
if
(
auto
acc
=
ring
::
Manager
::
instance
().
getAccount
<
RingAccount
>
(
account
))
{
acc
->
lookupAddress
(
address
);
return
true
;
}
#endif
return
false
;
}
bool
registerName
(
const
std
::
string
&
account
,
const
std
::
string
&
password
,
const
std
::
string
&
name
)
{
#if HAVE_RINGNS
if
(
auto
acc
=
ring
::
Manager
::
instance
().
getAccount
<
RingAccount
>
(
account
))
{
acc
->
registerName
(
password
,
name
);
return
true
;
}
#endif
return
false
;
}
}
// namespace DRing
src/client/ring_signal.cpp
View file @
f062220c
...
...
@@ -65,6 +65,8 @@ getSignalHandlers()
exported_callback
<
DRing
::
ConfigurationSignal
::
IncomingTrustRequest
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
ExportOnRingEnded
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
KnownDevicesChanged
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
NameRegistrationEnded
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
RegisteredNameFound
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
MediaParametersChanged
>
(),
exported_callback
<
DRing
::
ConfigurationSignal
::
Error
>
(),
#ifdef __ANDROID__
...
...
src/dring/account_const.h
View file @
f062220c
...
...
@@ -76,6 +76,7 @@ enum class testAccountICEInitializationStatus : int {
namespace
VolatileProperties
{
constexpr
static
const
char
ACTIVE
[]
=
"Account.active"
;
constexpr
static
const
char
REGISTERED_NAME
[]
=
"Account.registredName"
;
// Volatile parameters
namespace
Registration
{
...
...
@@ -222,12 +223,12 @@ constexpr static const char ALLOW_FROM_TRUSTED [] = "DHT.AllowFromTrusted";
}
//namespace DRing::Account::DHT
namespace
ETH
{
namespace
RingNS
{
constexpr
static
const
char
KEY_FILE
[]
=
"
ETH.keyFile
"
;
constexpr
static
const
char
ACCOUNT
[]
=
"ETH
.account"
;
constexpr
static
const
char
URI
[]
=
"
RingNS.uri
"
;
constexpr
static
const
char
ACCOUNT
[]
=
"RingNS
.account"
;
}
//namespace DRing::Account::
ETH
}
//namespace DRing::Account::
RingNS
namespace
CodecInfo
{
...
...
src/dring/call_const.h
View file @
f062220c
...
...
@@ -44,6 +44,7 @@ namespace Details {
constexpr
static
char
CALL_TYPE
[]
=
"CALL_TYPE"
;
constexpr
static
char
PEER_NUMBER
[]
=
"PEER_NUMBER"
;
constexpr
static
char
REGISTERED_NAME
[]
=
"REGISTERED_NAME"
;
constexpr
static
char
DISPLAY_NAME
[]
=
"DISPLAY_NAME"
;
constexpr
static
char
CALL_STATE
[]
=
"CALL_STATE"
;
constexpr
static
char
CONF_ID
[]
=
"CONF_ID"
;
...
...
src/dring/configurationmanager_interface.h
View file @
f062220c
...
...
@@ -48,6 +48,10 @@ std::string addAccount(const std::map<std::string, std::string>& details);
bool
exportOnRing
(
const
std
::
string
&
accountID
,
const
std
::
string
&
password
);
std
::
map
<
std
::
string
,
std
::
string
>
getKnownRingDevices
(
const
std
::
string
&
accountID
);
bool
lookupName
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
name
);
bool
lookupAddress
(
const
std
::
string
&
account
,
const
std
::
string
&
nameserver
,
const
std
::
string
&
address
);
bool
registerName
(
const
std
::
string
&
account
,
const
std
::
string
&
password
,
const
std
::
string
&
name
);
void
removeAccount
(
const
std
::
string
&
accountID
);
void
setAccountEnabled
(
const
std
::
string
&
accountID
,
bool
enable
);
std
::
vector
<
std
::
string
>
getAccountList
();
...
...
@@ -216,10 +220,18 @@ struct ConfigurationSignal {
constexpr
static
const
char
*
name
=
"ExportOnRingEnded"
;
using
cb_type
=
void
(
const
std
::
string
&
/*account_id*/
,
int
state
,
const
std
::
string
&
pin
);
};
struct
NameRegistrationEnded
{
constexpr
static
const
char
*
name
=
"NameRegistrationEnded"
;
using
cb_type
=
void
(
const
std
::
string
&
/*account_id*/
,
int
state
,
const
std
::
string
&
name
);
};
struct
KnownDevicesChanged
{
constexpr
static
const
char
*
name
=
"KnownDevicesChanged"
;
using
cb_type
=
void
(
const
std
::
string
&
/*account_id*/
,
const
std
::
map
<
std
::
string
,
std
::
string
>&
devices
);
};
struct
RegisteredNameFound
{
constexpr
static
const
char
*
name
=
"RegisteredNameFound"
;
using
cb_type
=
void
(
const
std
::
string
&
/*account_id*/
,
int
state
,
const
std
::
string
&
/*address*/
,
const
std
::
string
&
/*name*/
);
};
struct
CertificatePinned
{
constexpr
static
const
char
*
name
=
"CertificatePinned"
;
using
cb_type
=
void
(
const
std
::
string
&
/*certId*/
);
...
...
src/ringdht/Makefile.am
View file @
f062220c
...
...
@@ -11,9 +11,7 @@ libringacc_la_CXXFLAGS = @CXXFLAGS@ @JSONCPP_CFLAGS@
libringacc_la_LIBADD
=
$(DHT_LIBS)
\
$(BOOST_SYSTEM_LIB)
\
$(BOOST_FILESYSTEM_LIB)
\
$(BOOST_RANDOM_LIB)
\
$(BOOST_THREAD_LIB)
\
./eth/libdevcore/libdevcore.la
\
./eth/libdevcrypto/libdevcrypto.la
...
...
@@ -24,3 +22,9 @@ libringacc_la_SOURCES = \
sip_transport_ice.h
\
sips_transport_ice.cpp
\
sips_transport_ice.h
if
RINGNS
libringacc_la_SOURCES
+=
\
namedirectory.cpp
\
namedirectory.h
endif
src/ringdht/namedirectory.cpp
0 → 100644
View file @
f062220c
/*
* Copyright (C) 2016 Savoir-faire Linux Inc.
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "namedirectory.h"
#include "logger.h"
#include "string_utils.h"
#include "thread_pool.h"
#include <json/json.h>
#include <restbed>
/* for visual studio */
#include <ciso646>
#include <sstream>
#include <regex>
namespace
ring
{
constexpr
const
char
*
const
QUERY_NAME
{
"/name/"
};
constexpr
const
char
*
const
QUERY_ADDR
{
"/addr/"
};
const
std
::
regex
NAME_VALIDATOR
{
"^[a-z0-9-_]{3,32}$"
};
const
std
::
regex
URI_VALIDATOR
{
"^(:?[a-zA-Z]+://)?([a-zA-Z0-9
\\
-._~%!$&'()*+,;=:
\\
[
\\
]]+)"
};
constexpr
size_t
MAX_RESPONSE_SIZE
{
1024
*
1024
};
std
::
string
hostFromUri
(
const
std
::
string
&
uri
)
{
std
::
smatch
pieces_match
;
if
(
std
::
regex_search
(
uri
,
pieces_match
,
URI_VALIDATOR
))
if
(
pieces_match
.
size
()
==
3
)
return
pieces_match
[
2
].
str
();
return
uri
;
}
NameDirectory
::
NameDirectory
(
const
std
::
string
&
s
)
:
serverUri_
(
s
),
serverHost_
(
hostFromUri
(
s
))
{}
NameDirectory
&
NameDirectory
::
instance
(
const
std
::
string
&
server
)
{
const
std
::
string
&
s
=
server
.
empty
()
?
DEFAULT_SERVER_URI
:
server
;
static
std
::
map
<
std
::
string
,
NameDirectory
>
instances
{};
auto
it
=
instances
.
emplace
(
s
,
NameDirectory
{
s
});
return
it
.
first
->
second
;
}
void
NameDirectory
::
lookupAddress
(
const
std
::
string
&
addr
,
LookupCallback
cb
)
{
auto
cacheRes
=
nameCache_
.
find
(
addr
);
if
(
cacheRes
!=
nameCache_
.
end
())
{
cb
(
cacheRes
->
second
,
Response
::
found
);
return
;
}
restbed
::
Uri
uri
(
serverUri_
+
QUERY_ADDR
+
addr
);
auto
req
=
std
::
make_shared
<
restbed
::
Request
>
(
uri
);
req
->
set_header
(
"Accept"
,
"*/*"
);
req
->
set_header
(
"Host"
,
serverHost_
);
RING_DBG
(
"Address lookup for %s: %s"
,
addr
.
c_str
(),
uri
.
to_string
().
c_str
());
auto
ret
=
restbed
::
Http
::
async
(
req
,
[
this
,
cb
,
addr
](
const
std
::
shared_ptr
<
restbed
::
Request
>
,
const
std
::
shared_ptr
<
restbed
::
Response
>
reply
)
{
if
(
reply
->
get_status_code
()
==
200
)
{
size_t
length
=
0
;
length
=
reply
->
get_header
(
"Content-Length"
,
length
);
if
(
length
>
MAX_RESPONSE_SIZE
)
{
cb
(
""
,
Response
::
error
);
return
;
}
restbed
::
Http
::
fetch
(
length
,
reply
);
std
::
string
body
;
reply
->
get_body
(
body
);
Json
::
Value
json
;
Json
::
Reader
reader
;
if
(
!
reader
.
parse
(
body
,
json
))
{
RING_ERR
(
"Address lookup for %s: can't parse server response: %s"
,
addr
.
c_str
(),
body
.
c_str
());
cb
(
""
,
Response
::
error
);
return
;
}
auto
name
=
json
[
"name"
].
asString
();
if
(
not
name
.
empty
())
{
RING_DBG
(
"Found name for %s: %s"
,
addr
.
c_str
(),
name
.
c_str
());
addrCache_
.
emplace
(
name
,
addr
);
nameCache_
.
emplace
(
addr
,
name
);
cb
(
name
,
Response
::
found
);
}
else
{
cb
(
""
,
Response
::
notFound
);
}
}
else
{
cb
(
""
,
Response
::
error
);
}
}).
share
();
// avoid blocking on future destruction
ThreadPool
::
instance
().
run
([
ret
](){
ret
.
get
();
});
}
static
const
std
::
string
HEX_PREFIX
{
"0x"
};
void
NameDirectory
::
lookupName
(
const
std
::
string
&
name
,
LookupCallback
cb
)
{
if
(
not
validateName
(
name
))
{
cb
(
name
,
Response
::
invalidName
);
return
;
}
auto
cacheRes
=
addrCache_
.
find
(
name
);
if
(
cacheRes
!=
addrCache_
.
end
())
{
cb
(
cacheRes
->
second
,
Response
::
found
);
return
;
}
restbed
::
Uri
uri
(
serverUri_
+
QUERY_NAME
+
name
);
auto
request
=
std
::
make_shared
<
restbed
::
Request
>
(
std
::
move
(
uri
));
request
->
set_header
(
"Accept"
,
"*/*"
);
request
->
set_header
(
"Host"
,
serverHost_
);
RING_DBG
(
"Name lookup for %s: %s"
,
name
.
c_str
(),
uri
.
to_string
().
c_str
());
auto
ret
=
restbed
::
Http
::
async
(
request
,
[
this
,
cb
,
name
](
const
std
::
shared_ptr
<
restbed
::
Request
>
,
const
std
::
shared_ptr
<
restbed
::
Response
>
reply
)
{
auto
code
=
reply
->
get_status_code
();
if
(
code
!=
200
)
RING_DBG
(
"Name lookup for %s: got reply code %d"
,
name
.
c_str
(),
code
);
if
(
code
>=
200
&&
code
<
300
)
{
size_t
length
=
0
;
length
=
reply
->
get_header
(
"Content-Length"
,
length
);
if
(
length
>
MAX_RESPONSE_SIZE
)
{
cb
(
""
,
Response
::
error
);
return
;
}
restbed
::
Http
::
fetch
(
length
,
reply
);
std
::
string
body
;
reply
->
get_body
(
body
);
Json
::
Value
json
;
Json
::
Reader
reader
;
if
(
!
reader
.
parse
(
body
,
json
))
{
RING_ERR
(
"Name lookup for %s: can't parse server response: %s"
,
name
.
c_str
(),
body
.
c_str
());
cb
(
""
,
Response
::
error
);
return
;
}
auto
addr
=
json
[
"addr"
].
asString
();
if
(
!
addr
.
compare
(
0
,
HEX_PREFIX
.
size
(),
HEX_PREFIX
))
addr
=
addr
.
substr
(
HEX_PREFIX
.
size
());
if
(
not
addr
.
empty
())
{
RING_DBG
(
"Found address for %s: %s"
,
name
.
c_str
(),
addr
.
c_str
());
addrCache_
.
emplace
(
name
,
addr
);
nameCache_
.
emplace
(
addr
,
name
);
cb
(
addr
,
Response
::
found
);
}
else
{
cb
(
""
,
Response
::
notFound
);
}
}
else
if
(
code
>=
400
&&
code
<
500
)
{
cb
(
""
,
Response
::
notFound
);
}
else
{
cb
(
""
,
Response
::
error
);
}
}).
share
();
// avoid blocking on future destruction
ThreadPool
::
instance
().
run
([
ret
](){
ret
.
get
();
});
}
bool
NameDirectory
::
validateName
(
const
std
::
string
&
name
)
const
{
return
std
::
regex_match
(
name
,
NAME_VALIDATOR
);
}
void
NameDirectory
::
registerName
(
const
std
::
string
&
addr
,
const
std
::
string
&
name
,
const
std
::
string
&
owner
,
RegistrationCallback
cb
)
{
if
(
not
validateName
(
name
))
{
cb
(
RegistrationResponse
::
invalidName
);
return
;
}
auto
cacheRes
=
addrCache_
.
find
(
name
);
if
(
cacheRes
!=
addrCache_
.
end
())
{
if
(
cacheRes
->
second
==
addr
)
cb
(
RegistrationResponse
::
success
);
else
cb
(
RegistrationResponse
::
alreadyTaken
);
return
;
}
auto
request
=
std
::
make_shared
<
restbed
::
Request
>
(
restbed
::
Uri
(
serverUri_
+
QUERY_NAME
+
name
));
request
->
set_header
(
"Accept"
,
"*/*"
);