├── jitpack.yml ├── libp2p ├── gradle.properties └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── libp2p │ │ │ ├── discovery │ │ │ └── mdns │ │ │ │ ├── impl │ │ │ │ ├── package-info.java │ │ │ │ ├── tasks │ │ │ │ │ ├── package-info.java │ │ │ │ │ └── DNSTask.java │ │ │ │ ├── constants │ │ │ │ │ ├── package-info.java │ │ │ │ │ ├── DNSOptionCode.java │ │ │ │ │ └── DNSOperationCode.java │ │ │ │ └── util │ │ │ │ │ └── NamedThreadFactory.java │ │ │ │ ├── AnswerListener.java │ │ │ │ └── package-info.java │ │ │ └── protocol │ │ │ └── circuit │ │ │ └── HostConsumer.java │ ├── kotlin │ │ └── io │ │ │ └── libp2p │ │ │ ├── core │ │ │ ├── PeerInfo.kt │ │ │ ├── mux │ │ │ │ └── NegotiatedStreamMuxer.kt │ │ │ ├── Discoverer.kt │ │ │ ├── crypto │ │ │ │ └── Hash.kt │ │ │ ├── multistream │ │ │ │ ├── NegotiatedProtocol.kt │ │ │ │ ├── StrictProtocolBinding.kt │ │ │ │ ├── MultistreamProtocol.kt │ │ │ │ ├── ProtocolMatcher.kt │ │ │ │ └── Multistream.kt │ │ │ ├── ConnectionHandler.kt │ │ │ ├── AddressBook.kt │ │ │ ├── dsl │ │ │ │ └── BuilderJ.kt │ │ │ ├── StreamHandler.kt │ │ │ ├── Connection.kt │ │ │ ├── multiformats │ │ │ │ └── MultiaddrComponent.kt │ │ │ ├── security │ │ │ │ └── SecureChannel.kt │ │ │ ├── P2PChannel.kt │ │ │ ├── P2PChannelHandler.kt │ │ │ └── Stream.kt │ │ │ ├── etc │ │ │ ├── events │ │ │ │ ├── MuxSession.kt │ │ │ │ ├── SecureChannel.kt │ │ │ │ └── ProtocolNegotiation.kt │ │ │ ├── util │ │ │ │ ├── netty │ │ │ │ │ ├── mux │ │ │ │ │ │ ├── RemoteWriteClosed.kt │ │ │ │ │ │ └── MuxId.kt │ │ │ │ │ ├── StringSuffixCodec.kt │ │ │ │ │ ├── SplitEncoder.kt │ │ │ │ │ ├── InboundTrafficLimitHandler.kt │ │ │ │ │ ├── TotalTimeoutHandler.kt │ │ │ │ │ ├── NettyUtil.kt │ │ │ │ │ ├── CachingChannelPipeline.kt │ │ │ │ │ └── ByteBufQueue.kt │ │ │ │ └── MultiaddrUtils.kt │ │ │ ├── BroadcastConnectionHandler.kt │ │ │ ├── BroadcastChannelVisitor.kt │ │ │ ├── types │ │ │ │ ├── DurationExt.kt │ │ │ │ ├── BufferExt.kt │ │ │ │ ├── WBytes.kt │ │ │ │ └── OtherExt.kt │ │ │ └── Attributes.kt │ │ │ ├── pubsub │ │ │ ├── AllowlistTopicSubscriptionFilter.kt │ │ │ ├── Errors.kt │ │ │ ├── TopicSubscriptionFilter.kt │ │ │ ├── PubsubProtocol.kt │ │ │ ├── PubsubCrypto.kt │ │ │ └── MaxCountTopicSubscriptionFilter.kt │ │ │ ├── security │ │ │ ├── secio │ │ │ │ └── SecioError.kt │ │ │ ├── noise │ │ │ │ └── NoiseSecureChannelSession.kt │ │ │ └── SecureChannelError.kt │ │ │ ├── protocol │ │ │ ├── ProtocolMessageHandler.kt │ │ │ ├── ProtobufProtocolHandler.kt │ │ │ └── ProtocolHandler.kt │ │ │ ├── transport │ │ │ ├── implementation │ │ │ │ ├── NettyTransport.kt │ │ │ │ ├── StreamOverNetty.kt │ │ │ │ ├── ConnectionOverNetty.kt │ │ │ │ └── P2PChannelOverNetty.kt │ │ │ ├── quic │ │ │ │ ├── QuicStream.kt │ │ │ │ └── QuicStreamReadCloseEventConverter.kt │ │ │ ├── ws │ │ │ │ ├── WebFrameCodec.kt │ │ │ │ ├── WebSocketServerHandshakeListener.kt │ │ │ │ ├── WebSocketClientInitializer.kt │ │ │ │ ├── WebSocketServerInitializer.kt │ │ │ │ ├── WebSocketClientHandshake.kt │ │ │ │ └── WsTransport.kt │ │ │ └── tcp │ │ │ │ └── TcpTransport.kt │ │ │ ├── mux │ │ │ ├── yamux │ │ │ │ ├── YamuxStreamIdGenerator.kt │ │ │ │ ├── YamuxType.kt │ │ │ │ ├── YamuxId.kt │ │ │ │ ├── YamuxFrame.kt │ │ │ │ ├── YamuxFlag.kt │ │ │ │ └── YamuxStreamMuxer.kt │ │ │ ├── mplex │ │ │ │ ├── MplexId.kt │ │ │ │ └── MplexStreamMuxer.kt │ │ │ └── MuxerException.kt │ │ │ ├── host │ │ │ └── MemoryAddressBook.kt │ │ │ └── multistream │ │ │ ├── MultistreamProtocolDebug.kt │ │ │ └── MultistreamImpl.kt │ └── proto │ │ ├── voucher.proto │ │ ├── plaintext.proto │ │ ├── crypto.proto │ │ ├── spipe.proto │ │ ├── autonat.proto │ │ ├── identify.proto │ │ ├── envelope.proto │ │ ├── relay.proto │ │ └── circuit.proto │ ├── testFixtures │ ├── java │ │ └── io │ │ │ └── libp2p │ │ │ └── tools │ │ │ └── p2pd │ │ │ ├── libp2pj │ │ │ ├── util │ │ │ │ ├── Cid.java │ │ │ │ └── Util.java │ │ │ ├── exceptions │ │ │ │ ├── UnsupportedTransportException.java │ │ │ │ └── MalformedMultiaddressException.java │ │ │ ├── StreamHandler.java │ │ │ ├── Stream.java │ │ │ ├── Protocol.java │ │ │ ├── Connector.java │ │ │ ├── Peer.java │ │ │ ├── PeerInfo.java │ │ │ ├── DHT.java │ │ │ ├── Transport.java │ │ │ └── Host.java │ │ │ ├── P2PDError.java │ │ │ ├── DaemonLauncher.java │ │ │ ├── StreamHandlerWrapper.java │ │ │ ├── AsyncDaemonExecutor.java │ │ │ └── NettyStream.java │ └── kotlin │ │ └── io │ │ └── libp2p │ │ ├── tools │ │ ├── ByteBufExt.kt │ │ ├── P2pdRunner.kt │ │ ├── CountingPingProtocol.kt │ │ ├── DnsAvailability.kt │ │ ├── TestLogAppender.kt │ │ ├── DoNothingProtocol.kt │ │ └── protobuf │ │ │ └── ProtobufUtils.kt │ │ └── transport │ │ └── NullConnectionUpgrader.kt │ └── test │ ├── kotlin │ └── io │ │ └── libp2p │ │ ├── pubsub │ │ ├── flood │ │ │ └── FloodPubsubRouterTest.kt │ │ ├── AllowlistTopicSubscriptionFilterTest.kt │ │ └── gossip │ │ │ └── GossipTwoHostTest.kt │ │ ├── security │ │ ├── secio │ │ │ └── SecIoSecureChannelTest.kt │ │ ├── plaintext │ │ │ └── PlaintextInsecureChannelTest.kt │ │ ├── noise │ │ │ └── NoiseSecureChannelTest.kt │ │ └── tls │ │ │ └── TlsSecureChannelTest.kt │ │ ├── etc │ │ ├── types │ │ │ ├── BooleanExtTest.kt │ │ │ ├── AsyncExtTest.kt │ │ │ ├── ByteArrayExtTest.kt │ │ │ └── ByteBufExtTest.kt │ │ ├── util │ │ │ └── netty │ │ │ │ └── StringSuffixCodecTest.kt │ │ └── encode │ │ │ └── Base58Test.kt │ │ ├── core │ │ └── multiformats │ │ │ └── ProtocolTest.kt │ │ └── crypto │ │ └── KeyTypesTest.kt │ └── resources │ └── log4j2-test.xml ├── .gitattributes ├── examples ├── android-chatter │ ├── gradle.properties │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ └── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── resources │ │ │ └── log4j2.xml │ │ │ └── AndroidManifest.xml │ └── proguard-rules.pro ├── chatter │ └── build.gradle ├── pinger │ ├── build.gradle │ └── src │ │ └── main │ │ ├── resources │ │ └── log4j2.xml │ │ └── java │ │ └── io │ │ └── libp2p │ │ └── example │ │ └── ping │ │ └── Pinger.java └── cli-chatter │ ├── build.gradle │ └── src │ └── main │ ├── resources │ └── log4j2.xml │ └── kotlin │ └── io │ └── libp2p │ └── example │ └── chat │ └── Chatter.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── funding.json ├── tools ├── schedulers │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── libp2p │ │ └── tools │ │ └── schedulers │ │ ├── RunnableEx.java │ │ ├── ControlledExecutorService.java │ │ ├── ControlledSchedulers.java │ │ ├── ControlledSchedulersImpl.java │ │ ├── LoggerMDCExecutor.java │ │ └── LatestExecutor.java └── simulator │ ├── src │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── libp2p │ │ │ └── simulate │ │ │ ├── MessageDelayer.kt │ │ │ ├── util │ │ │ ├── MessageSizeEstimator.kt │ │ │ ├── gradle │ │ │ │ └── DefaultGradleApplication.kt │ │ │ ├── MiscExt.kt │ │ │ ├── StringExt.kt │ │ │ └── CollectionExt.kt │ │ │ ├── topology │ │ │ ├── CustomTopologyGraph.kt │ │ │ ├── AbstractGraphTopology.kt │ │ │ ├── FixedTopology.kt │ │ │ ├── AllToAllTopology.kt │ │ │ ├── RandomNPeers.kt │ │ │ └── JGraphtTopologyGraph.kt │ │ │ ├── SimConnection.kt │ │ │ ├── Network.kt │ │ │ ├── SimChannel.kt │ │ │ ├── stats │ │ │ ├── WritableStats.kt │ │ │ ├── SimpleStatsImpl.kt │ │ │ ├── Stats.kt │ │ │ ├── StatsFactory.kt │ │ │ ├── collect │ │ │ │ └── gossip │ │ │ │ │ └── GossipMessageCollector.kt │ │ │ └── ApacheStatsImpl.kt │ │ │ ├── delay │ │ │ ├── SimpleBandwidthTracker.kt │ │ │ ├── TimeDelayer.kt │ │ │ ├── SequentialBandwidthTracker.kt │ │ │ ├── SequentialDelayer.kt │ │ │ ├── LoggingDelayer.kt │ │ │ └── ChannelMessageDelayer.kt │ │ │ ├── SimPeer.kt │ │ │ ├── SimStream.kt │ │ │ ├── stream │ │ │ ├── Libp2pConnectionImpl.kt │ │ │ └── Libp2pStreamImpl.kt │ │ │ ├── RandomValue.kt │ │ │ ├── Bandwidth.kt │ │ │ ├── Topology.kt │ │ │ ├── AbstractSimPeer.kt │ │ │ └── gossip │ │ │ └── router │ │ │ └── SimGossipRouterBuilder.kt │ └── test │ │ └── kotlin │ │ └── io │ │ └── libp2p │ │ └── simulate │ │ ├── util │ │ └── CollectionExtTest.kt │ │ ├── gossip │ │ └── GossipSimPeerTest.kt │ │ └── topology │ │ └── TopologyTest.kt │ ├── build.gradle │ └── README.md ├── .github ├── workflows │ ├── stale.yml │ ├── generated-pr.yml │ ├── publish.yml │ └── build.yml └── ISSUE_TEMPLATE │ ├── config.yml │ ├── enhancement.yml │ └── feature_request.yml ├── interop-test-client ├── build.gradle.kts └── src │ └── test │ └── resources │ └── compose.yaml ├── Dockerfile ├── install-run-ipfs.sh ├── detekt └── config.yml ├── LICENSE-MIT └── settings.gradle /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk11 -------------------------------------------------------------------------------- /libp2p/gradle.properties: -------------------------------------------------------------------------------- 1 | mavenArtifactId=jvm-libp2p -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.bat text eol=crlf 3 | *.png binary 4 | -------------------------------------------------------------------------------- /examples/android-chatter/gradle.properties: -------------------------------------------------------------------------------- 1 | libp2p.gradle.custom = true 2 | -------------------------------------------------------------------------------- /examples/chatter/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | api project(':libp2p') 3 | } 4 | 5 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | 3 | org.gradle.jvmargs=-Xmx1G 4 | android.useAndroidX=true 5 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/package-info.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.discovery.mdns.impl; 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/tasks/package-info.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.discovery.mdns.impl.tasks; 2 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/constants/package-info.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.discovery.mdns.impl.constants; 2 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x0be3a0fa062180bdfbfdefa993b09acd9edcae93ba0d8d5829dd01c138268f40" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Libp2p-Chatter 3 | 4 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libp2p/jvm-libp2p/HEAD/examples/android-chatter/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/protocol/circuit/HostConsumer.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.protocol.circuit; 2 | 3 | import io.libp2p.core.*; 4 | 5 | public interface HostConsumer { 6 | 7 | void setHost(Host us); 8 | } 9 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/PeerInfo.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | 5 | data class PeerInfo( 6 | val peerId: PeerId, 7 | val addresses: List 8 | ) 9 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/voucher.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package io.libp2p.protocol.circuit.pb; 4 | 5 | message Voucher { 6 | required bytes relay = 1; 7 | required bytes peer = 2; 8 | required uint64 expiration = 3; 9 | } -------------------------------------------------------------------------------- /libp2p/src/main/proto/plaintext.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package plaintext.pb; 4 | 5 | import "crypto.proto"; 6 | 7 | message Exchange { 8 | optional bytes id = 1; 9 | optional crypto.pb.PublicKey pubkey = 2; 10 | } 11 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/util/Cid.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj.util; 2 | 3 | public class Cid { 4 | 5 | public byte[] toBytes() { 6 | throw new UnsupportedOperationException(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/mux/NegotiatedStreamMuxer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.mux 2 | 3 | import io.libp2p.core.multistream.NegotiatedProtocol 4 | 5 | typealias NegotiatedStreamMuxer = NegotiatedProtocol 6 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/events/MuxSession.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.events 2 | 3 | import io.libp2p.core.mux.StreamMuxer 4 | 5 | data class MuxSessionInitialized(val session: StreamMuxer.Session) 6 | 7 | data class MuxSessionFailed(val exception: Throwable) 8 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/mux/RemoteWriteClosed.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty.mux 2 | 3 | /** 4 | * This Netty user event is fired to the [Stream] channel when remote peer closes its write side of the Stream 5 | */ 6 | object RemoteWriteClosed 7 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/RunnableEx.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | /** The same as standard Runnable which can throw unchecked exception */ 4 | public interface RunnableEx { 5 | void run() throws Exception; 6 | } 7 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/P2PDError.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd; 2 | 3 | /** Created by Anton Nashatyrev on 14.12.2018. */ 4 | public class P2PDError extends RuntimeException { 5 | public P2PDError(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/pinger/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'application' 3 | } 4 | 5 | dependencies { 6 | implementation project(':libp2p') 7 | 8 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl") 9 | } 10 | 11 | application { 12 | mainClassName = 'io.libp2p.example.Pinger' 13 | } -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/events/SecureChannel.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.events 2 | 3 | import io.libp2p.core.security.SecureChannel 4 | 5 | data class SecureChannelInitialized(val session: SecureChannel.Session) 6 | 7 | data class SecureChannelFailed(val exception: Throwable) 8 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/pubsub/flood/FloodPubsubRouterTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub.flood 2 | 3 | import io.libp2p.pubsub.DeterministicFuzz 4 | import io.libp2p.pubsub.PubsubRouterTest 5 | 6 | class FloodPubsubRouterTest : PubsubRouterTest(DeterministicFuzz.createFloodFuzzRouterFactory()) 7 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/AllowlistTopicSubscriptionFilter.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | class AllowlistTopicSubscriptionFilter(private val allowedTopics: Set) : TopicSubscriptionFilter { 4 | override fun canSubscribe(topic: Topic): Boolean = allowedTopics.contains(topic) 5 | } 6 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/ByteBufExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import io.netty.buffer.ByteBuf 4 | 5 | fun ByteBuf.readAllBytesAndRelease(): ByteArray { 6 | val arr = ByteArray(readableBytes()) 7 | this.readBytes(arr) 8 | this.release() 9 | return arr 10 | } 11 | -------------------------------------------------------------------------------- /examples/cli-chatter/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'application' 3 | } 4 | 5 | dependencies { 6 | implementation project(':examples:chatter') 7 | 8 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl") 9 | } 10 | 11 | application { 12 | mainClassName = 'io.libp2p.example.chat.ChatterKt' 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close Stale Issues 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 15 | -------------------------------------------------------------------------------- /.github/workflows/generated-pr.yml: -------------------------------------------------------------------------------- 1 | name: Close Generated PRs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | stale: 14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1 15 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/AnswerListener.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.discovery.mdns; 2 | 3 | import io.libp2p.discovery.mdns.impl.DNSRecord; 4 | import java.util.EventListener; 5 | import java.util.List; 6 | 7 | public interface AnswerListener extends EventListener { 8 | void answersReceived(List answers); 9 | } 10 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 5 | networkTimeout=10000 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/security/secio/SecIoSecureChannelTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.secio 2 | 3 | import io.libp2p.security.CipherSecureChannelTest 4 | import org.junit.jupiter.api.Tag 5 | 6 | @Tag("secure-channel") 7 | class SecIoSecureChannelTest : CipherSecureChannelTest( 8 | ::SecIoSecureChannel, 9 | listOf(), 10 | "/secio/1.0.0" 11 | ) 12 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/exceptions/UnsupportedTransportException.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj.exceptions; 2 | 3 | /** Created by Anton Nashatyrev on 11.12.2018. */ 4 | public class UnsupportedTransportException extends RuntimeException { 5 | public UnsupportedTransportException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/Discoverer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import java.util.concurrent.CompletableFuture 4 | 5 | typealias PeerListener = (PeerInfo) -> Unit 6 | 7 | interface Discoverer { 8 | fun start(): CompletableFuture 9 | fun stop(): CompletableFuture 10 | val newPeerFoundListeners: MutableCollection 11 | } 12 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/exceptions/MalformedMultiaddressException.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj.exceptions; 2 | 3 | /** Created by Anton Nashatyrev on 11.12.2018. */ 4 | public class MalformedMultiaddressException extends RuntimeException { 5 | public MalformedMultiaddressException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/MessageDelayer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import java.util.concurrent.CompletableFuture 4 | 5 | fun interface MessageDelayer { 6 | fun delay(size: Long): CompletableFuture 7 | 8 | companion object { 9 | val NO_DELAYER = MessageDelayer { CompletableFuture.completedFuture(null) } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/util/MessageSizeEstimator.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.util 2 | 3 | import io.netty.buffer.ByteBuf 4 | 5 | typealias MsgSizeEstimator = (Any) -> Long 6 | 7 | val GeneralSizeEstimator: MsgSizeEstimator = { msg -> 8 | when (msg) { 9 | is ByteBuf -> msg.readableBytes().toLong() 10 | else -> 0 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/CustomTopologyGraph.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.TopologyGraph 4 | 5 | class CustomTopologyGraph( 6 | override val edges: Collection 7 | ) : TopologyGraph { 8 | 9 | override fun calcDiameter(): Int { 10 | TODO("Not yet implemented") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/security/plaintext/PlaintextInsecureChannelTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.plaintext 2 | 3 | import io.libp2p.security.SecureChannelTestBase 4 | import org.junit.jupiter.api.Tag 5 | 6 | @Tag("secure-channel") 7 | class PlaintextInsecureChannelTest : SecureChannelTestBase( 8 | ::PlaintextInsecureChannel, 9 | listOf(), 10 | "/plaintext/2.0.0" 11 | ) 12 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/events/ProtocolNegotiation.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.events 2 | 3 | /** 4 | * The user event emitted when protocol negotiation succeeds. 5 | */ 6 | data class ProtocolNegotiationSucceeded(val proto: String) 7 | 8 | /** 9 | * The user event emitted when protocol negotiation fails. 10 | */ 11 | data class ProtocolNegotiationFailed(val attempted: List) 12 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/crypto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package crypto.pb; 4 | 5 | enum KeyType { 6 | RSA = 0; 7 | Ed25519 = 1; 8 | Secp256k1 = 2; 9 | ECDSA = 3; 10 | Curve25519 = 4; 11 | } 12 | 13 | message PublicKey { 14 | required KeyType Type = 1; 15 | required bytes Data = 2; 16 | } 17 | 18 | message PrivateKey { 19 | required KeyType Type = 1; 20 | required bytes Data = 2; 21 | } 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/security/secio/SecioError.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.secio 2 | 3 | import io.libp2p.security.SecureHandshakeError 4 | 5 | class NoCommonAlgos : SecureHandshakeError() 6 | class InvalidSignature : SecureHandshakeError() 7 | class InvalidNegotiationState : SecureHandshakeError() 8 | class SelfConnecting : SecureHandshakeError() 9 | 10 | class MacMismatch : SecureHandshakeError() 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Technical Questions 4 | url: https://github.com/libp2p/jvm-libp2p/discussions/new?category=q-a 5 | about: Please ask technical questions in the jvm-libp2p Github Discussions forum. 6 | - name: Community-wide libp2p Discussion 7 | url: https://discuss.libp2p.io 8 | about: Discussions and questions about the libp2p community. 9 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/SimConnection.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import java.util.concurrent.CompletableFuture 4 | 5 | interface SimConnection { 6 | 7 | val dialer: SimPeer 8 | val listener: SimPeer 9 | 10 | val streams: List 11 | 12 | val closed: CompletableFuture 13 | 14 | var connectionLatency: MessageDelayer 15 | 16 | fun close() 17 | } 18 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/StreamHandler.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** Created by Anton Nashatyrev on 18.12.2018. */ 6 | public interface StreamHandler { 7 | 8 | void onCreate(Stream stream); 9 | 10 | void onRead(ByteBuffer data); 11 | 12 | void onClose(); 13 | 14 | void onError(Throwable error); 15 | } 16 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/protocol/ProtocolMessageHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.protocol 2 | 3 | import io.libp2p.core.Stream 4 | 5 | interface ProtocolMessageHandler { 6 | fun onActivated(stream: Stream) = Unit 7 | fun onMessage(stream: Stream, msg: TMessage) = Unit 8 | fun onClosed(stream: Stream) = Unit 9 | fun onReadClosed(stream: Stream) = Unit 10 | fun onException(cause: Throwable?) = Unit 11 | } 12 | -------------------------------------------------------------------------------- /interop-test-client/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.cli.jvm.compiler.findMainClass 2 | 3 | plugins { 4 | id("application") 5 | id("kotlin") 6 | } 7 | 8 | application { 9 | mainClass = "io.libp2p.interop.InteropTestAgentKt" 10 | } 11 | 12 | dependencies { 13 | implementation(project(":libp2p")) 14 | implementation("redis.clients:jedis:6.1.0") 15 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl") 16 | } 17 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Stream.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** Created by Anton Nashatyrev on 18.12.2018. */ 6 | public interface Stream { 7 | 8 | boolean isInitiator(); 9 | 10 | void write(ByteBuffer data); 11 | 12 | void flush(); 13 | 14 | void close(); 15 | 16 | TEndpoint getRemoteAddress(); 17 | 18 | TEndpoint getLocalAddress(); 19 | } 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse-temurin:11-jdk AS build 2 | COPY . /jvm-libp2p 3 | WORKDIR /jvm-libp2p 4 | RUN ./gradlew build -x test --no-daemon 5 | 6 | FROM eclipse-temurin:11-jdk 7 | WORKDIR /jvm-libp2p 8 | COPY --from=build /jvm-libp2p/interop-test-client/build/distributions/interop-test-client*.tar . 9 | RUN tar -xf interop-test-client*.tar && rm interop-test-client*.tar 10 | 11 | ENTRYPOINT ["/jvm-libp2p/interop-test-client-develop/bin/interop-test-client"] 12 | EXPOSE 4001 13 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Protocol.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | /** Created by Anton Nashatyrev on 18.12.2018. */ 4 | public class Protocol { 5 | private final String name; 6 | 7 | public Protocol(String name) { 8 | this.name = name; 9 | } 10 | 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return getName(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/crypto/Hash.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.crypto 2 | 3 | import org.bouncycastle.jcajce.provider.digest.SHA1 4 | import org.bouncycastle.jcajce.provider.digest.SHA256 5 | import org.bouncycastle.jcajce.provider.digest.SHA512 6 | 7 | fun sha1(data: ByteArray): ByteArray = SHA1.Digest().digest(data) 8 | fun sha256(data: ByteArray): ByteArray = SHA256.Digest().digest(data) 9 | fun sha512(data: ByteArray): ByteArray = SHA512.Digest().digest(data) 10 | -------------------------------------------------------------------------------- /install-run-ipfs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | wget https://dist.ipfs.io/kubo/v0.34.1/kubo_v0.34.1_linux-amd64.tar.gz -O /tmp/kubo_linux-amd64.tar.gz 3 | hash="$(sha256sum /tmp/kubo_linux-amd64.tar.gz)" 4 | expected=42045802fe60c64fb01350bc071190c534d600fe269759c06e27e22b2012fd3e 5 | if [[ "$hash" != "$expected" ]] 6 | then 7 | echo "incorrect ipfs hash!" 1>&2 8 | exit 64 9 | fi 10 | tar -xvf /tmp/kubo_linux-amd64.tar.gz 11 | export PATH=$PATH:$PWD/kubo/ 12 | ipfs init 13 | ipfs daemon --routing=dhtserver & 14 | -------------------------------------------------------------------------------- /libp2p/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/implementation/NettyTransport.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.implementation 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | import io.libp2p.core.transport.Transport 5 | import io.netty.channel.Channel 6 | 7 | /** 8 | * A `Transport` which relies on a Netty `Channel` 9 | */ 10 | interface NettyTransport : Transport { 11 | 12 | fun localAddress(nettyChannel: Channel): Multiaddr 13 | 14 | fun remoteAddress(nettyChannel: Channel): Multiaddr 15 | } 16 | -------------------------------------------------------------------------------- /examples/pinger/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/Network.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | interface Network { 4 | 5 | val peers: List 6 | 7 | val activeConnections: List 8 | 9 | val topologyGraph: TopologyGraph 10 | } 11 | 12 | class ImmutableNetworkImpl( 13 | override val activeConnections: List, 14 | override val topologyGraph: TopologyGraph 15 | ) : Network { 16 | override val peers = activeConnections.map { it.dialer }.distinct() 17 | } 18 | -------------------------------------------------------------------------------- /examples/cli-chatter/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/mux/MuxId.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty.mux 2 | 3 | import io.netty.channel.ChannelId 4 | 5 | abstract class MuxId( 6 | val parentId: ChannelId, 7 | val id: Long 8 | ) : ChannelId { 9 | 10 | override fun compareTo(other: ChannelId?) = asShortText().compareTo(other?.asShortText() ?: "") 11 | override fun toString() = asLongText() 12 | 13 | abstract override fun hashCode(): Int 14 | abstract override fun equals(other: Any?): Boolean 15 | } 16 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /detekt/config.yml: -------------------------------------------------------------------------------- 1 | complexity: 2 | active: false 3 | 4 | naming: 5 | active: false 6 | 7 | empty-blocks: 8 | active: false 9 | 10 | style: 11 | active: false 12 | 13 | potential-bugs: 14 | ExplicitGarbageCollectionCall: 15 | active: false 16 | 17 | performance: 18 | SpreadOperator: 19 | active: false 20 | 21 | exceptions: 22 | TooGenericExceptionCaught: 23 | active: false 24 | TooGenericExceptionThrown: 25 | active: false 26 | ThrowingExceptionsWithoutMessageOrCause: 27 | active: false 28 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/AbstractGraphTopology.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.* 4 | import org.jgrapht.Graph 5 | import java.util.* 6 | 7 | abstract class AbstractGraphTopology : Topology { 8 | 9 | override var random = Random() 10 | 11 | abstract fun buildGraph(vertexCount: Int): Graph 12 | 13 | override fun generateGraph(verticesCount: Int): TopologyGraph = 14 | JGraphtTopologyGraph(buildGraph(verticesCount)) 15 | } 16 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/security/noise/NoiseSecureChannelTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.noise 2 | 3 | import io.libp2p.security.CipherSecureChannelTest 4 | import org.junit.jupiter.api.Tag 5 | import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable 6 | 7 | @DisabledIfEnvironmentVariable(named = "TRAVIS", matches = "true") 8 | @Tag("secure-channel") 9 | class NoiseSecureChannelTest : CipherSecureChannelTest( 10 | ::NoiseXXSecureChannel, 11 | listOf(), 12 | NoiseXXSecureChannel.announce 13 | ) 14 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/BroadcastConnectionHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.ConnectionHandler 5 | import java.util.concurrent.CopyOnWriteArrayList 6 | 7 | class BroadcastConnectionHandler( 8 | private val handlers: MutableList = CopyOnWriteArrayList() 9 | ) : ConnectionHandler.Broadcast, MutableList by handlers { 10 | override fun handleConnection(conn: Connection) = handlers.forEach { it.handleConnection(conn) } 11 | } 12 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/util/gradle/DefaultGradleApplication.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.util.gradle 2 | 3 | fun main(args: Array) { 4 | System.err.println("This is the default gradle main class executing with args: ${args.contentToString()}") 5 | System.err.println("ERROR: No main class was specified.") 6 | System.err.println("Use the command syntax below:") 7 | System.err.println("gradle :tools:simulator:run -PmainClass= [--args=\"you args\"]") 8 | System.exit(-1) 9 | } 10 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/security/noise/NoiseSecureChannelSession.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.noise 2 | 3 | import com.southernstorm.noise.protocol.CipherState 4 | import io.libp2p.core.PeerId 5 | import io.libp2p.core.crypto.PubKey 6 | import io.libp2p.core.security.SecureChannel 7 | 8 | class NoiseSecureChannelSession( 9 | localId: PeerId, 10 | remoteId: PeerId, 11 | remotePubKey: PubKey, 12 | val aliceCipher: CipherState, 13 | val bobCipher: CipherState 14 | ) : SecureChannel.Session(localId, remoteId, remotePubKey, null) 15 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/SimChannel.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | interface SimChannel { 4 | 5 | val stream: SimStream 6 | val isStreamInitiator: Boolean 7 | 8 | val peer get() = 9 | when { 10 | isStreamInitiator -> stream.streamInitiatorPeer 11 | else -> stream.streamAcceptorPeer 12 | } 13 | 14 | val msgVisitors: MutableList 15 | } 16 | 17 | interface SimChannelMessageVisitor { 18 | fun onInbound(message: Any) 19 | fun onOutbound(message: Any) 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | on: 3 | push: 4 | branches: 5 | - "develop" 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-java@v3 12 | with: 13 | distribution: temurin 14 | java-version: 11 15 | 16 | - name: Setup Gradle 17 | uses: gradle/gradle-build-action@v2 18 | 19 | - name: Publish to Cloudsmith 20 | run: ./gradlew publish -PcloudsmithUser=${{ secrets.CLOUDSMITH_USER }} -PcloudsmithApiKey=${{ secrets.CLOUDSMITH_API_KEY }} -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multistream/NegotiatedProtocol.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multistream 2 | 3 | import io.libp2p.core.P2PChannel 4 | import java.util.concurrent.CompletableFuture 5 | 6 | /** 7 | * Represents [ProtocolBinding] with exact protocol version which was agreed on 8 | */ 9 | open class NegotiatedProtocol>( 10 | val binding: TBinding, 11 | val protocol: ProtocolId 12 | ) { 13 | open fun initChannel(ch: P2PChannel): CompletableFuture = 14 | binding.initChannel(ch, protocol) 15 | } 16 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxStreamIdGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import java.util.concurrent.atomic.AtomicLong 4 | 5 | class YamuxStreamIdGenerator(connectionInitiator: Boolean) { 6 | 7 | private val idCounter = AtomicLong(if (connectionInitiator) 1L else 2L) // 0 is reserved 8 | 9 | fun next() = idCounter.getAndAdd(2) 10 | 11 | companion object { 12 | fun isRemoteSynStreamIdValid(isRemoteConnectionInitiator: Boolean, id: Long) = 13 | id > 0 && (if (isRemoteConnectionInitiator) id % 2 == 1L else id % 2 == 0L) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/spipe.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package spipe.pb; 4 | 5 | message Propose { 6 | optional bytes rand = 1; 7 | optional bytes pubkey = 2; 8 | optional string exchanges = 3; 9 | optional string ciphers = 4; 10 | optional string hashes = 5; 11 | } 12 | 13 | message Exchange { 14 | optional bytes epubkey = 1; 15 | optional bytes signature = 2; 16 | } 17 | 18 | message NoiseHandshakePayload { 19 | optional bytes libp2p_key = 1; 20 | optional bytes noise_static_key_signature = 2; 21 | optional bytes libp2p_data = 3; 22 | optional bytes libp2p_data_signature = 4; 23 | } -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Connector.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import java.io.Closeable; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.function.Supplier; 6 | 7 | /** Created by Anton Nashatyrev on 18.12.2018. */ 8 | public interface Connector { 9 | 10 | CompletableFuture dial(TEndpoint address, StreamHandler handler); 11 | 12 | CompletableFuture listen( 13 | TEndpoint listenAddress, Supplier> handlerFactory); 14 | } 15 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/WritableStats.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats 2 | 3 | interface WritableStats : Stats { 4 | 5 | fun addValue(value: Double) 6 | fun addValue(value: Int) = addValue(value.toDouble()) 7 | fun addValue(value: Long) = addValue(value.toDouble()) 8 | operator fun plusAssign(value: Number) = addValue(value.toDouble()) 9 | 10 | fun addAllValues(values: Collection) = values.forEach { addValue(it.toDouble()) } 11 | operator fun plusAssign(values: Collection) = addAllValues(values) 12 | 13 | fun reset() 14 | } 15 | -------------------------------------------------------------------------------- /interop-test-client/src/test/resources/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | dialer: 3 | build: . 4 | depends_on: 5 | - redis 6 | environment: 7 | transport: tcp 8 | is_dialer: true 9 | ip: 0.0.0.0 10 | muxer: mplex 11 | security: tls 12 | listener: 13 | init: true 14 | build: . 15 | depends_on: 16 | - redis 17 | environment: 18 | transport: tcp 19 | is_dialer: false 20 | ip: 0.0.0.0 21 | muxer: mplex 22 | security: tls 23 | redis: 24 | image: redis:7-alpine 25 | environment: 26 | REDIS_ARGS: --loglevel warning -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/BroadcastChannelVisitor.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc 2 | 3 | import io.libp2p.core.ChannelVisitor 4 | import io.libp2p.core.P2PChannel 5 | import java.util.concurrent.CopyOnWriteArrayList 6 | 7 | class BroadcastChannelVisitor( 8 | private val handlers: MutableList> = CopyOnWriteArrayList() 9 | ) : ChannelVisitor.Broadcast, MutableList> by handlers { 10 | 11 | override fun visit(channel: TChannel) { 12 | handlers.forEach { 13 | it.visit(channel) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/types/BooleanExtTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import org.junit.jupiter.api.Assertions.assertFalse 4 | import org.junit.jupiter.api.Test 5 | import java.util.concurrent.atomic.AtomicBoolean 6 | 7 | class BooleanExtTest { 8 | @Test 9 | fun testWhenTrue() { 10 | val shouldStayTrue = AtomicBoolean(true) 11 | val shouldBeChanged = AtomicBoolean(true) 12 | false.whenTrue { shouldStayTrue.set(false) } 13 | true.whenTrue { shouldBeChanged.set(false) } 14 | assert(shouldStayTrue.get()) 15 | assertFalse(shouldBeChanged.get()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/types/DurationExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import java.time.Duration 4 | 5 | val Number.millis: Duration 6 | get() = Duration.ofMillis(this.toLong()) 7 | 8 | val Number.seconds: Duration 9 | get() = Duration.ofSeconds(this.toLong()) 10 | 11 | val Number.minutes: Duration 12 | get() = Duration.ofMinutes(this.toLong()) 13 | 14 | val Number.hours: Duration 15 | get() = Duration.ofHours(this.toLong()) 16 | 17 | val Number.days: Duration 18 | get() = Duration.ofDays(this.toLong()) 19 | 20 | operator fun Duration.times(i: Int): Duration = Duration.ofMillis(toMillis() * i) 21 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/SimpleBandwidthTracker.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.Bandwidth 4 | import io.libp2p.simulate.BandwidthDelayer 5 | import io.libp2p.tools.delayedFuture 6 | import java.util.concurrent.CompletableFuture 7 | import java.util.concurrent.ScheduledExecutorService 8 | 9 | class SimpleBandwidthTracker( 10 | override val totalBandwidth: Bandwidth, 11 | val executor: ScheduledExecutorService 12 | ) : BandwidthDelayer { 13 | 14 | override fun delay(size: Long): CompletableFuture = 15 | executor.delayedFuture(totalBandwidth.getTransmitTime(size)) 16 | } 17 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/FixedTopology.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.Topology 4 | import io.libp2p.simulate.TopologyGraph 5 | import java.util.* 6 | 7 | class FixedTopology( 8 | val graph: TopologyGraph 9 | ) : Topology { 10 | 11 | override fun generateGraph(verticesCount: Int): TopologyGraph { 12 | require(verticesCount == graph.vertices.size) 13 | return graph 14 | } 15 | 16 | override var random: Random 17 | get() = TODO("Not yet implemented") 18 | set(_) {} 19 | } 20 | 21 | fun TopologyGraph.asFixedTopology() = FixedTopology(this) 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxType.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import io.libp2p.mux.InvalidFrameMuxerException 4 | 5 | /** 6 | * Contains all the permissible values for types in the yamux protocol. 7 | */ 8 | enum class YamuxType(val intValue: Int) { 9 | DATA(0), 10 | WINDOW_UPDATE(1), 11 | PING(2), 12 | GO_AWAY(3); 13 | 14 | companion object { 15 | private val intToTypeCache = values().associateBy { it.intValue } 16 | 17 | fun fromInt(intValue: Int): YamuxType = 18 | intToTypeCache[intValue] ?: throw InvalidFrameMuxerException("Invalid Yamux type value: $intValue") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multistream/StrictProtocolBinding.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multistream 2 | 3 | import io.libp2p.core.P2PChannel 4 | import io.libp2p.core.P2PChannelHandler 5 | import java.util.concurrent.CompletableFuture 6 | 7 | abstract class StrictProtocolBinding( 8 | announce: ProtocolId, 9 | open val protocol: P2PChannelHandler 10 | ) : ProtocolBinding { 11 | 12 | override val protocolDescriptor = ProtocolDescriptor(announce) 13 | 14 | override fun initChannel(ch: P2PChannel, selectedProtocol: String): CompletableFuture { 15 | return protocol.initChannel(ch) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/ControlledExecutorService.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | import java.util.concurrent.ScheduledExecutorService; 4 | 5 | /** 6 | * The ScheduledExecutorService which functions based on the current system time 7 | * supplied by {@link TimeController#getTime()} instead of System.currentTimeMillis() 8 | */ 9 | public interface ControlledExecutorService extends ScheduledExecutorService { 10 | 11 | /** 12 | * Sets up the {@link TimeController} instance which manages ordered tasks execution and provides 13 | * current time 14 | */ 15 | void setTimeController(TimeController timeController); 16 | } 17 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/AllToAllTopology.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.* 4 | import java.util.* 5 | 6 | class AllToAllTopology : Topology { 7 | 8 | override var random: Random 9 | get() = TODO("Not yet implemented") 10 | set(_) {} 11 | 12 | override fun generateGraph(verticesCount: Int): TopologyGraph = 13 | (0 until verticesCount) 14 | .flatMap { src -> 15 | (src + 1 until verticesCount) 16 | .map { dest -> 17 | TopologyGraph.Edge(src, dest) 18 | } 19 | } 20 | .let { CustomTopologyGraph(it) } 21 | } 22 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/TimeDelayer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.MessageDelayer 4 | import io.libp2p.tools.schedule 5 | import java.util.concurrent.CompletableFuture 6 | import java.util.concurrent.ScheduledExecutorService 7 | import kotlin.time.Duration 8 | 9 | class TimeDelayer( 10 | val executor: ScheduledExecutorService, 11 | val delaySupplier: () -> Duration 12 | ) : MessageDelayer { 13 | 14 | override fun delay(size: Long): CompletableFuture { 15 | val ret = CompletableFuture() 16 | executor.schedule(delaySupplier()) { 17 | ret.complete(null) 18 | } 19 | return ret 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/Errors.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | import io.libp2p.core.Libp2pException 4 | 5 | /** 6 | * Generic Pubsub exception 7 | */ 8 | open class PubsubException(message: String) : Libp2pException(message) 9 | 10 | /** 11 | * Is thrown when a client sends duplicate message 12 | */ 13 | class MessageAlreadySeenException(message: String) : PubsubException(message) 14 | 15 | /** 16 | * Throw when message validation failed 17 | */ 18 | class InvalidMessageException(message: String) : PubsubException(message) 19 | 20 | /** 21 | * Thrown when no suitable peers found to broadcast outbound exception 22 | */ 23 | class NoPeersForOutboundMessageException(message: String) : PubsubException(message) 24 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Peer.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | /** Created by Anton Nashatyrev on 18.12.2018. */ 4 | public class Peer { 5 | private final byte[] id; 6 | 7 | public Peer(byte[] id) { 8 | this.id = id; 9 | } 10 | 11 | public byte[] getIdBytes() { 12 | return id; 13 | } 14 | 15 | // public String getIdBase58() { 16 | // return Base58.encode(getIdBytes()); 17 | // } 18 | // 19 | // public String getIdHexString() { 20 | // return Hex.encodeHexString(getIdBytes()); 21 | // } 22 | 23 | // @Override 24 | // public String toString() { 25 | // return "Peer{" + "id=" + getIdBase58() + "}"; 26 | // } 27 | } 28 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/SimPeer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import io.libp2p.core.PeerId 4 | import java.util.concurrent.CompletableFuture 5 | 6 | typealias SimPeerId = Int 7 | 8 | interface SimPeer { 9 | 10 | val simPeerId: SimPeerId 11 | val name: String get() = simPeerId.toString() 12 | val peerId: PeerId 13 | val connections: List 14 | 15 | var inboundBandwidth: BandwidthDelayer 16 | var outboundBandwidth: BandwidthDelayer 17 | 18 | fun start() = CompletableFuture.completedFuture(Unit) 19 | 20 | fun connect(other: SimPeer): CompletableFuture 21 | 22 | fun stop(): CompletableFuture = CompletableFuture.completedFuture(Unit) 23 | } 24 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/SimpleStatsImpl.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats 2 | 3 | class SimpleStatsImpl : WritableStats { 4 | private var countVar = 0L 5 | private var sumVar = 0.0 6 | 7 | override fun addValue(value: Double) { 8 | countVar++ 9 | sumVar += value 10 | } 11 | 12 | override fun reset() { 13 | countVar = 0L 14 | sumVar = 0.0 15 | } 16 | 17 | override fun getCount() = countVar 18 | override fun getSum() = sumVar 19 | 20 | override fun plus(other: Stats) = 21 | SimpleStatsImpl().also { 22 | it.countVar = getCount() + other.getCount() 23 | it.sumVar = getSum() + other.getSum() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/PeerInfo.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import io.libp2p.core.multiformats.Multiaddr; 4 | import java.util.List; 5 | 6 | /** Created by Anton Nashatyrev on 20.12.2018. */ 7 | public class PeerInfo { 8 | private final Peer id; 9 | private final List addresses; 10 | 11 | public PeerInfo(Peer id, List addresses) { 12 | this.id = id; 13 | this.addresses = addresses; 14 | } 15 | 16 | public Peer getId() { 17 | return id; 18 | } 19 | 20 | public List getAddresses() { 21 | return addresses; 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | return "PeerInfo{" + "id=" + id + ", adresses=" + addresses + '}'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/cli-chatter/src/main/kotlin/io/libp2p/example/chat/Chatter.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.example.chat 2 | 3 | fun main() { 4 | val node = ChatNode(::println) 5 | 6 | println() 7 | println("Libp2p Chatter!") 8 | println("===============") 9 | println() 10 | println("This node is ${node.peerId}, listening on ${node.address}") 11 | println() 12 | println("Enter 'bye' to quit, enter 'alias ' to set chat name") 13 | println() 14 | 15 | var message: String? 16 | do { 17 | print(">> ") 18 | message = readLine()?.trim() 19 | 20 | if (message == null || message.isEmpty()) { 21 | continue 22 | } 23 | 24 | node.send(message) 25 | } while ("bye" != message) 26 | 27 | node.stop() 28 | } 29 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/Attributes.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.P2PChannel 5 | import io.libp2p.core.PeerId 6 | import io.libp2p.core.Stream 7 | import io.netty.channel.Channel 8 | import io.netty.util.AttributeKey 9 | import java.util.concurrent.CompletableFuture 10 | 11 | val STREAM = AttributeKey.newInstance("LIBP2P_STREAM")!! 12 | val CONNECTION = AttributeKey.newInstance("LIBP2P_CONNECTION")!! 13 | val PROTOCOL = AttributeKey.newInstance>("LIBP2P_PROTOCOL")!! 14 | val REMOTE_PEER_ID = AttributeKey.newInstance("LIBP2P_REMOTE_PEER_ID")!! 15 | 16 | fun Channel.getP2PChannel(): P2PChannel = if (hasAttr(CONNECTION)) attr(CONNECTION).get() else attr(STREAM).get() 17 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | gradle: 5 | strategy: 6 | matrix: 7 | os: [ubuntu-latest, windows-latest] 8 | runs-on: ${{ matrix.os }} 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-java@v3 12 | with: 13 | distribution: temurin 14 | java-version: 11 15 | - name: Install and run ipfs 16 | run: ./install-run-ipfs.sh 17 | 18 | - name: Setup Gradle 19 | uses: gradle/gradle-build-action@v2 20 | 21 | - name: Setup Android SDK 22 | uses: android-actions/setup-android@v3 23 | with: 24 | cmdline-tools-version: 8512546 25 | 26 | - name: Execute Gradle build 27 | run: ./gradlew -s build dokkaJar -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/Stats.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats 2 | 3 | import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics 4 | import org.apache.commons.math3.stat.descriptive.StatisticalSummary 5 | 6 | interface Stats { 7 | 8 | fun getCount(): Long = getStatisticalSummary().n 9 | 10 | fun getSum(): Double = getStatisticalSummary().sum 11 | 12 | fun getStatisticalSummary(): StatisticalSummary = TODO() 13 | 14 | fun getDescriptiveStatistics(): DescriptiveStatistics = TODO() 15 | 16 | // One of the following should be overridden 17 | operator fun plus(other: Stats): Stats = this + listOf(other) 18 | operator fun plus(others: List): Stats = 19 | (listOf(this) + others).reduce { a, b -> a + b } 20 | } 21 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/quic/QuicStream.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.quic 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.etc.types.toVoidCompletableFuture 5 | import io.libp2p.transport.implementation.StreamOverNetty 6 | import io.netty.handler.codec.quic.QuicStreamChannel 7 | import java.util.concurrent.CompletableFuture 8 | 9 | class QuicStream( 10 | val quicStreamChannel: QuicStreamChannel, 11 | connection: Connection, 12 | initiator: Boolean 13 | ) : StreamOverNetty(quicStreamChannel, connection, initiator) { 14 | 15 | init { 16 | pushHandler(QuicStreamReadCloseEventConverter()) 17 | } 18 | 19 | override fun closeWrite(): CompletableFuture { 20 | return quicStreamChannel.shutdownOutput().toVoidCompletableFuture() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/StatsFactory.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats 2 | 3 | interface StatsFactory { 4 | 5 | fun createStats(name: String = ""): WritableStats 6 | 7 | fun createStats(data: Collection): Stats = 8 | createStats().also { 9 | it += data 10 | } 11 | 12 | companion object { 13 | val DUMMY = object : WritableStats { 14 | override fun addValue(value: Double) {} 15 | override fun reset() {} 16 | override fun plus(other: Stats) = TODO() 17 | override fun toString() = "" 18 | } 19 | 20 | val DEFAULT: StatsFactory = object : StatsFactory { 21 | override fun createStats(name: String) = DescriptiveStatsImpl() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/P2pdRunner.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import io.libp2p.tools.p2pd.DaemonLauncher 4 | import java.io.File 5 | 6 | /** 7 | * Tries to find and starts Libp2p Daemon 8 | */ 9 | class P2pdRunner(val execNames: List = listOf("p2pd", "p2pd.exe"), val execSearchPaths: List = listOf()) { 10 | val predefinedSearchPaths = listOf( 11 | File(System.getProperty("user.home"), "go/bin").absoluteFile.canonicalPath 12 | ) 13 | 14 | fun findP2pdExe(): String? = 15 | (predefinedSearchPaths + execSearchPaths) 16 | .flatMap { path -> execNames.map { File(path, it) } } 17 | .firstOrNull { it.canExecute() } 18 | ?.absoluteFile?.canonicalPath 19 | 20 | fun launcher() = findP2pdExe()?.let { DaemonLauncher(it) } 21 | } 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/StringSuffixCodec.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.channel.ChannelHandlerContext 4 | import io.netty.handler.codec.DecoderException 5 | import io.netty.handler.codec.MessageToMessageCodec 6 | 7 | /** 8 | * Adds/removes trailing character from messages 9 | */ 10 | class StringSuffixCodec(val trailingChar: Char) : MessageToMessageCodec() { 11 | 12 | override fun encode(ctx: ChannelHandlerContext?, msg: String, out: MutableList) { 13 | out += (msg + trailingChar) 14 | } 15 | 16 | override fun decode(ctx: ChannelHandlerContext?, msg: String, out: MutableList) { 17 | if (!msg.endsWith(trailingChar)) throw DecoderException("Missing message end character") 18 | out += msg.substring(0, msg.length - 1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/SplitEncoder.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.handler.codec.MessageToMessageEncoder 6 | import kotlin.math.min 7 | 8 | /** 9 | * Splits large outbound buffers onto smaller chunks of specified max size 10 | */ 11 | class SplitEncoder(val maxSize: Int) : MessageToMessageEncoder() { 12 | override fun encode(ctx: ChannelHandlerContext, msg: ByteBuf, out: MutableList) { 13 | var startIdx = msg.readerIndex() 14 | while (startIdx < msg.writerIndex()) { 15 | val endIndex = min(startIdx + maxSize, msg.writerIndex()) 16 | out += msg.retainedSlice(startIdx, endIndex - startIdx) 17 | startIdx += maxSize 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/quic/QuicStreamReadCloseEventConverter.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.quic 2 | 3 | import io.libp2p.etc.util.netty.mux.RemoteWriteClosed 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.channel.ChannelInboundHandlerAdapter 6 | import io.netty.channel.socket.ChannelInputShutdownReadComplete 7 | 8 | /** 9 | * Convert QUIC library specific event on remote stream close to Libp2p specific event 10 | */ 11 | class QuicStreamReadCloseEventConverter : ChannelInboundHandlerAdapter() { 12 | 13 | override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) { 14 | if (evt == ChannelInputShutdownReadComplete.INSTANCE) { 15 | ctx.fireUserEventTriggered(RemoteWriteClosed) 16 | } else { 17 | super.userEventTriggered(ctx, evt) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multistream/MultistreamProtocol.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multistream 2 | 3 | import io.libp2p.core.P2PChannelHandler 4 | import io.libp2p.multistream.MultistreamProtocolDebugV1 5 | 6 | val MultistreamProtocolV1: MultistreamProtocolDebug = MultistreamProtocolDebugV1() 7 | 8 | interface MultistreamProtocol { 9 | 10 | val version: String 11 | 12 | /** 13 | * Creates [Multistream] implementation with a list of protocol bindings 14 | */ 15 | fun createMultistream(bindings: List>): Multistream 16 | } 17 | 18 | interface MultistreamProtocolDebug : MultistreamProtocol { 19 | 20 | fun copyWithHandlers( 21 | preHandler: P2PChannelHandler<*>? = null, 22 | postHandler: P2PChannelHandler<*>? = null 23 | ): MultistreamProtocol 24 | } 25 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxId.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import io.libp2p.etc.util.netty.mux.MuxId 4 | import io.netty.channel.ChannelId 5 | 6 | class YamuxId( 7 | parentId: ChannelId, 8 | id: Long, 9 | ) : MuxId(parentId, id) { 10 | 11 | override fun asShortText() = "${parentId.asShortText()}/$id" 12 | override fun asLongText() = "${parentId.asLongText()}/$id" 13 | 14 | override fun equals(other: Any?): Boolean { 15 | if (this === other) return true 16 | if (javaClass != other?.javaClass) return false 17 | return (other as YamuxId).id == id 18 | } 19 | 20 | override fun hashCode(): Int = id.hashCode() 21 | 22 | companion object { 23 | val SESSION_STREAM_ID = 0L 24 | fun sessionId(parentId: ChannelId) = YamuxId(parentId, SESSION_STREAM_ID) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/android-chatter/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/TopicSubscriptionFilter.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | interface TopicSubscriptionFilter { 4 | 5 | fun canSubscribe(topic: Topic): Boolean 6 | 7 | fun filterIncomingSubscriptions( 8 | subscriptions: Collection, 9 | currentlySubscribedTopics: Collection 10 | ): Collection { 11 | return subscriptions.filter { canSubscribe(it.topic) } 12 | } 13 | 14 | class AllowAllTopicSubscriptionFilter : TopicSubscriptionFilter { 15 | override fun canSubscribe(topic: Topic): Boolean = true 16 | override fun filterIncomingSubscriptions( 17 | subscriptions: Collection, 18 | currentlySubscribedTopics: Collection 19 | ): Collection = subscriptions 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/security/SecureChannelError.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security 2 | 3 | open class SecureChannelError : Exception { 4 | constructor() : super() 5 | constructor(message: String, cause: Throwable) : super(message, cause) 6 | constructor(message: String) : super(message) 7 | } 8 | 9 | open class SecureHandshakeError : SecureChannelError { 10 | constructor() : super() 11 | constructor(message: String) : super(message) 12 | } 13 | 14 | class InvalidRemotePubKey : SecureHandshakeError() 15 | class InvalidInitialPacket : SecureHandshakeError() 16 | 17 | open class CantDecryptInboundException : SecureChannelError { 18 | constructor(message: String, cause: Throwable) : super(message, cause) 19 | constructor(message: String) : super(message) 20 | } 21 | 22 | class InvalidMacException : CantDecryptInboundException("Invalid MAC") 23 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WebFrameCodec.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.handler.codec.MessageToMessageCodec 6 | import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame 7 | import io.netty.handler.codec.http.websocketx.WebSocketFrame 8 | 9 | class WebFrameCodec : MessageToMessageCodec() { 10 | override fun encode(ctx: ChannelHandlerContext, msg: ByteBuf, out: MutableList) { 11 | msg.retain() 12 | out.add(BinaryWebSocketFrame(msg)) 13 | } // encode 14 | 15 | override fun decode(ctx: ChannelHandlerContext, msg: WebSocketFrame, out: MutableList) { 16 | msg as BinaryWebSocketFrame 17 | out.add(msg.retain().content()) 18 | } // decode 19 | } // WebFrameCodoc 20 | -------------------------------------------------------------------------------- /tools/simulator/src/test/kotlin/io/libp2p/simulate/util/CollectionExtTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.util 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class CollectionExtTest { 7 | @Test 8 | fun transposeTest() { 9 | val t1 = listOf( 10 | mapOf( 11 | "a" to 11, 12 | "b" to 12, 13 | "c" to 13 14 | ), 15 | mapOf( 16 | "a" to 21, 17 | "b" to 22, 18 | "c" to 23 19 | ) 20 | ) 21 | 22 | val t2 = t1.transpose() 23 | 24 | assertEquals(2, t2["a"]!!.size) 25 | assertEquals(11, t2["a"]!![0]) 26 | assertEquals(21, t2["a"]!![1]) 27 | 28 | val t3 = t2.transpose() 29 | assertEquals(t1, t3) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/autonat.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package io.libp2p.protocol.autonat.pb; 4 | 5 | message Message { 6 | enum MessageType { 7 | DIAL = 0; 8 | DIAL_RESPONSE = 1; 9 | } 10 | 11 | enum ResponseStatus { 12 | OK = 0; 13 | E_DIAL_ERROR = 100; 14 | E_DIAL_REFUSED = 101; 15 | E_BAD_REQUEST = 200; 16 | E_INTERNAL_ERROR = 300; 17 | } 18 | 19 | message PeerInfo { 20 | optional bytes id = 1; 21 | repeated bytes addrs = 2; 22 | } 23 | 24 | message Dial { 25 | optional PeerInfo peer = 1; 26 | } 27 | 28 | message DialResponse { 29 | optional ResponseStatus status = 1; 30 | optional string statusText = 2; 31 | optional bytes addr = 3; 32 | } 33 | 34 | optional MessageType type = 1; 35 | optional Dial dial = 2; 36 | optional DialResponse dialResponse = 3; 37 | } 38 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/SequentialBandwidthTracker.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.Bandwidth 4 | import io.libp2p.simulate.BandwidthDelayer 5 | import io.libp2p.tools.delayedFuture 6 | import java.util.concurrent.CompletableFuture 7 | import java.util.concurrent.ScheduledExecutorService 8 | 9 | class SequentialBandwidthTracker( 10 | override val totalBandwidth: Bandwidth, 11 | val executor: ScheduledExecutorService 12 | ) : BandwidthDelayer { 13 | 14 | private var lastMessageFuture: CompletableFuture = CompletableFuture.completedFuture(null) 15 | 16 | override fun delay(size: Long): CompletableFuture { 17 | lastMessageFuture = lastMessageFuture.thenCompose { 18 | executor.delayedFuture(totalBandwidth.getTransmitTime(size)) 19 | } 20 | return lastMessageFuture 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/ConnectionHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.etc.BroadcastConnectionHandler 4 | 5 | /** 6 | * The same as [P2PChannelHandler] with the [Connection] specialized [P2PChannel] 7 | */ 8 | fun interface ConnectionHandler { 9 | 10 | fun handleConnection(conn: Connection) 11 | 12 | companion object { 13 | fun create(handler: (Connection) -> Unit): ConnectionHandler { 14 | return object : ConnectionHandler { 15 | override fun handleConnection(conn: Connection) { 16 | handler(conn) 17 | } 18 | } 19 | } 20 | fun createBroadcast(handlers: List = listOf()): Broadcast = 21 | BroadcastConnectionHandler().also { it += handlers } 22 | } 23 | 24 | interface Broadcast : ConnectionHandler, MutableList 25 | } 26 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/mplex/MplexId.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.mplex 2 | 3 | import io.libp2p.etc.util.netty.mux.MuxId 4 | import io.netty.channel.ChannelId 5 | 6 | class MplexId( 7 | parentId: ChannelId, 8 | id: Long, 9 | val initiator: Boolean 10 | ) : MuxId(parentId, id) { 11 | 12 | override fun asShortText() = "${parentId.asShortText()}/$id/$initiator" 13 | override fun asLongText() = "${parentId.asLongText()}/$id/$initiator" 14 | 15 | override fun equals(other: Any?): Boolean { 16 | if (this === other) return true 17 | if (javaClass != other?.javaClass) return false 18 | other as MplexId 19 | return id == other.id && initiator == other.initiator 20 | } 21 | 22 | override fun hashCode(): Int { 23 | var result = id.hashCode() 24 | result = 31 * result + initiator.hashCode() 25 | return result 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/CountingPingProtocol.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import io.libp2p.core.Stream 4 | import io.libp2p.protocol.PingController 5 | import io.libp2p.protocol.PingProtocol 6 | import io.netty.buffer.ByteBuf 7 | import java.util.concurrent.CompletableFuture 8 | 9 | class CountingPingProtocol : PingProtocol() { 10 | var pingsReceived: Int = 0 11 | 12 | override fun onStartResponder(stream: Stream): CompletableFuture { 13 | val handler = CountingPingResponderChannelHandler() 14 | stream.pushHandler(handler) 15 | return CompletableFuture.completedFuture(handler) 16 | } 17 | 18 | inner class CountingPingResponderChannelHandler : PingResponder() { 19 | override fun onMessage(stream: Stream, msg: ByteBuf) { 20 | ++pingsReceived 21 | super.onMessage(stream, msg) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/types/BufferExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.buffer.Unpooled 5 | import kotlin.math.min 6 | 7 | /** 8 | * Extends Netty's ByteBuf with syntactic sugar to extract a ByteArray (byte[] in Java) easily, 9 | * which is created by copy. 10 | */ 11 | fun ByteBuf.toByteArray(): ByteArray = ByteArray(this.readableBytes()).apply { 12 | slice().readBytes(this) 13 | } 14 | 15 | fun ByteBuf.toByteArray(from: Int = 0, to: Int = Int.MAX_VALUE): ByteArray { 16 | val toFinal = min(readableBytes(), to) 17 | val len = toFinal - from 18 | val ret = ByteArray(len) 19 | this.slice(from, toFinal - from).readBytes(ret) 20 | return ret 21 | } 22 | 23 | /** 24 | * Extends Kotlin's ByteArray (byte[] in Java) with syntactic sugar to wrap it in Netty's ByteBuf easily. 25 | */ 26 | fun ByteArray.toByteBuf(): ByteBuf = Unpooled.wrappedBuffer(this) 27 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/DHT.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import io.libp2p.tools.p2pd.libp2pj.util.Cid; 4 | import java.util.List; 5 | import java.util.concurrent.CompletableFuture; 6 | 7 | /** Created by Anton Nashatyrev on 21.12.2018. */ 8 | public interface DHT { 9 | CompletableFuture findPeer(Peer peerId); 10 | 11 | CompletableFuture> findPeersConnectedToPeer(Peer peerId); 12 | 13 | CompletableFuture> findProviders(Cid cid, int maxRetCount); 14 | 15 | CompletableFuture> getClosestPeers(byte[] key); 16 | 17 | CompletableFuture getPublicKey(Peer peerId); 18 | 19 | CompletableFuture getValue(byte[] key); 20 | 21 | CompletableFuture> searchValue(byte[] key); 22 | 23 | CompletableFuture putValue(byte[] key, byte[] value); 24 | 25 | CompletableFuture provide(Cid cid); 26 | } 27 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/SequentialDelayer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.MessageDelayer 4 | import java.util.concurrent.CompletableFuture 5 | import java.util.concurrent.ScheduledExecutorService 6 | 7 | class SequentialDelayer( 8 | val delegate: MessageDelayer, 9 | val executor: ScheduledExecutorService, 10 | ) : MessageDelayer { 11 | 12 | private var lastMessageFuture: CompletableFuture = CompletableFuture.completedFuture(null) 13 | 14 | override fun delay(size: Long): CompletableFuture { 15 | lastMessageFuture = lastMessageFuture.thenComposeAsync({ 16 | delegate.delay(size) 17 | }, executor) 18 | return lastMessageFuture 19 | } 20 | 21 | companion object { 22 | fun MessageDelayer.sequential(executor: ScheduledExecutorService) = 23 | SequentialDelayer(this, executor) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/RandomNPeers.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.etc.types.copy 4 | import org.jgrapht.Graph 5 | import org.jgrapht.generate.RandomRegularGraphGenerator 6 | import org.jgrapht.graph.DefaultUndirectedGraph 7 | 8 | data class RandomNPeers(val peersCount: Int = 10) : AbstractGraphTopology() { 9 | 10 | override fun buildGraph(vertexCount: Int): Graph { 11 | val peersVertex = (0 until vertexCount).iterator() 12 | val graph: Graph = DefaultUndirectedGraph(peersVertex::next, { Any() }, false) 13 | RandomRegularGraphGenerator(vertexCount, peersCount, random).generateGraph(graph) 14 | graph.edgeSet().copy().forEach { 15 | if (graph.getEdgeSource(it) == graph.getEdgeTarget(it)) { 16 | graph.removeEdge(it) 17 | } 18 | } 19 | return graph 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/SimStream.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import io.libp2p.core.multistream.ProtocolId 4 | 5 | interface SimStream { 6 | 7 | enum class StreamInitiator { CONNECTION_DIALER, CONNECTION_LISTENER } 8 | 9 | val connection: SimConnection 10 | val streamInitiator: StreamInitiator 11 | val streamProtocol: ProtocolId 12 | 13 | val streamInitiatorPeer get() = 14 | when (streamInitiator) { 15 | StreamInitiator.CONNECTION_DIALER -> connection.dialer 16 | StreamInitiator.CONNECTION_LISTENER -> connection.listener 17 | } 18 | val streamAcceptorPeer get() = 19 | when (streamInitiator) { 20 | StreamInitiator.CONNECTION_DIALER -> connection.listener 21 | StreamInitiator.CONNECTION_LISTENER -> connection.dialer 22 | } 23 | 24 | val initiatorChannel: SimChannel 25 | val acceptorChannel: SimChannel 26 | } 27 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/InboundTrafficLimitHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.libp2p.core.ProtocolViolationException 4 | import io.netty.buffer.ByteBuf 5 | import io.netty.channel.ChannelHandlerContext 6 | import io.netty.channel.ChannelInboundHandlerAdapter 7 | 8 | /** 9 | * Limits the total inbound traffic for the Channel 10 | */ 11 | class InboundTrafficLimitHandler( 12 | private var inboundBytesLimit: Long 13 | ) : ChannelInboundHandlerAdapter() { 14 | 15 | override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { 16 | msg as ByteBuf 17 | inboundBytesLimit -= msg.readableBytes() 18 | if (inboundBytesLimit >= 0) { 19 | ctx.fireChannelRead(msg) 20 | } else { 21 | msg.release() 22 | ctx.fireExceptionCaught(ProtocolViolationException("Inbound traffic quota reached")) 23 | ctx.close() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/topology/JGraphtTopologyGraph.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.TopologyGraph 4 | import org.jgrapht.Graph 5 | import org.jgrapht.GraphMetrics 6 | 7 | class JGraphtTopologyGraph( 8 | val graph: Graph 9 | ) : TopologyGraph { 10 | 11 | override val edges: Collection = 12 | graph.edgeSet() 13 | .map { TopologyGraph.Edge(graph.getEdgeSource(it), graph.getEdgeTarget(it)) } 14 | 15 | init { 16 | assert(edges.all { it.srcV != it.destV }) 17 | 18 | // check no duplicate edges between any of to vertices 19 | assert( 20 | edges 21 | .map { listOf(it.srcV, it.destV).sorted() } 22 | .distinct() 23 | .size == edges.size 24 | ) 25 | } 26 | 27 | override fun calcDiameter(): Int = GraphMetrics.getDiameter(graph).toInt() 28 | } 29 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WebSocketServerHandshakeListener.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.netty.channel.ChannelHandler 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.channel.ChannelInboundHandlerAdapter 6 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler 7 | 8 | internal class WebSocketServerHandshakeListener( 9 | private val connectionBuilder: ChannelHandler 10 | ) : ChannelInboundHandlerAdapter() { 11 | 12 | override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) { 13 | if (evt is WebSocketServerProtocolHandler.HandshakeComplete) { 14 | ctx.pipeline().addLast(WebFrameCodec()) 15 | ctx.pipeline().addLast(connectionBuilder) 16 | ctx.pipeline().remove(this) 17 | ctx.fireChannelActive() 18 | } 19 | super.userEventTriggered(ctx, evt) 20 | } 21 | } // WebSocketServerHandshakeListener 22 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/LoggingDelayer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.BandwidthDelayer 4 | import java.util.concurrent.CompletableFuture 5 | import java.util.concurrent.atomic.AtomicInteger 6 | 7 | class LoggingDelayer( 8 | val delegate: BandwidthDelayer, 9 | val logger: (String) -> Unit 10 | ) : BandwidthDelayer { 11 | 12 | val counter = AtomicInteger(0) 13 | 14 | override val totalBandwidth = delegate.totalBandwidth 15 | 16 | override fun delay(size: Long): CompletableFuture { 17 | val id = counter.getAndIncrement() 18 | logger("[$id] Started $size") 19 | return delegate.delay(size) 20 | .thenApply { 21 | logger("[$id] Completed $size") 22 | } 23 | } 24 | 25 | companion object { 26 | fun BandwidthDelayer.logging(logger: (String) -> Unit) = LoggingDelayer(this, logger) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/DnsAvailability.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import org.junit.jupiter.api.Assumptions 4 | import java.net.Inet4Address 5 | import java.net.Inet6Address 6 | import java.net.InetAddress 7 | 8 | class DnsAvailability { 9 | companion object { 10 | val ip4DnsAvailable = 11 | InetAddress.getAllByName("localhost") 12 | .filter { it is Inet4Address } 13 | .isNotEmpty() 14 | val ip6DnsAvailable = 15 | InetAddress.getAllByName("localhost") 16 | .filter { it is Inet6Address } 17 | .isNotEmpty() 18 | 19 | fun assumeIp4Dns(message: String = "IP4 DNS resolution not available") = 20 | Assumptions.assumeTrue(ip4DnsAvailable, message) 21 | 22 | fun assumeIp6Dns(message: String = "IP6 DNS resolution not available") = 23 | Assumptions.assumeTrue(ip6DnsAvailable, message) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/types/AsyncExtTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import org.junit.jupiter.api.Assertions 4 | import org.junit.jupiter.api.Test 5 | import java.util.concurrent.CompletableFuture 6 | 7 | class AsyncExtTest { 8 | 9 | @Test 10 | fun testThenApplyAll() { 11 | val futs = List(3) { CompletableFuture() } 12 | val allFut = futs.thenApplyAll { it.sum() } 13 | assert(!allFut.isDone) 14 | futs[0].complete(1) 15 | assert(!allFut.isDone) 16 | futs[1].complete(2) 17 | assert(!allFut.isDone) 18 | futs[2].complete(3) 19 | assert(allFut.isDone) 20 | assert(allFut.get() == 6) 21 | } 22 | 23 | @Test 24 | fun testAnyCompleteWithCompletedExceptionally() { 25 | val anyComplete = anyComplete(completedExceptionally(RuntimeException("test"))) 26 | 27 | Assertions.assertTrue(anyComplete.isCompletedExceptionally) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools/simulator/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "application" 2 | 3 | dependencies { 4 | 5 | api project(':libp2p') 6 | api project(':tools:schedulers') 7 | 8 | implementation("io.netty:netty-handler") 9 | 10 | implementation("org.jgrapht:jgrapht-core:1.3.1") 11 | api("org.apache.commons:commons-math3:3.6.1") 12 | implementation("org.jetbrains.kotlin:kotlin-reflect:1.3.0") 13 | 14 | runtimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl") 15 | } 16 | 17 | 18 | if (project.hasProperty("mainClass")) { 19 | ext.javaMainClass = project.getProperty("mainClass") 20 | } else { 21 | ext.javaMainClass = "io.libp2p.simulate.util.gradle.DefaultGradleApplicationKt" 22 | } 23 | 24 | application { 25 | mainClassName = javaMainClass 26 | applicationDefaultJvmArgs = ['-Xmx12G', '-XX:+HeapDumpOnOutOfMemoryError'] 27 | 28 | if ( project.hasProperty('jvmArgs') ) { 29 | applicationDefaultJvmArgs = applicationDefaultJvmArgs + project.jvmArgs.split('\\s+').toList() 30 | } 31 | } -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/util/Util.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj.util; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** Created by Anton Nashatyrev on 17.12.2018. */ 7 | public class Util { 8 | 9 | public static byte[] concat(List arrays) { 10 | byte[] ret = new byte[arrays.stream().mapToInt(arr -> arr.length).sum()]; 11 | int off = 0; 12 | for (byte[] bb : arrays) { 13 | System.arraycopy(bb, 0, ret, off, bb.length); 14 | off += bb.length; 15 | } 16 | return ret; 17 | } 18 | 19 | /** https://developers.google.com/protocol-buffers/docs/encoding */ 20 | public static byte[] encodeUVariant(long n) { 21 | int size = 0; 22 | byte[] ret = new byte[10]; 23 | while (n > 0) { 24 | if (size > 0) ret[size - 1] |= 0b10000000; 25 | ret[size++] = (byte) (n & 0b01111111); 26 | n >>>= 7; 27 | } 28 | return Arrays.copyOfRange(ret, 0, size); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/types/ByteArrayExtTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import org.junit.jupiter.api.Assertions 4 | import org.junit.jupiter.api.Test 5 | 6 | class ByteArrayExtTest { 7 | 8 | @Test 9 | fun numberEncodingTest() { 10 | val ushorts = listOf(0x0, 0x1, 0x7F, 0x80, 0xFF, 0x0100, 0x0101, 0x0102, 0x7FFF, 0x8000, 0xFFFF) 11 | ushorts.forEach { 12 | Assertions.assertEquals(it, it.uShortToBytesBigEndian().toUShortBigEndian()) 13 | } 14 | val uints = ushorts + listOf(0x10000, 0x7FFFFFFF, 0x80000000.toInt(), 0xFFFFFFFF.toInt()) 15 | uints.forEach { 16 | Assertions.assertEquals(it, it.toBytesBigEndian().toIntBigEndian()) 17 | } 18 | val ulongs = uints.map { it.toLong() } + listOf(0x100000000, 0x7FFFFFFFFFFFFFFF, Long.MIN_VALUE, -1) 19 | ulongs.forEach { 20 | Assertions.assertEquals(it, it.toBytesBigEndian().toLongBigEndian()) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxFrame.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import io.libp2p.etc.util.netty.mux.MuxId 4 | import io.netty.buffer.ByteBuf 5 | import io.netty.buffer.DefaultByteBufHolder 6 | import io.netty.buffer.Unpooled 7 | 8 | /** 9 | * Contains the fields that comprise a yamux frame. 10 | * @param id the ID of the stream. 11 | * @param flags the flags for this frame. 12 | * @param length the length field for this frame. 13 | * @param data the data segment. 14 | */ 15 | class YamuxFrame(val id: MuxId, val type: YamuxType, val flags: Set, val length: Long, val data: ByteBuf? = null) : 16 | DefaultByteBufHolder(data ?: Unpooled.EMPTY_BUFFER) { 17 | 18 | override fun toString(): String { 19 | val dataString = if (data == null) "" else ", len=${data.readableBytes()}, $data" 20 | val flagsString = flags.joinToString("+") 21 | return "YamuxFrame(id=$id, type=$type, flags=$flagsString, length=$length$dataString)" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Transport.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import io.libp2p.core.multiformats.Multiaddr; 4 | import java.io.Closeable; 5 | import java.util.concurrent.CompletableFuture; 6 | import java.util.function.Supplier; 7 | 8 | /** Created by Anton Nashatyrev on 10.12.2018. */ 9 | public interface Transport extends Connector { 10 | 11 | @Override 12 | CompletableFuture dial(Multiaddr multiaddress, StreamHandler dialHandler); 13 | 14 | @Override 15 | CompletableFuture listen( 16 | Multiaddr multiaddress, Supplier> handlerFactory); 17 | 18 | interface Listener extends Closeable { 19 | 20 | @Override 21 | void close(); 22 | 23 | Multiaddr getLocalMultiaddress(); 24 | 25 | default CompletableFuture getPublicMultiaddress() { 26 | return CompletableFuture.completedFuture(getLocalMultiaddress()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/MuxerException.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux 2 | 3 | import io.libp2p.core.Libp2pException 4 | import io.libp2p.etc.util.netty.mux.MuxId 5 | 6 | open class MuxerException(message: String, ex: Exception?) : Libp2pException(message, ex) 7 | 8 | class AckBacklogLimitExceededMuxerException(message: String) : MuxerException(message, null) 9 | 10 | open class ReadMuxerException(message: String, ex: Exception?) : MuxerException(message, ex) 11 | open class WriteMuxerException(message: String, ex: Exception?) : MuxerException(message, ex) 12 | 13 | class UnknownStreamIdMuxerException(muxId: MuxId) : ReadMuxerException("Stream with id $muxId not found", null) 14 | 15 | class InvalidFrameMuxerException(message: String) : ReadMuxerException(message, null) 16 | 17 | class WriteBufferOverflowMuxerException(message: String) : WriteMuxerException(message, null) 18 | class ClosedForWritingMuxerException(muxId: MuxId) : 19 | WriteMuxerException("Couldn't write, stream was closed for writing: $muxId", null) 20 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/libp2pj/Host.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd.libp2pj; 2 | 3 | import io.libp2p.core.multiformats.Multiaddr; 4 | import java.io.Closeable; 5 | import java.util.List; 6 | import java.util.concurrent.CompletableFuture; 7 | import java.util.function.Supplier; 8 | 9 | /** Created by Anton Nashatyrev on 18.12.2018. */ 10 | public interface Host extends Muxer { 11 | 12 | Peer getMyId(); 13 | 14 | List getListenAddresses(); 15 | 16 | CompletableFuture connect(List peerAddresses, Peer peerId); 17 | 18 | @Override 19 | CompletableFuture dial(MuxerAdress muxerAdress, StreamHandler handler); 20 | 21 | @Override 22 | CompletableFuture listen( 23 | MuxerAdress muxerAdress, Supplier> handlerFactory); 24 | 25 | void close(); 26 | 27 | DHT getDht(); 28 | 29 | // Peerstore getPeerStore(); 30 | 31 | // Network getNetwork(); 32 | 33 | // ConnectionManager getConnectionManager(); 34 | } 35 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/AddressBook.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | import java.util.concurrent.CompletableFuture 5 | 6 | /** 7 | * The address book holds known addresses for peers. 8 | */ 9 | interface AddressBook { 10 | 11 | /** 12 | * Equivalent to getAddrs(id). 13 | */ 14 | operator fun get(id: PeerId): CompletableFuture?> = getAddrs(id) 15 | 16 | /** 17 | * Returns the addresses we know for a given peer, or nil if we know zero. 18 | */ 19 | fun getAddrs(id: PeerId): CompletableFuture?> 20 | 21 | /** 22 | * Overrides all addresses for a given peer with the specified ones. 23 | */ 24 | fun setAddrs(id: PeerId, ttl: Long, vararg addrs: Multiaddr): CompletableFuture 25 | 26 | /** 27 | * Adds addresses for a peer, replacing the TTL if the address already existed. 28 | */ 29 | fun addAddrs(id: PeerId, ttl: Long, vararg addrs: Multiaddr): CompletableFuture 30 | } 31 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/util/MiscExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.* 5 | import java.util.concurrent.Callable 6 | import java.util.concurrent.CompletableFuture 7 | import java.util.concurrent.ScheduledExecutorService 8 | import java.util.concurrent.ScheduledFuture 9 | import java.util.concurrent.TimeUnit 10 | import kotlin.time.Duration 11 | 12 | private val LOG_TIME_FORMAT = SimpleDateFormat("hh:mm:ss.SSS") 13 | 14 | fun log(s: String) { 15 | println("[${LOG_TIME_FORMAT.format(Date())}] $s") 16 | } 17 | 18 | fun ScheduledExecutorService.delayedFuture(delay: Duration): CompletableFuture { 19 | val fut = CompletableFuture() 20 | this.schedule({ fut.complete(null) }, delay.inWholeMilliseconds, TimeUnit.MILLISECONDS) 21 | return fut 22 | } 23 | 24 | fun ScheduledExecutorService.schedule(delay: Duration, callable: () -> R): ScheduledFuture = 25 | this.schedule(Callable { callable() }, delay.inWholeMilliseconds, TimeUnit.MILLISECONDS) 26 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multistream/ProtocolMatcher.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multistream 2 | 3 | /** 4 | * A matcher that evaluates whether a given protocol activates based on its protocol ID. 5 | */ 6 | interface ProtocolMatcher { 7 | 8 | /** 9 | * Evaluates this matcher against a proposed protocol ID. 10 | */ 11 | fun matches(proposed: ProtocolId): Boolean 12 | 13 | companion object { 14 | @JvmStatic 15 | fun strict(protocol: ProtocolId) = object : ProtocolMatcher { 16 | override fun matches(proposed: ProtocolId) = protocol == proposed 17 | } 18 | 19 | @JvmStatic 20 | fun prefix(protocolPrefix: String) = object : ProtocolMatcher { 21 | override fun matches(proposed: ProtocolId) = proposed.startsWith(protocolPrefix) 22 | } 23 | 24 | @JvmStatic 25 | fun list(protocols: Collection) = object : ProtocolMatcher { 26 | override fun matches(proposed: ProtocolId) = proposed in protocols 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.yml: -------------------------------------------------------------------------------- 1 | name: Enhancement 2 | description: Suggest an improvement to an existing jvm-libp2p feature. 3 | body: 4 | - type: textarea 5 | attributes: 6 | label: Description 7 | description: Describe the enhancement that you are proposing. 8 | validations: 9 | required: true 10 | - type: textarea 11 | attributes: 12 | label: Motivation 13 | description: Explain why this enhancement is beneficial. 14 | validations: 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: Current Implementation 19 | description: Describe the current implementation. 20 | validations: 21 | required: true 22 | - type: dropdown 23 | attributes: 24 | label: Are you planning to do it yourself in a pull request ? 25 | description: Any contribution is greatly appreciated. We are more than happy to provide help on the process. 26 | options: 27 | - "Yes" 28 | - "No" 29 | - Maybe 30 | validations: 31 | required: true 32 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/dsl/BuilderJ.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.dsl 2 | 3 | import io.libp2p.core.Host 4 | import java.util.function.Consumer 5 | 6 | /** 7 | * Creates Java friendly [io.libp2p.core.Host] builder 8 | */ 9 | fun hostJ( 10 | defaultMode: Builder.Defaults, 11 | fn: Consumer 12 | ): Host { 13 | val builder = BuilderJ() 14 | fn.accept(builder) 15 | return builder.build(defaultMode) 16 | } 17 | 18 | class BuilderJ : Builder() { 19 | public override val identity = super.identity 20 | public override val secureChannels = super.secureChannels 21 | public override val muxers = super.muxers 22 | public override val secureTransports = super.secureTransports 23 | public override val transports = super.transports 24 | public override val addressBook = super.addressBook 25 | public override val protocols = super.protocols 26 | public override val connectionHandlers = super.connectionHandlers 27 | public override val network = super.network 28 | public override val debug = super.debug 29 | } 30 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stream/Libp2pConnectionImpl.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stream 2 | 3 | import io.libp2p.core.PeerId 4 | import io.libp2p.core.crypto.PubKey 5 | import io.libp2p.core.multiformats.Multiaddr 6 | import io.libp2p.core.security.SecureChannel 7 | import io.libp2p.simulate.util.DummyChannel 8 | import io.libp2p.simulate.util.NullTransport 9 | import io.libp2p.transport.implementation.ConnectionOverNetty 10 | 11 | class Libp2pConnectionImpl( 12 | val remoteAddr: Multiaddr, 13 | isInitiator: Boolean, 14 | localPubkey: PubKey, 15 | remotePubkey: PubKey, 16 | ) : ConnectionOverNetty( 17 | DummyChannel(), 18 | NullTransport(), 19 | isInitiator 20 | ) { 21 | init { 22 | setSecureSession( 23 | SecureChannel.Session( 24 | PeerId.fromPubKey(localPubkey), 25 | PeerId.fromPubKey(remotePubkey), 26 | remotePubkey, 27 | null 28 | ) 29 | ) 30 | } 31 | 32 | override fun remoteAddress() = remoteAddr 33 | } 34 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/protocol/ProtobufProtocolHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.protocol 2 | 3 | import com.google.protobuf.MessageLite 4 | import io.libp2p.core.Stream 5 | import io.netty.handler.codec.protobuf.ProtobufDecoder 6 | import io.netty.handler.codec.protobuf.ProtobufEncoder 7 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder 8 | import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender 9 | 10 | abstract class ProtobufProtocolHandler( 11 | private val protobufMessagePrototype: MessageLite, 12 | initiatorTrafficLimit: Long, 13 | responderTrafficLimit: Long 14 | ) : ProtocolHandler(initiatorTrafficLimit, responderTrafficLimit) { 15 | 16 | override fun initProtocolStream(stream: Stream) { 17 | with(stream) { 18 | pushHandler(ProtobufVarint32FrameDecoder()) 19 | pushHandler(ProtobufVarint32LengthFieldPrepender()) 20 | pushHandler(ProtobufDecoder(protobufMessagePrototype)) 21 | pushHandler(ProtobufEncoder()) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/types/WBytes.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import com.google.protobuf.ByteString 4 | 5 | /** 6 | * `ByteArray` wrapper with `equals()`, `hashCode()` and `toString()` 7 | */ 8 | class WBytes(val array: ByteArray) { 9 | 10 | operator fun plus(other: WBytes) = (array + other.array).toWBytes() 11 | operator fun plus(other: ByteArray) = (array + other).toWBytes() 12 | 13 | override fun equals(other: Any?): Boolean { 14 | if (this === other) return true 15 | if (javaClass != other?.javaClass) return false 16 | 17 | other as WBytes 18 | 19 | if (!array.contentEquals(other.array)) return false 20 | 21 | return true 22 | } 23 | 24 | override fun hashCode(): Int { 25 | return array.contentHashCode() 26 | } 27 | 28 | override fun toString() = array.toHex() 29 | } 30 | 31 | fun ByteArray.toWBytes() = WBytes(this) 32 | fun String.toWBytes() = this.fromHex().toWBytes() 33 | fun WBytes.toProtobuf() = this.array.toProtobuf() 34 | fun ByteString.toWBytes() = this.toByteArray().toWBytes() 35 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/collect/gossip/GossipMessageCollector.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats.collect.gossip 2 | 3 | import io.libp2p.pubsub.gossip.CurrentTimeSupplier 4 | import io.libp2p.simulate.Network 5 | import io.libp2p.simulate.gossip.GossipPubMessageGenerator 6 | import io.libp2p.simulate.gossip.GossipSimPeer 7 | import io.libp2p.simulate.stats.collect.ConnectionsMessageCollector 8 | import pubsub.pb.Rpc 9 | import pubsub.pb.Rpc.RPC 10 | 11 | typealias GossipMessageIdGenerator = (Rpc.Message) -> GossipMessageId 12 | 13 | fun GossipSimPeer.getMessageIdGenerator(): GossipMessageIdGenerator = { 14 | this.router.messageFactory(it).messageId 15 | } 16 | 17 | class GossipMessageCollector( 18 | network: Network, 19 | timeSupplier: CurrentTimeSupplier, 20 | val msgGenerator: GossipPubMessageGenerator, 21 | val gossipMessageIdGenerator: GossipMessageIdGenerator 22 | ) : ConnectionsMessageCollector(network, timeSupplier) { 23 | 24 | fun gatherResult() = 25 | GossipMessageResult(deliveredMessages, msgGenerator, gossipMessageIdGenerator) 26 | } 27 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/host/MemoryAddressBook.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.host 2 | 3 | import io.libp2p.core.AddressBook 4 | import io.libp2p.core.PeerId 5 | import io.libp2p.core.multiformats.Multiaddr 6 | import java.util.concurrent.CompletableFuture 7 | import java.util.concurrent.ConcurrentHashMap 8 | 9 | class MemoryAddressBook : AddressBook { 10 | val map = 11 | ConcurrentHashMap>() 12 | 13 | override fun getAddrs(id: PeerId): CompletableFuture?> { 14 | return CompletableFuture.completedFuture(map[id]) 15 | } 16 | 17 | override fun setAddrs(id: PeerId, ttl: Long, vararg addrs: Multiaddr): CompletableFuture { 18 | map[id] = listOf(*addrs) 19 | return CompletableFuture.completedFuture(null) 20 | } 21 | 22 | override fun addAddrs(id: PeerId, ttl: Long, vararg addrs: Multiaddr): CompletableFuture { 23 | map.compute(id) { _, existingAddrs -> 24 | (existingAddrs ?: emptyList()) + listOf(*addrs) 25 | } 26 | return CompletableFuture.completedFuture(null) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/PubsubProtocol.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | import io.libp2p.core.multistream.ProtocolId 4 | 5 | enum class PubsubProtocol(val announceStr: ProtocolId) { 6 | 7 | Gossip_V_1_0("/meshsub/1.0.0"), 8 | Gossip_V_1_1("/meshsub/1.1.0"), 9 | Gossip_V_1_2("/meshsub/1.2.0"), 10 | Floodsub("/floodsub/1.0.0"); 11 | 12 | companion object { 13 | fun fromProtocol(protocol: ProtocolId) = PubsubProtocol.values().find { protocol == it.announceStr } 14 | ?: throw NoSuchElementException("No PubsubProtocol found with protocol $protocol") 15 | } 16 | 17 | /** 18 | * https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.1.md#prune-backoff-and-peer-exchange 19 | */ 20 | fun supportsBackoffAndPX(): Boolean { 21 | return this == Gossip_V_1_1 || this == Gossip_V_1_2 22 | } 23 | 24 | /** 25 | * https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.2.md#idontwant-message 26 | */ 27 | fun supportsIDontWant(): Boolean { 28 | return this == Gossip_V_1_2 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stream/Libp2pStreamImpl.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stream 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.Stream 5 | import io.libp2p.etc.PROTOCOL 6 | import io.libp2p.etc.types.toVoidCompletableFuture 7 | import io.libp2p.transport.implementation.P2PChannelOverNetty 8 | import io.netty.channel.Channel 9 | import java.util.concurrent.CompletableFuture 10 | 11 | class Libp2pStreamImpl( 12 | override val connection: Connection, 13 | ch: Channel, 14 | initiator: Boolean 15 | ) : P2PChannelOverNetty(ch, initiator), Stream { 16 | 17 | init { 18 | nettyChannel.attr(PROTOCOL).set(CompletableFuture()) 19 | } 20 | 21 | override fun remotePeerId() = connection.secureSession().remoteId 22 | 23 | override fun getProtocol(): CompletableFuture = nettyChannel.attr(PROTOCOL).get() 24 | 25 | override fun writeAndFlush(msg: Any) { 26 | nettyChannel.writeAndFlush(msg) 27 | } 28 | 29 | override fun closeWrite(): CompletableFuture = 30 | nettyChannel.disconnect().toVoidCompletableFuture() 31 | } 32 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/StreamHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import java.util.concurrent.CompletableFuture 4 | 5 | /** 6 | * The pair of [Futures] as a result of initiating a [Stream] 7 | * 8 | * @property stream Is completed when a [Stream] instance was successfully created 9 | * this property is used for low level Stream manipulations (like closing it) 10 | * 11 | * @property controller Is completed when the underlying client protocol is initiated. 12 | * When the [stream] future is failed this future is also failed 13 | * While the [stream] can be created successfully the protocol may fail 14 | * to instantiate and this future would fail 15 | */ 16 | data class StreamPromise( 17 | val stream: CompletableFuture = CompletableFuture(), 18 | val controller: CompletableFuture = CompletableFuture() 19 | ) 20 | 21 | /** 22 | * The same as [P2PChannelHandler] with the [Stream] specialized [P2PChannel] 23 | */ 24 | fun interface StreamHandler { 25 | 26 | fun handleStream(stream: Stream): CompletableFuture 27 | } 28 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/Connection.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | import io.libp2p.core.mux.StreamMuxer 5 | import io.libp2p.core.security.SecureChannel 6 | import io.libp2p.core.transport.Transport 7 | 8 | interface Connection : P2PChannel { 9 | /** 10 | * Returns the [io.libp2p.core.mux.StreamMuxer.Session] which is capable of creating 11 | * new [Stream]s 12 | */ 13 | fun muxerSession(): StreamMuxer.Session 14 | 15 | /** 16 | * Returns the [io.libp2p.core.security.SecureChannel.Session] which contains 17 | * security attributes of this connection 18 | */ 19 | fun secureSession(): SecureChannel.Session 20 | 21 | /** 22 | * Returns the [io.libp2p.core.transport.Transport] instance behind this [Connection] 23 | */ 24 | fun transport(): Transport 25 | 26 | /** 27 | * Returns the local [Multiaddr] of this [Connection] 28 | */ 29 | fun localAddress(): Multiaddr 30 | 31 | /** 32 | * Returns the remote [Multiaddr] of this [Connection] 33 | */ 34 | fun remoteAddress(): Multiaddr 35 | } 36 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/util/StringExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.util 2 | 3 | import kotlin.math.max 4 | 5 | fun String.align(width: Int, alignLeft: Boolean = true, fillChar: Char = ' '): String { 6 | val n = max(1, width - length) 7 | return if (alignLeft) this + fillChar.toString().repeat(n) else fillChar.toString().repeat(n) + this 8 | } 9 | 10 | fun String.formatTable(firstLineHeaders: Boolean = true, separator: String = "\t", alignLeft: Boolean = true): String { 11 | val list = this.split("\n").map { it.split(separator) } 12 | require(list.map { it.size }.minOrNull() == list.map { it.size }.maxOrNull()) { "Different number of columns" } 13 | val colSizes = list[0].indices.map { col -> list.map { it[col].length + 1 }.maxOrNull() } 14 | val strings = list.map { raw -> 15 | raw.indices.map { raw[it].align(colSizes[it]!!, alignLeft) } 16 | .joinToString("") 17 | }.toMutableList() 18 | 19 | if (firstLineHeaders) { 20 | strings.add(1, colSizes.map { "-".repeat(it!! - 1) + " " }.joinToString("")) 21 | } 22 | return strings.joinToString("\n") 23 | } 24 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/core/multiformats/ProtocolTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multiformats 2 | 3 | import io.libp2p.etc.types.readUvarint 4 | import io.libp2p.etc.types.toByteBuf 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | 8 | /** 9 | * Created by Anton Nashatyrev on 11.06.2019. 10 | */ 11 | class ProtocolTest { 12 | @Test 13 | fun protocolEncodingRoundTripping() { 14 | for (p in Protocol.values()) { 15 | val protocol = if (p == Protocol.IPFS) Protocol.P2P else p 16 | // IPFS and P2P are equivalent 17 | 18 | val roundTrippedId = p.encoded.toByteBuf().readUvarint().toInt() 19 | val roundTrippedProtocol = Protocol.getOrThrow(roundTrippedId) 20 | 21 | assertEquals(protocol, roundTrippedProtocol) 22 | } 23 | } 24 | 25 | @Test 26 | fun tcpProtocolProperties() { 27 | assertEquals(Protocol.TCP, Protocol.get("tcp")) 28 | assertEquals(Protocol.TCP, Protocol.get(6)) 29 | assertEquals("12345", Protocol.TCP.bytesToAddress(Protocol.TCP.addressToBytes("12345"))) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/types/OtherExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import com.google.common.base.Throwables 4 | import kotlin.reflect.KClass 5 | 6 | fun Boolean.whenTrue(run: () -> Unit): Boolean { 7 | if (this) { 8 | run() 9 | } 10 | return this 11 | } 12 | 13 | class Deferrable { 14 | private val actions: MutableList<() -> Unit> = mutableListOf() 15 | 16 | fun defer(f: () -> Unit) { 17 | actions.add(f) 18 | } 19 | 20 | fun execute() { 21 | actions.asReversed().forEach { 22 | try { 23 | it() 24 | } catch (e: Exception) { 25 | e.printStackTrace() 26 | } 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * Acts like Go defer 33 | */ 34 | fun defer(f: (Deferrable) -> T): T { 35 | val deferrable = Deferrable() 36 | try { 37 | return f(deferrable) 38 | } finally { 39 | deferrable.execute() 40 | } 41 | } 42 | 43 | fun Throwable.hasCauseOfType(clazz: KClass) = 44 | Throwables.getCausalChain(this) 45 | .filter(clazz::isInstance) 46 | .any() 47 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/TestLogAppender.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import org.apache.logging.log4j.Level 4 | import org.apache.logging.log4j.LogManager 5 | import org.apache.logging.log4j.core.LogEvent 6 | import org.apache.logging.log4j.core.Logger 7 | import org.apache.logging.log4j.core.appender.AbstractAppender 8 | import java.util.ArrayList 9 | 10 | class TestLogAppender : AbstractAppender("test", null, null, false, null), AutoCloseable { 11 | val logs: MutableList = ArrayList() 12 | 13 | fun install(): TestLogAppender { 14 | (LogManager.getRootLogger() as Logger).addAppender(this) 15 | start() 16 | return this 17 | } 18 | 19 | fun uninstall() { 20 | stop() 21 | (LogManager.getRootLogger() as Logger).removeAppender(this) 22 | } 23 | 24 | override fun close() { 25 | uninstall() 26 | } 27 | 28 | fun hasAny(level: Level) = logs.any { it.level == level } 29 | fun hasAnyWarns() = hasAny(Level.ERROR) || hasAny(Level.WARN) 30 | 31 | override fun append(event: LogEvent) { 32 | logs += event.toImmutable() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxFlag.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import io.libp2p.mux.InvalidFrameMuxerException 4 | 5 | /** 6 | * Contains all the permissible values for flags in the yamux protocol. 7 | */ 8 | enum class YamuxFlag(val intFlag: Int) { 9 | SYN(1), 10 | ACK(2), 11 | FIN(4), 12 | RST(8); 13 | 14 | val asSet: Set = setOf(this) 15 | 16 | companion object { 17 | val NONE = emptySet() 18 | 19 | private val validFlagCombinations = mapOf( 20 | 0 to NONE, 21 | SYN.intFlag to SYN.asSet, 22 | ACK.intFlag to ACK.asSet, 23 | FIN.intFlag to FIN.asSet, 24 | RST.intFlag to RST.asSet, 25 | ) 26 | 27 | fun fromInt(flags: Int) = 28 | validFlagCombinations[flags] ?: throw InvalidFrameMuxerException("Invalid Yamux flags value: $flags") 29 | 30 | fun Set.toInt() = this 31 | .fold(0) { acc, flag -> acc or flag.intFlag } 32 | .also { require(it in validFlagCombinations) { "Invalid Yamux flags combination: $this" } } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WebSocketClientInitializer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.netty.channel.ChannelHandler 4 | import io.netty.channel.ChannelInitializer 5 | import io.netty.channel.socket.SocketChannel 6 | import io.netty.handler.codec.http.HttpClientCodec 7 | import io.netty.handler.codec.http.HttpObjectAggregator 8 | import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler 9 | 10 | internal class WebSocketClientInitializer( 11 | private val connectionBuilder: ChannelHandler, 12 | private val url: String 13 | ) : ChannelInitializer() { 14 | 15 | override fun initChannel(ch: SocketChannel) { 16 | val pipeline = ch.pipeline() 17 | 18 | pipeline.addLast(HttpClientCodec()) 19 | pipeline.addLast(HttpObjectAggregator(65536)) 20 | pipeline.addLast(WebSocketClientCompressionHandler(0)) 21 | pipeline.addLast( 22 | WebSocketClientHandshake( 23 | connectionBuilder, 24 | url 25 | ) 26 | ) 27 | } // initChannel 28 | } // WebSocketServerInitializer 29 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/PubsubCrypto.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | import io.libp2p.core.crypto.PrivKey 4 | import io.libp2p.core.crypto.marshalPublicKey 5 | import io.libp2p.core.crypto.unmarshalPublicKey 6 | import io.libp2p.etc.types.toProtobuf 7 | import pubsub.pb.Rpc 8 | 9 | val SignPrefix = "libp2p-pubsub:".toByteArray() 10 | 11 | fun pubsubSign(msg: Rpc.Message, key: PrivKey): Rpc.Message { 12 | if (msg.hasKey() || msg.hasSignature()) throw IllegalArgumentException("Message to sign should not contain 'key' or 'signature' fields") 13 | val signature = key.sign(SignPrefix + msg.toByteArray()) 14 | return Rpc.Message.newBuilder(msg) 15 | .setSignature(signature.toProtobuf()) 16 | .setKey(marshalPublicKey(key.publicKey()).toProtobuf()) 17 | .build() 18 | } 19 | 20 | fun pubsubValidate(msg: Rpc.Message): Boolean { 21 | val msgToSign = Rpc.Message.newBuilder(msg) 22 | .clearSignature() 23 | .clearKey() 24 | .build() 25 | return unmarshalPublicKey(msg.key.toByteArray()).verify( 26 | SignPrefix + msgToSign.toByteArray(), 27 | msg.signature.toByteArray() 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multiformats/MultiaddrComponent.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multiformats 2 | 3 | import io.netty.buffer.ByteBuf 4 | import java.util.Objects 5 | 6 | /** 7 | * Parsed component of [Multiaddr] 8 | */ 9 | class MultiaddrComponent( 10 | val protocol: Protocol, 11 | val value: ByteArray? 12 | ) { 13 | val stringValue by lazy { if (value != null) protocol.bytesToAddress(value) else null } 14 | 15 | init { 16 | protocol.validate(value) 17 | } 18 | 19 | fun serialize(buf: ByteBuf) { 20 | buf.writeBytes(protocol.encoded) 21 | protocol.writeAddressBytes(buf, value) 22 | } 23 | 24 | override fun equals(other: Any?): Boolean { 25 | if (this === other) return true 26 | if (other !is MultiaddrComponent) return false 27 | if (protocol != other.protocol) return false 28 | if (!value.contentEquals(other.value)) return false 29 | return true 30 | } 31 | override fun hashCode() = Objects.hash(protocol, value.contentHashCode()) 32 | override fun toString() = "/${protocol.typeName}" + 33 | (if (stringValue != null) "/$stringValue" else "") 34 | } 35 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/RandomValue.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import java.util.Random 4 | 5 | interface RandomValue { 6 | 7 | fun next(): Double 8 | 9 | companion object { 10 | fun const(constVal: Double) = object : RandomValue { 11 | override fun next() = constVal 12 | } 13 | fun uniform(from: Double, to: Double, rnd: Random) = object : RandomValue { 14 | override fun next() = from + rnd.nextDouble() * (to - from) 15 | } 16 | } 17 | } 18 | 19 | interface RandomDistribution { 20 | fun newValue(rnd: Random): RandomValue 21 | 22 | companion object { 23 | fun const(constVal: Double) = ConstRandomDistr(constVal) 24 | fun uniform(from: Double, to: Double) = UniformRandomDistr(from, to) 25 | } 26 | 27 | data class ConstRandomDistr(val constVal: Double) : RandomDistribution { 28 | override fun newValue(rnd: Random) = RandomValue.const(constVal) 29 | } 30 | data class UniformRandomDistr(val from: Double, val to: Double) : RandomDistribution { 31 | override fun newValue(rnd: Random) = RandomValue.uniform(from, to, rnd) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WebSocketServerInitializer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.netty.channel.ChannelHandler 4 | import io.netty.channel.ChannelInitializer 5 | import io.netty.channel.socket.SocketChannel 6 | import io.netty.handler.codec.http.HttpObjectAggregator 7 | import io.netty.handler.codec.http.HttpServerCodec 8 | import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler 9 | import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler 10 | 11 | internal class WebSocketServerInitializer( 12 | private val connectionBuilder: ChannelHandler 13 | ) : ChannelInitializer() { 14 | 15 | override fun initChannel(ch: SocketChannel) { 16 | val pipeline = ch.pipeline() 17 | 18 | pipeline.addLast(HttpServerCodec()) 19 | pipeline.addLast(HttpObjectAggregator(65536)) 20 | pipeline.addLast(WebSocketServerCompressionHandler(0)) 21 | pipeline.addLast(WebSocketServerProtocolHandler("/", null, true)) 22 | pipeline.addLast(WebSocketServerHandshakeListener(connectionBuilder)) 23 | } // initChannel 24 | } // WebSocketServerInitializer 25 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/Bandwidth.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import java.util.concurrent.CompletableFuture 4 | import kotlin.time.Duration 5 | import kotlin.time.Duration.Companion.milliseconds 6 | 7 | data class Bandwidth(val bytesPerSecond: Long) { 8 | fun getTransmitTimeMillis(size: Long): Long = (size * 1000 / bytesPerSecond) 9 | fun getTransmitTime(size: Long): Duration = getTransmitTimeMillis(size).milliseconds 10 | 11 | fun getTransmitSize(timeMillis: Long): Long = 12 | bytesPerSecond * timeMillis / 1000 13 | 14 | operator fun div(d: Int) = Bandwidth(bytesPerSecond / d) 15 | 16 | companion object { 17 | val UNLIM = Bandwidth(Long.MAX_VALUE) 18 | fun mbitsPerSec(mbsec: Int) = Bandwidth(mbsec.toLong() * (1 shl 20) / 10) 19 | } 20 | } 21 | 22 | interface BandwidthDelayer : MessageDelayer { 23 | 24 | val totalBandwidth: Bandwidth 25 | 26 | companion object { 27 | val UNLIM_BANDWIDTH = object : BandwidthDelayer { 28 | override val totalBandwidth = Bandwidth.UNLIM 29 | override fun delay(size: Long) = CompletableFuture.completedFuture(Unit) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/Topology.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import io.libp2p.simulate.topology.CustomTopologyGraph 4 | import java.util.Random 5 | 6 | interface Topology { 7 | 8 | var random: Random 9 | 10 | fun generateGraph(verticesCount: Int): TopologyGraph 11 | } 12 | 13 | interface TopologyGraph { 14 | data class Edge(val srcV: Int, val destV: Int) 15 | 16 | val edges: Collection 17 | 18 | val vertices get() = 19 | edges.flatMap { listOf(it.srcV, it.destV) }.distinct().sorted() 20 | 21 | fun calcDiameter(): Int 22 | 23 | fun connect(peers: List): Network { 24 | require(peers.size == vertices.size) 25 | return edges 26 | .map { peers[it.srcV].connect(peers[it.destV]).join() } 27 | .let { ImmutableNetworkImpl(it, this) } 28 | } 29 | 30 | companion object { 31 | fun customTopology(vararg vertices: Pair) = 32 | CustomTopologyGraph( 33 | vertices.map { Edge(it.first, it.second) } 34 | ) 35 | } 36 | } 37 | 38 | fun Topology.generateAndConnect(peers: List) = generateGraph(peers.size).connect(peers) 39 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/MultiaddrUtils.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util 2 | 3 | import io.libp2p.core.InternalErrorException 4 | import io.libp2p.core.multiformats.Multiaddr 5 | import io.libp2p.core.multiformats.Protocol 6 | import java.net.* 7 | 8 | class MultiaddrUtils { 9 | 10 | companion object { 11 | 12 | fun inetAddressToIpMultiaddr(addr: InetAddress): Multiaddr { 13 | val proto = when (addr) { 14 | is Inet4Address -> Protocol.IP4 15 | is Inet6Address -> Protocol.IP6 16 | else -> throw InternalErrorException("Unknown address type $addr") 17 | } 18 | return Multiaddr.empty() 19 | .withComponent(proto, addr.hostAddress) 20 | } 21 | 22 | fun inetSocketAddressToTcpMultiaddr(addr: InetSocketAddress): Multiaddr = 23 | inetAddressToIpMultiaddr(addr.address) 24 | .withComponent(Protocol.TCP, addr.port.toString()) 25 | 26 | fun inetSocketAddressToUdpMultiaddr(addr: InetSocketAddress): Multiaddr = 27 | inetAddressToIpMultiaddr(addr.address) 28 | .withComponent(Protocol.UDP, addr.port.toString()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/multistream/MultistreamProtocolDebug.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.multistream 2 | 3 | import io.libp2p.core.P2PChannelHandler 4 | import io.libp2p.core.multistream.MultistreamProtocol 5 | import io.libp2p.core.multistream.MultistreamProtocolDebug 6 | import io.libp2p.core.multistream.ProtocolBinding 7 | import io.libp2p.etc.types.seconds 8 | import java.time.Duration 9 | 10 | val DEFAULT_NEGOTIATION_TIME_LIMIT = 10.seconds 11 | 12 | class MultistreamProtocolDebugV1( 13 | private val negotiationTimeLimit: Duration = DEFAULT_NEGOTIATION_TIME_LIMIT, 14 | private val preHandler: P2PChannelHandler<*>? = null, 15 | private val postHandler: P2PChannelHandler<*>? = null 16 | ) : MultistreamProtocolDebug { 17 | 18 | override val version = "1.0.0" 19 | 20 | override fun createMultistream(bindings: List>) = 21 | MultistreamImpl(bindings, preHandler, postHandler, negotiationTimeLimit) 22 | 23 | override fun copyWithHandlers( 24 | preHandler: P2PChannelHandler<*>?, 25 | postHandler: P2PChannelHandler<*>? 26 | ): MultistreamProtocol = MultistreamProtocolDebugV1(negotiationTimeLimit, preHandler, postHandler) 27 | } 28 | -------------------------------------------------------------------------------- /examples/android-chatter/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/security/SecureChannel.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.security 2 | 3 | import io.libp2p.core.PeerId 4 | import io.libp2p.core.crypto.PubKey 5 | import io.libp2p.core.multistream.ProtocolBinding 6 | import io.libp2p.core.mux.NegotiatedStreamMuxer 7 | 8 | /** 9 | * The SecureChannel interface is implemented by all security channels, such as SecIO, TLS 1.3, Noise, and so on. 10 | */ 11 | interface SecureChannel : ProtocolBinding { 12 | 13 | open class Session( 14 | /** 15 | * The peer ID of the local peer. 16 | */ 17 | val localId: PeerId, 18 | 19 | /** 20 | * The peer ID of the remote peer. 21 | */ 22 | val remoteId: PeerId, 23 | 24 | /** 25 | * The public key of the remote peer. 26 | */ 27 | val remotePubKey: PubKey, 28 | 29 | /** 30 | * Contains muxer if security protocol supports 31 | * [Early Multiplexer Negotiation](https://docs.libp2p.io/concepts/multiplex/early-negotiation/) 32 | * and the protocol was successfully negotiated. Else contains `null` 33 | */ 34 | val earlyMuxer: NegotiatedStreamMuxer? 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/TotalTimeoutHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.channel.ChannelException 4 | import io.netty.channel.ChannelHandlerAdapter 5 | import io.netty.channel.ChannelHandlerContext 6 | import java.time.Duration 7 | import java.util.concurrent.ScheduledFuture 8 | import java.util.concurrent.TimeUnit 9 | 10 | /** 11 | * Handler which closes connection on timeout unless removed 12 | */ 13 | class TotalTimeoutHandler(val timeout: Duration) : ChannelHandlerAdapter() { 14 | private var timeoutTask: ScheduledFuture<*>? = null 15 | 16 | override fun handlerAdded(ctx: ChannelHandlerContext) { 17 | timeoutTask = ctx.executor().schedule({ onTimeout(ctx) }, timeout.toMillis(), TimeUnit.MILLISECONDS) 18 | } 19 | 20 | override fun handlerRemoved(ctx: ChannelHandlerContext) { 21 | cancel() 22 | } 23 | 24 | private fun cancel() { 25 | timeoutTask?.cancel(false) 26 | } 27 | 28 | private fun onTimeout(ctx: ChannelHandlerContext) { 29 | ctx.fireExceptionCaught(TotalTimeoutException()) 30 | ctx.close() 31 | timeoutTask = null 32 | } 33 | } 34 | 35 | class TotalTimeoutException : ChannelException() 36 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/NettyUtil.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.libp2p.etc.types.addAfter 4 | import io.netty.channel.Channel 5 | import io.netty.channel.ChannelHandler 6 | import io.netty.channel.ChannelInitializer 7 | import io.netty.util.internal.StringUtil 8 | 9 | class NettyInit(val channel: Channel, thisHandler: ChannelHandler) { 10 | private var lastLocalHandler = thisHandler 11 | fun addLastLocal(handler: ChannelHandler) { 12 | channel.pipeline().addAfter(lastLocalHandler, generateName(channel, handler), handler) 13 | lastLocalHandler = handler 14 | } 15 | } 16 | 17 | fun nettyInitializer(initer: (NettyInit) -> Unit): ChannelInitializer { 18 | return object : ChannelInitializer() { 19 | override fun initChannel(ch: Channel) { 20 | initer.invoke(NettyInit(ch, this)) 21 | } 22 | } 23 | } 24 | 25 | private fun generateName(ch: Channel, handler: ChannelHandler): String { 26 | val className = StringUtil.simpleClassName(handler.javaClass) 27 | val names = ch.pipeline().names().toSet() 28 | return (0..Int.MAX_VALUE).asSequence().map { "$className#$it" }.find { it !in names } ?: "Unexpected" 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/identify.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package identify.pb; 4 | 5 | message Identify { 6 | 7 | // protocolVersion determines compatibility between peers 8 | optional string protocolVersion = 5; // e.g. ipfs/1.0.0 9 | 10 | // agentVersion is like a UserAgent string in browsers, or client version in bittorrent 11 | // includes the client name and client. 12 | optional string agentVersion = 6; // e.g. go-ipfs/0.1.0 13 | 14 | // publicKey is this node's public key (which also gives its node.ID) 15 | // - may not need to be sent, as secure channel implies it has been sent. 16 | // - then again, if we change / disable secure channel, may still want it. 17 | optional bytes publicKey = 1; 18 | 19 | // listenAddrs are the multiaddrs the sender node listens for open connections on 20 | repeated bytes listenAddrs = 2; 21 | 22 | // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives 23 | // this is useful information to convey to the other side, as it helps the remote endpoint 24 | // determine whether its connection to the local peer goes through NAT. 25 | optional bytes observedAddr = 4; 26 | 27 | // protocols are the services this node is running 28 | repeated string protocols = 3; 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/DoNothingProtocol.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | import io.libp2p.core.Stream 4 | import io.libp2p.core.multistream.StrictProtocolBinding 5 | import io.libp2p.protocol.ProtocolHandler 6 | import io.libp2p.protocol.ProtocolMessageHandler 7 | import io.netty.buffer.ByteBuf 8 | import java.util.concurrent.CompletableFuture 9 | 10 | interface DoNothingController 11 | 12 | class DoNothing : DoNothingBinding(DoNothingProtocol()) 13 | 14 | open class DoNothingBinding(nullProtocol: DoNothingProtocol) : 15 | StrictProtocolBinding("/ipfs/do-nothing/1.0.0", nullProtocol) 16 | 17 | class DoNothingProtocol : ProtocolHandler(Long.MAX_VALUE, Long.MAX_VALUE) { 18 | override fun onStartInitiator(stream: Stream) = addDoNothingHandler(stream) 19 | override fun onStartResponder(stream: Stream) = addDoNothingHandler(stream) 20 | 21 | private fun addDoNothingHandler(stream: Stream): CompletableFuture { 22 | val handler = DoNothingHandler() 23 | stream.pushHandler(handler) 24 | return CompletableFuture.completedFuture(handler) 25 | } 26 | 27 | inner class DoNothingHandler : ProtocolMessageHandler, DoNothingController 28 | } 29 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/util/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | // Copyright 2003-2012 Arthur van Hoff, Rick Blair 2 | // Licensed under Apache License version 2.0 3 | // Original license LGPL 4 | 5 | package io.libp2p.discovery.mdns.impl.util; 6 | 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.ThreadFactory; 9 | 10 | /** 11 | * Custom thread factory which sets the name to make it easier to identify where the pooled threads 12 | * were created. 13 | * 14 | * @author Trejkaz, Pierre Frisch 15 | */ 16 | public class NamedThreadFactory implements ThreadFactory { 17 | private final ThreadFactory _delegate; 18 | private final String _namePrefix; 19 | 20 | /** 21 | * Constructs the thread factory. 22 | * 23 | * @param namePrefix a prefix to append to thread names (will be separated from the default thread 24 | * name by a space.) 25 | */ 26 | public NamedThreadFactory(String namePrefix) { 27 | this._namePrefix = namePrefix; 28 | _delegate = Executors.defaultThreadFactory(); 29 | } 30 | 31 | @Override 32 | public Thread newThread(Runnable runnable) { 33 | Thread thread = _delegate.newThread(runnable); 34 | thread.setName(_namePrefix + ' ' + thread.getName()); 35 | return thread; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tools/simulator/README.md: -------------------------------------------------------------------------------- 1 | # jvm-libp2p Gossip simulator 2 | 3 | ## Description 4 | 5 | This is Gossip simulator which may simulate networks as large as 10000 peers 6 | 7 | The simulator is _deterministic_. That is: 8 | - yields 100% identical results across different runs with the same configuration and the same random seed 9 | - a simulation may forward current time as needed 10 | 11 | ## Configuring simulation 12 | 13 | All simulations are configured programmatically inside the simulation code. 14 | 15 | You could make a copy of an existing simulation (from `io.libp2p.simulate.main` package) or create a new one 16 | and change simulation configuration right in the Kotlin class 17 | 18 | ## Running simulation with gradle 19 | 20 | Any main function could be run from CLI with gradle using the following syntax: 21 | ```shell 22 | > gradle :tools:simulator:run -PmainClass= [--args="you args"] 23 | ``` 24 | 25 | For example to run the sample simulation use the command below: 26 | ```shell 27 | > gradle :tools:simulator:run -PmainClass=io.libp2p.simulate.main.SimpleSimulationKt 28 | ``` 29 | 30 | ## License 31 | 32 | Dual-licensed under MIT and ASLv2, by way of the [Permissive License 33 | Stack](https://protocol.ai/blog/announcing-the-permissive-license-stack/). 34 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/util/netty/StringSuffixCodecTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.channel.embedded.EmbeddedChannel 4 | import io.netty.handler.codec.DecoderException 5 | import org.junit.jupiter.api.Assertions.assertEquals 6 | import org.junit.jupiter.api.Test 7 | import org.junit.jupiter.api.assertThrows 8 | 9 | class StringSuffixCodecTest { 10 | val channel = EmbeddedChannel(StringSuffixCodec('\n')) 11 | 12 | @Test 13 | fun encodeAppendTrailingChar() { 14 | channel.writeOutbound("theMessage") 15 | val result = channel.readOutbound() 16 | assertEquals(result, "theMessage\n") 17 | } 18 | 19 | @Test 20 | fun decodeStripsTrailingChar() { 21 | channel.writeInbound("theMessage\n") 22 | val result = channel.readInbound() 23 | assertEquals(result, "theMessage") 24 | } 25 | 26 | @Test 27 | fun decodeOnlyStripsSingleTrailingChar() { 28 | channel.writeInbound("theMessage\n\n") 29 | val result = channel.readInbound() 30 | assertEquals(result, "theMessage\n") 31 | } 32 | 33 | @Test 34 | fun decodeThrowsWhenTrailingCharMissing() { 35 | assertThrows { channel.writeInbound("theMessage") } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/implementation/StreamOverNetty.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.implementation 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.PeerId 5 | import io.libp2p.core.Stream 6 | import io.libp2p.etc.PROTOCOL 7 | import io.libp2p.etc.types.toVoidCompletableFuture 8 | import io.netty.channel.Channel 9 | import java.util.concurrent.CompletableFuture 10 | 11 | open class StreamOverNetty( 12 | ch: Channel, 13 | override val connection: Connection, 14 | initiator: Boolean 15 | ) : Stream, P2PChannelOverNetty(ch, initiator) { 16 | init { 17 | nettyChannel.attr(PROTOCOL).set(CompletableFuture()) 18 | } 19 | 20 | /** 21 | * Returns the [PeerId] of the remote peer [Connection] which this 22 | * [Stream] created on 23 | */ 24 | override fun remotePeerId() = connection.secureSession().remoteId 25 | 26 | /** 27 | * @return negotiated protocol 28 | */ 29 | override fun getProtocol(): CompletableFuture = nettyChannel.attr(PROTOCOL).get() 30 | 31 | override fun writeAndFlush(msg: Any) { 32 | nettyChannel.writeAndFlush(msg) 33 | } 34 | 35 | override fun closeWrite(): CompletableFuture { 36 | return nettyChannel.disconnect().toVoidCompletableFuture() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/package-info.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.discovery.mdns; 2 | 3 | /** 4 | * Java code in this package is derived from the JmDNS project. 5 | * 6 | *

JmDNS is a Java implementation of multi-cast DNS and can be used for service registration and 7 | * discovery in local area networks. JmDNS is fully compatible with Apple's Bonjour. The project was 8 | * originally started in December 2002 by Arthur van Hoff at Strangeberry. In November 2003 the 9 | * project was moved to SourceForge, and the name was changed from JRendezvous to JmDNS for legal 10 | * reasons. Many thanks to Stuart Cheshire for help and moral support. In 2014, it was been moved 11 | * from Sourceforge to Github by Kai Kreuzer with the kind approval from Arthur and Rick. 12 | * 13 | *

https://github.com/jmdns/jmdns/ JmDNS was 14 | * originally licensed under the GNU Lesser General Public License as jRendevous. It was re-released 15 | * under the Apache License, Version 2.0 in 2005. It is under those terms it is reused here. 16 | * 17 | *

JmDNS License Notice
18 | * JmDNS 20 | * Changelog 21 | */ 22 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/ControlledSchedulers.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | import java.time.Duration; 4 | 5 | /** 6 | * Special Schedulers implementation which is mostly suitable for testing and simulation. The system 7 | * time is controlled manually and all the schedulers execute tasks according to this time. Initial 8 | * system time is equal to 0 9 | */ 10 | public interface ControlledSchedulers extends Schedulers { 11 | 12 | /** 13 | * Sets current time. 14 | * 15 | * @throws IllegalStateException if this instance is dependent on a parent {@link TimeController} 16 | * @see TimeController#setTime(long) 17 | */ 18 | default void setCurrentTime(long newTime) { 19 | getTimeController().setTime(newTime); 20 | } 21 | 22 | /** Just a handy helper method for {@link #setCurrentTime(long)} */ 23 | default void addTime(Duration duration) { 24 | addTime(duration.toMillis()); 25 | } 26 | 27 | /** Just a handy helper method for {@link #setCurrentTime(long)} */ 28 | default void addTime(long millis) { 29 | setCurrentTime(getCurrentTime() + millis); 30 | } 31 | 32 | /** 33 | * Returns {@link TimeController} which manages tasks ordered execution and supplies current time 34 | * for this instance 35 | */ 36 | TimeController getTimeController(); 37 | } 38 | -------------------------------------------------------------------------------- /examples/pinger/src/main/java/io/libp2p/example/ping/Pinger.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.example.ping; 2 | 3 | import io.libp2p.core.Host; 4 | import io.libp2p.core.dsl.HostBuilder; 5 | import io.libp2p.core.multiformats.Multiaddr; 6 | import io.libp2p.protocol.Ping; 7 | import io.libp2p.protocol.PingController; 8 | import java.util.concurrent.ExecutionException; 9 | 10 | public class Pinger { 11 | public static void main(String[] args) throws ExecutionException, InterruptedException { 12 | // Create a libp2p node and configure it 13 | // to accept TCP connections on a random port 14 | Host node = new HostBuilder().protocol(new Ping()).listen("/ip4/127.0.0.1/tcp/0").build(); 15 | 16 | // start listening 17 | node.start().get(); 18 | 19 | System.out.print("Node started and listening on "); 20 | System.out.println(node.listenAddresses()); 21 | 22 | if (args.length > 0) { 23 | Multiaddr address = Multiaddr.fromString(args[0]); 24 | PingController pinger = new Ping().dial(node, address).getController().get(); 25 | 26 | System.out.println("Sending 5 ping messages to " + address.toString()); 27 | for (int i = 1; i <= 5; ++i) { 28 | long latency = pinger.ping().get(); 29 | System.out.println("Ping " + i + ", latency " + latency + "ms"); 30 | } 31 | 32 | node.stop().get(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/delay/ChannelMessageDelayer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.delay 2 | 3 | import io.libp2p.simulate.BandwidthDelayer 4 | import io.libp2p.simulate.MessageDelayer 5 | import io.libp2p.simulate.delay.SequentialDelayer.Companion.sequential 6 | import java.util.concurrent.CompletableFuture 7 | import java.util.concurrent.ScheduledExecutorService 8 | 9 | class ChannelMessageDelayer( 10 | executor: ScheduledExecutorService, 11 | localOutboundBandwidthDelayer: BandwidthDelayer, 12 | connectionLatencyDelayer: MessageDelayer, 13 | remoteInboundBandwidthDelayer: BandwidthDelayer, 14 | ) : MessageDelayer { 15 | 16 | private val sequentialOutboundBandwidthDelayer = localOutboundBandwidthDelayer.sequential(executor) 17 | private val sequentialInboundBandwidthDelayer = remoteInboundBandwidthDelayer.sequential(executor) 18 | 19 | private val delayer = MessageDelayer { size -> 20 | CompletableFuture.allOf( 21 | sequentialOutboundBandwidthDelayer.delay(size) 22 | .thenCompose { connectionLatencyDelayer.delay(size) }, 23 | connectionLatencyDelayer.delay(size) 24 | .thenCompose { sequentialInboundBandwidthDelayer.delay(size) } 25 | ).thenApply { } 26 | } 27 | 28 | override fun delay(size: Long): CompletableFuture = delayer.delay(size) 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/P2PChannel.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.netty.channel.ChannelHandler 4 | import java.util.concurrent.CompletableFuture 5 | 6 | interface P2PChannel { 7 | /** 8 | * Indicates whether this peer is either _initiator_ or _responder_ of the underlying channel 9 | * Most of the protocols behave either as a _client_ or _server_ correspondingly depending 10 | * on this flag 11 | */ 12 | val isInitiator: Boolean 13 | 14 | /** 15 | * Inserts [ChannelHandler]s at the last position of this pipeline. 16 | */ 17 | fun pushHandler(handler: ChannelHandler) 18 | 19 | /** 20 | * Appends a [ChannelHandler] at the last position of this pipeline. 21 | */ 22 | fun pushHandler(name: String, handler: ChannelHandler) 23 | 24 | /** 25 | * Inserts a [ChannelHandler] before an existing handler of this 26 | * pipeline. 27 | */ 28 | fun addHandlerBefore(baseName: String, name: String, handler: ChannelHandler) 29 | 30 | /** 31 | * Closes the channel. Returns a [CompletableFuture] which completes when the 32 | * channel has closed 33 | */ 34 | fun close(): CompletableFuture 35 | 36 | /** 37 | * Returns the [CompletableFuture] which is completed when this channel is closed 38 | */ 39 | fun closeFuture(): CompletableFuture 40 | } 41 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/CachingChannelPipeline.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.channel.Channel 4 | import io.netty.channel.DefaultChannelPipeline 5 | 6 | // TODO experimental 7 | class CachingChannelPipeline(channel: Channel) : DefaultChannelPipeline(channel) { 8 | 9 | enum class EventType { Message, Exception, UserEvent, Active, Inactive } 10 | class Event(val type: EventType, val data: Any?) 11 | 12 | override fun onUnhandledInboundMessage(msg: Any?) { 13 | super.onUnhandledInboundMessage(msg) 14 | } 15 | 16 | override fun onUnhandledInboundChannelReadComplete() { 17 | super.onUnhandledInboundChannelReadComplete() 18 | } 19 | 20 | override fun onUnhandledInboundUserEventTriggered(evt: Any?) { 21 | super.onUnhandledInboundUserEventTriggered(evt) 22 | } 23 | 24 | override fun onUnhandledInboundException(cause: Throwable?) { 25 | super.onUnhandledInboundException(cause) 26 | } 27 | 28 | override fun onUnhandledChannelWritabilityChanged() { 29 | super.onUnhandledChannelWritabilityChanged() 30 | } 31 | 32 | override fun onUnhandledInboundChannelActive() { 33 | super.onUnhandledInboundChannelActive() 34 | } 35 | 36 | override fun onUnhandledInboundChannelInactive() { 37 | super.onUnhandledInboundChannelInactive() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/envelope.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package io.libp2p.protocol.circuit.crypto.pb; 4 | 5 | enum KeyType { 6 | RSA = 0; 7 | Ed25519 = 1; 8 | Secp256k1 = 2; 9 | ECDSA = 3; 10 | Curve25519 = 4; 11 | } 12 | 13 | message PublicKey { 14 | KeyType Type = 1; 15 | bytes Data = 2; 16 | } 17 | 18 | message PrivateKey { 19 | KeyType Type = 1; 20 | bytes Data = 2; 21 | } 22 | 23 | // Envelope encloses a signed payload produced by a peer, along with the public 24 | // key of the keypair it was signed with so that it can be statelessly validated 25 | // by the receiver. 26 | // 27 | // The payload is prefixed with a byte string that determines the type, so it 28 | // can be deserialized deterministically. Often, this byte string is a 29 | // multicodec. 30 | message Envelope { 31 | // public_key is the public key of the keypair the enclosed payload was 32 | // signed with. 33 | PublicKey public_key = 1; 34 | 35 | // payload_type encodes the type of payload, so that it can be deserialized 36 | // deterministically. 37 | bytes payload_type = 2; 38 | 39 | // payload is the actual payload carried inside this envelope. 40 | bytes payload = 3; 41 | 42 | // signature is the signature produced by the private key corresponding to 43 | // the enclosed public key, over the payload, prefixing a domain string for 44 | // additional security. 45 | bytes signature = 5; 46 | } 47 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/relay.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package relay.pb; 4 | 5 | message CircuitRelay { 6 | 7 | enum Status { 8 | SUCCESS = 100; 9 | HOP_SRC_ADDR_TOO_LONG = 220; 10 | HOP_DST_ADDR_TOO_LONG = 221; 11 | HOP_SRC_MULTIADDR_INVALID = 250; 12 | HOP_DST_MULTIADDR_INVALID = 251; 13 | HOP_NO_CONN_TO_DST = 260; 14 | HOP_CANT_DIAL_DST = 261; 15 | HOP_CANT_OPEN_DST_STREAM = 262; 16 | HOP_CANT_SPEAK_RELAY = 270; 17 | HOP_CANT_RELAY_TO_SELF = 280; 18 | STOP_SRC_ADDR_TOO_LONG = 320; 19 | STOP_DST_ADDR_TOO_LONG = 321; 20 | STOP_SRC_MULTIADDR_INVALID = 350; 21 | STOP_DST_MULTIADDR_INVALID = 351; 22 | STOP_RELAY_REFUSED = 390; 23 | MALFORMED_MESSAGE = 400; 24 | } 25 | 26 | enum Type { // RPC identifier, either HOP, STOP or STATUS 27 | HOP = 1; 28 | STOP = 2; 29 | STATUS = 3; 30 | CAN_HOP = 4; 31 | } 32 | 33 | message Peer { 34 | required bytes id = 1; // peer id 35 | repeated bytes addrs = 2; // peer's known addresses 36 | } 37 | 38 | optional Type type = 1; // Type of the message 39 | 40 | optional Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STOP 41 | optional Peer dstPeer = 3; 42 | 43 | optional Status code = 4; // Status code, used when Type is STATUS 44 | } 45 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/ControlledSchedulersImpl.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ScheduledExecutorService; 5 | 6 | public class ControlledSchedulersImpl extends AbstractSchedulers implements ControlledSchedulers { 7 | 8 | private TimeController timeController = new TimeControllerImpl(); 9 | 10 | @Override 11 | public long getCurrentTime() { 12 | return timeController.getTime(); 13 | } 14 | 15 | @Override 16 | public void setCurrentTime(long newTime) { 17 | timeController.setTime(newTime); 18 | } 19 | 20 | @Override 21 | protected Scheduler createExecutorScheduler(ScheduledExecutorService executorService) { 22 | return new ErrorHandlingScheduler( 23 | new ExecutorScheduler(executorService, this::getCurrentTime), e -> e.printStackTrace()); 24 | } 25 | 26 | @Override 27 | protected ScheduledExecutorService createExecutor(String namePattern, int threads) { 28 | ControlledExecutorServiceImpl service = 29 | new ControlledExecutorServiceImpl(createDelegateExecutor()); 30 | service.setTimeController(timeController); 31 | return service; 32 | } 33 | 34 | @Override 35 | public TimeController getTimeController() { 36 | return timeController; 37 | } 38 | 39 | protected Executor createDelegateExecutor() { 40 | return Runnable::run; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libp2p/src/main/proto/circuit.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package io.libp2p.protocol.circuit.pb; 4 | 5 | message HopMessage { 6 | enum Type { 7 | RESERVE = 0; 8 | CONNECT = 1; 9 | STATUS = 2; 10 | } 11 | 12 | required Type type = 1; 13 | 14 | optional Peer peer = 2; 15 | optional Reservation reservation = 3; 16 | optional Limit limit = 4; 17 | 18 | optional Status status = 5; 19 | } 20 | 21 | message StopMessage { 22 | enum Type { 23 | CONNECT = 0; 24 | STATUS = 1; 25 | } 26 | 27 | required Type type = 1; 28 | 29 | optional Peer peer = 2; 30 | optional Limit limit = 3; 31 | 32 | optional Status status = 4; 33 | } 34 | 35 | message Peer { 36 | required bytes id = 1; 37 | repeated bytes addrs = 2; 38 | } 39 | 40 | message Reservation { 41 | required uint64 expire = 1; // Unix expiration time (UTC) 42 | repeated bytes addrs = 2; // relay addrs for reserving peer 43 | optional bytes voucher = 3; // reservation voucher 44 | } 45 | 46 | message Limit { 47 | optional uint32 duration = 1; // seconds 48 | optional uint64 data = 2; // bytes 49 | } 50 | 51 | enum Status { 52 | OK = 100; 53 | RESERVATION_REFUSED = 200; 54 | RESOURCE_LIMIT_EXCEEDED = 201; 55 | PERMISSION_DENIED = 202; 56 | CONNECTION_FAILED = 203; 57 | NO_RESERVATION = 204; 58 | MALFORMED_MESSAGE = 400; 59 | UNEXPECTED_MESSAGE = 401; 60 | } 61 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/AbstractSimPeer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate 2 | 3 | import java.util.* 4 | import java.util.concurrent.CompletableFuture 5 | import java.util.concurrent.atomic.AtomicInteger 6 | import kotlin.collections.ArrayList 7 | 8 | abstract class AbstractSimPeer : SimPeer { 9 | 10 | override val simPeerId = counter.getAndIncrement() 11 | 12 | override val connections: MutableList = Collections.synchronizedList(ArrayList()) 13 | 14 | override fun connect(other: SimPeer): CompletableFuture { 15 | return connectImpl(other).thenApply { conn -> 16 | val otherAbs = other as? AbstractSimPeer 17 | connections += conn 18 | otherAbs?.connections?.add(conn) 19 | conn.closed.thenAccept { 20 | connections -= conn 21 | otherAbs?.connections?.remove(conn) 22 | } 23 | conn 24 | } 25 | } 26 | 27 | abstract fun connectImpl(other: SimPeer): CompletableFuture 28 | 29 | override fun equals(other: Any?): Boolean { 30 | if (this === other) return true 31 | if (javaClass != other?.javaClass) return false 32 | other as AbstractSimPeer 33 | return name == other.name 34 | } 35 | 36 | override fun hashCode(): Int = name.hashCode() 37 | 38 | companion object { 39 | val counter = AtomicInteger() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/crypto/KeyTypesTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.crypto 2 | 3 | import io.libp2p.crypto.keys.generateEcdsaKeyPair 4 | import io.libp2p.crypto.keys.generateEd25519KeyPair 5 | import io.libp2p.crypto.keys.generateRsaKeyPair 6 | import io.libp2p.crypto.keys.generateSecp256k1KeyPair 7 | import org.junit.jupiter.api.Assertions.assertTrue 8 | import org.junit.jupiter.api.Test 9 | 10 | class KeyTypesTest { 11 | 12 | @Test 13 | fun ed25519() { 14 | val pair = generateEd25519KeyPair() 15 | val toSign = "G'day!".toByteArray() 16 | val signed = pair.first.sign(toSign) 17 | assertTrue(pair.second.verify(toSign, signed)) 18 | } 19 | 20 | @Test 21 | fun rsa() { 22 | val pair = generateRsaKeyPair(2048) 23 | val toSign = "G'day!".toByteArray() 24 | val signed = pair.first.sign(toSign) 25 | assertTrue(pair.second.verify(toSign, signed)) 26 | } 27 | 28 | @Test 29 | fun secp256k1() { 30 | val pair = generateSecp256k1KeyPair() 31 | val toSign = "G'day!".toByteArray() 32 | val signed = pair.first.sign(toSign) 33 | assertTrue(pair.second.verify(toSign, signed)) 34 | } 35 | 36 | @Test 37 | fun ecdsa() { 38 | val pair = generateEcdsaKeyPair() // p-256 39 | val toSign = "G'day!".toByteArray() 40 | val signed = pair.first.sign(toSign) 41 | assertTrue(pair.second.verify(toSign, signed)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/multistream/Multistream.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core.multistream 2 | 3 | import io.libp2p.core.P2PChannelHandler 4 | 5 | /** 6 | * Represents 'multistream' concept: https://github.com/multiformats/multistream-select 7 | * 8 | * This is a handler which can be applied to either [io.libp2p.core.Connection] or [io.libp2p.core.Stream] 9 | * performs the negotiation with remote party on supported protocol and sets up the corresponding 10 | * protocol handler. 11 | * 12 | * The distinction should be made between _initiator_ and _responder_ [Multistream] roles. 13 | * 14 | * The _initiator_ [Multistream] basically has only a single [bindings] entry with desired protocol or 15 | * a set of bindings for different protocol versions. The first matching protocol is initiated and 16 | * the protocol [TController] is supplied to the client for further actions 17 | * 18 | * The _responder_ [Multistream] basically contains the list of all supported protocols. 19 | * The protocol is instantiated by a remote request 20 | */ 21 | interface Multistream : P2PChannelHandler { 22 | 23 | /** 24 | * For _responder_ role this is the list of all supported protocols for this peer 25 | * For _initiator_ role this is the list of protocols the initiator wants to instantiate. 26 | * Basically this is either a single protocol or a protocol versions 27 | */ 28 | val bindings: List> 29 | } 30 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/etc/util/netty/ByteBufQueue.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.util.netty 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.buffer.Unpooled 5 | 6 | class ByteBufQueue { 7 | private val data: MutableList = mutableListOf() 8 | 9 | fun push(buf: ByteBuf) { 10 | data += buf 11 | } 12 | 13 | fun take(maxLength: Int): ByteBuf { 14 | val wholeBuffers = mutableListOf() 15 | var size = 0 16 | while (data.isNotEmpty()) { 17 | val bufLen = data.first().readableBytes() 18 | if (size + bufLen > maxLength) break 19 | size += bufLen 20 | wholeBuffers += data.removeAt(0) 21 | if (size == maxLength) break 22 | } 23 | 24 | val partialBufferSlice = 25 | when { 26 | data.isEmpty() -> null 27 | size == maxLength -> null 28 | else -> data.first() 29 | } 30 | ?.let { buf -> 31 | val remainingBytes = maxLength - size 32 | buf.readRetainedSlice(remainingBytes) 33 | } 34 | 35 | val allBuffers = wholeBuffers + listOfNotNull(partialBufferSlice) 36 | return Unpooled.wrappedBuffer(*allBuffers.toTypedArray()) 37 | } 38 | 39 | fun dispose() { 40 | data.forEach { it.release() } 41 | } 42 | 43 | fun readableBytes(): Int = data.sumOf { it.readableBytes() } 44 | } 45 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/pubsub/AllowlistTopicSubscriptionFilterTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | import org.assertj.core.api.Assertions.assertThat 4 | import org.junit.jupiter.api.Test 5 | 6 | internal class AllowlistTopicSubscriptionFilterTest { 7 | 8 | private val filter = AllowlistTopicSubscriptionFilter(hashSetOf("a", "b", "c", "d")) 9 | 10 | @Test 11 | fun `only allow whitelisted topics`() { 12 | val result = filter.filterIncomingSubscriptions( 13 | listOf( 14 | PubsubSubscription("a", true), 15 | PubsubSubscription("b", false), 16 | PubsubSubscription("c", true), 17 | PubsubSubscription("d", true), 18 | PubsubSubscription("e", true), 19 | PubsubSubscription("f", false), 20 | PubsubSubscription("g", false), 21 | ), 22 | listOf() 23 | ) 24 | 25 | assertThat(result).isEqualTo( 26 | listOf( 27 | PubsubSubscription("a", true), 28 | PubsubSubscription("b", false), 29 | PubsubSubscription("c", true), 30 | PubsubSubscription("d", true), 31 | ) 32 | ) 33 | } 34 | 35 | @Test 36 | fun `return empty list when no allowed topics`() { 37 | val result = filter.filterIncomingSubscriptions(listOf(PubsubSubscription("nope", true)), listOf()) 38 | assertThat(result).isEmpty() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/DaemonLauncher.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | 8 | public class DaemonLauncher { 9 | 10 | public static class Daemon { 11 | public final P2PDHost host; 12 | private final Process process; 13 | 14 | public Daemon(P2PDHost host, Process process) { 15 | this.host = host; 16 | this.process = process; 17 | } 18 | 19 | public void kill() { 20 | process.destroyForcibly(); 21 | } 22 | } 23 | 24 | private final String daemonPath; 25 | private int commandPort = 11111; 26 | 27 | public DaemonLauncher(String daemonPath) { 28 | this.daemonPath = daemonPath; 29 | } 30 | 31 | public Daemon launch(int nodePort, String... commandLineArgs) { 32 | ArrayList args = new ArrayList<>(); 33 | int cmdPort = commandPort++; 34 | args.add(daemonPath); 35 | args.add("-listen"); 36 | args.add("/ip4/127.0.0.1/tcp/" + cmdPort); 37 | args.add("-hostAddrs"); 38 | args.add("/ip4/127.0.0.1/tcp/" + nodePort); 39 | args.addAll(Arrays.asList(commandLineArgs)); 40 | try { 41 | Process process = new ProcessBuilder(args).inheritIO().start(); 42 | return new Daemon(new P2PDHost(new InetSocketAddress("127.0.0.1", cmdPort)), process); 43 | } catch (IOException e) { 44 | throw new RuntimeException(e); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/pubsub/gossip/GossipTwoHostTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub.gossip 2 | 3 | import io.libp2p.core.pubsub.MessageApi 4 | import io.libp2p.core.pubsub.Subscriber 5 | import io.libp2p.core.pubsub.Topic 6 | import io.libp2p.etc.types.toByteArray 7 | import io.libp2p.etc.types.toByteBuf 8 | import io.libp2p.mux.mplex.DEFAULT_MAX_MPLEX_FRAME_DATA_LENGTH 9 | import org.assertj.core.api.Assertions.assertThat 10 | import org.junit.jupiter.api.Test 11 | import java.util.concurrent.TimeUnit 12 | 13 | class GossipTwoHostTest : TwoGossipHostTestBase() { 14 | 15 | override val params = GossipParams(maxGossipMessageSize = DEFAULT_MAX_MPLEX_FRAME_DATA_LENGTH * 2) 16 | 17 | @Test 18 | fun `test message larger than mplex frame`() { 19 | connect() 20 | 21 | val topic = Topic("topic") 22 | 23 | val messages = mutableListOf() 24 | gossip2.subscribe(Subscriber { messages += it }, topic) 25 | 26 | waitForSubscribed(router1, topic.topic) 27 | 28 | val msgSize = DEFAULT_MAX_MPLEX_FRAME_DATA_LENGTH + 10 29 | val msgBytes = ByteArray(msgSize) { 0xab.toByte() } 30 | 31 | val res = gossip1.createPublisher(null) 32 | .publish(msgBytes.toByteBuf(), topic) 33 | 34 | res.get(10, TimeUnit.SECONDS) 35 | 36 | waitFor { messages.isNotEmpty() } 37 | 38 | assertThat(messages) 39 | .hasSize(1) 40 | .allMatch { it.data.toByteArray().contentEquals(msgBytes) } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/P2PChannelHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.etc.BroadcastChannelVisitor 4 | import java.util.concurrent.CompletableFuture 5 | 6 | /** 7 | * The central entry point for every protocol which is responsible for initializing [P2PChannel] 8 | */ 9 | fun interface P2PChannelHandler { 10 | 11 | /** 12 | * Should initialize the underlying Netty [io.netty.channel.Channel] **synchronously** 13 | * and **on the calling thread** 14 | * Returns the [Future] which is completed with the protocol [TController] 15 | * when all necessary protocol negotiations are done. 16 | */ 17 | fun initChannel(ch: P2PChannel): CompletableFuture 18 | 19 | fun toStreamHandler(): StreamHandler = StreamHandler { stream -> initChannel(stream) } 20 | } 21 | 22 | fun interface ChannelVisitor { 23 | 24 | fun visit(channel: TChannel) 25 | 26 | fun toChannelHandler(): P2PChannelHandler = P2PChannelHandler { 27 | @Suppress("UNCHECKED_CAST") 28 | visit(it as TChannel) 29 | CompletableFuture.completedFuture(Unit) 30 | } 31 | 32 | interface Broadcast : ChannelVisitor, MutableList> 33 | 34 | companion object { 35 | fun createBroadcast(vararg handlers: ChannelVisitor) = 36 | BroadcastChannelVisitor().also { it += handlers } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/implementation/ConnectionOverNetty.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.implementation 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.multiformats.Multiaddr 5 | import io.libp2p.core.mux.StreamMuxer 6 | import io.libp2p.core.security.SecureChannel 7 | import io.libp2p.etc.CONNECTION 8 | import io.netty.channel.Channel 9 | 10 | /** 11 | * A Connection is a high-level wrapper around a Netty Channel representing the conduit to a peer. 12 | * 13 | * It exposes libp2p components and semantics via methods and properties. 14 | */ 15 | open class ConnectionOverNetty( 16 | ch: Channel, 17 | private val nettyTransport: NettyTransport, 18 | initiator: Boolean 19 | ) : Connection, P2PChannelOverNetty(ch, initiator) { 20 | private lateinit var muxerSession: StreamMuxer.Session 21 | private lateinit var secureSession: SecureChannel.Session 22 | 23 | init { 24 | ch.attr(CONNECTION).set(this) 25 | } 26 | 27 | fun setMuxerSession(ms: StreamMuxer.Session) { 28 | muxerSession = ms 29 | } 30 | fun setSecureSession(ss: SecureChannel.Session) { 31 | secureSession = ss 32 | } 33 | 34 | override fun muxerSession() = muxerSession 35 | override fun secureSession() = secureSession 36 | override fun transport() = nettyTransport 37 | 38 | override fun localAddress(): Multiaddr = nettyTransport.localAddress(nettyChannel) 39 | override fun remoteAddress(): Multiaddr = nettyTransport.remoteAddress(nettyChannel) 40 | } 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest a new feature in jvm-libp2p 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | If you'd like to suggest a feature related to libp2p but not specifically related to the JVM implementation, please file an issue at https://github.com/libp2p/specs instead. 8 | - type: textarea 9 | attributes: 10 | label: Description 11 | description: Briefly describe the feature that you are requesting. 12 | validations: 13 | required: true 14 | - type: textarea 15 | attributes: 16 | label: Motivation 17 | description: Explain why this feature is needed. 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Requirements 23 | description: Write a list of what you want this feature to do. 24 | placeholder: "1." 25 | validations: 26 | required: true 27 | - type: textarea 28 | attributes: 29 | label: Open questions 30 | description: Use this section to ask any questions that are related to the feature. 31 | validations: 32 | required: false 33 | - type: dropdown 34 | attributes: 35 | label: Are you planning to do it yourself in a pull request ? 36 | description: Any contribution is greatly appreciated. We are more than happy to provide help on the process. 37 | options: 38 | - "Yes" 39 | - "No" 40 | - Maybe 41 | validations: 42 | required: true 43 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/mplex/MplexStreamMuxer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.mplex 2 | 3 | import io.libp2p.core.ChannelVisitor 4 | import io.libp2p.core.Connection 5 | import io.libp2p.core.P2PChannel 6 | import io.libp2p.core.StreamHandler 7 | import io.libp2p.core.multistream.MultistreamProtocol 8 | import io.libp2p.core.multistream.ProtocolDescriptor 9 | import io.libp2p.core.mux.StreamMuxer 10 | import io.libp2p.core.mux.StreamMuxerDebug 11 | import java.util.concurrent.CompletableFuture 12 | 13 | class MplexStreamMuxer( 14 | val inboundStreamHandler: StreamHandler<*>, 15 | private val multistreamProtocol: MultistreamProtocol 16 | ) : StreamMuxer, StreamMuxerDebug { 17 | 18 | override val protocolDescriptor = ProtocolDescriptor("/mplex/6.7.0") 19 | override var muxFramesDebugHandler: ChannelVisitor? = null 20 | 21 | override fun initChannel(ch: P2PChannel, selectedProtocol: String): CompletableFuture { 22 | val muxSessionReady = CompletableFuture() 23 | 24 | val mplexFrameCodec = MplexFrameCodec() 25 | ch.pushHandler(mplexFrameCodec) 26 | muxFramesDebugHandler?.also { it.visit(ch as Connection) } 27 | ch.pushHandler( 28 | MplexHandler( 29 | multistreamProtocol, 30 | mplexFrameCodec.maxFrameDataLength, 31 | muxSessionReady, 32 | inboundStreamHandler 33 | ) 34 | ) 35 | 36 | return muxSessionReady 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/LoggerMDCExecutor.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.Executor; 6 | import java.util.function.Supplier; 7 | import org.slf4j.MDC; 8 | 9 | public class LoggerMDCExecutor implements Executor { 10 | 11 | private final List mdcKeys = new ArrayList<>(); 12 | private final List> mdcValueSuppliers = new ArrayList<>(); 13 | private final Executor delegateExecutor; 14 | 15 | public LoggerMDCExecutor() { 16 | this(Runnable::run); 17 | } 18 | 19 | public LoggerMDCExecutor(Executor delegateExecutor) { 20 | this.delegateExecutor = delegateExecutor; 21 | } 22 | 23 | public LoggerMDCExecutor add(String mdcKey, Supplier mdcValueSupplier) { 24 | mdcKeys.add(mdcKey); 25 | mdcValueSuppliers.add(mdcValueSupplier); 26 | return this; 27 | } 28 | 29 | @Override 30 | public void execute(Runnable command) { 31 | List oldValues = new ArrayList<>(mdcKeys.size()); 32 | for (int i = 0; i < mdcKeys.size(); i++) { 33 | oldValues.add(MDC.get(mdcKeys.get(i))); 34 | MDC.put(mdcKeys.get(i), mdcValueSuppliers.get(i).get()); 35 | } 36 | delegateExecutor.execute(command); 37 | for (int i = 0; i < mdcKeys.size(); i++) { 38 | if (oldValues.get(i) == null) { 39 | MDC.remove(mdcKeys.get(i)); 40 | } else { 41 | MDC.put(mdcKeys.get(i), oldValues.get(i)); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/encode/Base58Test.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.encode 2 | 3 | import org.junit.jupiter.api.Assertions.assertArrayEquals 4 | import org.junit.jupiter.api.Assertions.assertEquals 5 | import org.junit.jupiter.params.ParameterizedTest 6 | import org.junit.jupiter.params.provider.Arguments 7 | import org.junit.jupiter.params.provider.MethodSource 8 | import java.math.BigInteger 9 | 10 | class Base58Test { 11 | 12 | companion object { 13 | @JvmStatic 14 | fun params() = listOf( 15 | Arguments.of("hello world", "Hello World".toByteArray(), "JxF12TrwUP45BMd"), 16 | Arguments.of("number", BigInteger.valueOf(3471844090L).toByteArray(), "16Ho7Hs"), 17 | Arguments.of("zero 1 lengthBits", ByteArray(1), "1"), 18 | Arguments.of("zero 7 lengthBits", ByteArray(7), "1111111"), 19 | Arguments.of("nil", ByteArray(0), "") 20 | ) 21 | } 22 | 23 | @ParameterizedTest 24 | @MethodSource("params") 25 | fun `Base58 circular encoding - decoding works`( 26 | @Suppress("UNUSED_PARAMETER")name: String, 27 | bytes: ByteArray, 28 | encoded: String 29 | ) { 30 | val (enc, dec) = Pair(Base58.encode(bytes), Base58.decode(encoded)) 31 | assertArrayEquals(bytes, dec, "expected decoded value to parameter") 32 | assertEquals(encoded, enc, "expected encoded value to match parameter") 33 | assertEquals(encoded, Base58.encode(dec), "expected circular test to succeed") // re-encode. 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/gossip/router/SimGossipRouterBuilder.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.gossip.router 2 | 3 | import io.libp2p.pubsub.gossip.GossipRouter 4 | import io.libp2p.pubsub.gossip.builders.GossipRouterBuilder 5 | import kotlin.time.Duration 6 | 7 | class SimGossipRouterBuilder : GossipRouterBuilder() { 8 | var serializeMessagesToBytes: Boolean = false 9 | var additionalHeartbeatDelay: Duration = Duration.ZERO 10 | 11 | override fun createGossipRouter(): GossipRouter { 12 | val gossipScore = 13 | scoreFactory(scoreParams, scheduledAsyncExecutor, currentTimeSuppluer) { gossipRouterEventListeners += it } 14 | 15 | val router = SimGossipRouter( 16 | params = params, 17 | scoreParams = scoreParams, 18 | currentTimeSupplier = currentTimeSuppluer, 19 | random = random, 20 | name = name, 21 | mCache = mCache, 22 | score = gossipScore, 23 | subscriptionTopicSubscriptionFilter = subscriptionTopicSubscriptionFilter, 24 | protocol = protocol, 25 | executor = scheduledAsyncExecutor, 26 | messageFactory = messageFactory, 27 | seenMessages = seenCache, 28 | messageValidator = messageValidator, 29 | serializeToBytes = serializeMessagesToBytes, 30 | additionalHeartbeatDelay = additionalHeartbeatDelay 31 | ) 32 | 33 | router.eventBroadcaster.listeners += gossipRouterEventListeners 34 | return router 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/StreamHandlerWrapper.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd; 2 | 3 | import io.libp2p.tools.p2pd.libp2pj.Stream; 4 | import io.libp2p.tools.p2pd.libp2pj.StreamHandler; 5 | import java.nio.ByteBuffer; 6 | import java.util.function.Consumer; 7 | 8 | /** Created by Anton Nashatyrev on 18.12.2018. */ 9 | public class StreamHandlerWrapper implements StreamHandler { 10 | private final StreamHandler delegate; 11 | private Consumer> onCreateListener; 12 | private Runnable onCloseListener; 13 | 14 | public StreamHandlerWrapper(StreamHandler delegate) { 15 | this.delegate = delegate; 16 | } 17 | 18 | public StreamHandlerWrapper onCreate(Consumer> listener) { 19 | this.onCreateListener = listener; 20 | return this; 21 | } 22 | 23 | public StreamHandlerWrapper onClose(Runnable listener) { 24 | this.onCloseListener = listener; 25 | return this; 26 | } 27 | 28 | @Override 29 | public void onCreate(Stream stream) { 30 | delegate.onCreate(stream); 31 | if (onCreateListener != null) { 32 | onCreateListener.accept(stream); 33 | } 34 | } 35 | 36 | @Override 37 | public void onRead(ByteBuffer data) { 38 | delegate.onRead(data); 39 | } 40 | 41 | @Override 42 | public void onClose() { 43 | delegate.onClose(); 44 | if (onCloseListener != null) { 45 | onCloseListener.run(); 46 | } 47 | } 48 | 49 | @Override 50 | public void onError(Throwable error) { 51 | delegate.onError(error); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/pubsub/MaxCountTopicSubscriptionFilter.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.pubsub 2 | 3 | class MaxCountTopicSubscriptionFilter( 4 | private val maxSubscriptionsPerRequest: Int, 5 | private val maxSubscribedTopics: Int, 6 | private val delegateFilter: TopicSubscriptionFilter 7 | ) : TopicSubscriptionFilter { 8 | override fun canSubscribe(topic: Topic): Boolean = 9 | delegateFilter.canSubscribe(topic) 10 | 11 | override fun filterIncomingSubscriptions( 12 | subscriptions: Collection, 13 | currentlySubscribedTopics: Collection 14 | ): Collection { 15 | if (subscriptions.size > maxSubscriptionsPerRequest) { 16 | throw InvalidMessageException("Too many subscriptions per request") 17 | } 18 | val filteredSubscriptions = 19 | delegateFilter.filterIncomingSubscriptions(subscriptions, currentlySubscribedTopics) 20 | 21 | var unsubscribed = 0 22 | var newSubscribed = 0 23 | filteredSubscriptions.forEach { subscription: PubsubSubscription -> 24 | val currentlySubscribed = currentlySubscribedTopics.contains(subscription.topic) 25 | if (subscription.subscribe && !currentlySubscribed) newSubscribed++ 26 | if (!subscription.subscribe && currentlySubscribed) unsubscribed++ 27 | } 28 | 29 | if (currentlySubscribedTopics.size + newSubscribed - unsubscribed > maxSubscribedTopics) { 30 | throw InvalidMessageException("Too many subscribed topics") 31 | } 32 | return filteredSubscriptions 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WebSocketClientHandshake.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.netty.channel.ChannelHandler 4 | import io.netty.channel.ChannelHandlerContext 5 | import io.netty.channel.SimpleChannelInboundHandler 6 | import io.netty.handler.codec.http.DefaultHttpHeaders 7 | import io.netty.handler.codec.http.FullHttpResponse 8 | import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory 9 | import io.netty.handler.codec.http.websocketx.WebSocketVersion 10 | import java.net.URI 11 | 12 | internal class WebSocketClientHandshake( 13 | private val connectionHandler: ChannelHandler, 14 | val url: String 15 | ) : SimpleChannelInboundHandler() { 16 | 17 | private val handshaker = WebSocketClientHandshakerFactory.newHandshaker( 18 | URI(url), 19 | WebSocketVersion.V13, 20 | null, 21 | true, 22 | DefaultHttpHeaders() 23 | ) 24 | 25 | override fun channelActive(ctx: ChannelHandlerContext) { 26 | handshaker.handshake(ctx.channel()) 27 | } 28 | 29 | public override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) { 30 | val ch = ctx.channel() 31 | if (!handshaker.isHandshakeComplete) { 32 | handshaker.finishHandshake(ch, msg as FullHttpResponse) 33 | ctx.pipeline().addLast(WebFrameCodec()) 34 | ctx.pipeline().addLast(connectionHandler) 35 | ctx.pipeline().remove(this) 36 | ctx.fireChannelActive() 37 | return 38 | } 39 | 40 | throw IllegalStateException("Unexpected message in WebSocket Client") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/implementation/P2PChannelOverNetty.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.implementation 2 | 3 | import io.libp2p.core.P2PChannel 4 | import io.libp2p.etc.types.toVoidCompletableFuture 5 | import io.netty.channel.Channel 6 | import io.netty.channel.ChannelHandler 7 | 8 | /** 9 | * The central class of the library which represents a channel where all communication 10 | * events happen. It is backed up by the Netty [Channel] where all the workflow happens 11 | * 12 | * This class might be thought of as a common denominator of [Connection] and [Stream] classes 13 | * 14 | * @param nettyChannel the underlying Netty channel 15 | */ 16 | abstract class P2PChannelOverNetty( 17 | val nettyChannel: Channel, 18 | override val isInitiator: Boolean 19 | ) : P2PChannel { 20 | private val closeCompletableFuture by lazy { nettyChannel.closeFuture().toVoidCompletableFuture() } 21 | 22 | override fun pushHandler(handler: ChannelHandler) { 23 | nettyChannel.pipeline().addLast(handler) 24 | } 25 | override fun pushHandler(name: String, handler: ChannelHandler) { 26 | nettyChannel.pipeline().addLast(name, handler) 27 | } 28 | 29 | override fun addHandlerBefore(baseName: String, name: String, handler: ChannelHandler) { 30 | nettyChannel.pipeline().addBefore(baseName, name, handler) 31 | } 32 | 33 | override fun close() = nettyChannel.close().toVoidCompletableFuture() 34 | 35 | override fun closeFuture() = closeCompletableFuture 36 | override fun toString(): String { 37 | return "P2PChannelOverNetty(nettyChannel=$nettyChannel, isInitiator=$isInitiator)" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/stats/ApacheStatsImpl.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.stats 2 | 3 | import io.libp2p.simulate.util.smartRound 4 | import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics 5 | import org.apache.commons.math3.stat.descriptive.SummaryStatistics 6 | 7 | data class BasicStatsImpl( 8 | private val aStats: SummaryStatistics = SummaryStatistics() 9 | ) : WritableStats { 10 | 11 | override fun addValue(value: Double) { 12 | aStats.addValue(value) 13 | } 14 | 15 | override fun reset() { 16 | aStats.clear() 17 | } 18 | 19 | override fun getStatisticalSummary() = aStats 20 | 21 | override fun plus(other: Stats): Stats = TODO() 22 | } 23 | 24 | data class DescriptiveStatsImpl( 25 | private val aStats: DescriptiveStatistics = DescriptiveStatistics() 26 | ) : WritableStats { 27 | 28 | override fun addValue(value: Double) { 29 | aStats.addValue(value) 30 | } 31 | 32 | override fun reset() { 33 | aStats.clear() 34 | } 35 | 36 | override fun getStatisticalSummary() = aStats 37 | override fun getDescriptiveStatistics() = aStats 38 | 39 | override fun plus(other: Stats): Stats { 40 | other as DescriptiveStatsImpl 41 | return DescriptiveStatsImpl(DescriptiveStatistics(aStats.values + other.aStats.values)) 42 | } 43 | 44 | override fun toString(): String { 45 | return "" + getCount() + ":" + 46 | getDescriptiveStatistics().min.smartRound() + "/" + 47 | getDescriptiveStatistics().getPercentile(50.0).smartRound() + "/" + 48 | getDescriptiveStatistics().max.smartRound() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/protocol/ProtocolHandler.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.protocol 2 | 3 | import io.libp2p.core.Libp2pException 4 | import io.libp2p.core.P2PChannel 5 | import io.libp2p.core.P2PChannelHandler 6 | import io.libp2p.core.Stream 7 | import io.libp2p.etc.util.netty.InboundTrafficLimitHandler 8 | import java.util.concurrent.CompletableFuture 9 | 10 | abstract class ProtocolHandler( 11 | private val initiatorTrafficLimit: Long, 12 | private val responderTrafficLimit: Long 13 | ) : P2PChannelHandler { 14 | 15 | override fun initChannel(ch: P2PChannel): CompletableFuture { 16 | val stream = ch as Stream 17 | 18 | // establish traffic limiter 19 | val inboundTrafficLimit = if (stream.isInitiator) responderTrafficLimit else initiatorTrafficLimit 20 | if (inboundTrafficLimit < Long.MAX_VALUE) { 21 | stream.pushHandler(InboundTrafficLimitHandler(inboundTrafficLimit)) 22 | } 23 | 24 | initProtocolStream(stream) 25 | 26 | return if (stream.isInitiator) { 27 | onStartInitiator(stream) 28 | } else { 29 | onStartResponder(stream) 30 | } 31 | } 32 | 33 | protected open fun initProtocolStream(stream: Stream) {} 34 | 35 | protected open fun onStartInitiator(@Suppress("UNUSED_PARAMETER")stream: Stream): CompletableFuture { 36 | throw Libp2pException("This protocol has no initiator") 37 | } 38 | protected open fun onStartResponder(@Suppress("UNUSED_PARAMETER")stream: Stream): CompletableFuture { 39 | throw Libp2pException("This protocol has no responder") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/AsyncDaemonExecutor.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd; 2 | 3 | import io.netty.channel.unix.DomainSocketAddress; 4 | import java.net.InetSocketAddress; 5 | import java.net.SocketAddress; 6 | import java.util.concurrent.CompletableFuture; 7 | import java.util.function.Function; 8 | 9 | /** Created by Anton Nashatyrev on 20.12.2018. */ 10 | public class AsyncDaemonExecutor { 11 | private final SocketAddress address; 12 | 13 | public AsyncDaemonExecutor(SocketAddress address) { 14 | this.address = address; 15 | } 16 | 17 | public CompletableFuture executeWithDaemon( 18 | Function> executor) { 19 | CompletableFuture daemonFut = getDaemon(); 20 | return daemonFut 21 | .thenCompose(executor) 22 | .whenComplete( 23 | (r, t) -> { 24 | if (!daemonFut.isCompletedExceptionally()) { 25 | try { 26 | daemonFut.get().close(); 27 | } catch (Exception e) { 28 | } 29 | } 30 | }); 31 | } 32 | 33 | public CompletableFuture getDaemon() { 34 | ControlConnector connector; 35 | if (address instanceof InetSocketAddress) { 36 | connector = new TCPControlConnector(); 37 | } else if (address instanceof DomainSocketAddress) { 38 | connector = new UnixSocketControlConnector(); 39 | } else { 40 | throw new IllegalArgumentException(); 41 | } 42 | 43 | return connector.connect(address); 44 | } 45 | 46 | public SocketAddress getAddress() { 47 | return address; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/etc/types/ByteBufExtTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.etc.types 2 | 3 | import io.netty.buffer.ByteBuf 4 | import io.netty.buffer.Unpooled 5 | import org.assertj.core.api.Assertions.assertThat 6 | import org.junit.jupiter.params.ParameterizedTest 7 | import org.junit.jupiter.params.provider.MethodSource 8 | 9 | class ByteBufExtTest { 10 | 11 | companion object { 12 | @JvmStatic 13 | fun byteBufCases(): List { 14 | val sampleBytes = ByteArray(100) { it.toByte() }.toByteBuf() 15 | return listOf( 16 | Unpooled.buffer(), 17 | sampleBytes.slice(0, 1), 18 | sampleBytes.slice(0, 2), 19 | sampleBytes.slice(0, 3), 20 | sampleBytes.slice(0, 4), 21 | sampleBytes.slice(0, 5), 22 | sampleBytes.slice(0, 6), 23 | sampleBytes.slice(0, 7), 24 | sampleBytes.slice(0, 100), 25 | ) 26 | } 27 | } 28 | 29 | @ParameterizedTest 30 | @MethodSource("byteBufCases") 31 | fun testSliceMaxSize(bufCase: ByteBuf) { 32 | val buf = bufCase.copy() 33 | val slices = buf.sliceMaxSize(3) 34 | 35 | assertThat(slices.map { it.readableBytes() }) 36 | .allMatch { it <= 3 } 37 | .allMatch { it > 0 } 38 | val slicesConcat = Unpooled.wrappedBuffer(*slices.toTypedArray()).toByteArray() 39 | assertThat(slicesConcat.contentEquals(bufCase.toByteArray())).isTrue() 40 | 41 | slices.forEach { it.release() } 42 | 43 | assertThat(slices).allMatch { it.refCnt() == 0 } 44 | assertThat(buf.refCnt()).isZero() 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/core/Stream.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.core 2 | 3 | import io.libp2p.protocol.ProtocolMessageHandler 4 | import io.libp2p.protocol.ProtocolMessageHandlerAdapter 5 | import java.util.concurrent.CompletableFuture 6 | 7 | /** 8 | * Represents a multiplexed stream over wire connection 9 | */ 10 | interface Stream : P2PChannel { 11 | val connection: Connection 12 | 13 | /** 14 | * Returns the [PeerId] of the remote peer [Connection] which this 15 | * [Stream] created on 16 | */ 17 | fun remotePeerId(): PeerId 18 | 19 | /** 20 | * @return negotiated protocol 21 | */ 22 | fun getProtocol(): CompletableFuture 23 | 24 | fun pushHandler(protocolHandler: ProtocolMessageHandler) { 25 | pushHandler(ProtocolMessageHandlerAdapter(this, protocolHandler)) 26 | } 27 | 28 | fun writeAndFlush(msg: Any) 29 | 30 | /** 31 | * Resets the [Stream]. That means the stream is to be abruptly terminated. 32 | * This method is basically used when any error occurs while communicating 33 | * @see close 34 | * @see closeWrite 35 | */ 36 | fun reset() = close() 37 | 38 | /** 39 | * Equivalent to [reset]. 40 | * To close the [Stream] just from the local side use [closeWrite] 41 | */ 42 | override fun close(): CompletableFuture 43 | 44 | /** 45 | * Closes the local side of the [Stream]. 46 | * [closeWrite] means that local party completed writing to the [Stream] 47 | * @see io.libp2p.etc.util.netty.mux.RemoteWriteClosed to be notified on the remote 48 | * stream write side closing 49 | */ 50 | fun closeWrite(): CompletableFuture 51 | } 52 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | google() 6 | } 7 | } 8 | 9 | dependencyResolutionManagement { 10 | repositories { 11 | mavenCentral() 12 | maven { url "https://artifacts.consensys.net/public/maven/maven/" } 13 | maven { url "https://jitpack.io" } 14 | google() 15 | } 16 | } 17 | 18 | rootProject.name = 'jvm-libp2p' 19 | 20 | include ':libp2p' 21 | include ':tools:schedulers' 22 | include ':tools:simulator' 23 | include ':examples:chatter' 24 | include ':examples:cli-chatter' 25 | include ':examples:pinger' 26 | include 'interop-test-client' 27 | 28 | def getAndroidSdkDir() { 29 | def localPropertiesSdkDir = null 30 | if (file('local.properties').canRead()) { 31 | def properties = new Properties() 32 | properties.load(file('local.properties').newDataInputStream()) 33 | localPropertiesSdkDir = properties.getProperty('sdk.dir') 34 | } 35 | def androidHomeEnv = System.getenv("ANDROID_HOME") 36 | if (localPropertiesSdkDir != null) { 37 | return localPropertiesSdkDir 38 | } else { 39 | return androidHomeEnv 40 | } 41 | } 42 | 43 | if (getAndroidSdkDir() != null) { 44 | println "Build configured with Android submodules using Android SDK: ${getAndroidSdkDir()}" 45 | include ':examples:android-chatter' 46 | } else { 47 | println "Build configured without Android submodules." 48 | println " To include Android submodules define a valid SDK location with an ANDROID_HOME environment variable " 49 | println " or by setting the sdk.dir path in your project's local properties file local.properties." 50 | } 51 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/constants/DNSOptionCode.java: -------------------------------------------------------------------------------- 1 | /** */ 2 | package io.libp2p.discovery.mdns.impl.constants; 3 | 4 | /** 5 | * DNS option code. 6 | * 7 | * @author Arthur van Hoff, Pierre Frisch, Rick Blair 8 | */ 9 | public enum DNSOptionCode { 10 | 11 | /** Token */ 12 | Unknown("Unknown", 65535), 13 | /** Long-Lived Queries Option [http://files.dns-sd.org/draft-sekar-dns-llq.txt] */ 14 | LLQ("LLQ", 1), 15 | /** Update Leases Option [http://files.dns-sd.org/draft-sekar-dns-ul.txt] */ 16 | UL("UL", 2), 17 | /** Name Server Identifier Option [RFC5001] */ 18 | NSID("NSID", 3), 19 | /** Owner Option [draft-cheshire-edns0-owner-option] */ 20 | Owner("Owner", 4); 21 | 22 | private final String _externalName; 23 | 24 | private final int _index; 25 | 26 | DNSOptionCode(String name, int index) { 27 | _externalName = name; 28 | _index = index; 29 | } 30 | 31 | /** 32 | * Return the string representation of this type 33 | * 34 | * @return String 35 | */ 36 | public String externalName() { 37 | return _externalName; 38 | } 39 | 40 | /** 41 | * Return the numeric value of this type 42 | * 43 | * @return String 44 | */ 45 | public int indexValue() { 46 | return _index; 47 | } 48 | 49 | /** 50 | * @param optioncode 51 | * @return label 52 | */ 53 | public static DNSOptionCode resultCodeForFlags(int optioncode) { 54 | int maskedIndex = optioncode; 55 | for (DNSOptionCode aCode : DNSOptionCode.values()) { 56 | if (aCode._index == maskedIndex) return aCode; 57 | } 58 | return Unknown; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return this.name() + " index " + this.indexValue(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/mux/yamux/YamuxStreamMuxer.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.mux.yamux 2 | 3 | import io.libp2p.core.ChannelVisitor 4 | import io.libp2p.core.Connection 5 | import io.libp2p.core.P2PChannel 6 | import io.libp2p.core.StreamHandler 7 | import io.libp2p.core.multistream.MultistreamProtocol 8 | import io.libp2p.core.multistream.ProtocolDescriptor 9 | import io.libp2p.core.mux.StreamMuxer 10 | import io.libp2p.core.mux.StreamMuxerDebug 11 | import java.util.concurrent.CompletableFuture 12 | 13 | class YamuxStreamMuxer( 14 | val inboundStreamHandler: StreamHandler<*>, 15 | private val multistreamProtocol: MultistreamProtocol, 16 | private val maxBufferedConnectionWrites: Int, 17 | private val ackBacklogLimit: Int 18 | ) : StreamMuxer, StreamMuxerDebug { 19 | 20 | override val protocolDescriptor = ProtocolDescriptor("/yamux/1.0.0") 21 | override var muxFramesDebugHandler: ChannelVisitor? = null 22 | 23 | override fun initChannel(ch: P2PChannel, selectedProtocol: String): CompletableFuture { 24 | val muxSessionReady = CompletableFuture() 25 | 26 | val yamuxFrameCodec = YamuxFrameCodec() 27 | ch.pushHandler(yamuxFrameCodec) 28 | muxFramesDebugHandler?.also { it.visit(ch as Connection) } 29 | ch.pushHandler( 30 | YamuxHandler( 31 | multistreamProtocol, 32 | yamuxFrameCodec.maxFrameDataLength, 33 | muxSessionReady, 34 | inboundStreamHandler, 35 | ch.isInitiator, 36 | maxBufferedConnectionWrites, 37 | ackBacklogLimit 38 | ) 39 | ) 40 | 41 | return muxSessionReady 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tools/simulator/src/test/kotlin/io/libp2p/simulate/gossip/GossipSimPeerTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.gossip 2 | 3 | import io.libp2p.core.pubsub.Subscriber 4 | import io.libp2p.core.pubsub.Topic 5 | import io.libp2p.etc.types.toByteBuf 6 | import io.libp2p.simulate.gossip.router.SimGossipRouterBuilder 7 | import io.libp2p.tools.schedulers.ControlledExecutorServiceImpl 8 | import io.libp2p.tools.schedulers.TimeControllerImpl 9 | import org.junit.jupiter.api.Assertions 10 | import org.junit.jupiter.api.Test 11 | import java.util.* 12 | import java.util.function.Consumer 13 | 14 | class GossipSimPeerTest { 15 | @Test 16 | fun simplest1() { 17 | val timeController = TimeControllerImpl() 18 | 19 | val createPeer = { 20 | val peer = GossipSimPeer(1, Random()) 21 | peer.routerBuilder = SimGossipRouterBuilder().also { 22 | it.serializeMessagesToBytes = true 23 | } 24 | 25 | peer.pubsubLogs = { true } 26 | peer.simExecutor = ControlledExecutorServiceImpl(timeController) 27 | peer.currentTime = { timeController.time } 28 | peer.subscribe(Topic("aaa")) 29 | peer 30 | } 31 | 32 | val p1 = createPeer() 33 | val p2 = createPeer() 34 | 35 | p1.connect(p2).get() 36 | var gotIt = false 37 | p2.api.subscribe(Consumer { gotIt = true }, Topic("a")) 38 | val p1Pub = p1.api.createPublisher(p1.keyPair.first, 0) 39 | p1Pub.publish("Hello".toByteArray().toByteBuf(), Topic("a")) 40 | 41 | Assertions.assertTrue(gotIt) 42 | } 43 | 44 | companion object { 45 | fun GossipSimPeer.subscribe(topic: Topic) = 46 | this.api.subscribe(Subscriber {}, topic) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/multistream/MultistreamImpl.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.multistream 2 | 3 | import io.libp2p.core.P2PChannel 4 | import io.libp2p.core.P2PChannelHandler 5 | import io.libp2p.core.multistream.Multistream 6 | import io.libp2p.core.multistream.ProtocolBinding 7 | import java.time.Duration 8 | import java.util.concurrent.CompletableFuture 9 | 10 | class MultistreamImpl( 11 | override val bindings: List>, 12 | val preHandler: P2PChannelHandler<*>? = null, 13 | val postHandler: P2PChannelHandler<*>? = null, 14 | val negotiationTimeLimit: Duration = DEFAULT_NEGOTIATION_TIME_LIMIT 15 | ) : Multistream { 16 | 17 | override fun initChannel(ch: P2PChannel): CompletableFuture { 18 | return with(ch) { 19 | preHandler?.also { 20 | it.initChannel(ch) 21 | } 22 | pushHandler( 23 | if (ch.isInitiator) { 24 | Negotiator.createRequesterInitializer( 25 | negotiationTimeLimit, 26 | *bindings.flatMap { it.protocolDescriptor.announceProtocols }.toTypedArray() 27 | ) 28 | } else { 29 | Negotiator.createResponderInitializer( 30 | negotiationTimeLimit, 31 | bindings.map { it.protocolDescriptor.protocolMatcher } 32 | ) 33 | } 34 | ) 35 | postHandler?.also { 36 | it.initChannel(ch) 37 | } 38 | val protocolSelect = ProtocolSelect(bindings) 39 | pushHandler(protocolSelect) 40 | protocolSelect.selectedFuture 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/tasks/DNSTask.java: -------------------------------------------------------------------------------- 1 | // Licensed under Apache License version 2.0 2 | package io.libp2p.discovery.mdns.impl.tasks; 3 | 4 | import io.libp2p.discovery.mdns.impl.DNSOutgoing; 5 | import io.libp2p.discovery.mdns.impl.DNSQuestion; 6 | import io.libp2p.discovery.mdns.impl.JmDNSImpl; 7 | import io.libp2p.discovery.mdns.impl.constants.DNSConstants; 8 | import java.io.IOException; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.ScheduledExecutorService; 11 | 12 | public abstract class DNSTask implements Runnable { 13 | private final JmDNSImpl _jmDNSImpl; 14 | protected final ScheduledExecutorService _scheduler = Executors.newScheduledThreadPool(1); 15 | 16 | protected DNSTask(JmDNSImpl jmDNSImpl) { 17 | super(); 18 | this._jmDNSImpl = jmDNSImpl; 19 | } 20 | 21 | protected JmDNSImpl dns() { 22 | return _jmDNSImpl; 23 | } 24 | 25 | public abstract void start(); 26 | 27 | protected abstract String getName(); 28 | 29 | @Override 30 | public String toString() { 31 | return this.getName(); 32 | } 33 | 34 | protected DNSOutgoing addQuestion(DNSOutgoing out, DNSQuestion rec) throws IOException { 35 | DNSOutgoing newOut = out; 36 | try { 37 | newOut.addQuestion(rec); 38 | } catch (final IOException e) { 39 | int flags = newOut.getFlags(); 40 | boolean multicast = newOut.isMulticast(); 41 | int maxUDPPayload = newOut.getMaxUDPPayload(); 42 | int id = newOut.getId(); 43 | 44 | newOut.setFlags(flags | DNSConstants.FLAGS_TC); 45 | newOut.setId(id); 46 | this._jmDNSImpl.send(newOut); 47 | 48 | newOut = new DNSOutgoing(flags, multicast, maxUDPPayload); 49 | newOut.addQuestion(rec); 50 | } 51 | return newOut; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tools/schedulers/src/main/java/io/libp2p/tools/schedulers/LatestExecutor.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.schedulers; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * Processes events submitted via {@link #newEvent(T)} with the specified eventProcessor 7 | * on the specified scheduler. 8 | * 9 | *

Guarantees that the latest event would be processed, though other intermediate events could be 10 | * skipped. 11 | * 12 | *

Skips subsequent events if any previous is still processing. Avoids creating scheduling a task 13 | * for each event thus allowing frequent events submitting. 14 | */ 15 | public class LatestExecutor { 16 | private final Scheduler scheduler; 17 | private final Consumer eventProcessor; 18 | private T latestEvent = null; 19 | private boolean processingEvent; 20 | 21 | public LatestExecutor(Scheduler scheduler, Consumer eventProcessor) { 22 | this.scheduler = scheduler; 23 | this.eventProcessor = eventProcessor; 24 | } 25 | 26 | /** 27 | * Submits a new event for processing. This particular event may not be processed if a subsequent 28 | * event submitted shortly 29 | */ 30 | public synchronized void newEvent(T event) { 31 | latestEvent = event; 32 | startEvent(); 33 | } 34 | 35 | private synchronized void startEvent() { 36 | if (!processingEvent) { 37 | if (latestEvent != null) { 38 | T event = latestEvent; 39 | latestEvent = null; 40 | 41 | processingEvent = true; 42 | scheduler.execute(() -> runEvent(event)); 43 | } 44 | } 45 | } 46 | 47 | private void runEvent(T event) { 48 | eventProcessor.accept(event); 49 | synchronized (this) { 50 | processingEvent = false; 51 | } 52 | startEvent(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/tcp/TcpTransport.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.tcp 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | import io.libp2p.core.multiformats.Protocol.DNSADDR 5 | import io.libp2p.core.multiformats.Protocol.P2PCIRCUIT 6 | import io.libp2p.core.multiformats.Protocol.TCP 7 | import io.libp2p.core.multiformats.Protocol.WS 8 | import io.libp2p.etc.util.MultiaddrUtils 9 | import io.libp2p.transport.ConnectionUpgrader 10 | import io.libp2p.transport.implementation.ConnectionBuilder 11 | import io.libp2p.transport.implementation.PlainNettyTransport 12 | import io.netty.channel.ChannelHandler 13 | import java.net.InetSocketAddress 14 | import java.net.SocketAddress 15 | 16 | /** 17 | * The TCP transport can establish libp2p connections via TCP endpoints. 18 | * 19 | * Given that TCP by itself is not authenticated, encrypted, nor multiplexed, this transport uses the upgrader to 20 | * shim those capabilities via dynamic negotiation. 21 | */ 22 | open class TcpTransport( 23 | upgrader: ConnectionUpgrader 24 | ) : PlainNettyTransport(upgrader) { 25 | 26 | override fun handles(addr: Multiaddr) = 27 | handlesHost(addr) && 28 | addr.has(TCP) && 29 | !addr.has(WS) && 30 | !addr.has(DNSADDR) && 31 | !addr.has(P2PCIRCUIT) 32 | 33 | override fun serverTransportBuilder( 34 | connectionBuilder: ConnectionBuilder, 35 | addr: Multiaddr 36 | ): ChannelHandler? = null 37 | 38 | override fun clientTransportBuilder( 39 | connectionBuilder: ConnectionBuilder, 40 | addr: Multiaddr 41 | ): ChannelHandler? = null 42 | 43 | override fun toMultiaddr(addr: SocketAddress): Multiaddr = 44 | MultiaddrUtils.inetSocketAddressToTcpMultiaddr(addr as InetSocketAddress) 45 | } // class TcpTransport 46 | -------------------------------------------------------------------------------- /libp2p/src/main/kotlin/io/libp2p/transport/ws/WsTransport.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport.ws 2 | 3 | import io.libp2p.core.multiformats.Multiaddr 4 | import io.libp2p.core.multiformats.Protocol.TCP 5 | import io.libp2p.core.multiformats.Protocol.WS 6 | import io.libp2p.etc.util.MultiaddrUtils 7 | import io.libp2p.transport.ConnectionUpgrader 8 | import io.libp2p.transport.implementation.ConnectionBuilder 9 | import io.libp2p.transport.implementation.PlainNettyTransport 10 | import io.netty.channel.ChannelHandler 11 | import java.net.InetSocketAddress 12 | import java.net.SocketAddress 13 | 14 | /** 15 | * The WS transport can establish libp2p connections 16 | * via WebSockets endpoints. 17 | */ 18 | class WsTransport( 19 | upgrader: ConnectionUpgrader 20 | ) : PlainNettyTransport(upgrader) { 21 | 22 | override fun handles(addr: Multiaddr) = 23 | handlesHost(addr) && 24 | addr.has(TCP) && 25 | addr.has(WS) 26 | 27 | override fun serverTransportBuilder( 28 | connectionBuilder: ConnectionBuilder, 29 | addr: Multiaddr 30 | ): ChannelHandler? { 31 | return WebSocketServerInitializer(connectionBuilder) 32 | } // serverTransportBuilder 33 | 34 | override fun clientTransportBuilder( 35 | connectionBuilder: ConnectionBuilder, 36 | addr: Multiaddr 37 | ): ChannelHandler? { 38 | val host = hostFromMultiaddr(addr) 39 | val port = portFromMultiaddr(addr) 40 | val url = "ws://$host:$port/" 41 | 42 | return WebSocketClientInitializer(connectionBuilder, url) 43 | } // clientTransportBuilder 44 | 45 | override fun toMultiaddr(addr: SocketAddress): Multiaddr = 46 | MultiaddrUtils.inetSocketAddressToTcpMultiaddr(addr as InetSocketAddress) 47 | .withComponent(WS) 48 | } // class WsTransport 49 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/tools/protobuf/ProtobufUtils.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools 2 | 3 | /** 4 | * When protobuf message is converted to String it prints binary data ([ByteSequence]) by escaping bytes as 5 | * characters. 6 | * The string looks like `\026\030L\034E?\226\374` 7 | * This functions converts this representation back to bytes. 8 | * This can be handy when sorting out logs 9 | */ 10 | fun parseProtobufBytesToString(str: String): ByteArray { 11 | val bytes = mutableListOf() 12 | var pos = 0 13 | while (pos < str.length) { 14 | bytes += when (str[pos]) { 15 | '\\' -> { 16 | pos++ 17 | when (str[pos]) { 18 | in '0'..'9' -> { 19 | val r = ( 20 | (("" + str[pos]).toInt() shl 6) or 21 | (("" + str[pos + 1]).toInt() shl 3) or 22 | (("" + str[pos + 2]).toInt()) 23 | ).toByte() 24 | pos += 2 25 | r 26 | } 27 | 'a' -> 0x07 28 | 'b' -> '\b'.code.toByte() 29 | 'f' -> 0xC 30 | 'n' -> '\n'.code.toByte() 31 | 'r' -> '\r'.code.toByte() 32 | 't' -> '\t'.code.toByte() 33 | 'v' -> 0x0b 34 | '\\' -> '\\'.code.toByte() 35 | '\'' -> '\''.code.toByte() 36 | '"' -> '"'.code.toByte() 37 | else -> throw IllegalArgumentException("Invalid escape char") 38 | }.also { pos++ } 39 | } 40 | else -> str[pos++].code.toByte() 41 | } 42 | } 43 | return bytes.toByteArray() 44 | } 45 | -------------------------------------------------------------------------------- /tools/simulator/src/test/kotlin/io/libp2p/simulate/topology/TopologyTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.topology 2 | 3 | import io.libp2p.simulate.TopologyGraph 4 | import org.assertj.core.api.Assertions.assertThat 5 | import org.junit.jupiter.api.Test 6 | import java.util.* 7 | 8 | class TopologyTest { 9 | 10 | fun TopologyGraph.getVertexInboundEdges(vertex: Int): Collection = edges.filter { it.destV == vertex } 11 | fun TopologyGraph.getVertexOutboundEdges(vertex: Int): Collection = edges.filter { it.srcV == vertex } 12 | fun TopologyGraph.getVertexEdges(vertex: Int) = getVertexInboundEdges(vertex) + getVertexOutboundEdges(vertex) 13 | fun TopologyGraph.Edge.getOther(vertex: Int) = 14 | when (vertex) { 15 | srcV -> destV 16 | destV -> srcV 17 | else -> throw IllegalArgumentException() 18 | } 19 | 20 | @Test 21 | fun allToAllTopologyTest() { 22 | val graph = AllToAllTopology().generateGraph(100) 23 | 24 | assertThat(graph.vertices).isEqualTo((0 until 100).toList()) 25 | assertThat(graph.edges).hasSize(4950) 26 | } 27 | 28 | @Test 29 | fun randomNTopologyTest() { 30 | val rnd = Random(1) 31 | val topology = RandomNPeers(30) 32 | .also { it.random = rnd } 33 | 34 | repeat(100) { 35 | val graph = topology.generateGraph(300) 36 | 37 | assertThat(graph.vertices).isEqualTo((0 until 300).toList()) 38 | graph.vertices.forEach { vertex -> 39 | val vertexEdges = graph.getVertexEdges(vertex) 40 | assertThat(vertexEdges.map { it.getOther(vertex) }.distinct()).hasSize(vertexEdges.size) 41 | assertThat(vertexEdges.size).isBetween(20, 30) 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /libp2p/src/test/kotlin/io/libp2p/security/tls/TlsSecureChannelTest.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.security.tls 2 | 3 | import io.libp2p.core.PeerId 4 | import io.libp2p.core.crypto.KeyType 5 | import io.libp2p.core.crypto.generateKeyPair 6 | import io.libp2p.core.multistream.MultistreamProtocolDebug 7 | import io.libp2p.core.mux.StreamMuxerProtocol 8 | import io.libp2p.multistream.MultistreamProtocolDebugV1 9 | import io.libp2p.security.InvalidRemotePubKey 10 | import io.libp2p.security.SecureChannelTestBase 11 | import io.libp2p.tools.TestChannel 12 | import org.assertj.core.api.Assertions 13 | import org.junit.jupiter.api.Tag 14 | import org.junit.jupiter.api.Test 15 | import java.util.concurrent.TimeUnit 16 | 17 | val MultistreamProtocolV1: MultistreamProtocolDebug = MultistreamProtocolDebugV1() 18 | 19 | @Tag("secure-channel") 20 | class TlsSecureChannelTest : SecureChannelTestBase( 21 | ::TlsSecureChannel, 22 | listOf(StreamMuxerProtocol.getYamux().createMuxer(MultistreamProtocolV1, listOf())), 23 | TlsSecureChannel.announce 24 | ) { 25 | @Test 26 | fun `incorrect initiator remote PeerId should throw`() { 27 | val (privKey1, _) = generateKeyPair(KeyType.ECDSA) 28 | val (privKey2, _) = generateKeyPair(KeyType.ECDSA) 29 | val (_, wrongPubKey) = generateKeyPair(KeyType.ECDSA) 30 | 31 | val protocolSelect1 = makeSelector(privKey1, muxerIds) 32 | val protocolSelect2 = makeSelector(privKey2, muxerIds) 33 | 34 | val eCh1 = makeDialChannel("#1", protocolSelect1, PeerId.fromPubKey(wrongPubKey)) 35 | val eCh2 = makeListenChannel("#2", protocolSelect2) 36 | 37 | TestChannel.interConnect(eCh1, eCh2) 38 | 39 | Assertions.assertThatThrownBy { protocolSelect1.selectedFuture.get(10, TimeUnit.SECONDS) } 40 | .hasCauseInstanceOf(InvalidRemotePubKey::class.java) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libp2p/src/main/java/io/libp2p/discovery/mdns/impl/constants/DNSOperationCode.java: -------------------------------------------------------------------------------- 1 | /** */ 2 | package io.libp2p.discovery.mdns.impl.constants; 3 | 4 | /** 5 | * DNS operation code. 6 | * 7 | * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer, Pierre Frisch, Rick Blair 8 | */ 9 | public enum DNSOperationCode { 10 | /** Query [RFC1035] */ 11 | Query("Query", 0), 12 | /** IQuery (Inverse Query, Obsolete) [RFC3425] */ 13 | IQuery("Inverse Query", 1), 14 | /** Status [RFC1035] */ 15 | Status("Status", 2), 16 | /** Unassigned */ 17 | Unassigned("Unassigned", 3), 18 | /** Notify [RFC1996] */ 19 | Notify("Notify", 4), 20 | /** Update [RFC2136] */ 21 | Update("Update", 5); 22 | 23 | /** DNS RCode types are encoded on the last 4 bits */ 24 | static final int OpCode_MASK = 0x7800; 25 | 26 | private final String _externalName; 27 | 28 | private final int _index; 29 | 30 | DNSOperationCode(String name, int index) { 31 | _externalName = name; 32 | _index = index; 33 | } 34 | 35 | /** 36 | * Return the string representation of this type 37 | * 38 | * @return String 39 | */ 40 | public String externalName() { 41 | return _externalName; 42 | } 43 | 44 | /** 45 | * Return the numeric value of this type 46 | * 47 | * @return String 48 | */ 49 | public int indexValue() { 50 | return _index; 51 | } 52 | 53 | /** 54 | * @param flags 55 | * @return label 56 | */ 57 | public static DNSOperationCode operationCodeForFlags(int flags) { 58 | int maskedIndex = (flags & OpCode_MASK) >> 11; 59 | for (DNSOperationCode aCode : DNSOperationCode.values()) { 60 | if (aCode._index == maskedIndex) return aCode; 61 | } 62 | return Unassigned; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return this.name() + " index " + this.indexValue(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/kotlin/io/libp2p/transport/NullConnectionUpgrader.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.transport 2 | 3 | import io.libp2p.core.Connection 4 | import io.libp2p.core.PeerId 5 | import io.libp2p.core.StreamPromise 6 | import io.libp2p.core.crypto.KeyType 7 | import io.libp2p.core.crypto.generateKeyPair 8 | import io.libp2p.core.multistream.MultistreamProtocol 9 | import io.libp2p.core.multistream.ProtocolBinding 10 | import io.libp2p.core.mux.StreamMuxer 11 | import io.libp2p.core.security.SecureChannel 12 | import java.util.concurrent.CompletableFuture 13 | 14 | class NullMultistreamProtocol : MultistreamProtocol { 15 | override val version = "0.0.0" 16 | 17 | override fun createMultistream(bindings: List>) = TODO() 18 | } 19 | 20 | class NullConnectionUpgrader : 21 | ConnectionUpgrader(NullMultistreamProtocol(), emptyList(), NullMultistreamProtocol(), emptyList()) { 22 | 23 | override fun establishSecureChannel(connection: Connection): CompletableFuture { 24 | val nonsenseSession = SecureChannel.Session( 25 | PeerId.random(), 26 | PeerId.random(), 27 | generateKeyPair(KeyType.RSA).second, 28 | null 29 | ) 30 | return CompletableFuture.completedFuture(nonsenseSession) 31 | } // establishSecureChannel 32 | 33 | override fun establishMuxer(connection: Connection): CompletableFuture { 34 | return CompletableFuture.completedFuture(DoNothingMuxerSession()) 35 | } // establishMuxer 36 | 37 | private class DoNothingMuxerSession : StreamMuxer.Session { 38 | override fun createStream(protocols: List>): StreamPromise { 39 | throw NotImplementedError("Test only. Shouldn't be called") 40 | } 41 | } 42 | } // class NullConnectionUpgrader 43 | -------------------------------------------------------------------------------- /tools/simulator/src/main/kotlin/io/libp2p/simulate/util/CollectionExt.kt: -------------------------------------------------------------------------------- 1 | package io.libp2p.simulate.util 2 | 3 | import kotlin.reflect.full.memberProperties 4 | 5 | fun Collection>.toMap() = this.map { it.key to it.value }.toMap() 6 | 7 | fun Collection.countValues(): Map = countValuesBy { it } 8 | 9 | fun Collection.countValuesBy(keyExtractor: (T) -> K): Map = 10 | this.groupBy { keyExtractor(it) }.mapValues { (_, list) -> list.size } 11 | 12 | operator fun List.get(subIndexes: IntRange) = subList(subIndexes.first, subIndexes.last + 1) 13 | fun Map.setKeys(f: (K) -> K): Map = asSequence().map { f(it.key) to it.value }.toMap() 14 | operator fun Map.plus(other: Map): Map = 15 | (asSequence() + other.asSequence()).map { it.key to it.value }.toMap() 16 | 17 | fun List>.transpose(): Map> = flatMap { it.asIterable() }.groupBy({ it.key }, { it.value }) 18 | fun Map>.transpose(): List> { 19 | val list = asSequence() 20 | .toList() 21 | .flatMap { kv -> 22 | kv.value.mapIndexed { i, v -> 23 | kv.key to (i to v) 24 | } 25 | } 26 | val indexedMap = list.groupBy { it.second.first } 27 | val ret = indexedMap.map { it.value.associate { it.first to it.second.second } } 28 | return ret 29 | } 30 | 31 | fun Any.propertiesAsMap() = javaClass.kotlin.memberProperties.map { it.name to it.get(this) }.toMap() 32 | fun > Collection.isOrdered() = 33 | this 34 | .windowed(2) { l -> l[1] >= l[0] } 35 | .all { it } 36 | 37 | fun > Collection.min() = this 38 | .reduce { acc, t -> if (acc < t) acc else t } 39 | fun > Collection.max() = this 40 | .reduce { acc, t -> if (acc > t) acc else t } 41 | -------------------------------------------------------------------------------- /libp2p/src/testFixtures/java/io/libp2p/tools/p2pd/NettyStream.java: -------------------------------------------------------------------------------- 1 | package io.libp2p.tools.p2pd; 2 | 3 | import io.libp2p.tools.p2pd.libp2pj.Muxer; 4 | import io.libp2p.tools.p2pd.libp2pj.Stream; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.Channel; 7 | import java.nio.ByteBuffer; 8 | 9 | /** Created by Anton Nashatyrev on 14.12.2018. */ 10 | public class NettyStream implements Stream { 11 | 12 | private final Channel channel; 13 | private final boolean initiator; 14 | private final Muxer.MuxerAdress localAddress; 15 | private final Muxer.MuxerAdress remoteAddress; 16 | 17 | public NettyStream( 18 | Channel channel, 19 | boolean initiator, 20 | Muxer.MuxerAdress localAddress, 21 | Muxer.MuxerAdress remoteAddress) { 22 | this.channel = channel; 23 | this.initiator = initiator; 24 | this.localAddress = localAddress; 25 | this.remoteAddress = remoteAddress; 26 | } 27 | 28 | public NettyStream(Channel channel, boolean initiator) { 29 | this(channel, initiator, null, null); 30 | } 31 | 32 | @Override 33 | public void write(ByteBuffer data) { 34 | channel.write(Unpooled.wrappedBuffer(data)); 35 | } 36 | 37 | @Override 38 | public void flush() { 39 | channel.flush(); 40 | } 41 | 42 | @Override 43 | public boolean isInitiator() { 44 | return initiator; 45 | } 46 | 47 | @Override 48 | public void close() { 49 | channel.close(); 50 | } 51 | 52 | @Override 53 | public Muxer.MuxerAdress getRemoteAddress() { 54 | return remoteAddress; 55 | } 56 | 57 | @Override 58 | public Muxer.MuxerAdress getLocalAddress() { 59 | return localAddress; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "NettyStream{" 65 | + getLocalAddress() 66 | + (isInitiator() ? " -> " : " <- ") 67 | + getRemoteAddress(); 68 | } 69 | } 70 | --------------------------------------------------------------------------------