Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipc command & native control interface #54

Merged
merged 2 commits into from Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitignore
@@ -0,0 +1,20 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
*.a
*.jnilib
*.o
*.class

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

#misc
p2pclient/java/libp2pd.h
p2pclient/java/p2pd.h
30 changes: 25 additions & 5 deletions Makefile
@@ -1,10 +1,30 @@
bin: deps
go install ./...
SHELL := /bin/sh

gx:
go get github.com/whyrusleeping/gx
go get github.com/whyrusleeping/gx-go
include config.mk

.PHONY : all java-daemon go-daemon daemon-shared-object deps gx clean
.DEFAULT_GOAL : go-daemon

all: deps go-daemon java-daemon daemon-shared-object

java-daemon:
cd $(BDIR) && make $@

daemon-shared-object:
cd $(BDIR) && make $@

go-daemon:
cd $(DDIR) && go install ./...

deps: gx
gx --verbose install --global
gx-go rewrite

gx:
go get github.com/whyrusleeping/gx
go get github.com/whyrusleeping/gx-go

clean:
gx-go uw
cd $(BDIR) && make $@

42 changes: 42 additions & 0 deletions bindings/Makefile
@@ -0,0 +1,42 @@
SHELL := /bin/sh

include ../config.mk

CC = gcc
CFLAGS = -O2 -fPIC
LFLAGS = $(OS_LFLAGS) -shared

JAVA_HOME = $(shell java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home' | sed 's/\s*java.home = //' | sed 's/\/jre//')
JAVA_INCLUDES = -I$(JAVA_HOME)/include/$(OS) -I$(JAVA_HOME)/include
CLASS_PATH = .
vpath %.class $(CLASS_PATH)

DNAME = p2pd

.PHONY : java-daemon daemon-shared-object clean

java-daemon: daemon-shared-object $(DNAME).class

daemon-shared-object: lib$(DNAME).$(EXT)

lib%.$(EXT): java-%.o go-%.a
$(CC) $(LFLAGS) -o $@ $^

java-%.o: go-%.a
$(CC) $(CFLAGS) -c java/java-$*.c $(JAVA_INCLUDES) -o $@

go-p2p.a:
go build -o $@ -buildmode=c-archive main.go

go-%.a:
go build -o $@ -buildmode=c-archive ../$*/main.go

%.class:
cd java/examples && javac $*.java && mv $@ ../../$@

clean:
rm -f *.o \
&& rm -f *.a \
&& rm -f *.$(EXT) \
&& rm -f *.class \
&& rm -f *.h
22 changes: 22 additions & 0 deletions bindings/java/examples/p2pd.java
@@ -0,0 +1,22 @@
public class p2pd {
private static final String NAME = "p2pd";
public static native void startDaemon(String arg1);
public static native void stopDaemon();
static {
try {

System.loadLibrary ( NAME ) ;

} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
System.exit(1);
}
}
public static void main(String[] args) {
String parsedArgs = NAME;
if( args.length > 0 ){
parsedArgs += "|" + String.join("|", args);
}
startDaemon(parsedArgs);
}
}
19 changes: 19 additions & 0 deletions bindings/java/java-p2pd.c
@@ -0,0 +1,19 @@
#include "java-p2pd.h"
#include "../go-p2pd.h"

JNIEXPORT void JNICALL Java_p2pd_startDaemon (JNIEnv *jenv, jclass jcls, jstring jarg1){
char *arg1 = (char *) 0 ;
(void)jenv;
(void)jcls;
arg1 = 0;
if (jarg1) {
arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0);
if (!arg1) return ;
}
startDaemon(arg1);
if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1);
}

JNIEXPORT void JNICALL Java_p2pd_stopDaemon (JNIEnv *jenv, jclass jcls){
stopDaemon();
}
16 changes: 16 additions & 0 deletions bindings/java/java-p2pd.h
@@ -0,0 +1,16 @@
#include <jni.h>

