Giter Club home page Giter Club logo

nng's Introduction

Welcome to nanomsg

Release MIT License Linux Windows Darwin Discord

The nanomsg library is a simple high-performance implementation of several "scalability protocols". These scalability protocols are light-weight messaging protocols which can be used to solve a number of very common messaging patterns, such as request/reply, publish/subscribe, surveyor/respondent, and so forth. These protocols can run over a variety of transports such as TCP, UNIX sockets, and even WebSocket.

For more information check the website.

Prerequisites

  1. Windows.

    • Windows Vista or newer (Windows XP and 2003 are NOT supported)
    • Microsoft Visual Studio 2010 (including C++) or newer, or mingw-w64. (Specifically mingw and older Microsoft compilers are NOT supported, and we do not test mingw-w64 at all, so YMMV.)
    • CMake 2.8.12 or newer, available in $PATH as cmake
  2. POSIX (Linux, MacOS X, UNIX)

    • ANSI C compiler supporting C89
    • POSIX pthreads (should be present on all modern POSIX systems)
    • BSD sockets support for both TCP and UNIX domain sockets
    • CMake (http://cmake.org) 2.8.12 or newer, available in $PATH as cmake
  3. Documentation (optional)

Quick Build Instructions

These steps here are the minimum steps to get a default Debug build. Using CMake you can do many other things, including setting additional variables, setting up for static builds, or generation project or solution files for different development environments. Please check the CMake website for all the various options that CMake supports.

POSIX

This assumes you have a shell in the project directory, and have the cmake and suitable compilers (and any required supporting tools like linkers or archivers) on your path.

  1. % mkdir build
  2. % cd build
  3. % cmake ..
  4. % cmake --build .
  5. % ctest .
  6. % sudo cmake --build . --target install
  7. % sudo ldconfig (if on Linux)

Windows

This assumes you are in a command or powershell window and have the appropriate variables setup to support Visual Studio, typically by running vcvarsall.bat or similar with the appropriate argument(s). It also assumes you are in the project directory.

  1. md build
  2. cd build
  3. cmake ..
  4. cmake --build . --config Debug
  5. ctest -C Debug .
  6. cmake --build . --config Debug --target install NB: This may have to be done using an Administrator account.

Alternatively, you can build and install nanomsg using vcpkg dependency manager:

  1. git clone https://github.com/Microsoft/vcpkg.git
  2. cd vcpkg
  3. ./bootstrap-vcpkg.bat
  4. ./vcpkg integrate install
  5. ./vcpkg install nanomsg

The nanomsg port in vcpkg is kept up to date by microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Static Library

We normally build a dynamic library (.so or .DLL) by default.

If you want a static library (.a or .LIB), configure by passing -DNN_STATIC_LIB=ON to the first cmake command.

POSIX

POSIX systems will need to link with the libraries normally used when building network applications. For some systems this might mean -lnsl or -lsocket.

Windows

You will also need to define NN_STATIC_LIB in your compilation environment when building programs that use this library. This is required because of the way Windows changes symbol names depending on whether the symbols should be exported in a DLL or not.

When using the .LIB on Windows, you will also need to link with the ws2_32, mswsock, and advapi32 libraries, as nanomsg depends on them.

Support

This library is considered to be in "sustaining" mode, which means that new feature development has ended, and bug fixes are made only when strictly necessary for severe issues.

New development is now occurring in the NNG project, which offers both protocol and API compatibility with this project. Please consider using NNG for new projects.

Please see the file SUPPORT for more details.

nng's People

Contributors

alvin1221 avatar c-o-r-e avatar casaroli avatar codypiersall avatar dehorsley avatar dependabot[bot] avatar drbitboy avatar gdamore avatar hugolm84 avatar jake-ruyi avatar janjaapbos avatar jaylinyu avatar l0pital avatar liamstask avatar lilywangl avatar lkesteloot avatar mbush00 avatar mzipay avatar neachdainn avatar paddor avatar phreed avatar phsilva avatar qxsoftware avatar robiwano avatar shikokuchuo avatar suntonix avatar unspecd avatar urkle avatar voutilad avatar wanghaemq 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  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

nng's Issues

Consider making Windows use threadpools

Thread Pools offer some attractive benefits over raw I/O completion ports, including a simpler programming model and better automatic scaling. We might be able to use these to handle taskq type tasks too!

make device() use aios directly

We could save several extra context switches by using AIOs directly from within nni_device.

If we implement #45 this becomes even more easy. This can also possibly benefit from #22

Security attributes support

nanomsg has a framework for setting up security_attributes (passing through via a property). We should add the same support.

Add other UNIX systems

The CMake and platform support is pretty explicitly just supporting Windows, Linux, and MacOS right now.

The code can easily support any modern UNIX, and we should try ensure that the various BSDs, Solaris, illumos, HP-UX, and AIX.

Address properties

Implement property support to get / set addresses (remote and local).

Sockets should be uint32_t's (handles) not pointers.

We want to convert our external API to one that uses socket handles (integers) rather than pointers.

This will let us hold reference counts, and also detect use after free (particularly if we try not to reuse socket IDs too often). Our idhash code lets us allocate ids dynamically quickly and easily, and we can use this to get a quick handle on sockets.

Use of the global table of socket IDs will also allow us to cleverly detect when there are no more active sockets, and finalize the platform, meaning we can close any leaks provided that the application properly does nng_close() on sockets.

nanomsg compatibility layer

We need to implement an API compatibility shim for nanomsg.

The things we will have to add are:

a) message allocation etc. (NN_MSG)
b) integer socket descriptors (and a socket descriptor table)
c) NN_RECVFD, NN_SENDFD, etc.

