Peer to Peer discovery on LAN - java

So, as the title might have suggested I am having a bit of trouble in my Java project. What I want to do is this:
I have two Computers running application X
Also have another three Computers running application Y
What i need to do is to establish a connection between a X and an Y. For example, someone uses the computer running X, and after the discovrey process, they will be returned a list of computers running the Y app, and their IP, and the other way around.
I've done this using UDP broadcasting, but sometimes it fails. The computers are connected via WiFi, so basically through a router. On many occasions, any of the X computers can see the Y ones via my UDP discovery method, but sometimes not, unless I manually point the IP, sometimes not even then.
Here is a code for discovering servers listening on a specific port:
public static ArrayList<InetAddress> searchComputer() {
ArrayList<InetAddress> targets = new ArrayList<InetAddress>();
try {
c = new DatagramSocket();
c.setBroadcast(true);
byte[] sendData = "DISCOVER_PC_SERVER_REQUEST".getBytes();
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), 2005);
c.send(sendPacket);
} catch (Exception e) {}
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = (NetworkInterface) interfaces.nextElement();
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue;
}
for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
InetAddress broadcast = interfaceAddress.getBroadcast();
if (broadcast == null) {
continue;
}
try {
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, 8888);
c.send(sendPacket);
} catch (Exception e) { }
}
}
byte[] recvBuf = new byte[15000];
DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
if (useInstant) {
c.setSoTimeout(500);
}
else {
c.setSoTimeout(4000); //EXECUTE THE WHILE FOR 4 SECONDS, THEN RETURN WHATEVER THE RESULTS ARE.
}
while (true) {
c.receive(receivePacket);
String message = new String(receivePacket.getData()).trim();
if (message.equals("DISCOVER_PC_SERVER_RESPONSE")) {
// return receivePacket.getAddress();
targets.add(receivePacket.getAddress());
}
}
// c.close();
} catch (IOException ex){}
return targets;
}
And here is my "server":
private void start_Discovery() throws Exception {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
socket = new DatagramSocket(2005, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while (true) {
// System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
//Packet received
// System.out.println(getClass().getName() + ">>>Discovery packet received from: " + packet.getAddress().getHostAddress());
// System.out.println(getClass().getName() + ">>>Packet received; data: " + new String(packet.getData()));
//See if the packet holds the right command (message)
String message = new String(packet.getData()).trim();
if (message.equals("DISCOVER_ANDROID_SERVER_REQUEST")) {
byte[] sendData = "DISCOVER_ANDROID_SERVER_RESPONSE".getBytes();
//Send a response
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), packet.getPort());
socket.send(sendPacket);
// System.out.println(getClass().getName() + ">>>Sent packet to: " + sendPacket.getAddress().getHostAddress());
}
}
}
Why sometimes they can't see each other, even if they are connected to the same router?
EXTRA: Is there a special case, the X computers are connected via LAN, and the Y ones via WiFi?

Why sometimes they can't see each other, even if they are connected to
the same router?
Because Broadcasting is done using UDP services which are connectionless protocols. With UDP you just send packets of data (datagrams) to some IP address on the network. You have no guarantee that the data will arrive.
Is there a special case, the X computers are connected via LAN, and
the Y ones via WiFi?
Even, the X cmputers are connected via LAN and the Y ones via WiFi, they all belong to the same network of router. Hence,network-discovery and network-services will be available. There won't be any problem with that. It's all fair and not different than the case which you're having!

Related

Java - getting IP address of server listening on a port

