Giter Site home page Giter Site logo

servalproject / serval-dna Goto Github PK

View Code? Open in Web Editor NEW
170.0 28.0 79.0 29.51 MB

The Serval Project's core daemon that implements Distributed Numbering Architecture (DNA), MDP, VoMP, Rhizome, MeshMS, etc.

Home Page: http://servalproject.org

License: Other

Emacs Lisp 0.01% Makefile 0.38% Shell 5.88% C 89.39% Java 2.00% Python 0.23% M4 1.07% Batchfile 0.03% CMake 0.06% Assembly 0.63% Smarty 0.04% PHP 0.01% Swift 0.30% VBScript 0.01%

serval-dna's Introduction

Serval DNA

Serval Project, September 2017

Serval DNA is the core component of the Serval Mesh app for Android and the Serval Mesh Extender long-range mesh networking device. It is a daemon process that performs all the central services of the Serval mesh network such as dynamic routing, encryption and authentication, file distribution, messaging, and voice telephony.

Any device with Wi-Fi connectivity that runs the Serval DNA daemon can participate in the Serval mesh network.

Download, build and test

  • INSTALL.md contains instructions for downloading, building and testing Serval DNA on Linux, Mac OS-X, and similar platforms

  • Notes for Developers contains useful information for developers of Serval DNA, which may also help resolve build issues

Configuration

Documentation

Bugs and issues

Bugs can be reported and inspected using the GitHub issue tracker.

What is in this repository?

This repository contains:

The servald executable is a multi-purpose program that can be invoked directly from the command line, run as a daemon process, or invoked via JNI from within a Java program or via the [Swift module][] from within a Swift program. The servald executable is really many commands built into one; the command-line arguments select which command to run. Some commands are stand-alone utilities, some start and stop the servald daemon process, some communicate with the servald daemon as an MDP client, and others via a two-way pipe called the monitor interface.

The following protocols and services are implemented in servald:

  • The Distributed Numbering Architecture (DNA) is the key innovation that makes mesh telephony viable in the absence of any infrastructure, eg, in the aftermath of a natural disaster or in remote locations. DNA is a protocol carried over MDP (see below) that asks many devices at once if they will answer a phone number (DID). A device will respond with its own subscriber identity (SID) if its user has “claimed” that DID. This allows phone calls to be established over the mesh using conventional phone numbers.

  • The Serval Keyring is a flat file containing all the user identities on a single device. Each identity is a set of elliptic curve secret cryptographic keys that belong to a single “mesh subscriber”, indexed by the subscriber's 256-bit public key, called a SID. Each identity in the keyring is locked by its own user-chosen password (called a PIN in the code and documentation), using elliptic curve cryptography to protect locked entries from theft or tampering, and steganography to allow the user to plausibly deny the existence of locked identities.

  • The Mesh Datagram Protocol (MDP) is Serval's own layer 3 protocol designed for secure mesh networking. It is completely independent of Internet protocols such as IP and UDP, although for the time being it is implemented as an “overlay” network based on UDP/IP because that is the interface that Linux and other operating systems provide for sending data over Wi-Fi. However, MDP could easily be implemented directly over a layer 2 data link such as Wi-Fi or Ethernet MAC. MDP uses subscribers' public keys (SID) as source and destination addresses, has a 32-bit port number analogous to the 16-bit port number used in TCP/IP, and encrypts all packet contents by default, using the public key (SID) of the destination.

  • The Voice over Mesh Protocol (VoMP) is Serval's own call negotiation and two-way audio streaming protocol used to implement mesh voice calls. It fills the same role as SIP/RTS, the dominant protocol used for Voice over Internet Protocol, but VoMP is designed for the variable and unstable conditions of wireless mesh networks. VoMP's session state model and signalling can handle packet loss, mid-call re-routing and re-connection where SIP would fail. VoMP's audio streaming can encapsulate many codecs and even DTMF (dialpad button) signalling.

  • Rhizome is a content storage and distribution service implemented using SQLite and a content-exchange protocol based on MDP. It can be used to disseminate content like images, videos, documents, software upgrades, etc. Each piece of content in Rhizome is called a “bundle”, which has two parts: a manifest that describes the content, and the payload, which is the content itself. Each bundle has its own unique cryptographic identifier that allows any recipient to verify that it has not been tampered with. A bundle's payload may be encrypted by the author so that only the designated recipient can read it.

  • The MeshMS messaging service sends short text messages using Rhizome as its transport. Each message thread is stored and carried in a pair of journal bundles, one for each direction (ply).

  • Serval Infrastructure services may optionally be deployed on any devices in the mesh to expose external services to mesh subscribers and vice versa (eg, VoIP gateways, SMS satellite links, packetised web), and to overcome scalability limitations of a perfectly decentralised mesh (eg, central telephone directory). Serval Infrastructure is implemented as a daemon with its own executable called directory_service.