Plus a whole bunch of other more straight-forward stuff.

Restore the old idhash logic for sockets

The new-fangled object hash turned out not to be such a great idea, and in particular the deferred destruction is really obtuse. As we stopped using object hashes for pipes or eps as a matter of improving clarity of the code, we should do the same here.

Timer priority list improvements

The timer logic uses a logical minheap, implemented as a sorted linked list. Insertions into this list, which can happen reasonably often, are thus O(n).

That said, most of the timeouts are kind of FIFO like... we can pop from the beginning of the list and add to the end of the list -- in general a new timer will have a later timeout than some earlier added ones.

There may be some interesting exceptions to this. For example, survey or req retry timeouts might be quite long, while individual send/recv timeouts might be relatively short.

There are at least three kinds of optimization to consider:

a) Converting to a minheap. This would convert insert into O(log n), but it may have the bad effect of making removal of the min also O(log n). (It also makes removal of the node O(log(n))

b) Breaking the list/heap into per-CPU based ones, and running a separate timeout thread for each real CPU. This may reduce some lock contention, and it would lead to generally shorter queues on the lists. (Note that it may break slightly the property that two events, both with timeouts very near to each other, run in a specific order. I do not think we have any requirement that timeouts be strictly ordered.)

c) Breaking the list up into near and long term expirations. Basically two threads (or more) using a binning strategy; this would probably avoid some unpleasant mixing of timeouts coming from very different sources causing longer list traversals, and might insulate the current linked list approach so that it tends to much more often behave in the optimal O(1) case.

My initial instinct is that we probably want to some combination of b and/or c. I feel pretty strongly that the O(log(n)) behavior of a true minheap is going to perform poorly.

Note that item "c" could still be backed by a single thread (or single thread per CPU), just looking at the minimum of both lists instead of just one.

A very nice project for an external contributor to do would be to model all these and see how they really behave.

SURVEY hang in Travis

Travis occasionally hangs in timeout on the Survey. We need to understand why this occurs (race?) and fix. Note that we think we've seen a similar problem with the pipeline test too.

TLS transport

We can implement at TLS transport now, pretty easily, I think. We just need to choose a TLS framework (mbed TLS?) and implement it.

