🐛 Fix connectivity issues and improve code
This commit is contained in:
parent
fe9fa0ba2f
commit
519f457476
22
build.gradle
22
build.gradle
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.2.41'
|
ext.kotlin_version = '1.2.71'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
@ -31,8 +31,8 @@ subprojects {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7"
|
||||||
compile "org.jetbrains.kotlin:kotlin-reflect"
|
implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@ -139,21 +139,21 @@ subprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependency 'ch.dissem.msgpack:msgpack:2.0.1'
|
dependency 'ch.dissem.msgpack:msgpack:2.0.1'
|
||||||
dependency 'org.bouncycastle:bcprov-jdk15on:1.59'
|
dependency 'org.bouncycastle:bcprov-jdk15on:1.60'
|
||||||
dependency 'com.madgag.spongycastle:prov:1.58.0.0'
|
dependency 'com.madgag.spongycastle:prov:1.58.0.0'
|
||||||
dependency 'org.apache.commons:commons-text:1.2'
|
dependency 'org.apache.commons:commons-text:1.5'
|
||||||
dependency 'org.flywaydb:flyway-core:5.0.7'
|
dependency 'org.flywaydb:flyway-core:5.2.0'
|
||||||
dependency 'com.beust:klaxon:2.1.7'
|
dependency 'com.beust:klaxon:3.0.8'
|
||||||
|
|
||||||
dependency 'args4j:args4j:2.33'
|
dependency 'args4j:args4j:2.33'
|
||||||
dependency 'org.ini4j:ini4j:0.5.4'
|
dependency 'org.ini4j:ini4j:0.5.4'
|
||||||
dependency 'com.h2database:h2:1.4.196'
|
dependency 'com.h2database:h2:1.4.197'
|
||||||
|
|
||||||
dependency 'org.hamcrest:java-hamcrest:2.0.0.0'
|
dependency 'org.hamcrest:java-hamcrest:2.0.0.0'
|
||||||
dependency 'com.nhaarman:mockito-kotlin:1.5.0'
|
dependency 'com.nhaarman:mockito-kotlin:1.6.0'
|
||||||
|
|
||||||
dependency 'org.junit.jupiter:junit-jupiter-api:5.2.0'
|
dependency 'org.junit.jupiter:junit-jupiter-api:5.3.1'
|
||||||
dependency 'org.junit.jupiter:junit-jupiter-engine:5.2.0'
|
dependency 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,36 +39,26 @@ data class ObjectMessage(
|
|||||||
var nonce: ByteArray? = null,
|
var nonce: ByteArray? = null,
|
||||||
val expiresTime: Long,
|
val expiresTime: Long,
|
||||||
val payload: ObjectPayload,
|
val payload: ObjectPayload,
|
||||||
val type: Long,
|
val type: Long = payload.type?.number ?: throw IllegalArgumentException("payload must have type defined"),
|
||||||
/**
|
/**
|
||||||
* The object's version
|
* The object's version
|
||||||
*/
|
*/
|
||||||
val version: Long,
|
val version: Long = payload.version,
|
||||||
val stream: Long
|
val stream: Long = payload.stream
|
||||||
) : MessagePayload {
|
) : MessagePayload {
|
||||||
|
|
||||||
override val command: MessagePayload.Command = MessagePayload.Command.OBJECT
|
override val command: MessagePayload.Command = MessagePayload.Command.OBJECT
|
||||||
|
|
||||||
constructor(
|
|
||||||
nonce: ByteArray? = null,
|
|
||||||
expiresTime: Long,
|
|
||||||
payload: ObjectPayload,
|
|
||||||
stream: Long
|
|
||||||
) : this(
|
|
||||||
nonce,
|
|
||||||
expiresTime,
|
|
||||||
payload,
|
|
||||||
payload.type?.number ?: throw IllegalArgumentException("payload must have type defined"),
|
|
||||||
payload.version,
|
|
||||||
stream
|
|
||||||
)
|
|
||||||
|
|
||||||
val inventoryVector: InventoryVector
|
val inventoryVector: InventoryVector
|
||||||
get() {
|
get() {
|
||||||
return InventoryVector(Bytes.truncate(cryptography().doubleSha512(
|
return InventoryVector(
|
||||||
nonce ?: throw IllegalStateException("nonce must be set"),
|
Bytes.truncate(
|
||||||
payloadBytesWithoutNonce
|
cryptography().doubleSha512(
|
||||||
), 32))
|
nonce ?: throw IllegalStateException("nonce must be set"),
|
||||||
|
payloadBytesWithoutNonce
|
||||||
|
), 32
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val isEncrypted: Boolean
|
private val isEncrypted: Boolean
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 Christian Basler
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ch.dissem.bitmessage.factory
|
|
||||||
|
|
||||||
import ch.dissem.bitmessage.constants.Network.HEADER_SIZE
|
|
||||||
import ch.dissem.bitmessage.constants.Network.MAX_PAYLOAD_SIZE
|
|
||||||
import ch.dissem.bitmessage.exception.NodeException
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.nio.ByteBuffer
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.math.max
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A pool for [ByteBuffer]s. As they may use up a lot of memory,
|
|
||||||
* they should be reused as efficiently as possible.
|
|
||||||
*/
|
|
||||||
object BufferPool {
|
|
||||||
private val LOG = LoggerFactory.getLogger(BufferPool::class.java)
|
|
||||||
|
|
||||||
private var limit: Int? = null
|
|
||||||
private var strictLimit = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a limit to how many buffers the pool handles. If strict is set to true, it will not issue any
|
|
||||||
* buffers once the limit is reached and will throw a NodeException instead. Otherwise, it will simply
|
|
||||||
* ignore returned buffers once the limit is reached (and therefore garbage collected)
|
|
||||||
*/
|
|
||||||
fun setLimit(limit: Int, strict: Boolean = false) {
|
|
||||||
this.limit = limit
|
|
||||||
this.strictLimit = strict
|
|
||||||
pools.values.forEach { it.limit = limit }
|
|
||||||
pools[HEADER_SIZE]!!.limit = 2 * limit
|
|
||||||
pools[MAX_PAYLOAD_SIZE]!!.limit = max(limit / 2, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val pools = mapOf(
|
|
||||||
HEADER_SIZE to Pool(),
|
|
||||||
54 to Pool(),
|
|
||||||
1000 to Pool(),
|
|
||||||
60000 to Pool(),
|
|
||||||
MAX_PAYLOAD_SIZE to Pool()
|
|
||||||
)
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun allocate(capacity: Int): ByteBuffer {
|
|
||||||
val targetSize = getTargetSize(capacity)
|
|
||||||
val pool = pools[targetSize] ?: throw IllegalStateException("No pool for size $targetSize available")
|
|
||||||
|
|
||||||
return if (pool.isEmpty) {
|
|
||||||
if (pool.hasCapacity || !strictLimit) {
|
|
||||||
LOG.trace("Creating new buffer of size $targetSize")
|
|
||||||
ByteBuffer.allocate(targetSize)
|
|
||||||
} else {
|
|
||||||
throw NodeException("pool limit for capacity $capacity is reached")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pool.pop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a buffer that has the size of the Bitmessage network message header, 24 bytes.
|
|
||||||
|
|
||||||
* @return a buffer of size 24
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
fun allocateHeaderBuffer(): ByteBuffer {
|
|
||||||
val pool = pools[HEADER_SIZE] ?: throw IllegalStateException("No pool for header available")
|
|
||||||
return if (pool.isEmpty) {
|
|
||||||
if (pool.hasCapacity || !strictLimit) {
|
|
||||||
LOG.trace("Creating new buffer of header")
|
|
||||||
ByteBuffer.allocate(HEADER_SIZE)
|
|
||||||
} else {
|
|
||||||
throw NodeException("pool limit for header buffer is reached")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pool.pop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun deallocate(buffer: ByteBuffer) {
|
|
||||||
buffer.clear()
|
|
||||||
val pool = pools[buffer.capacity()]
|
|
||||||
?: throw IllegalArgumentException("Illegal buffer capacity ${buffer.capacity()} one of ${pools.keys} expected.")
|
|
||||||
pool.push(buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTargetSize(capacity: Int): Int {
|
|
||||||
for (size in pools.keys) {
|
|
||||||
if (size >= capacity) return size
|
|
||||||
}
|
|
||||||
throw IllegalArgumentException("Requested capacity too large: requested=$capacity; max=$MAX_PAYLOAD_SIZE")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* There is a race condition where the limit could be ignored for an allocation, but I think the consequences
|
|
||||||
* are benign.
|
|
||||||
*/
|
|
||||||
class Pool {
|
|
||||||
private val stack = Stack<ByteBuffer>()
|
|
||||||
private var capacity = 0
|
|
||||||
internal var limit: Int? = null
|
|
||||||
set(value) {
|
|
||||||
capacity = value ?: 0
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
val isEmpty
|
|
||||||
get() = stack.isEmpty()
|
|
||||||
|
|
||||||
val hasCapacity
|
|
||||||
@Synchronized
|
|
||||||
get() = limit == null || capacity > 0
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun pop(): ByteBuffer {
|
|
||||||
capacity--
|
|
||||||
return stack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Synchronized
|
|
||||||
fun push(buffer: ByteBuffer) {
|
|
||||||
if (hasCapacity) {
|
|
||||||
stack.push(buffer)
|
|
||||||
}
|
|
||||||
// else, let it be collected by the garbage collector
|
|
||||||
capacity++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,8 +30,7 @@ import java.util.*
|
|||||||
* Similar to the [V3MessageFactory], but used for NIO buffers which may or may not contain a whole message.
|
* Similar to the [V3MessageFactory], but used for NIO buffers which may or may not contain a whole message.
|
||||||
*/
|
*/
|
||||||
class V3MessageReader {
|
class V3MessageReader {
|
||||||
private var headerBuffer: ByteBuffer? = null
|
val buffer: ByteBuffer = ByteBuffer.allocate(MAX_PAYLOAD_SIZE)
|
||||||
private var dataBuffer: ByteBuffer? = null
|
|
||||||
|
|
||||||
private var state: ReaderState? = ReaderState.MAGIC
|
private var state: ReaderState? = ReaderState.MAGIC
|
||||||
private var command: String? = null
|
private var command: String? = null
|
||||||
@ -40,89 +39,83 @@ class V3MessageReader {
|
|||||||
|
|
||||||
private val messages = LinkedList<NetworkMessage>()
|
private val messages = LinkedList<NetworkMessage>()
|
||||||
|
|
||||||
fun getActiveBuffer(): ByteBuffer {
|
|
||||||
if (state != null && state != ReaderState.DATA) {
|
|
||||||
if (headerBuffer == null) {
|
|
||||||
headerBuffer = BufferPool.allocateHeaderBuffer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return if (state == ReaderState.DATA)
|
|
||||||
dataBuffer ?: throw IllegalStateException("data buffer is null")
|
|
||||||
else
|
|
||||||
headerBuffer ?: throw IllegalStateException("header buffer is null")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
if (state != ReaderState.DATA) {
|
if (state != ReaderState.DATA) {
|
||||||
getActiveBuffer() // in order to initialize
|
buffer.flip()
|
||||||
headerBuffer?.flip() ?: throw IllegalStateException("header buffer is null")
|
|
||||||
}
|
}
|
||||||
when (state) {
|
var s = when (state) {
|
||||||
V3MessageReader.ReaderState.MAGIC -> magic(headerBuffer ?: throw IllegalStateException("header buffer is null"))
|
ReaderState.MAGIC -> magic()
|
||||||
V3MessageReader.ReaderState.HEADER -> header(headerBuffer ?: throw IllegalStateException("header buffer is null"))
|
ReaderState.HEADER -> header()
|
||||||
V3MessageReader.ReaderState.DATA -> data(dataBuffer ?: throw IllegalStateException("data buffer is null"))
|
ReaderState.DATA -> data()
|
||||||
|
else -> ReaderState.WAIT_FOR_DATA
|
||||||
|
}
|
||||||
|
while (s != ReaderState.WAIT_FOR_DATA) {
|
||||||
|
s = when (state) {
|
||||||
|
ReaderState.MAGIC -> magic()
|
||||||
|
ReaderState.HEADER -> header()
|
||||||
|
ReaderState.DATA -> data(flip = false)
|
||||||
|
else -> ReaderState.WAIT_FOR_DATA
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun magic(headerBuffer: ByteBuffer) {
|
private fun magic(): ReaderState = if (!findMagicBytes(buffer)) {
|
||||||
if (!findMagicBytes(headerBuffer)) {
|
buffer.compact()
|
||||||
headerBuffer.compact()
|
ReaderState.WAIT_FOR_DATA
|
||||||
return
|
} else {
|
||||||
} else {
|
state = ReaderState.HEADER
|
||||||
state = ReaderState.HEADER
|
ReaderState.HEADER
|
||||||
header(headerBuffer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun header(headerBuffer: ByteBuffer) {
|
private fun header(): ReaderState {
|
||||||
if (headerBuffer.remaining() < 20) {
|
if (buffer.remaining() < 20) {
|
||||||
headerBuffer.compact()
|
buffer.compact()
|
||||||
headerBuffer.limit(20)
|
return ReaderState.WAIT_FOR_DATA
|
||||||
return
|
|
||||||
}
|
}
|
||||||
command = getCommand(headerBuffer)
|
command = getCommand(buffer)
|
||||||
length = Decode.uint32(headerBuffer).toInt()
|
length = Decode.uint32(buffer).toInt()
|
||||||
if (length > MAX_PAYLOAD_SIZE) {
|
if (length > MAX_PAYLOAD_SIZE) {
|
||||||
throw NodeException("Payload of " + length + " bytes received, no more than " +
|
throw NodeException(
|
||||||
MAX_PAYLOAD_SIZE + " was expected.")
|
"Payload of " + length + " bytes received, no more than " +
|
||||||
|
MAX_PAYLOAD_SIZE + " was expected."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
headerBuffer.get(checksum)
|
buffer.get(checksum)
|
||||||
state = ReaderState.DATA
|
state = ReaderState.DATA
|
||||||
this.headerBuffer = null
|
return ReaderState.DATA
|
||||||
BufferPool.deallocate(headerBuffer)
|
|
||||||
this.dataBuffer = BufferPool.allocate(length).apply {
|
|
||||||
clear()
|
|
||||||
limit(length)
|
|
||||||
data(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun data(dataBuffer: ByteBuffer) {
|
private fun data(flip: Boolean = true): ReaderState {
|
||||||
if (dataBuffer.position() < length) {
|
if (flip) {
|
||||||
return
|
if (buffer.position() < length) {
|
||||||
} else {
|
return ReaderState.WAIT_FOR_DATA
|
||||||
dataBuffer.flip()
|
} else {
|
||||||
|
buffer.flip()
|
||||||
|
}
|
||||||
|
} else if (buffer.remaining() < length) {
|
||||||
|
buffer.compact()
|
||||||
|
return ReaderState.WAIT_FOR_DATA
|
||||||
}
|
}
|
||||||
if (!testChecksum(dataBuffer)) {
|
if (!testChecksum(buffer)) {
|
||||||
state = ReaderState.MAGIC
|
state = ReaderState.MAGIC
|
||||||
this.dataBuffer = null
|
buffer.clear()
|
||||||
BufferPool.deallocate(dataBuffer)
|
|
||||||
throw NodeException("Checksum failed for message '$command'")
|
throw NodeException("Checksum failed for message '$command'")
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
V3MessageFactory.getPayload(
|
V3MessageFactory.getPayload(
|
||||||
command ?: throw IllegalStateException("command is null"),
|
command ?: throw IllegalStateException("command is null"),
|
||||||
ByteArrayInputStream(dataBuffer.array(),
|
ByteArrayInputStream(
|
||||||
dataBuffer.arrayOffset() + dataBuffer.position(), length),
|
buffer.array(),
|
||||||
|
buffer.arrayOffset() + buffer.position(), length
|
||||||
|
),
|
||||||
length
|
length
|
||||||
)?.let { messages.add(NetworkMessage(it)) }
|
)?.let { messages.add(NetworkMessage(it)) }
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
throw NodeException(e.message)
|
throw NodeException(e.message)
|
||||||
} finally {
|
} finally {
|
||||||
state = ReaderState.MAGIC
|
state = ReaderState.MAGIC
|
||||||
this.dataBuffer = null
|
|
||||||
BufferPool.deallocate(dataBuffer)
|
|
||||||
}
|
}
|
||||||
|
return ReaderState.MAGIC
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessages(): MutableList<NetworkMessage> {
|
fun getMessages(): MutableList<NetworkMessage> {
|
||||||
@ -163,8 +156,10 @@ class V3MessageReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun testChecksum(buffer: ByteBuffer): Boolean {
|
private fun testChecksum(buffer: ByteBuffer): Boolean {
|
||||||
val payloadChecksum = cryptography().sha512(buffer.array(),
|
val payloadChecksum = cryptography().sha512(
|
||||||
buffer.arrayOffset() + buffer.position(), length)
|
buffer.array(),
|
||||||
|
buffer.arrayOffset() + buffer.position(), length
|
||||||
|
)
|
||||||
for (i in checksum.indices) {
|
for (i in checksum.indices) {
|
||||||
if (checksum[i] != payloadChecksum[i]) {
|
if (checksum[i] != payloadChecksum[i]) {
|
||||||
return false
|
return false
|
||||||
@ -173,17 +168,7 @@ class V3MessageReader {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* De-allocates all buffers. This method should be called iff the reader isn't used anymore, i.e. when its
|
|
||||||
* connection is severed.
|
|
||||||
*/
|
|
||||||
fun cleanup() {
|
|
||||||
state = null
|
|
||||||
headerBuffer?.let { BufferPool.deallocate(it) }
|
|
||||||
dataBuffer?.let { BufferPool.deallocate(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum class ReaderState {
|
private enum class ReaderState {
|
||||||
MAGIC, HEADER, DATA
|
MAGIC, HEADER, DATA, WAIT_FOR_DATA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,12 @@ class CryptographyTest {
|
|||||||
|
|
||||||
@Test(expected = IOException::class)
|
@Test(expected = IOException::class)
|
||||||
fun ensureExceptionForInsufficientProofOfWork() {
|
fun ensureExceptionForInsufficientProofOfWork() {
|
||||||
val objectMessage = ObjectMessage.Builder()
|
val objectMessage = ObjectMessage(
|
||||||
.nonce(ByteArray(8))
|
nonce = ByteArray(8),
|
||||||
.expiresTime(UnixTime.now + 28 * DAY)
|
expiresTime = UnixTime.now + 28 * DAY,
|
||||||
.objectType(0)
|
payload = GenericPayload.read(0, 1, ByteArrayInputStream(ByteArray(0)), 0),
|
||||||
.payload(GenericPayload.read(0, 1, ByteArrayInputStream(ByteArray(0)), 0))
|
type = 0
|
||||||
.build()
|
)
|
||||||
crypto.checkProofOfWork(objectMessage, 1000, 1000)
|
crypto.checkProofOfWork(objectMessage, 1000, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +86,8 @@ class CryptographyTest {
|
|||||||
val objectMessage = ObjectMessage(
|
val objectMessage = ObjectMessage(
|
||||||
nonce = ByteArray(8),
|
nonce = ByteArray(8),
|
||||||
expiresTime = UnixTime.now + 2 * MINUTE,
|
expiresTime = UnixTime.now + 2 * MINUTE,
|
||||||
type = 0,
|
|
||||||
payload = GenericPayload.read(0, 1, ByteArrayInputStream(ByteArray(0)), 0),
|
payload = GenericPayload.read(0, 1, ByteArrayInputStream(ByteArray(0)), 0),
|
||||||
version = 0,
|
type = 0
|
||||||
stream = 1
|
|
||||||
)
|
)
|
||||||
val waiter = CallbackWaiter<ByteArray>()
|
val waiter = CallbackWaiter<ByteArray>()
|
||||||
crypto.doProofOfWork(objectMessage, 1000, 1000,
|
crypto.doProofOfWork(objectMessage, 1000, 1000,
|
||||||
@ -154,13 +152,19 @@ class CryptographyTest {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TEST_VALUE = "teststring".toByteArray()
|
val TEST_VALUE = "teststring".toByteArray()
|
||||||
val TEST_SHA1 = DatatypeConverter.parseHexBinary(""
|
val TEST_SHA1 = DatatypeConverter.parseHexBinary(
|
||||||
+ "b8473b86d4c2072ca9b08bd28e373e8253e865c4")
|
""
|
||||||
val TEST_SHA512 = DatatypeConverter.parseHexBinary(""
|
+ "b8473b86d4c2072ca9b08bd28e373e8253e865c4"
|
||||||
+ "6253b39071e5df8b5098f59202d414c37a17d6a38a875ef5f8c7d89b0212b028"
|
)
|
||||||
+ "692d3d2090ce03ae1de66c862fa8a561e57ed9eb7935ce627344f742c0931d72")
|
val TEST_SHA512 = DatatypeConverter.parseHexBinary(
|
||||||
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(""
|
""
|
||||||
+ "cd566972b5e50104011a92b59fa8e0b1234851ae")
|
+ "6253b39071e5df8b5098f59202d414c37a17d6a38a875ef5f8c7d89b0212b028"
|
||||||
|
+ "692d3d2090ce03ae1de66c862fa8a561e57ed9eb7935ce627344f742c0931d72"
|
||||||
|
)
|
||||||
|
val TEST_RIPEMD160 = DatatypeConverter.parseHexBinary(
|
||||||
|
""
|
||||||
|
+ "cd566972b5e50104011a92b59fa8e0b1234851ae"
|
||||||
|
)
|
||||||
|
|
||||||
private val crypto = SpongyCryptography()
|
private val crypto = SpongyCryptography()
|
||||||
|
|
||||||
|
@ -24,16 +24,16 @@ task fatCapsule(type: FatCapsule) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':core')
|
implementation project(':core')
|
||||||
compile project(':networking')
|
implementation project(':networking')
|
||||||
compile project(':repositories')
|
implementation project(':repositories')
|
||||||
compile project(':cryptography-bc')
|
implementation project(':cryptography-bc')
|
||||||
compile project(':wif')
|
implementation project(':wif')
|
||||||
compile 'org.slf4j:slf4j-simple'
|
implementation 'org.slf4j:slf4j-simple'
|
||||||
compile 'args4j:args4j'
|
implementation 'args4j:args4j'
|
||||||
compile 'com.h2database:h2'
|
implementation 'com.h2database:h2'
|
||||||
compile 'org.apache.commons:commons-text'
|
implementation 'org.apache.commons:commons-text'
|
||||||
testCompile 'com.nhaarman:mockito-kotlin'
|
testImplementation 'com.nhaarman:mockito-kotlin'
|
||||||
testCompile 'org.junit.jupiter:junit-jupiter-api'
|
testImplementation 'org.junit.jupiter:junit-jupiter-api'
|
||||||
testRuntime 'org.junit.jupiter:junit-jupiter-engine'
|
testRuntime 'org.junit.jupiter:junit-jupiter-engine'
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,7 @@ public class Application {
|
|||||||
System.out.println(ctx.status());
|
System.out.println(ctx.status());
|
||||||
System.out.println();
|
System.out.println();
|
||||||
System.out.println("c) cleanup inventory");
|
System.out.println("c) cleanup inventory");
|
||||||
|
System.out.println("n) remove known nodes");
|
||||||
System.out.println("r) resend unacknowledged messages");
|
System.out.println("r) resend unacknowledged messages");
|
||||||
System.out.println(COMMAND_BACK);
|
System.out.println(COMMAND_BACK);
|
||||||
|
|
||||||
@ -123,6 +124,9 @@ public class Application {
|
|||||||
case "c":
|
case "c":
|
||||||
ctx.cleanup();
|
ctx.cleanup();
|
||||||
break;
|
break;
|
||||||
|
case "n":
|
||||||
|
ctx.internals().getNodeRegistry().cleanup();
|
||||||
|
break;
|
||||||
case "r":
|
case "r":
|
||||||
ctx.resendUnacknowledgedMessages();
|
ctx.resendUnacknowledgedMessages();
|
||||||
break;
|
break;
|
||||||
|
@ -63,6 +63,7 @@ public class Main {
|
|||||||
.inventory(new JdbcInventory(jdbcConfig))
|
.inventory(new JdbcInventory(jdbcConfig))
|
||||||
.messageRepo(new JdbcMessageRepository(jdbcConfig))
|
.messageRepo(new JdbcMessageRepository(jdbcConfig))
|
||||||
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
.powRepo(new JdbcProofOfWorkRepository(jdbcConfig))
|
||||||
|
.labelRepo(new JdbcLabelRepository(jdbcConfig))
|
||||||
.networkHandler(new NioNetworkHandler())
|
.networkHandler(new NioNetworkHandler())
|
||||||
.cryptography(new BouncyCryptography());
|
.cryptography(new BouncyCryptography());
|
||||||
ctxBuilder.getPreferences().setPort(48444);
|
ctxBuilder.getPreferences().setPort(48444);
|
||||||
|
@ -26,6 +26,7 @@ import ch.dissem.bitmessage.ports.Labeler
|
|||||||
import ch.dissem.bitmessage.repository.*
|
import ch.dissem.bitmessage.repository.*
|
||||||
import ch.dissem.bitmessage.utils.TTL
|
import ch.dissem.bitmessage.utils.TTL
|
||||||
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
import ch.dissem.bitmessage.utils.UnixTime.MINUTE
|
||||||
|
import com.nhaarman.mockito_kotlin.any
|
||||||
import com.nhaarman.mockito_kotlin.spy
|
import com.nhaarman.mockito_kotlin.spy
|
||||||
import com.nhaarman.mockito_kotlin.timeout
|
import com.nhaarman.mockito_kotlin.timeout
|
||||||
import com.nhaarman.mockito_kotlin.verify
|
import com.nhaarman.mockito_kotlin.verify
|
||||||
@ -34,7 +35,6 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
|||||||
import org.junit.jupiter.api.Assertions.assertTimeoutPreemptively
|
import org.junit.jupiter.api.Assertions.assertTimeoutPreemptively
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.ArgumentMatchers.any
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.time.Duration.ofMinutes
|
import java.time.Duration.ofMinutes
|
||||||
import java.time.Duration.ofSeconds
|
import java.time.Duration.ofSeconds
|
||||||
@ -126,7 +126,7 @@ class SystemTest {
|
|||||||
verify(
|
verify(
|
||||||
aliceLabeler,
|
aliceLabeler,
|
||||||
timeout(TimeUnit.MINUTES.toMillis(2)).atLeastOnce()
|
timeout(TimeUnit.MINUTES.toMillis(2)).atLeastOnce()
|
||||||
).markAsAcknowledged(any<Plaintext>())
|
).markAsAcknowledged(any())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ class SystemTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DebugLabeler internal constructor(private val name: String) : DefaultLabeler() {
|
internal open class DebugLabeler internal constructor(private val name: String) : DefaultLabeler() {
|
||||||
private val LOG = LoggerFactory.getLogger("Labeler")
|
private val LOG = LoggerFactory.getLogger("Labeler")
|
||||||
private lateinit var alice: String
|
private lateinit var alice: String
|
||||||
private lateinit var bob: String
|
private lateinit var bob: String
|
||||||
|
@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains everything used by both the old streams-oriented NetworkHandler and the new NioNetworkHandler,
|
* Contains everything used by both the old streams-oriented NetworkHandler and the new NioNetworkHandler,
|
||||||
@ -165,11 +166,12 @@ class Connection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the TCP timeout starts out at 20 seconds
|
// According to the specification, the TCP timeout starts out at 20 seconds
|
||||||
// after verack messages are exchanged, the timeout is raised to 10 minutes
|
// after verack messages are exchanged, the timeout is raised to 10 minutes
|
||||||
|
// Let's tweak these numbers a bit:
|
||||||
fun isExpired(): Boolean = when (state) {
|
fun isExpired(): Boolean = when (state) {
|
||||||
State.CONNECTING -> io.lastUpdate < System.currentTimeMillis() - 20000
|
State.CONNECTING -> io.lastUpdate < System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(9)
|
||||||
State.ACTIVE -> io.lastUpdate < System.currentTimeMillis() - 600000
|
State.ACTIVE -> io.lastUpdate < System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(3)
|
||||||
State.DISCONNECTED -> true
|
State.DISCONNECTED -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ import ch.dissem.bitmessage.entity.GetData
|
|||||||
import ch.dissem.bitmessage.entity.MessagePayload
|
import ch.dissem.bitmessage.entity.MessagePayload
|
||||||
import ch.dissem.bitmessage.entity.NetworkMessage
|
import ch.dissem.bitmessage.entity.NetworkMessage
|
||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
||||||
import ch.dissem.bitmessage.exception.NodeException
|
|
||||||
import ch.dissem.bitmessage.factory.V3MessageReader
|
import ch.dissem.bitmessage.factory.V3MessageReader
|
||||||
import ch.dissem.bitmessage.utils.UnixTime
|
import ch.dissem.bitmessage.utils.UnixTime
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@ -42,7 +41,7 @@ class ConnectionIO(
|
|||||||
) {
|
) {
|
||||||
private val headerOut: ByteBuffer = ByteBuffer.allocate(HEADER_SIZE)
|
private val headerOut: ByteBuffer = ByteBuffer.allocate(HEADER_SIZE)
|
||||||
private var payloadOut: ByteBuffer? = null
|
private var payloadOut: ByteBuffer? = null
|
||||||
private var reader: V3MessageReader? = V3MessageReader()
|
private val reader = V3MessageReader()
|
||||||
internal val sendingQueue: Deque<MessagePayload> = ConcurrentLinkedDeque<MessagePayload>()
|
internal val sendingQueue: Deque<MessagePayload> = ConcurrentLinkedDeque<MessagePayload>()
|
||||||
|
|
||||||
internal var lastUpdate = System.currentTimeMillis()
|
internal var lastUpdate = System.currentTimeMillis()
|
||||||
@ -55,8 +54,7 @@ class ConnectionIO(
|
|||||||
headerOut.flip()
|
headerOut.flip()
|
||||||
}
|
}
|
||||||
|
|
||||||
val inBuffer: ByteBuffer
|
val inBuffer: ByteBuffer = reader.buffer
|
||||||
get() = reader?.getActiveBuffer() ?: throw NodeException("Node is disconnected")
|
|
||||||
|
|
||||||
fun updateWriter() {
|
fun updateWriter() {
|
||||||
if (!headerOut.hasRemaining() && !sendingQueue.isEmpty()) {
|
if (!headerOut.hasRemaining() && !sendingQueue.isEmpty()) {
|
||||||
@ -78,7 +76,7 @@ class ConnectionIO(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun updateReader() {
|
fun updateReader() {
|
||||||
reader?.let { reader ->
|
reader.let { reader ->
|
||||||
reader.update()
|
reader.update()
|
||||||
if (!reader.getMessages().isEmpty()) {
|
if (!reader.getMessages().isEmpty()) {
|
||||||
val iterator = reader.getMessages().iterator()
|
val iterator = reader.getMessages().iterator()
|
||||||
@ -96,11 +94,11 @@ class ConnectionIO(
|
|||||||
|
|
||||||
fun updateSyncStatus() {
|
fun updateSyncStatus() {
|
||||||
if (!isSyncFinished) {
|
if (!isSyncFinished) {
|
||||||
isSyncFinished = reader?.getMessages()?.isEmpty() ?: true && syncFinished(null)
|
isSyncFinished = reader.getMessages().isEmpty() && syncFinished(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun syncFinished(msg: NetworkMessage?): Boolean {
|
private fun syncFinished(msg: NetworkMessage?): Boolean {
|
||||||
if (mode != Connection.Mode.SYNC) {
|
if (mode != Connection.Mode.SYNC) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -127,10 +125,6 @@ class ConnectionIO(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun disconnect() {
|
fun disconnect() {
|
||||||
reader?.let {
|
|
||||||
it.cleanup()
|
|
||||||
reader = null
|
|
||||||
}
|
|
||||||
payloadOut = null
|
payloadOut = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +145,7 @@ class ConnectionIO(
|
|||||||
|| headerOut.hasRemaining()
|
|| headerOut.hasRemaining()
|
||||||
|| payloadOut?.hasRemaining() ?: false
|
|| payloadOut?.hasRemaining() ?: false
|
||||||
|
|
||||||
fun nothingToSend() = sendingQueue.isEmpty()
|
private fun nothingToSend() = sendingQueue.isEmpty()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val LOG = LoggerFactory.getLogger(ConnectionIO::class.java)
|
val LOG = LoggerFactory.getLogger(ConnectionIO::class.java)
|
||||||
|
@ -77,12 +77,12 @@ class NetworkConnectionInitializer(
|
|||||||
activateConnection()
|
activateConnection()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw NodeException("Received unsupported version " + version.version + ", disconnecting.")
|
throw NodeException("Received unsupported version ${version.version}, disconnecting.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun activateConnection() {
|
private fun activateConnection() {
|
||||||
LOG.info("Successfully established connection with node " + node)
|
LOG.info("Successfully established connection with node $node")
|
||||||
markActive(version.streams)
|
markActive(version.streams)
|
||||||
node.time = UnixTime.now
|
node.time = UnixTime.now
|
||||||
if (mode != Connection.Mode.SYNC) {
|
if (mode != Connection.Mode.SYNC) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package ch.dissem.bitmessage.networking.nio
|
package ch.dissem.bitmessage.networking.nio
|
||||||
|
|
||||||
import ch.dissem.bitmessage.InternalContext
|
import ch.dissem.bitmessage.InternalContext
|
||||||
|
import ch.dissem.bitmessage.constants.Network.HEADER_SIZE
|
||||||
import ch.dissem.bitmessage.constants.Network.NETWORK_MAGIC_NUMBER
|
import ch.dissem.bitmessage.constants.Network.NETWORK_MAGIC_NUMBER
|
||||||
import ch.dissem.bitmessage.entity.CustomMessage
|
import ch.dissem.bitmessage.entity.CustomMessage
|
||||||
import ch.dissem.bitmessage.entity.GetData
|
import ch.dissem.bitmessage.entity.GetData
|
||||||
@ -24,7 +25,6 @@ import ch.dissem.bitmessage.entity.NetworkMessage
|
|||||||
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
import ch.dissem.bitmessage.entity.valueobject.InventoryVector
|
||||||
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
import ch.dissem.bitmessage.entity.valueobject.NetworkAddress
|
||||||
import ch.dissem.bitmessage.exception.NodeException
|
import ch.dissem.bitmessage.exception.NodeException
|
||||||
import ch.dissem.bitmessage.factory.BufferPool
|
|
||||||
import ch.dissem.bitmessage.factory.V3MessageReader
|
import ch.dissem.bitmessage.factory.V3MessageReader
|
||||||
import ch.dissem.bitmessage.networking.nio.Connection.Mode.*
|
import ch.dissem.bitmessage.networking.nio.Connection.Mode.*
|
||||||
import ch.dissem.bitmessage.ports.NetworkHandler
|
import ch.dissem.bitmessage.ports.NetworkHandler
|
||||||
@ -94,29 +94,26 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
override fun send(server: InetAddress, port: Int, request: CustomMessage): CustomMessage {
|
override fun send(server: InetAddress, port: Int, request: CustomMessage): CustomMessage {
|
||||||
SocketChannel.open(InetSocketAddress(server, port)).use { channel ->
|
SocketChannel.open(InetSocketAddress(server, port)).use { channel ->
|
||||||
channel.configureBlocking(true)
|
channel.configureBlocking(true)
|
||||||
val headerBuffer = BufferPool.allocateHeaderBuffer()
|
val headerBuffer = ByteBuffer.allocate(HEADER_SIZE)
|
||||||
val payloadBuffer = NetworkMessage(request).writer().writeHeaderAndGetPayloadBuffer(headerBuffer)
|
val payloadBuffer = NetworkMessage(request).writer().writeHeaderAndGetPayloadBuffer(headerBuffer)
|
||||||
headerBuffer.flip()
|
headerBuffer.flip()
|
||||||
while (headerBuffer.hasRemaining()) {
|
while (headerBuffer.hasRemaining()) {
|
||||||
channel.write(headerBuffer)
|
channel.write(headerBuffer)
|
||||||
}
|
}
|
||||||
BufferPool.deallocate(headerBuffer)
|
|
||||||
while (payloadBuffer.hasRemaining()) {
|
while (payloadBuffer.hasRemaining()) {
|
||||||
channel.write(payloadBuffer)
|
channel.write(payloadBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
val reader = V3MessageReader()
|
val reader = V3MessageReader()
|
||||||
while (channel.isConnected && reader.getMessages().isEmpty()) {
|
while (channel.isConnected && reader.getMessages().isEmpty()) {
|
||||||
if (channel.read(reader.getActiveBuffer()) > 0) {
|
if (channel.read(reader.buffer) > 0) {
|
||||||
reader.update()
|
reader.update()
|
||||||
} else {
|
} else {
|
||||||
reader.cleanup()
|
|
||||||
throw NodeException("No response from node $server")
|
throw NodeException("No response from node $server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val networkMessage: NetworkMessage?
|
val networkMessage: NetworkMessage?
|
||||||
if (reader.getMessages().isEmpty()) {
|
if (reader.getMessages().isEmpty()) {
|
||||||
reader.cleanup()
|
|
||||||
throw NodeException("No response from node $server")
|
throw NodeException("No response from node $server")
|
||||||
} else {
|
} else {
|
||||||
networkMessage = reader.getMessages().first()
|
networkMessage = reader.getMessages().first()
|
||||||
@ -125,7 +122,6 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
if (networkMessage.payload is CustomMessage) {
|
if (networkMessage.payload is CustomMessage) {
|
||||||
return networkMessage.payload as CustomMessage
|
return networkMessage.payload as CustomMessage
|
||||||
} else {
|
} else {
|
||||||
reader.cleanup()
|
|
||||||
throw NodeException("Unexpected response from node $server: ${networkMessage.payload.javaClass}")
|
throw NodeException("Unexpected response from node $server: ${networkMessage.payload.javaClass}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,14 +192,14 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
request(delayed)
|
request(delayed)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(30000)
|
Thread.sleep(10000)
|
||||||
} catch (e: InterruptedException) {
|
} catch (e: InterruptedException) {
|
||||||
return@thread
|
return@thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread("selector worker", {
|
thread("selector worker") {
|
||||||
try {
|
try {
|
||||||
val serverChannel = ServerSocketChannel.open()
|
val serverChannel = ServerSocketChannel.open()
|
||||||
this.serverChannel = serverChannel
|
this.serverChannel = serverChannel
|
||||||
@ -272,10 +268,13 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
else -> key.interestOps(OP_READ)
|
else -> key.interestOps(OP_READ)
|
||||||
}
|
}
|
||||||
} catch (e: CancelledKeyException) {
|
} catch (e: CancelledKeyException) {
|
||||||
|
LOG.debug("${e.message}: ${connection.node}", e)
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
} catch (e: NodeException) {
|
} catch (e: NodeException) {
|
||||||
|
LOG.debug("${e.message}: ${connection.node}", e)
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
LOG.debug("${e.message}: ${connection.node}", e)
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,10 +305,11 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
channel.configureBlocking(false)
|
channel.configureBlocking(false)
|
||||||
channel.connect(InetSocketAddress(address.toInetAddress(), address.port))
|
channel.connect(InetSocketAddress(address.toInetAddress(), address.port))
|
||||||
val connection = Connection(ctx, CLIENT, address, requestedObjects, 0)
|
val connection = Connection(ctx, CLIENT, address, requestedObjects, 0)
|
||||||
connections.put(
|
|
||||||
connection,
|
connections[connection] = channel.register(selector, OP_CONNECT, connection)
|
||||||
channel.register(selector, OP_CONNECT, connection)
|
|
||||||
)
|
LOG.debug("Connection registered to $address")
|
||||||
|
|
||||||
} catch (ignore: NoRouteToHostException) {
|
} catch (ignore: NoRouteToHostException) {
|
||||||
// We'll try to connect to many offline nodes, so
|
// We'll try to connect to many offline nodes, so
|
||||||
// this is expected to happen quite a lot.
|
// this is expected to happen quite a lot.
|
||||||
@ -321,7 +321,11 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
LOG.error(e.message, e)
|
LOG.error(e.message, e)
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
LOG.error(e.message, e)
|
if (e.message == "Network is unreachable") {
|
||||||
|
LOG.debug("Network is unreachable: $address")
|
||||||
|
} else {
|
||||||
|
LOG.error("${e.message}: $address", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -335,7 +339,7 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
// isn't nice though.
|
// isn't nice though.
|
||||||
LOG.error(e.message, e)
|
LOG.error(e.message, e)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun thread(threadName: String, runnable: () -> Unit): Thread {
|
private fun thread(threadName: String, runnable: () -> Unit): Thread {
|
||||||
@ -380,7 +384,7 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
val distribution = HashMap<Connection, MutableList<InventoryVector>>()
|
val distribution = HashMap<Connection, MutableList<InventoryVector>>()
|
||||||
for ((connection, _) in connections) {
|
for ((connection, _) in connections) {
|
||||||
if (connection.state == Connection.State.ACTIVE) {
|
if (connection.state == Connection.State.ACTIVE) {
|
||||||
distribution.put(connection, mutableListOf<InventoryVector>())
|
distribution[connection] = mutableListOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (distribution.isEmpty()) {
|
if (distribution.isEmpty()) {
|
||||||
@ -455,7 +459,7 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
val outgoing = outgoingConnections[stream] ?: 0
|
val outgoing = outgoingConnections[stream] ?: 0
|
||||||
streamProperties.add(
|
streamProperties.add(
|
||||||
Property(
|
Property(
|
||||||
"stream " + stream, Property("nodes", incoming + outgoing),
|
"stream $stream", Property("nodes", incoming + outgoing),
|
||||||
Property("incoming", incoming),
|
Property("incoming", incoming),
|
||||||
Property("outgoing", outgoing)
|
Property("outgoing", outgoing)
|
||||||
)
|
)
|
||||||
@ -476,8 +480,8 @@ class NioNetworkHandler(private val magicNetworkNumber: Int = NETWORK_MAGIC_NUMB
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOG = LoggerFactory.getLogger(NioNetworkHandler::class.java)
|
private val LOG = LoggerFactory.getLogger(NioNetworkHandler::class.java)
|
||||||
private val REQUESTED_OBJECTS_MAX_TIME = (2 * 60000).toLong() // 2 minutes in ms
|
private const val REQUESTED_OBJECTS_MAX_TIME = 2 * 60000L // 2 minutes in ms
|
||||||
private val DELAYED = java.lang.Long.MIN_VALUE
|
private const val DELAYED = java.lang.Long.MIN_VALUE
|
||||||
|
|
||||||
private fun write(channel: SocketChannel, connection: ConnectionIO) {
|
private fun write(channel: SocketChannel, connection: ConnectionIO) {
|
||||||
writeBuffer(connection.outBuffers, channel)
|
writeBuffer(connection.outBuffers, channel)
|
||||||
|
Loading…
Reference in New Issue
Block a user