Copyright and licensing

Serval DNA is free software produced by the Serval Project and many contributors. Its source code is licensed to the public under the GNU General Public License version 2. Its technical documentation is licensed to the public under the Creative Commons Attribution 4.0 International licence. All source code and technical documentation is freely available from the Serval Project's serval-dna Git repository on GitHub.

The copyright in most of the source code in Serval DNA is held by Serval Project Inc., a not-for-profit association incorporated in the state of South Australia in the Commonwealth of Australia for the purpose of developing the Serval mesh software. The COPYRIGHT file contains a full list of all those who hold copyright in portions of the Serval DNA source code.

The Serval Project will accept contributions for which copyright has been assigned to Serval Project Inc., or which are licensed to either Serval Project Inc. or to the public on terms that allow the Serval Project to freely redistribute and re-license the code under non-restrictive terms, for example, to release Serval DNA as part of a product distributed through the Apple app store.

Individual developers may assign copyright in their contributions by signing the Serval Project Developer Agreement - Individual, and organisations by signing the Serval Project Developer Agreement - Entity.


Copyright 2015 Serval Project Inc.
Copyright 2016-2017 Flinders University
CC-BY-4.0 This document is available under the Creative Commons Attribution 4.0 International licence.

serval-dna's People

Contributors

danielo avatar gardners avatar lakeman avatar petterreinholdtsen avatar quixotique avatar rom1v avatar tobiaswooldridge avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serval-dna's Issues

Opaque Rhizome bundle version number

The Rhizome manifest version number is currently implemented as GMT time in milliseconds since the standard Unix epoch. The date field can be made optional for users who do not wish to expose the time at which their anonymous posts were made, but the version field is not optional for Rhizome. Therefore, it must be re-implemented to not reveal anything about the time or place of authorship, or even the number of revisions.

The proposed design is:

  • use a 56-bit unsigned integer for version numbers
  • initialise the version of every new bundle with a random integer in the approximate range 1e4 - 1e6 (32 bits)
  • increment the version on every revision by a random integer in the range 1 - 1e6 (32 bits)
  • use an unsigned comparison between version numbers in Rhizome
  • handle version overrun by simply not allowing the version number to wrap -- the “update bundle” operation fails with an error (which should be extremely rare)

When this is done, the BAR format may have to be updated. See issue #19.

Report Rhizome database errors to command line caller

See issue #1 for the background.

At present, an error in the rhizome_store_file() function does not appear to be reported as failure by the rhizome add file command. This, and all other potential failures in servald commands used by Batphone MeshMS logic, must be found and fixed.

Rhizome direct operations: push, pull, sync

To support Rhizome file sharing and MeshMS via infrastructure, it must be possible to configure Rhizome to connect directly to other Rhizome servers at know locations.

This issue will support a single, optional remote Rhizome instance defined by the configuration items:

  • rhizome.direct.address a string passed to getaddrinfo(3)
  • rhizome.direct.port a port number in decimal

Setting either of these without the other will log a warning and ignore it when any of the commands described below is invoked.

The following new servald commands will query servald for local bundles, then connect directly to the configured remote instance, send IHAVE announcements in batches to announce all locally stored bundles, then receive IHAVE and SENDME replies from the remote instance, then perform GET and/or POST operations to exchange bundles:

  • servald rhizome push will only perform POST operations to satisfy the SENDME replies from the direct remote
  • servald rhizome pull will only perform GET operations to fetch any bundles discovered from IHAVE announcements from the direct remote
  • servald rhizome sync will perform a mixture of POST and GET operations, equivalent to performing a push and a pull

These commands will terminate when all bundles identified by the initial IHAVE/SENDME exchange have been transferred. If other bundles become available during the session, these will not be detected.

Publicly shared files in Rhizome should be fetchable via HTTP for non serval clients

We have a web server that currently serves installed apk's. This can be used in hotspot mode to spread the software to other devices.

The web interface is currently very simple.

We need a nice home page with a simple link to download the apk. A browseable list of files currently in Rhizome (should be the same as the Rhizome list).

And a publish file web interface.

Mantis severity: minor
Mantis priority: normal
Mantis project: Core Project
Can reproduce: have not tried

Recover from Rhizome database lock errors using sleep-retry

See issue #1 for the full background.

All Rhizome database queries, SELECT and UPDATE, should detect SQLite database lock failures (sqlite3_step() returns SQLITE_BUSY) and handle it by sleeping briefly then re-trying the query, repeatedly until a maximum timeout limit is reached.

In the servald server process, the timeout must be very short, for example 30 ms, so that it does not introduce unacceptable latency into the server's responsiveness which would degrade real-time services like VoMP.

In other processes, ie, those which access the Rhizome database directly through the servald command-line or JNI interfaces, the timeout can be much longer. Ideally it should be configurable on a per-process basis or even made an optional parameter to every Rhizome command.