FreeRTOS support

A question has come up about integration in FreeRTOS. It would be meaningful to demonstrate that the code works for FreeRTOS as an example non-mainstream platform.

Crash in IPC (POSIX)

The IPC test occasionally crashes, due to a race condition in the posix poller.

Essentially, pollq makes an assumption that nothing will have rearmed the file descriptor while it is running the callback. This is not quite true, since a pipe accessing the other direction at the wrong time can indeed cause a problem here.

The pollq logic for poll() is a bit obtuse, so it might be a great idea to go back and rethink this to use simpler registration of pollq items that records outstanding aios, and uses aios to trigger completion.

NNG_FLAG_SYNCH should be the default

Arguably, NNG_FLAG_SYNCH behavior is the preferred behavior in all circumstances. Users using the new API should have to request ASYNC behavior explicitly (NOWAIT flag?)

Close pipe by ID

For messages, we could store the PIPE ID as a message property. This could then be used by the application to conditionally close the underlying pipe (if it still exists). Using IDs here would solve questions about use-after-free, and avoid needing to hold any locks or long term reference counts.

Complete the endpoint API

We specified an API for endpoints, that allowed endpoints to be created, giving the ability to change the endpoint properties, before starting up listen/connect. We need to implement that.

Consider a heap/priority queue for the aio timeouts

The AIO timeout logic uses a really naive sorted list for ordering timeouts. This can lead to some pretty unfortunate performance impacts (O(n)). A priority heap would be faster for insertion by far. (Note that running the timeout thread is still O(1) with the linked list, and would remain so with any sane heap implementation.)

Move DNS out of tcp transport

DNS resolver stuff really needs to be done not inside the specific transports, but rather outside. We should think about how best to make use of this in more generic fashion.

Statistics support

The API specification for the stats is complete, but we need to write code to back it up.

Make transports pluggable

The current transports are hard-wired into the library. We need to make these pluggable.

This will mean that transports will need to have access to the guts of the library, and we will need to change the transports fixed array into a linked list with registration routines.

It should not be necessary to support unregistering transports.

udp

@gdamore, are you planning or thinking about giving nng a udp://protocol?

open protocol by "name" (symbol) instead number

In support of #38 we should convert to a better API, using a pattern like we have for mangos.

Imagine that instead of nng_open(nng_socket *, uint16_t proto) we just have something more like nng_pairv0_open(nng_socket *);

This means that the protocols will need to have to have a different way to pass their ops vector into some kind of internal "socket_open_proto()" call. This has the benefit that applications need never know about the protocol number.

This is really good, because most applications don't need to know the protocol numbers at all; this also allows for pluggable protocols to be built by alllowing them to supply their ops vectors at call time, without requiring any kind of startup constructor/initialization to register them into the main list of protocols.

(Sadly, we still need to do this for transports, for now at least.)

Convert string/errno statements into a table

One of the poorer code coverage reports relates to all the various cases for various error codes. We should move these into an initialized table then use a simple loop over them. This would greatly improve the code coverage reports.

Occasional orphaned pipe or endpoint?

When running the ipc test in a tight loop, we will occasionally see failures like this:

Failures:

  * Listen and accept (Assertion Failed)
  File: /home/parallels/Projects/nng/tests/trantest.h
  Line: 92
  Test: nng_listen(tt->repsock, tt->addr, &ep, NNG_FLAG_SYNCH) == 0

(Sometimes it can be a dial failure too.) I'm fairly certain that what is happening here is that the /tmp/nng_ipc_test pipe isn't getting cleaned up (and I think I've seen a similar problem with TCP), resulting in EADDRINUSE. After the program exits, the thing is gone.

It takes many runs to trigger this failure. Usually several hundred at least. This is on an Ubuntu vm, but I think I've seen failures in MacOS too.

I added a slight delay in my loop, and that didn't fix the problem (but it took a lot longer to hit, of course.) (I was hoping that maybe this was an operating system level race, where close() didn't free the resource entirely... no such luck.)

