AeroToss: исправлен broadcast адрес + логирование
- getBroadcastAddress() вычисляет реальный broadcast адрес подсети - Логирование: TCP подключения, UDP broadcast, найденные устройства - Логирование broadcast ошибок для отладки
This commit is contained in:
@@ -37,12 +37,12 @@ class TcpDiscovery(
|
|||||||
override fun startDiscovery(servicePort: Int) {
|
override fun startDiscovery(servicePort: Int) {
|
||||||
if (serverThread != null) return
|
if (serverThread != null) return
|
||||||
|
|
||||||
// TCP server
|
|
||||||
serverThread = Thread {
|
serverThread = Thread {
|
||||||
try {
|
try {
|
||||||
val ss = ServerSocket(TCP_PORT, 50, InetAddress.getByName("0.0.0.0"))
|
val ss = ServerSocket(TCP_PORT, 50, InetAddress.getByName("0.0.0.0"))
|
||||||
serverSocket = ss
|
serverSocket = ss
|
||||||
println("AeroToss: TCP=$TCP_PORT, service=$servicePort, type=$myDeviceType, name=$deviceName")
|
val myIp = findMyIp()
|
||||||
|
println("AeroToss: TCP server=$TCP_PORT service=$servicePort type=$myDeviceType ip=$myIp name=$deviceName")
|
||||||
while (!Thread.currentThread().isInterrupted) {
|
while (!Thread.currentThread().isInterrupted) {
|
||||||
try {
|
try {
|
||||||
val client = ss.accept()
|
val client = ss.accept()
|
||||||
@@ -53,17 +53,19 @@ class TcpDiscovery(
|
|||||||
}
|
}
|
||||||
ss.close()
|
ss.close()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (!Thread.currentThread().isInterrupted) println("AeroToss: Server error: ${e.message}")
|
if (!Thread.currentThread().isInterrupted) println("AeroToss: TCP server error: ${e.message}")
|
||||||
}
|
}
|
||||||
}.apply { isDaemon = true; name = "aerotoss-tcp"; start() }
|
}.apply { isDaemon = true; name = "aerotoss-tcp"; start() }
|
||||||
|
|
||||||
// UDP broadcast
|
|
||||||
discoveryThread = Thread {
|
discoveryThread = Thread {
|
||||||
try {
|
try {
|
||||||
val socket = DatagramSocket(UDP_PORT, InetAddress.getByName("0.0.0.0"))
|
val socket = DatagramSocket(UDP_PORT, InetAddress.getByName("0.0.0.0"))
|
||||||
socket.broadcast = true
|
socket.broadcast = true
|
||||||
socket.soTimeout = 2000
|
socket.soTimeout = 2000
|
||||||
udpSocket = socket
|
udpSocket = socket
|
||||||
|
|
||||||
|
println("AeroToss: UDP broadcast port=$UDP_PORT")
|
||||||
|
|
||||||
var lastBroadcast = System.currentTimeMillis()
|
var lastBroadcast = System.currentTimeMillis()
|
||||||
while (!Thread.currentThread().isInterrupted) {
|
while (!Thread.currentThread().isInterrupted) {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
@@ -75,6 +77,8 @@ class TcpDiscovery(
|
|||||||
try {
|
try {
|
||||||
val pkt = DatagramPacket(buf, buf.size)
|
val pkt = DatagramPacket(buf, buf.size)
|
||||||
socket.receive(pkt)
|
socket.receive(pkt)
|
||||||
|
val from = pkt.address.hostAddress
|
||||||
|
println("AeroToss: UDP received from $from")
|
||||||
onBroadcastReceived(pkt, servicePort)
|
onBroadcastReceived(pkt, servicePort)
|
||||||
} catch (_: java.net.SocketTimeoutException) {}
|
} catch (_: java.net.SocketTimeoutException) {}
|
||||||
}
|
}
|
||||||
@@ -88,10 +92,13 @@ class TcpDiscovery(
|
|||||||
private fun handleRequest(client: Socket, servicePort: Int) {
|
private fun handleRequest(client: Socket, servicePort: Int) {
|
||||||
try {
|
try {
|
||||||
client.use { sock ->
|
client.use { sock ->
|
||||||
|
val from = sock.inetAddress?.hostAddress ?: "unknown"
|
||||||
|
println("AeroToss: TCP connection from $from")
|
||||||
sock.soTimeout = 5000
|
sock.soTimeout = 5000
|
||||||
val reader = sock.getInputStream().bufferedReader()
|
val reader = sock.getInputStream().bufferedReader()
|
||||||
val writer = sock.getOutputStream().bufferedWriter()
|
val writer = sock.getOutputStream().bufferedWriter()
|
||||||
val line = reader.readLine() ?: return
|
val line = reader.readLine() ?: return
|
||||||
|
println("AeroToss: TCP request: $line")
|
||||||
if (line == "DISCOVER") {
|
if (line == "DISCOVER") {
|
||||||
val resp = DiscoveryResponse(
|
val resp = DiscoveryResponse(
|
||||||
id = deviceId,
|
id = deviceId,
|
||||||
@@ -100,20 +107,48 @@ class TcpDiscovery(
|
|||||||
port = servicePort,
|
port = servicePort,
|
||||||
ip = findMyIp()
|
ip = findMyIp()
|
||||||
)
|
)
|
||||||
writer.write(json.encodeToString(resp))
|
val jsonStr = json.encodeToString(resp)
|
||||||
|
writer.write(jsonStr)
|
||||||
writer.newLine()
|
writer.newLine()
|
||||||
writer.flush()
|
writer.flush()
|
||||||
|
println("AeroToss: TCP response: $jsonStr")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (_: Exception) {}
|
} catch (e: Exception) {
|
||||||
|
println("AeroToss: TCP handler error: ${e.message}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun broadcast(socket: DatagramSocket, servicePort: Int) {
|
private fun broadcast(socket: DatagramSocket, servicePort: Int) {
|
||||||
try {
|
try {
|
||||||
val msg = "AEROTOSS:$TCP_PORT:$servicePort:$deviceId:$deviceName"
|
val msg = "AEROTOSS:$TCP_PORT:$servicePort:$deviceId:$deviceName"
|
||||||
val pkt = DatagramPacket(msg.toByteArray(Charsets.UTF_8), msg.length, InetAddress.getByName("255.255.255.255"), UDP_PORT)
|
val data = msg.toByteArray(Charsets.UTF_8)
|
||||||
|
val broadcastAddr = getBroadcastAddress()
|
||||||
|
println("AeroToss: Broadcasting to $broadcastAddr:$UDP_PORT")
|
||||||
|
val pkt = DatagramPacket(data, data.size, broadcastAddr, UDP_PORT)
|
||||||
socket.send(pkt)
|
socket.send(pkt)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("AeroToss: Broadcast error: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getBroadcastAddress(): InetAddress {
|
||||||
|
try {
|
||||||
|
val interfaces = NetworkInterface.getNetworkInterfaces()
|
||||||
|
while (interfaces.hasMoreElements()) {
|
||||||
|
val iface = interfaces.nextElement()
|
||||||
|
if (iface.isLoopback || !iface.isUp) continue
|
||||||
|
for (interfaceAddress in iface.interfaceAddresses) {
|
||||||
|
val broadcast = interfaceAddress.broadcast
|
||||||
|
if (broadcast != null && interfaceAddress.address is java.net.Inet4Address) {
|
||||||
|
println("AeroToss: Found broadcast ${broadcast.hostAddress} on ${iface.name}")
|
||||||
|
return broadcast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (_: Exception) {}
|
} catch (_: Exception) {}
|
||||||
|
println("AeroToss: Using default broadcast 255.255.255.255")
|
||||||
|
return InetAddress.getByName("255.255.255.255")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onBroadcastReceived(pkt: DatagramPacket, myServicePort: Int) {
|
private fun onBroadcastReceived(pkt: DatagramPacket, myServicePort: Int) {
|
||||||
@@ -130,13 +165,18 @@ class TcpDiscovery(
|
|||||||
if (remoteServicePort == myServicePort) return
|
if (remoteServicePort == myServicePort) return
|
||||||
|
|
||||||
val host = pkt.address.hostAddress ?: return
|
val host = pkt.address.hostAddress ?: return
|
||||||
|
println("AeroToss: Broadcast from $host:$remoteTcpPort name=$remoteName")
|
||||||
val device = queryRemote(host, remoteTcpPort)
|
val device = queryRemote(host, remoteTcpPort)
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
discoveredDevices[device.id] = device
|
discoveredDevices[device.id] = device
|
||||||
_devices.value = discoveredDevices.values.toList()
|
_devices.value = discoveredDevices.values.toList()
|
||||||
println("AeroToss: Found ${device.name} [${device.type}] at ${device.hostAddress}:${device.port}")
|
println("AeroToss: Found ${device.name} [${device.type}] at ${device.hostAddress}:${device.port}")
|
||||||
|
} else {
|
||||||
|
println("AeroToss: Failed to query $host:$remoteTcpPort")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("AeroToss: Broadcast processing error: ${e.message}")
|
||||||
}
|
}
|
||||||
} catch (_: Exception) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun queryRemote(host: String, tcpPort: Int): Device? {
|
private fun queryRemote(host: String, tcpPort: Int): Device? {
|
||||||
@@ -150,7 +190,7 @@ class TcpDiscovery(
|
|||||||
writer.newLine()
|
writer.newLine()
|
||||||
writer.flush()
|
writer.flush()
|
||||||
val line = reader.readLine() ?: return null
|
val line = reader.readLine() ?: return null
|
||||||
val resp = json.decodeFromString<DiscoveryResponse>(line)
|
json.decodeFromString<DiscoveryResponse>(line).let { resp ->
|
||||||
Device(
|
Device(
|
||||||
id = resp.id,
|
id = resp.id,
|
||||||
name = resp.name,
|
name = resp.name,
|
||||||
@@ -159,18 +199,27 @@ class TcpDiscovery(
|
|||||||
port = resp.port
|
port = resp.port
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (_: Exception) { null }
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
println("AeroToss: queryRemote $host:$tcpPort failed: ${e.message}")
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findMyIp(): String {
|
private fun findMyIp(): String {
|
||||||
return try {
|
try {
|
||||||
NetworkInterface.getNetworkInterfaces()?.toList()
|
val interfaces = NetworkInterface.getNetworkInterfaces()
|
||||||
?.filter { it.isUp && !it.isLoopback }
|
while (interfaces.hasMoreElements()) {
|
||||||
?.flatMap { it.inetAddresses.toList() }
|
val iface = interfaces.nextElement()
|
||||||
?.filterIsInstance<java.net.Inet4Address>()
|
if (iface.isLoopback || !iface.isUp) continue
|
||||||
?.firstOrNull { isPrivate(it) }
|
for (addr in iface.inetAddresses) {
|
||||||
?.hostAddress ?: "127.0.0.1"
|
if (addr is java.net.Inet4Address && isPrivate(addr)) {
|
||||||
} catch (_: Exception) { "127.0.0.1" }
|
return addr.hostAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {}
|
||||||
|
return "127.0.0.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isPrivate(addr: java.net.InetAddress): Boolean {
|
private fun isPrivate(addr: java.net.InetAddress): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user