I have a server listening on a certain port for client request.. Ex. 9000
Now my client doesn't know the server ip but knows the port to send requests.. How do I know from the client side what is the IP of the server on listening on that certain port?
Both server and client is on the same physical network..
The server always listen on port 9000 for any clients request..
The clients send requests to the server and expects a result...
Sometimes the server changes IP (because of DHCP).. So i want my client to know the server IP when it change...
You can think of the IP address and the Port as the street address of a house (≈ IP address) and an apartment number (≈ Port). Deducing the IP address from a Port number is just as impossible as deducing a street address from an apartment number.
If the nodes are in the same local network (same address class and no router in between),
you should use a UDP broadcast to make a "network discovery".
Schematically:
- The client broadcasts a call and wait for response.
- The server receive the call (the UDP boradcast call do not needs an IP address, only the port is required)
and answer to the client (do some handshake).
- The client receive the UDP packet, it contains the IP address of the sender node (the server).
Client Side:
public void broadcastCall(){
try {
//Open a random port to send the package
DatagramSocket c = new DatagramSocket();
c.setBroadcast(true);
byte[] sendData = "DISCOVER_SERVER_REQUEST".getBytes();
/*
* Try the 255.255.255.255 broadcast
* (or use the boradcas address of you network class like 192.168.1.255)
* port 9100
*/
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length,
InetAddress.getByName("255.255.255.255"), 9100);
c.send(sendPacket);
System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
//Wait for a response
byte[] recvBuf = new byte[15000];
DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
c.receive(receivePacket);
//We have a response
System.out.println(getClass().getName() + ">>> Broadcast response from server: " + receivePacket.getAddress().getHostAddress());
/*
* NOW you have the server IP in receivePacket.getAddress()
*/
//Close the port!
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Server side:
public void broadcastResponder() {
try {
/*
* open receive datagram broadcast socket port 9100
*/
DatagramSocket socket = new DatagramSocket(9100, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
System.out.println(getClass().getName() + ">>>Ready to receive broadcast packets!");
//Receive a packet
byte[] recvBuf = new byte[15000];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet); // This method blocks until a datagram is received
//Packet received
System.out.println(getClass().getName() + ">>>Discovery packet received from: " + packet.getAddress().getHostAddress());
byte[] sendData = "DISCOVER_SERVER_RESPONSE".getBytes();
//Send a response
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), packet.getPort());
socket.send(sendPacket);
System.out.println(getClass().getName() + ">>>Sent packet to: " + sendPacket.getAddress().getHostAddress());
// close socket
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}

Java Multicast Socket not sending out data

It's my first post so it may be not well stylished but I tried...
So... I have two machines, both running Java. I want them to run something like this.
Client: sends multicast to listening servers.
Server(s): the server captures the multicast and sends a unicast back with name of local machine that server runs on.
Client: receives the unicast with the server adress(es) and makes a list with their hostnames.
But the client doesn't even send the multicast (I was watching wireshark capturing packets)
It only sends something when I put 230.0.0.1 as multicast address, but then, the server doesn't receive the packet.
EDIT: When I send a unicast packet to the server it responds fine.
Here is my code:
try
{
//The client runs on LeJOS EV3 so I used their classes a bit
LCDOutputStream lcd = new LCDOutputStream();
PrintStream p = new PrintStream(lcd);
while(true)
{
if(Button.waitForAnyPress() == Button.ID_ESCAPE)
{
break;
}
byte[] buf = this.writeString("get_ip");
DatagramSocket sender = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("230.0.0.1"), 5555);
sender.send(packet);
sender.close();
p.println("Sent Multicast");
}
p.close();
lcd.close();
}
catch(Exception e)
{
console.printException(e);
}
Here is the server code:
MulticastSocket s = new MulticastSocket(5555);
s.joinGroup(InetAddress.getByName("225.1.1.1"));
while(true)
{
try
{
/*
* 225.1.100.1
*
DataSender.Impl.reply("225.1.100.1", 5555, InetAddress.getLocalHost().getHostName(), "get_ip");*/
byte[] buf = new byte[256];
DatagramPacket p = new DatagramPacket(buf, buf.length);
s.receive(p);
System.out.println("DEBUG: received request");
}
catch(IOException e)
{
e.printStackTrace();
break;
}
}
s.close();
The comments made by ecle in response to the following post helped me resolve a similar issue: Java Multicast sample program is unable to deliver packets within LAN (across hosts). In my case, adding setInterface(<server address>); worked. For example:
MulticastSocket s = new MulticastSocket(5555);
s.setInterface(<server address>);
s.joinGroup(InetAddress.getByName("225.1.1.1"));

Datagram sockets with Java client and Python server