This fix will not resolve the Rhizome database locking issue correctly. That is the scope of issue #1. But it will reduce the likelihood of database errors causing failures in MeshMS, so the software can still be used as a demonstration and proof of concept.

Rhizome protocol tests broken by recent peer list changes

Commit 32cd46c broke the first four rhizomeprotocol tests:

1. New bundle and update transfer to one node... ERROR
2. Big new bundle transfers to one node... ERROR
3. New bundle transfers to four nodes... ERROR
4. Payload deletion transfers to one node... ERROR
4 tests, 0 pass, 0 fail, 4 error

The ERRORs are caused by the servald id allpeers command returning no results, where it used to list the peers that had been discovered via the dummy interface.

Allow DNS names in Directory Service client config

In overlay_address.c load_subscriber_address(), refactor to allow asynchronous resolution of configured domain names. This would avoid the problem of hard-configured IP addresses, which may change.

Anonymous collection of statistics

Determine the required statistics & metrics (and other information) required from the install and the running of the software on a day to day basis, set up reporting back to us.

Mantis severity: minor
Mantis priority: normal
Mantis project: Core Project
Related to: mantis:0000090 UI - Anonymous collection of statistics, and the notification of same
Related to: servalproject/batphone#48 display information being sent back to project for review
Related to: servalproject/batphone#38 Need an activity display that asks a user for permission to upload diagnostic information to ServalHQ
Can reproduce: have not tried

Asynchronous DNS resolution