More work to track this down is needed.

SSH based transport

Jason Aten has proposed the creation of a SSH transport. This could be lots easier to work with than say TLS, and so its worth investigating. We should try to use a 3rd party SSH library though.

expose aio to applications

The AIO paradigm for async IO is super useful and powerful -- much much better than other things we might come up with. We should expose this directly to user programs. In fact, we think this may be superior to the notification hacks we have.

REQ round-robin load-balancing

We need to implement round-robin load balancing for REQ. (Note that mangos has this bug too.) Right now we are just letting pipes race to get the pipe, and relying on the scheduler to provide fair access. Under load this works out, but during lighter conditions it can lead to less optimal scheduling. Instead, we should aim to distribute the work evenly.

pipeline leaks a pipe

After some level of testing, it would appear that we have a situation where valgrind reports leaks in the pipeline test. The leak is apparently a dialing pipe, and occurs when we close the socket immediately after starting a dial.

Performance needs work

We greatly improved performance recently, but it still needs a lot more work. We are several multiples slower than stock nanomsg and mangos. Lock contention is suspected.

Double free found in stress testing

Stress testing the ipc test program in a tight loop, we found this:

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./ipc'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f764ee08428 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
54	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x7f764a2f1700 (LWP 18825))]
(gdb) bt
#0  0x00007f764ee08428 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007f764ee0a02a in __GI_abort () at abort.c:89
#2  0x00007f764ee4a7ea in __libc_message (do_abort=do_abort@entry=2, 
    fmt=fmt@entry=0x7f764ef63e98 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f764ee5337a in malloc_printerr (ar_ptr=<optimized out>, 
    ptr=<optimized out>, 
    str=0x7f764ef63fa8 "double free or corruption (out)", action=3)
    at malloc.c:5006
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0)
    at malloc.c:3867
#5  0x00007f764ee5753c in __GI___libc_free (mem=<optimized out>)
    at malloc.c:2968
#6  0x0000000000411853 in nni_free (ptr=0x7f763c0008c0, size=176)
    at /home/parallels/Projects/nng/src/platform/posix/posix_alloc.c:27
#7  0x000000000041aecd in nni_posix_pipedesc_fini (pd=0x7f763c0008c0)
    at /home/parallels/Projects/nng/src/platform/posix/posix_pipedesc.c:334
#8  0x0000000000419e74 in nni_plat_ipc_pipe_fini (p=0x7f763c0008c0)
    at /home/parallels/Projects/nng/src/platform/posix/posix_ipc.c:159
#9  0x00000000004136d4 in nni_ipc_pipe_fini (arg=0x7f76340008c0)
    at /home/parallels/Projects/nng/src/transport/ipc/ipc.c:93
#10 0x000000000040db71 in nni_pipe_destroy (p=0x7f7634000da0)
    at /home/parallels/Projects/nng/src/core/pipe.c:60
#11 0x000000000040dd48 in nni_pipe_reap (p=0x7f7634000da0)
    at /home/parallels/Projects/nng/src/core/pipe.c:136
#12 0x00000000004106ff in nni_taskq_thread (self=0xa46c30)
    at /home/parallels/Projects/nng/src/core/taskq.c:44
#13 0x0000000000410f52 in nni_thr_wrap (arg=0xa46c38)
    at /home/parallels/Projects/nng/src/core/thread.c:88
#14 0x0000000000412265 in nni_plat_thr_main (arg=0xa46c38)
    at /home/parallels/Projects/nng/src/platform/posix/posix_thread.c:185
#15 0x00007f764f1a46ba in start_thread (arg=0x7f764a2f1700)
    at pthread_create.c:333
#16 0x00007f764eeda3dd in clone ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

autoscale based on CPUs available

We need a platform-specific way to inquire as to how many CPUs are available. This should be used to automatically tune the number of threads used for the system wide taskq; it may be used to drive other decisions later.