#ifndef _Included_p2pd
#define _Included_p2pd
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_p2pd_startDaemon (JNIEnv *, jclass, jstring);

JNIEXPORT void JNICALL Java_p2pd_stopDaemon (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif
12 changes: 12 additions & 0 deletions config.mk
@@ -0,0 +1,12 @@
OS = $(shell uname -s | tr '[:upper:]' '[:lower:]')

ifeq ($(OS), linux)
EXT = so
OS_LFLAGS =
else ifeq ($(OS), darwin)
EXT = dylib
OS_LFLAGS = -mmacosx-version-min=$(shell defaults read loginwindow SystemVersionStampAsString) -framework CoreFoundation -framework Security
endif

DDIR = p2pd
BDIR = bindings
12 changes: 12 additions & 0 deletions daemon.go
Expand Up @@ -4,7 +4,10 @@ import (
"context"
"fmt"
"net"
"os"
"os/signal"
"sync"
"syscall"

logging "github.com/ipfs/go-log"
libp2p "github.com/libp2p/go-libp2p"
Expand Down Expand Up @@ -54,6 +57,15 @@ func NewDaemon(ctx context.Context, path string, opts ...libp2p.Option) (*Daemon

go d.listen()

sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
go func(ln net.Listener, c chan os.Signal) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one for an orderly shutdown.

sig := <-c
log.Debugf("Caught signal %s: shutting down.\n", sig)
ln.Close()
os.Exit(0)
}(d.listener, sigc)

return d, nil
}

Expand Down
176 changes: 176 additions & 0 deletions p2pd.go
@@ -0,0 +1,176 @@
package p2pd

import (
"context"
"flag"
"fmt"
"os"
"strings"
"time"

libp2p "github.com/libp2p/go-libp2p"
connmgr "github.com/libp2p/go-libp2p-connmgr"
ps "github.com/libp2p/go-libp2p-pubsub"
quic "github.com/libp2p/go-libp2p-quic-transport"
)

// DaemonConfig defines the configuration options
type DaemonConfig struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually I'd like us to bring in some grouping/organisation to the daemon config, but definitely not a showstopper here. See related: #35.

sock *string
quiet *bool
id *string
bootstrap *bool
bootstrapPeers *string
dht *bool
dhtClient *bool
connMgr *bool
connMgrLo *int
connMgrHi *int
connMgrGrace *int
QUIC *bool
natPortMap *bool
pubsub *bool
pubsubRouter *string
pubsubSign *bool
pubsubSignStrict *bool
gossipsubHeartbeatInterval *int
gossipsubHeartbeatInitialDelay *int
args []string
}

func Initialize() DaemonConfig {
config := DaemonConfig{
sock: flag.String("sock", "/tmp/p2pd.sock", "daemon control socket path"),
quiet: flag.Bool("q", false, "be quiet"),
id: flag.String("id", "", "peer identity; private key file"),
bootstrap: flag.Bool("b", false, "connects to bootstrap peers and bootstraps the dht if enabled"),
bootstrapPeers: flag.String("bootstrapPeers", "", "comma separated list of bootstrap peers; defaults to the IPFS DHT peers"),
dht: flag.Bool("dht", true, "Enables the DHT in full node mode"),
dhtClient: flag.Bool("dhtClient", true, "Enables the DHT in client mode"),
connMgr: flag.Bool("connManager", false, "Enables the Connection Manager"),
connMgrLo: flag.Int("connLo", 256, "Connection Manager Low Water mark"),
connMgrHi: flag.Int("connHi", 512, "Connection Manager High Water mark"),
connMgrGrace: flag.Int("connGrace", 120, "Connection Manager grace period (in seconds)"),
QUIC: flag.Bool("quic", false, "Enables the QUIC transport"),
natPortMap: flag.Bool("natPortMap", false, "Enables NAT port mapping"),
pubsub: flag.Bool("pubsub", false, "Enables pubsub"),
pubsubRouter: flag.String("pubsubRouter", "gossipsub", "Specifies the pubsub router implementation"),
pubsubSign: flag.Bool("pubsubSign", true, "Enables pubsub message signing"),
pubsubSignStrict: flag.Bool("pubsubSignStrict", false, "Enables pubsub strict signature verification"),
gossipsubHeartbeatInterval: flag.Int("gossipsubHeartbeatInterval", 0, "Specifies the gossipsub heartbeat interval"),
gossipsubHeartbeatInitialDelay: flag.Int("gossipsubHeartbeatInitialDelay", 0, "Specifies the gossipsub initial heartbeat delay"),
}
flag.Parse()
config.args = flag.Args()
// delete control socket if it already exists
if _, err := os.Stat(*config.sock); !os.IsNotExist(err) {
err = os.Remove(*config.sock)
if err != nil {
log.Fatal(err)
}
}
return config
}