A directory service can be configured with a dns name (see #18). But this call might block.
Move this name resolution to a worker thread or find an asynchronous dns library to include. This will also involve adding a state model for dealing with the results in an asynchronous manner.

Rhizome encrypted payloads for MeshMS

Build support for encrypted payloads into Rhizome, using the recipient's public key. The creator of a bundle must pass the clear payload content to the rhizome add command and must specify the recipient SID and a flag enabling/disabling encryption in the manifest using the recipient and crypt fields. Servald will encrypt the payload and store it encrypted. The payload hash will be computed from the encrypted form, so it can be verified by intermediate nodes. The servald rhizome extract file command will produce the clear payload by decrypting the payload, or will return an error if the recipient's identity is not available in the keyring.

This will then be used for all MeshMS bundles, to achieve truly private messaging.

@gardners wrote in an email 23 May 2012:

I think the safest semantic for rhizome encryption is to have to specify CRYPT=NO to any bundle payload that is to be en claire. Thus if the CRYPT flag is missing, encryption will be attempted, and accepting the bundle may fail. We can have a “encrypt/make public” selection in the share file dialog. Not sure what the best approach is there, maybe a pull-down, or just an “encrypt payload” checkbox.

Rhizome database space patrol

The Rhizome database currently grows without limit. The following features must be implemented:

  • remove old payloads when a manifest is updated with a new one
  • evict old content to stay within size limit setting

Mantis severity: minor
Mantis priority: normal
Mantis project: Core Project
Product version: 0.09 Shiny
Target version: 0.09 Shiny
Can reproduce: always

Refine BAR format

Currently we waste space in BARs by having 7 bytes for file size. Only the log2 of the file size is ever needed, so we can save 6 bytes.

These extra bytes can be used to provide more of the BID prefix, so that collisions become exceedingly improbably. At present with 64 bits, we expect 50% chance of a collision once there are about 2^32 bundles in existence. Adding 48 bits to get 112 bits means that we would need 2^56 bundles, or approximately 8 million for every person on the planet. This is clearly a helpful move.

We can also reduce the version field to 32 bits if we change the manifest semantics to monotonically increasing values instead of using a notional milli-second clock.

Probably also makes sense to have a short bit field somewhere (eg the upper 3 bits of (log2(filesize)-10), which will never be used to indicate version of BAR format. This could probably be done retrospectively now using the MSB of the file size in this way.

Serval Directory Service

In order to dial by phone number over the internet, we need a central directory service that can resolve from phone numbers to subscriber id's.

  • server has a separate mdp client that binds to a well known port number
  • mdp packet sent to the directory server (initially on the same box as the routing service, in the same packet used for IP&port discovery), containing phone number, name & sid
  • on receipt of this mdp packet on the server, add the details to a database table
  • leverage dna helper infrastructure to query the database and respond to lookup requests with sid uri's
  • modify lookup requests to send a copy of the packet to the directory server

Rhizome file list is too slow

Servald is currently doing too much processing to determine which files you have published while retrieving the list of all files. We need to remove this check from the file listing, and add a separate command to perform this test that can be called from the file details activity.

Test cases for monitor interface

Need a new test script called monitor with some test cases for the monitor interface. Some ideas to start with:

  • test peer announcements: start server instance A, connect to A with monitor CLI client, then start server instance B and assert that peer discovery of B is reported to the CLI client
  • test that Rhizome bundle arrivals are announced
  • test the DNA lookup function used by the Asterisk plugin

Must ensure that the tests PASS on Solaris as well as Linux and Mac OS X.

Refactor socket code (merge Daniel's branches)

In the daniel branch 15eb6c5 between 22 and 24 June 2012, @DanielO factored duplicate socket instantiation code into a new socket.c source file, and made it easier to switch between abstract and normal Unix domain sockets.

In the sockets branch fd1f91d,on 30 July 2012, @DanielO refactored unix domain socket naming into a separate file, also called socket.c. This branch may be a re-work of the daniel branch, merely applied to a more recent version of the master branch. Or, it may contain novel work.

The work in these two branches needs review, and if it is valuable, it should be merged into the latest version of the code.

sqlite creating zeroblobs is VERY slow on WR703N hardware

It can take minutes to create an empty blob, presumably because sqlite zeroes out the storage, during which time servald is unresponsive. This is one of the causes of #46.

It seems that in this situation storing large blobs as regular files would be much, much faster. Should probably be a configurable option.

It may also make sense to adjust the database page size to suit the native page size of the underlying flash storage we are using (a USB memory stick in this case).

Porting to Solaris

The 'solaris' branch has changes to port Serval to Solaris.

After some changes (and one outright bug fix 2ccbc54 basic things work.

Note that the version of Bash installed on serval1 is very old so I am using a hand built bash 4.2.

However many tests fail, eg

==== tests/config
1. Get creates instance directory... PASS
2. Set creates instance directory... PASS
3. Get an unset config item... PASS
4. Set and get a single config item... PASS
5. Get all config items... PASS
6. Set a single config item twice... PASS
7. Delete an unset config item... PASS
8. Delete single config item... PASS
9. Config item names are case insensitive... PASS
10. Config item names can have internal dots... PASS
11. Debug config options affect verbosity... PASS
12. Debug config options override debug.all... PASS
12 tests, 12 pass, 0 fail, 0 error
==== tests/dnahelper
1. Non-existent DNA helper executable... PASS
2. DNA helper configured argument... FAIL
3. DNA helper returns one valid reply... FAIL
4. DNA helper returns two valid replies... FAIL
5. DNA helper returns three valid replies... FAIL
6. DNA helper returns empty URI... FAIL
7. DNA helper returns invalid URI, missing scheme... FAIL
8. DNA helper returns invalid URI, invalid char... FAIL
9. DNA helper returns invalid URI, empty hierarchical part... FAIL
10. DNA helper returns mismatched token... FAIL
11. DNA helper returns empty token... FAIL
12. DNA helper returns invalid token... FAIL
13. DNA helper returns invalid token, too long... FAIL
14. DNA helper returns invalid token, too short... FAIL
15. DNA helper returns mismatched DID... FAIL
16. DNA helper returns empty DID... FAIL
17. DNA helper returns invalid DID... FAIL
18. DNA helper returns invalid DID, too long... FAIL
19. DNA helper returns invalid DID, too short... FAIL
20. DNA helper returns invalid reply, missing delimiter... FAIL
21. DNA helper returns invalid reply, name too long... FAIL
22. DNA helper returns invalid reply, empty line... FAIL
23. DNA helper returns invalid reply, missing newline... FAIL
24. DNA helper process takes too long to reply and is restarted... FAIL
25. DNA helper spurious output after DONE is ignored... FAIL
26. DNA helper process dies unexpectedly and is restarted... FAIL
26 tests, 1 pass, 25 fail, 0 error
==== tests/dnaprotocol
1. Start three servald servers with dummy interfaces... PASS
2. Lookup by wildcard... PASS
3. Lookup by empty string... PASS
4. Lookup non-existent phone number... PASS
5. Lookup local phone number... PASS
6. Lookup remote phone number... PASS
7. Node info auto-resolves for local identities... PASS
8. Node info resolves remote identities... PASS
9. Lookup phone number three nodes reply... FAIL
10. Lookup phone number two nodes reply... FAIL
11. Lookup phone number one node replies... FAIL
11 tests, 8 pass, 3 fail, 0 error
==== tests/jni
1. Serval JNI echo Hello world... ERROR
2. Serval non-JNI output delimiter environment variable... PASS
3. Serval JNI repeated calls in same process... ERROR
3 tests, 1 pass, 0 fail, 2 error
==== tests/rhizomeops
1. Initial list is empty...
2. Add with no author and no manifest file...
3. Add with no manifest file... FAIL
4. Add with no author makes manifest without BK... FAIL
5. Add with non-existent manifest file... FAIL
6. Add with minimal manifest file... FAIL
7. Add with empty payload... FAIL
8. List contains one file after one add... FAIL
9. Extract manifest after one add... ERROR
10. Extract non-existent manifest... PASS
11. Extract manifest using invalid ID... PASS
12. Extract file after one add... ERROR
13. Extract non-existent file... PASS
14. Extract file using invalid ID... PASS
15. Add same manifest detects duplicate... ERROR
16. Add mismatched manifest/payload fails... ERROR
17. Add new payload to existing manifest with same version fails... ERROR
18. Add new payload to existing manifest with new version... ERROR
19. Cannot add new payload to authorless manifest... ERROR
20. Add new payload to authorless manifest with bundle secret... ERROR
21. Add new payload to existing manifest with automatic version... ERROR
22. Add with unsupported service fails... PASS
23. First add MeshMS creates manifest... PASS
24. Subsequent add MeshMS updates manifest and removes old payload... PASS
25. Add MeshMS without sender fails... PASS
26. Add MeshMS without recipient fails... PASS
27. Add MeshMS without author uses sender... PASS
28. List MeshMS manifests by filter... PASS
29. Can import a bundle created by another instance... ERROR
29 tests, 12 pass, 7 fail, 10 error
==== tests/rhizomeprotocol
1. New bundle and update transfer to one node... ERROR
2. Big new bundle transfers to one node... ERROR
3. New bundle transfers to four nodes... ERROR
4. Payload deletion transfers to one node... ERROR
5. One way push bundle to unconnected node... ERROR
6. One way pull bundle from unconnected node... ERROR
7. Two-way sync bundles between unconnected nodes... ERROR
8. Add file locally using HTTP, returns manifest... ERROR
8 tests, 0 pass, 0 fail, 8 error
==== tests/server
1. Starting server creates instance directory... PASS
2. Starting server gives no errors... PASS
3. Starting server with no configured interfaces gives error... PASS
4. Starting server on dummy interface gives no errors... PASS
5. Start server while already running... PASS
6. Stop server before it finishes starting... PASS
6 tests, 6 pass, 0 fail, 0 error

Mantis severity: minor
Mantis priority: normal
Mantis project: Porting
Can reproduce: N/A

Rhizome server process to avoid lock errors and reduce servald latency

The SQLite3 library locks all database operations to stop concurrent processes from corrupting the database. See http://www.sqlite.org/lockingv3.html. The scheme allows many concurrent readers or one single writer at a time.

The current architecture of Rhizome as implemented in servald allows more than one process to directly access the Rhizome database, which can produce lock conflicts. These conflicts cause the SQLite queries to fail immediately: the sqlite3_step() function returns MYSQL_BUSY.

On immediate consequence of these lock errors is in sending/receiving MeshMS messages. An incoming MeshMS message log (Rhizome bundle) causes the Batphone app to fork a thread which accesses the Rhizome database directly via calls to the servald command line operations rhizome list, rhizome extract manifest, rhizome extract file, and rhizome add file. Sometimes these operations fail because of a database lock error.

As a side issue (issue #3), these errors are not always reported back to the Java code, which continues on assuming the operation was successful. So a retry scheme cannot be implemented by the Batphone app.

The main issue is that MeshMS reception (acknowledgement) and sending should simply not be allowed fail because of database lock errors. The architecture must be made to deal with database concurrency issues completely and correctly.

This can be dealt with in three stages:

  1. A partial fix to reduce the impact of database lock errors and keep MeshMS reliable enough for demo purposes. Issue #2 introduces a low-level sleep-retry mechanism into all database accesses that should avoid the majority of lock errors.
  2. Issue #3 fixes the reporting of database lock errors to the Rhizome command-line operations that invoke them, so that Batphone Java code can detect and deal with the failure.
  3. The substance of this issue is to change the existing servald architecture to fix the issue properly, as described below.

All Rhizome database operations ought to be performed by a single Rhizome server process that should be a fork(2) of the servald process.

The Rhizome server will present a simple request-response interface to all other components of the Serval Mesh product, and all Rhizome database operations will be performed exclusively by that process, thus eliminating the risk of database lock errors under normal circumstances.

The Rhizome server can safely have very high latency if needed, and this will not affect the low-latency services offered by servald. If servald wishes to perform a Rhizome store operation, for example storing a paylod that was just received via HTTP, then it puts the data into request parameters (and optionally files in external storage), and sends a request to the Rhizome server, using its asynchronous i/o mechanism to wait for the server to accept and then complete the request. All command-line rhizome operations will do the same.

Harmonise source file lists for UNIX and Android build processes

Currently Android.mk and Makefile.in have lists of source files which are substantially the same.
This means that if you add a source file it has to be updated in two places, which encourages errors.
Also, adding a new source file currently requires modifying both those files, and then rerunning configure for native UNIX builds, when it probably isn't necessary.

Solution: push the source file lists out into some separate .mk files

Redundent check in vomp_generate_session_id()

In vomp_generate_session_id(), there is the following check:

if (session_id==vomp_call_states[i].local.session
    ||session_id==vomp_call_states[i].local.session){
  session_id=0;
  break;
}

I presume the second "local" should be "remote"?

Unable to use (Serval 0.90RC1 - Shiny) on HTC Desire HD

Platform : HCT Desire HD
OS : Android Version 2.3.7 / CyanogenMod

  • Install from the apk : Ok
  • Activate Wifi on the mobile phone
  • First start: Crash at startup with message "Fermeture soudaine de l'application, processus org.servalprojet"
  • reboot Mobile Phone
  • second start: same crash!
  • Manage Android Applications > Serval > Erase data
  • third start: looks ok but endless loop on Wifi test and unable to quit application.

I give up for now ;-(.*

Please note that with Serval version yet available on Google Play (serval 0.08) the Wifi test succeed on my phone.
Is there any log I can send to help troubleshout ?

servald stop & start misbehaving after killing deamon

After a segfault or other graceless shutdown, stop & start should be sufficient to ensure servald is running again.

Currently the following has been observed on android;

> su kill -9 $PID
JNI: stop
commandline.c:660:app_server_stop()  Servald pid=$PID for instance '/data/data/org.servalproject/var/serval-node' did not stop after 5 SIGHUP signals
return status = 255
JNI: start exec $PATH
commandline.c:546:app_server_start()  Server already running (pid=$PID)

Serval DNA C code uses ambiguous types

We use "long long" etc instead of things like uint_64t

Mantis severity: minor
Mantis priority: normal
Mantis project: Core Project
Product version: 0.09 Shiny
Can reproduce: N/A

Rhizome direct push does not finalise all sql statements

Returning from any command line function will now trigger the rhizome database to be closed.
If there are any sql statements that have not been finalised, an error will be logged.
Rhizome protocol tests "One way push..." (7) & "Two-way sync" (9) are now failing due to open sql statements.

Reserve Rhizome fetch slots by priority

The current Rhizome fetch code, recently improved in issue #17, allows up to four fetch operations to be in progress at any one time. The fetch slots are currently allocated in a first-come basis to the next fetch on the “candidates” queue, which is sorted by priority. Priority is currently derived from payload size; the larger the size, the lower the priority.

This logic can suffer from the pathological case of allowing four large, low-priority fetches to starve (postpone) many high-priority fetch candidates for a long time, if the four low-priority candidates appear before the high-priority ones.

The proposal to avoid this is simple: each fetch slot can be assigned a static priority threshold, and cannot be used for any fetch with a lower priority. By assigning the slots a range of priorities, there will always be at least one slot available for high-priority fetches because low-priority fetches will not be able to fill all the slots. The priority thresholds could be chosen to correspond to the following sizes:

slot 0: only for size ≤ 16 KiB
slot 1: only for size ≤ 128 KiB
slot 2: only for size ≤ 1 MiB
slot 3: for any size

The test case for this logic should start two servald instances running, then add eight bundles of different sizes (corresponding to each slot's range), in order from large to small. It should then check that the smaller bundles arrive before the larger ones.

Logging improvements to support field diagnosis

From the NAF 2 contract:

In order for the Serval Project to provide ongoing support to deployments of OpenBTS, it will be necessary for the Serval DNA to collect diagnostic logs and for users to send those logs to Serval engineers upon request. Serval DNA already has its own internal logging system, but it only writes to a single output stream, typically a file on disk.
This will require development of a more general log output mechanism for Serval DNA that can automatically rotate log files and retain incidents of note. The extent of crash diagnosis will depend on the level of debugging support present on the OpenBTS platform. It will also require instructions for users to enable and disable logging and a mechanism for sending logs to the Serval Project.

The following improvements will achieve this goal:

  • Provide another log level between INFO and DEBUG, called VERBOSE.
  • Include the symbolic name of the debug flag in each DEBUG log message to aid filtering of large log files.
  • Make all test scripts assert no ERROR or FATAL messages in server log files, and fix the failures that arise by converting WHY() messages to WARN() or INFO(), or by fixing the causes of the ERRORs directly.
  • New code to rotate log files based on configurable size and time limits with sensible defaults.
  • Expose a JNI command-line entry point to log to the Serval DNA logging system so that some Batphone activity, eg WiFi detection messages, can be logged to the Serval log files.
  • New servald command to collect the current log files into a single Rhizome bundle addressed to Serval.
  • Set up a servald daemon on serval1 to only receive pushed log bundles from Commotion OpenBTS sites.
  • Configure OpenBTS units with the IP addresses (or host names, see #18) of serval1.
  • Documentation in servald-dna/doc with instructions for pushing log files and configuring debug flags and logging levels.

Move MeshMS implementation into servald

The MeshMS logic should all be implemented as part of servald, so that it becomes a “core Serval service.” A command-line and monitor API must be designed to support all the MeshMS functions needed by Batphone. The objectives of this work are:

  • definition and development of the new MeshMS API should be driven by a new, complete test suite called meshms;
  • the new API should permit the elimination of the Batphone message database, so that Rhizome functions as the persistent message store;
  • the current Java implementation in https://github.com/servalproject/batphone/blob/development/src/org/servalproject/rhizome/Rhizome.java should be used as the reference for the MeshMS message log format, and interoperability between the original Java and new servald implementations should be proven, ie, messages sent by one can be received by the other;
  • the new implementation should make use of Rhizome journaling functions to prevent message log payloads from growing indefinitely.

As part of this work, the Rhizome manifest management code in servald will need to be refactored into a more formal, efficient and object-oriented form.

Rhizome manifest signature block type codes flawed

To date we have used a byte code for signature blocks where the code is equal to the length of the signature including the byte code. This allows one type of signature each of lengths 0 through 255.
Clearly a 0 byte signature is silly. Probably anything less than 4 bytes is silly on the basis of ease of brute-forcing. Signatures tend to be of sizes with reasonable alignments. Revised formulation is:

Lower 6 bits for:
(1+(0-63)) x 4 bytes for length of signature, excluding the one-byte type-and-length code.
Upper 2 bits for:
disambiguating between signature types (or uses) that share the same length.

We only have one signature type, which is CryptoSign, which used to have code 0x61, and under the new scheme would have code 0x17.

Test framework fails on OSX

OSX Mountain Lion has old Bash (3.2.48) and tests fail like so..


[ur 11:43] ~/projects/serval/batphone/jni/serval-dna >./tests/dnahelper 
1. Non-existent DNA helper executable...2. DNA helper configured argument...3. DNA helper returns one valid reply...4. DNA helper returns two valid replies...5. DNA helper returns three valid replies...6. DNA helper returns empty URI...7. DNA helper returns invalid URI, missing scheme...8. DNA helper returns invalid URI, invalid char...9. DNA helper returns invalid URI, empty hierarchical part...10. DNA helper returns mismatched token...11. DNA helper returns empty token...12. DNA helper returns invalid token...13. DNA helper returns invalid token, too long...14. DNA helper returns invalid token, too short...15. DNA helper returns mismatched DID...16. DNA helper returns empty DID...17. DNA helper returns invalid DID...18. DNA helper returns invalid DID, too long...19. DNA helper returns invalid DID, too short...20. DNA helper returns invalid reply, missing delimiter...21. DNA helper returns invalid reply, name too long...22. DNA helper returns invalid reply, empty line...23. DNA helper returns invalid reply, missing newline...24. DNA helper process takes too long to reply and is restarted...25. DNA helper spurious output after DONE is ignored...26. DNA helper process dies unexpectedly and is restarted...26 tests, 0 pass, 0 fail, 0 error
[ur 11:45] ~/projects/serval/batphone/jni/serval-dna >./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ExecArg1: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ExecError: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/TokenInvalidLong: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/DidMismatch: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/UriInvalid2: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/UriInvalid3: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/TokenInvalid: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/TokenInvalidShort: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyOk2: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/UriEmpty: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/UriInvalid1: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/DidInvalid: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyOk3: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/TokenMismatch: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/DidInvalidLong: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyInvalidLongName: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyOk1: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/DidEmpty: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/TokenEmpty: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyInvalidMissingDelim: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/DidInvalidShort: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyInvalidMissingNewline: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplyInvalidEmpty: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/HelperDies: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/ReplySpurious: No such file or directory
./tests/../testframework.sh: line 239: /var/folders/vw/9v3c0ztd1qj3ry2b_2cbrqfh0000gn/T//_tfw-28333/results/HelperTimeout: No such file or directory

Circumvent WiFi broadcast filters

Many phones set their WiFi drivers to deliberately drop incoming broadcast packets (eg, while the screen is off due to inactivity, the phone does not want broadcast traffic to keep waking it up), so we can't do peer discovery, or announce rhizome advertisements.

One solution is to periodically poke the addresses in our ARP table so that they can add us to their peer list. They will do the same for us, and so it should all work.

MDP (and possibly other traffic types) are having trouble with packet radio links

Getting lots of errors like:
DEBUG: [ 2384] 05:09:47.529 rhizome_fetch.c:1090:rhizome_fetch_mdp_slot_callback() MDP connection timed out: last RX 10070ms ago (read 0 of 9216 bytes)
and very few MDP completion notices.
This might be the result of lots of discarded packets on the RX side, apparently due to "malformed packet". Packet radio packets are now CRC protected, so malformed packets seems unlikely, since they should get filtered out. Maybe we are passing packets with one too many or one too few bytes?

Subscriber internet routing service [SIRS]

[aka gateway of last resort]

Serval Mesh lets you communicate with your local neighbours, now it's time to add the capability to route packets globally.

  • for control of any potential scalability issues, registration with the gateway should be via invitation only
  • the invitation should include the SID and name/IP of the server which should be added to servald config
  • servald should send a packet on connection to a network, and every interval to the routing service
  • the gateway should remember the IP and port from each incoming packet, and remember the mapping from SID
  • IP & port mappings may be serialised and reloaded after a restart
  • any packets addressed to a subscriber that is not reachable on the local network should be forwarded to the routing service

Servald needs to co-exist in other mesh networks

For servald to co-exist on another layer 3 routed network (eg BATMAN, olsr) we need to do the following;

  • separate routing discovery information from the resulting routing rules - Done
  • disable overlay routing discovery per interface - Done
  • compare the destination interface and address when aggregating payloads - Done
  • allow for "direct" neighbours reachable via a unicast address - Done
  • allow for broadcast packets to be sent via an external plugin that can use the routing engines own efficient flooding mechanism
  • on receipt of a flooded packet, remember the unicast address of the originating peer

Keyring test suite

The keyring commands need to be covered by a test suite: tests/keyring.

Of particular importance is to ensure that all the code dealing with PINs (keyring-wide and per-identity) is well covered and tested. This is necessary before we can start using a PIN-locked keyring file to store Serval Project authorities, such as the Rhizome Secret for publishing APK updates (see servalproject/batphone#33).

The keyring_seed() function is called whenever the server is started in overlay mode, which creates a PIN-less identity if none is present, so this is already extensively tested.

In order to test other keyring functions, it may be necessary to add more keyring commands or add extra arguments to existing commands.

Undertake Multihop calls via Mesh and VOMP

We need to be able to undertake multihop calls via the Mesh and VOMP

Mantis severity: block
Mantis priority: urgent
Mantis project: Core Project
Product version: 0.09 Shiny
Target version: 0.09 Shiny
Related to: mantis:0000180 Undertake Calls via Mesh and VOMP
Can reproduce: always

Redesign network packet format

There are a number of deficiencies in the current network format that are blocking the implementation of a number of features.

  • Cannot tell who sent a packet.
  • Cannot tell if a packet was missed.
  • Redundant packet type and port number.
  • No support for specifying payload QOS.
  • Announce packets have a fixed length subscriber id.
  • Payload length includes the variable length header which can't be known until the packet is assembled.

Since we must change the packet format anyway, it is worth investing the effort to build a single more flexible format and resolve all of these issues at once.

  • Packet sender and sequence number should be in the header, then we can ACK / NACK correctly.
  • All subscriber ID's should be valid, all broadcast and sid wire formats will be preceded by a type code, but full sid's should rarely be transmitted.
  • All payloads should be mdp payloads
  • Network health, routing and mdp bind payloads should have well known port numbers
  • Binding to port's should support registering an internal handler function, eg echo, vomp, dna lookup.
  • Incompatible payload format changes could also change port numbers.

Hanging up a non-existant vomp call should still "succeed"

If any vomp command is received via the monitor interface for a call that doesn't exist, a HANGUP should be sent out via the monitor interface to indicate that any call state should be discarded. We don't want the UI to appear unresponsive even though there is nothing to do.

Rhizome direct fails with a large number of bundles

The rhizome direct (pull/push/sync) processes have some issues and built in limitations on the number of bundles that can be handled.

When processing the list of bundles the server has requested, only the manifest id's in the first part of the http stream are being processed.

find_subscr_buffer() called indefinitely on Samsung Galaxy Nexus

While I don't have this problem on other phones, on Samsung Galaxy Nexus, find_subscr_buffer() is called very very often (~10 times per second). Do you have an idea of the source cause ?

Then, it causes a lot of "Dropped frames" due to expiry timeout in overlay_stuff_packet.

I/servald ( 4739): [ 4739] 11:21:35.032 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:35.033 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:35.034 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:35.136 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:35.163 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:35.443 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:35.443 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:35.648 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:35.648 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:35.852 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:36.057 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:36.058 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:36.060 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:36.160 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:36.171 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:36.467 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:36.467 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:36.671 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:36.672 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:36.876 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:37.082 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:37.082 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:37.083 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:37.287 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:37.287 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:37.492 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:37.492 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:37.492 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:37.702 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:37.703 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:37.900 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:37.906 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:37.982 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:38.148 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:38.176 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:38.515 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:38.516 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:38.516 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:38.721 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:38.721 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:38.924 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:38.925 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:38.989 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:39.152 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:39.180 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:39.540 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:39.540 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:39.541 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:39.744 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:39.745 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A
I/servald ( 4739): [ 4739] 11:21:39.908 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 380F
I/servald ( 4739): [ 4739] 11:21:39.911 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BE9FC8
I/servald ( 4739): [ 4739] 11:21:39.996 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of BF1E50
I/servald ( 4739): [ 4739] 11:21:40.159 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of FA2B
I/servald ( 4739): [ 4739] 11:21:40.184 overlay_address.c:298:find_subscr_buffer()  Asking for explanation of 5E6A

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.