Dynamic option numbering desired.

As we make transports and protocols pluggable, its likely that the framework will not know the option numbers apriori, and unless we want to get into managing the identifiers for option numbers, we should contemplate a mechanism where by option ids are "registered" dynamically, allowing applications to select options using a string. (The only other option is to create and manage a registry, which is a PITA and not scalable.)

I am proposing an API like this:

// gets the same value if option string is already known.  can return NNG_ENOMEM
// No unregister; but nng_fini() cleans them all up, hence protocols and transports
// need watch these.  Knowing the scope allows us to avoid passing transport options
// to protocols, and vice versa.  (Segregate by ID.)  (XXX: maybe we should register
// other information to help with discovery?)
enum { NNI_OPTION_SCOPE_PROTO, NNI_OPTION_SCOPE_TRANSPORT };
int nni_option_register(int *valuep, int scope, const char *name);

// Public API (nng.h)
int nng_option_lookup(int *valuep, const char *name);

Providers and transports will be expected to use names that are specific to them to avoid
collisions by scoping the option names with a "/". E.g. a TCP option could be "TCP/NoDelay".
Names without a "/" are assumed to be common, socked scoped.

Using a two step lookup will allow the hot code paths to just use integers like they always have done.

Websocket transport

We need a websocket transport.

The websocket client support is straightforward, and providing equivalent server functionality to nanomsg would be easy. It might be worth looking at (thinking about) richer integration into extant web frameworks. That said, its unclear how that would work with C.

Eliminate the separate timer

The timer logic we have in src/core/timer.c could probably go away now. The main timeouts we have are using aios and their builtin timers, and it seems that the timer.c code is now duplicate; it also forces yet another thread to be created.

Make protocols "pluggable", or at least optional

We should contemplate ways to remove the hardwired list of protocols. Probably some of these need to be compile time builtin by default, but arguably even then it can be controlled via conditional compilation.

It would also be nice to make it possible for 3rd parties to extend the protocols by giving them a wa to register new protocols with the framework. Probably the API needs to be versioned, because the internal guts of the communication between the core and the protocols is not very "clean", and it might be hard to separate them fully. (That said, some of the work there is already done.)

Documentation for the API

Formal API documentation is desired.

We should provide this in asciidoc form, just like nanomsg, and structure as man pages.

Endpoint close should be synchronous

We don't need to create a reaper thread.

We always have user context -- either via socket_close, or endpoint_close, or indirectly via nng_fini().

(Pipes still have async cleanups and need the reaper thing.)

We do need to use reference counting though, so that we can create an API for accessing endpoints. This will be handled much like the socket API.

Introduce event framework

We need eventing (and particularly readable/writeable events) to support integration in event loops, and in order to implement the compatibility layer for legacy nanomsg.

tcp sometimes fails to get a port

We see occasional errors from the TCP test at travis where it seems to fail to obtain a port, and hence listen() fails.

Probably we need to avoid hitting the same port over and over again -- my theory is that we are hitting port reuse and the mandatory TCP TIME_FIN delay.

consider abandoning macOS on travis

given that macOS is the slowest by far of the platforms for the CI, and given that we actually develop and test natively on macOS, it may be worth considering eliminating the use of macOS at Travis, at least for non-tagged builds. (Tagged releases should probably still be built and tested on macOS.)

Sure would be nice if we had a nice light weight container solution for macOS....

Consider using synchronous completions sometimes

Performance wise, we could eliminate a number of context switches if we used synchronous completions when we are already in a context that is safe to do so. For example, any of the callbacks executed from pollers or the IO completion threads can reasonably safely assume that that no locks are held, and therefore could execute completions without going through a taskq.

Probably the best way to do this is to create a nni_aio_finish_synch() routine that does the completion logic right in the context of the caller. Then call sites inside individual providers could be modified as needed. Note that some modes of this need to be called asynch -- such as any context where we are on a user's call stack.

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.