func Start(config DaemonConfig) {
var opts []libp2p.Option

if *config.id != "" {
key, err := ReadIdentity(*config.id)
if err != nil {
log.Fatal(err)
}

opts = append(opts, libp2p.Identity(key))
}

if *config.connMgr {
cm := connmgr.NewConnManager(*config.connMgrLo, *config.connMgrHi, time.Duration(*config.connMgrGrace))
opts = append(opts, libp2p.ConnectionManager(cm))
}

if *config.QUIC {
opts = append(opts,
libp2p.DefaultTransports,
libp2p.Transport(quic.NewTransport),
libp2p.ListenAddrStrings(
"/ip4/0.0.0.0/tcp/0",
"/ip4/0.0.0.0/udp/0/quic",
"/ip6/::1/tcp/0",
"/ip6/::1/udp/0/quic",
))
}

if *config.natPortMap {
opts = append(opts, libp2p.NATPortMap())
}

d, err := NewDaemon(context.Background(), *config.sock, opts...)
if err != nil {
log.Fatal(err)
}

if *config.pubsub {
if *config.gossipsubHeartbeatInterval > 0 {
ps.GossipSubHeartbeatInterval = time.Duration(*config.gossipsubHeartbeatInterval)
}

if *config.gossipsubHeartbeatInitialDelay > 0 {
ps.GossipSubHeartbeatInitialDelay = time.Duration(*config.gossipsubHeartbeatInitialDelay)
}

err = d.EnablePubsub(*config.pubsubRouter, *config.pubsubSign, *config.pubsubSignStrict)
if err != nil {
log.Fatal(err)
}
}

if *config.dht || *config.dhtClient {
err = d.EnableDHT(*config.dhtClient)
if err != nil {
log.Fatal(err)
}
}

if *config.bootstrapPeers != "" {
BootstrapPeers = strings.Split(*config.bootstrapPeers, ",")
}

if *config.bootstrap {
err = d.Bootstrap()
if err != nil {
log.Fatal(err)
}
}

if !*config.quiet {
fmt.Printf("Control socket: %s\n", *config.sock)
fmt.Printf("Peer ID: %s\n", d.ID().Pretty())
fmt.Printf("Peer Addrs:\n")
for _, addr := range d.Addrs() {
fmt.Printf("%s\n", addr.String())
}
if *config.bootstrap && *config.bootstrapPeers != "" {
fmt.Printf("Bootstrap peers:\n")
for _, p := range BootstrapPeers {
fmt.Printf("%s\n", p)
}
}
}

select {}
}

func Stop() {
p, _ := os.FindProcess(os.Getpid())
p.Signal(os.Interrupt)
}

func ProcessArgs(args *string) DaemonConfig {
//replace default config options with configs passed from external source
argsArray := strings.Split(*args, "|")
os.Args = argsArray
//call initialize() to get config
config := Initialize()
return config
}