I am triying to comunicate 2 machines through datagram sockets but I guess I am missing something...
Machine A is runs an Android App (client)
Machine B is a server writen in Python
I can send a message from A to B without any problem, but A never gets the answer from B, the code is the following:
Client (Java) :
InetAddress serverAddr = InetAddress.getByName("10.0.0.10");
DatagramSocket socket = new DatagramSocket();
byte[] bufSent = "register".getBytes();
DatagramPacket dpSent = new DatagramPacket(bufSent,bufSent.length, serverAddr, 8088);
socket.send(dpSent);
byte[] bufRecv = new byte[1024];
DatagramPacket dpReceive = new DatagramPacket(bufRecv, bufRecv.length);
socket.receive(dpReceive);
String serverMessage = new String(dpReceive.getData(), 0, dpReceive.getLength());
Log.v(LOGTAG, "Received " + serverMessage);
Server (Python):
import socket
UDP_IP_DEST = "10.0.0.11"
UDP_IP = "10.0.0.10"
UDP_PORT = 8088
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
if data:
print "received message:", data
sock.sendto("I got the message", (UDP_IP_DEST, UDP_PORT))
Does anyone see where is the mistake? The point is that I have tried to send the answer to another machine instead of the mobile and it works fine.
Thanks a lot.
I had a similar problem with receiving, here's some code we use in our app for Datagrams modified with your values, you can see we do a few things differently in the socket set up. mSocket is just a private DatagramSocket member variable. Give it a try. I think you might need to bind, and possible set the reuse address flag.
try
{
mSocket = new DatagramSocket(null);
mSocket.setReuseAddress(true);
mSocket.setBroadcast(false);
mSocket.bind(new InetSocketAddress(8088));
//Set a 1.5 second timeout for the coming receive calls
mSocket.setSoTimeout(1500);
String data = "myData";
DatagramPacket udpPacket = new DatagramPacket(data.getBytes(), data.length(), InetAddress.getByName("10.0.0.10"), 8088);
mSocket.send(udpPacket);
byte[] buf = new byte[1024];
DatagramPacket recvPacket = new DatagramPacket(buf, buf.length);
mSocket.receive(recvPacket);
String response = new String(recvPacket.getData());
}
catch (SocketException e)
{
e.printStackTrace();
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}

UDP Hole Punching Java Example

I want to do UDP Hole Punching with two clients with the help of a server with a static IP. The server waits for the two clients on port 7070 and 7071. After that it sends the IP address and port to each other. This part is working fine. But I'm not able to establish a communication between the two clients. I tried the code in different Wifi networks and in 3G mobile network. The client program throws the IO-Exception "No route to host".
The client code is used for both clients. Once executed with port 7070 and once with 7071.
Do you think I've implemented the UDP hole punching concept correctly? Any ideas to make it work?
Here's the server code first, followed by the client code.
Thank you for help.
Code of server:
public class UDPHolePunchingServer {
public static void main(String args[]) throws Exception {
// Waiting for Connection of Client1 on Port 7070
// ////////////////////////////////////////////////
// open serverSocket on Port 7070
DatagramSocket serverSocket1 = new DatagramSocket(7070);
System.out.println("Waiting for Client 1 on Port "
+ serverSocket1.getLocalPort());
// receive Data
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket1.receive(receivePacket);
// Get IP-Address and Port of Client1
InetAddress IPAddress1 = receivePacket.getAddress();
int port1 = receivePacket.getPort();
String msgInfoOfClient1 = IPAddress1 + "-" + port1 + "-";
System.out.println("Client1: " + msgInfoOfClient1);
// Waiting for Connection of Client2 on Port 7071
// ////////////////////////////////////////////////
// open serverSocket on Port 7071
DatagramSocket serverSocket2 = new DatagramSocket(7071);
System.out.println("Waiting for Client 2 on Port "
+ serverSocket2.getLocalPort());
// receive Data
receivePacket = new DatagramPacket(new byte[1024], 1024);
serverSocket2.receive(receivePacket);
// GetIP-Address and Port of Client1
InetAddress IPAddress2 = receivePacket.getAddress();
int port2 = receivePacket.getPort();
String msgInfoOfClient2 = IPAddress2 + "-" + port2 + "-";
System.out.println("Client2:" + msgInfoOfClient2);
// Send the Information to the other Client
// /////////////////////////////////////////////////
// Send Information of Client2 to Client1
serverSocket1.send(new DatagramPacket(msgInfoOfClient2.getBytes(),
msgInfoOfClient2.getBytes().length, IPAddress1, port1));
// Send Infos of Client1 to Client2
serverSocket2.send(new DatagramPacket(msgInfoOfClient1.getBytes(),
msgInfoOfClient1.getBytes().length, IPAddress2, port2));
//close Sockets
serverSocket1.close();
serverSocket2.close();
}
Code of client
public class UDPHolePunchingClient {
public static void main(String[] args) throws Exception {
// prepare Socket
DatagramSocket clientSocket = new DatagramSocket();
// prepare Data
byte[] sendData = "Hello".getBytes();
// send Data to Server with fix IP (X.X.X.X)
// Client1 uses port 7070, Client2 uses port 7071
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, InetAddress.getByName("X.X.X.X"), 7070);
clientSocket.send(sendPacket);
// receive Data ==> Format:"<IP of other Client>-<Port of other Client>"
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
clientSocket.receive(receivePacket);
// Convert Response to IP and Port
String response = new String(receivePacket.getData());
String[] splitResponse = response.split("-");
InetAddress ip = InetAddress.getByName(splitResponse[0].substring(1));
int port = Integer.parseInt(splitResponse[1]);
// output converted Data for check
System.out.println("IP: " + ip + " PORT: " + port);
// close socket and open new socket with SAME localport
int localPort = clientSocket.getLocalPort();
clientSocket.close();
clientSocket = new DatagramSocket(localPort);
// set Timeout for receiving Data
clientSocket.setSoTimeout(1000);
// send 5000 Messages for testing
for (int i = 0; i < 5000; i++) {
// send Message to other client
sendData = ("Datapacket(" + i + ")").getBytes();
sendPacket = new DatagramPacket(sendData, sendData.length, ip, port);
clientSocket.send(sendPacket);
// receive Message from other client
try {
receivePacket.setData(new byte[1024]);
clientSocket.receive(receivePacket);
System.out.println("REC: "
+ new String(receivePacket.getData()));
} catch (Exception e) {
System.out.println("SERVER TIMED OUT");
}
}
// close connection
clientSocket.close();
}
UPDATE
The code is generally working. I've tried it in two different home networks now and it's working. But it isn't working in my 3G or university network. In 3G, I verified that the NAT is mapping the two ports (the client port and by the router assigned port) together again, even after closing and opening the clientSocket. Has anyone an idea why it isn't working then?
UDP hole punching can't be achieved with all types of NAT. There is no universal or reliable way defined for all types of NAT. It is even very difficult for symmetric NAT.
Depending on the NAT behaviour, the port mapping could be different for different devices sending the UDP packets.
Like, If A sends a UDP packet to B, it may get some port like 50000. But if A sends a UDP packet to C, then it may get a different mapping like 50002. So, in your case sending a packet to server may give a client some port but sending a packet to other client may give some other port.
You shall read more about NAT behaviour here:
https://www.rfc-editor.org/rfc/rfc4787
https://www.rfc-editor.org/rfc/rfc5128
UDP hole punching not going through on 3G
For symmetric NAT (3G network connecting to a different mobile network), you need to do Multi-UDP hole punching.
See:
https://drive.google.com/file/d/0B1IimJ20gG0SY2NvaE4wRVVMbG8/view?usp=sharing
http://tools.ietf.org/id/draft-takeda-symmetric-nat-traversal-00.txt
https://www.goto.info.waseda.ac.jp/~wei/file/wei-apan-v10.pdf
http://journals.sfu.ca/apan/index.php/apan/article/view/75/pdf_31
Either that or relay all the data through a TURN server.
You rightly use a rendezvous server to inform each node of the others IP / port based on the UDP connection. However using the public IP and port which is the combination which will is obtained by the connection as you have, means that in scenarios where both hosts exist on the same private network hairpin translation is required by the NAT which is sometimes not supported.
To remedy this you can send the IP and port your node believes itself to have in the message to the server (private ip / port) and include this in the information each node receives on the other. Then attempt a connection on both the public combination (the one you are using) and the one I just mentioned and just use the first one which is successfully established.

UDP Holepunching behind NAT

I am trying to implement a simple sketch of UDP-Holepunching in Java to test it's concept and use it in my C/C++ application later on.
Concept:
As from Wikipedia I understood the concept as this:
Let A and B be clients behind an undefined networkstructure and C a well-known public reachable server.
A sends a packet to the server C, the server saves it's IP-Address and port. C will get the public IP-Address of A's NAT. Doing this, the NAT in front of A will create a route that will pass all packets on this port to A.
B does the same as A, sending a packet to server C, which will then save it's Address and port, B's NAT creates a route and so on.
At this point, C knows both address and port of each client. C will send the address and port of B to A and from A to B.
A sends a packet to B which will be rejected by B's NAT, but doing so will open a "hole" in A's NAT, letting further packets from B pass.
B sends a packet to A which will reach A, as a "hole" was "punched" before. Doing so will also open a "hole" in B's NAT, letting further packets from A pass.
The holepunch is now done and A and B should be able to communicate with each other P2P
This is all working well over localhost (which is not such a big surprise), but in a real-world-example this fails.
Problem:
A and B are both able to connect to server C, which gets their packets, stores their address and port and transmits it to the other client.
But at this point it fails. A and B are not able to communicate with each other.
So I am asking myself where I did wrong. I spent days searching for working examples in google and stackoverflow but all I stumbled upon is the suggestion to use STUN which is not what I want.
Implementation:
Below I will post my sketch in Java, as I do not know whether I have a problem with my concept or my implementation.
This is the code of the server:
public class Server
{
public static void main(String[] args)
{
int port1 = 0, port2 = 0;
String address1 = null, address2;
byte[] bytes = new byte[1024];
try
{
System.out.println("Server waiting");
DatagramSocket ds = new DatagramSocket(789);
while(!Thread.interrupted())
{
DatagramPacket p = new DatagramPacket(bytes, bytes.length);
ds.receive(p);
if(port1 == 0)
{
port1 = p.getPort();
address1 = p.getAddress().getHostAddress();
System.out.println("(1st) Server received:" + new String(bytes) + " from " + address1 + " on port " + port1);
}
else
{
port2 = p.getPort();
address2 = p.getAddress().getHostAddress();
System.out.println("(2nd) Server received:" + new String(bytes) + " from " + address1 + " on port " + port1);
sendConnDataTo(address1, port1, address2, port2, ds);
sendConnDataTo(address2, port2, address1, port1, ds);
}
}
ds.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static void sendConnDataTo(String a1, int p1, String a2, int p2, DatagramSocket ds)
{
byte[] bA, bP;
bA = a1.getBytes();
bP = Integer.toString(p1).getBytes();
DatagramPacket pck;
try
{
pck = new DatagramPacket(bA, bA.length, InetAddress.getByName(a2), p2);
ds.send(pck);
pck = new DatagramPacket(bP, bP.length, InetAddress.getByName(a2), p2);
ds.send(pck);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Please note, that this is just some sketch, no real application. The server should only receive packets from two clients, save their address and port and pass it to the other client.
This is the code of the client:
public class Client
{
private DatagramSocket socket;
private int init = 0;
private String target;
private int port;
public Client()
{
try
{
socket = new DatagramSocket();
}
catch(SocketException e)
{
e.printStackTrace();
}
Thread in = new Thread()
{
public void run()
{
while(true)
{
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
try
{
socket.receive(packet);
bytes = Arrays.copyOfRange(bytes, 0, packet.getLength());
String s = new String(bytes);
System.out.println("Received: " + s);
if(init == 0)
{
target = s;
System.out.println("Target: " + target);
init++;
}
else if(init == 1)
{
port = Integer.parseInt(s);
System.out.println("Port: " + port);
init++;
}
else System.out.println(new String(bytes));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
};
in.start();
connectToSupervisor();
}
private void connectToSupervisor()
{
byte[] bytes = new byte[1024];
System.out.println("Greeting server");
System.arraycopy("EHLO".getBytes(), 0, bytes, 0, 4);
try
{
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("localhost"), 789);
socket.send(packet);
System.out.println("Greetings sent...");
}
catch(IOException e)
{
e.printStackTrace();
}
send();
}
private void send()
{
while(init != 2)
{
try
{
Thread.sleep(20L);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println("Init completed!");
while(true)
{
byte[] b2 = "Hello".getBytes();
byte[] b1 = new byte[6];
System.arraycopy(b2, 0, b1, 0, b2.length);
try
{
DatagramPacket packet = new DatagramPacket(b1, b1.length, InetAddress.getByName(target), port);
socket.send(packet);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
new Client();
}
}
The client will just send a packet to the server, listen for packets from it, grab the connection-data from the other client and will then continuously send packets containing "Hello" to it.
I am sorry for the long code but I wanted to keep it complete.
I would be glad if anyone of you could point me to the mistakes I am doing, explain me why this is not working, give me a working example or at least point me to an alternative.
Your code seems to be correct. I tested your code and it works fine. The concept is also correct. But please check whether both the clients you run are within same NAT device or different NAT devices. If your are running both the clients under same NAT device then it may not work because not all NAT devices support hair pinning i.e, both clients send packets to NAT's external IP which needs to be passed to itself. For more information refer this link:
https://www.rfc-editor.org/rfc/rfc4787#section-6
Given your conceptual outline, I think there is an issue at point 4. Although A punches a hole through its own NAT, when B attempts to reach this hole it is unaware of the port on A's NAT (or more correctly/commonly - NAPT) and hence A's NAT drops the packet when B attempts to communicate.
Just a note for those following this great post, notice that in the server side, the second UDP packet received is announced as: System.out.println("(2nd) Server received:" + new String(bytes) + " from " + address1 + " on port " + port1); It should be System.out.println("(2nd) Server received:" + new String(bytes) + " from " + address2 + " on port " + port2); Its no big deal since its only an informative message, but it made me lose some time just wondering how the hell on earth the router was giving the same port to 2 different communications :P

Categories

Resources