In my application I'd like to get all the IP addresses that are taken by computers in the LAN using the broadcast address. I used the following code to determine the broadcast address.
InetAddress getBroadcastAddress()
{
try
{
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
Now that I have it, as far as I know, when one uses the broadcast address, every computer answers it, so if I simply send a "ping" message to that address, the computers of the LAN will answer it. How should I ping them in Android? What command would send me the taken addresses?
The following code simply returns the packet from the sending phone but I need the computers' addresses:
int PORT = 8080;
int DISCOVERY_PORT = 8080;
try
{
DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
String data="TEST";
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
getBroadcastAddress(), DISCOVERY_PORT);
socket.send(packet);
byte[] buf = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(buf, buf.length);
Log.w(Tags.DEBUG,"Receive start");
socket.receive(packet2);
Log.w(Tags.DEBUG,packet2.getAddress().toString());
}
catch (Exception e)
{
e.printStackTrace();
}
Is it even possible?
EDIT:
If I'm honest it works as it is written: my phone sends an UDP packet and my phone receives the incoming packages. As the only package is coming from my phone, it is obvious that the address is my phone's address. However, if the broadcast address is valid, each network interface should send the signal back. Am I correct?
You are partially correct.
When you send a UDP packet to a broadcast address, all the computers on the network will receive the packet, unless a router on the network restricts UDP packets being sent to the broadcast address. This is mostly the case on a corporate network.
But not all computers will reply to that packet, they need to know what to do with it.
Either you write a server application that understands your UDP packet and is configured to reply to that packet and deploy that server application to all of the computers on the network.
Or you implement an existing discovery protocol such as Bonjour (Mac) or SSDP (Windows)
I suggest you take a look at ZeroConf Service Discovery if you want to use existing protocols rather then deploying your own application.
http://en.wikipedia.org/wiki/Zero-configuration_networking#Service_discovery
I hope this explanation helps you with your problem.
Related
I intend to create an Android app that should discover computers on LAN. I tried to use ping the broadcast address. I've got two problems:
The determined broadcast address differs in Windows and on Android. Android tells me 10.255.255.255, http://www.remotemonitoringsystems.ca/broadcast.php tells me 10.111.111.255.
When I try to use the broadcast from command prompt, I get no result on any of the 2 addresses
In Android, I use the following code to determine the address:
InetAddress getBroadcastAddress()
{
try
{
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
What address should I use? Why can't I get any ping from computers on the LAN? How should I determine the existing computers on the LAN?
The approach was wrong.
Instead of pinging every existing computer, I should use the broadcast address to send out a specific message and receive reply from the computers that can read and understand that message.
That's how I eventually accomplished the task.
I want to receive mpegts over udp in my android application. I am using gstreamer for that. Right now, I am trying to send the mpegts stream from vlc player from the same computer over udp.
In my android application, I am giving the uri udp://10.0.2.2:1234 but the application gives error Could not get/set settings from/on resource. I have tried to get solutions from internet, but no luck so far.
1) UDP address range is from 224.0.0.0 to 239.255.255.255, so you cannot use 10.x.x.x
2) After you deal with adresses, refer to this link to deal with programmatic part:
Getting the Broadcast Address You need to access the wifi manager to get the DHCP info and construct a broadcast address from that:
InetAddress getBroadcastAddress() throws IOException {
WifiManager wifi = mContext.getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
Sending and Receiving UDP Broadcast Packets Having constructed the broadcast address, things work as normal. The following code would
send the string data over broadcast and then wait for a response:
DatagramSocket socket = new DatagramSocket(PORT);
socket.setBroadcast(true);
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
getBroadcastAddress(), DISCOVERY_PORT);
socket.send(packet);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
I'm currently developing an android app using SDK >= 16 which should be able to discover different android devices (later also iOS devices) in a local area network using the WiFi radio.
My first guess was to use multicast which turned out to be non functional on my Samsung Galaxy S2: packets are only received when sent from the same device.
My second guess is to actively scan the network using a limited IP address range and wait for a proper response. Unfortunately, this implies that the network uses DHCP to address the IP addresses.
None of the above solutions seem to be the perfect solution.
My current solution for my first guess:
public class MulticastReceiver extends AsyncTask<Activity, Integer, String> {
private static final String host = "224.1.1.1";
private static final int port = 5007;
private static final String TAG = "MulticastReceiver";
protected String doInBackground(Activity... activities) {
WifiManager wm = (WifiManager)activities[0].getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wm.createMulticastLock("mydebuginfo");
multicastLock.acquire();
String message = "Nothing";
if (multicastLock.isHeld()) {
Log.i(TAG, "held multicast lock");
}
try {
InetAddress addr = InetAddress.getByName(host);
MulticastSocket socket = new MulticastSocket(port);
socket.setTimeToLive(4);
socket.setReuseAddress(true);
socket.joinGroup(addr);
byte[] buf = new byte[5];
DatagramPacket recv = new DatagramPacket(buf, buf.length, addr, port);
socket.receive(recv);
message = new String(recv.getData());
socket.leaveGroup(addr);
socket.close();
} catch (Exception e) {
message = "ERROR " + e.toString();
}
multicastLock.release();
return message;
}
}
This code results in blocking on line socket.receive(recv); If I specify a timeout, I get a timeout exception.
Check my answer in very similar question Android Network Discovery Service (ish) before API 14
I do not belive that multicast is not working on Galaxy S2, some time ago when I was coding some network application, I made several test on many devices, some older like G1 but also on S2, S3 and Galaxy Tab 10.
But to be able to use multicast you must enable it programatically.
Have you used this piece of code?
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null){
WifiManager.MulticastLock lock = wifi.createMulticastLock("Log_Tag");
lock.acquire();
}
Check out http://developer.android.com/training/connect-devices-wirelessly/index.html It mentions two ways of finding local services- NSD and wifi direct.
I am experiencing a problem on Android when sending SIP packets over UDP to the port 5060 using a device instead of the emulator. The exception is:
java.net.SocketException: sendto failed: EPERM(Opereation not permitted)
On some devices such as the Galaxy Nexus the same code works bot on other devices such as the Asus Transformer TF101 and the Galaxy Tab 2 I am experiencing these problems. I have the required permission android.permission.INTERNET. When sending the same SIP packet over another port (say 9876) the packet is sent successfully. Even when sending other content over port 5060 (not SIP packets) the packet is still sent successfully. It seems that the combination of SIP packets over port 5060 are not being permitted on some devices. I created a test program to replicate this problem:
try
{
DatagramSocket clientSocket = new DatagramSocket();
InetAddress IPAddress = InetAddress.getByName("10.111.110.6");
byte[] sendData = new byte[1024];
byte[] receiveData = new byte[1024];
String sentence = "Register sip ...";
sendData = sentence.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, IPAddress, 5060);
clientSocket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
clientSocket.receive(receivePacket);
int x = receivePacket.getLength();
String modifiedSentence = new String(receivePacket.getData(), 0, x);
ds_tv.setText("FROM SERVER:" + modifiedSentence + " Length: "+ x);
clientSocket.close();
}
catch (Exception e)
{
Log.e("Test", e.getMessage());
ds_tv.setText(e.getMessage());
}
This test program consists just of a single button and the above code is called in its onClick() event. The packet consisting of the String sentence which contains the SIP registration packet is not sent over port 5060. If I modify the port, the packet is sent successfully and even if I modify the content of the string sentence. However if I send the SIP registration packet over port 5060 the SocketException occurs. I do not know what could be the problem or how to go about solving such an issue.
The problem has been solved and the error was being caused from the payload of the SIP packet. The CSeq value in the SIP packet was being set to 0 initially. Instead it had to start from 1.
I would like to know about the 'service discovery' mechanisms supported by android - particularly, Printer Discovery.
Does android provide such a discovery option? example : support for snmp broadcast?
I tried out an application "PrinterShare" link : http://www.printeranywhere.com/mobile.sdf where Printer Discovery is achieved through ipp.
Any help is appreciated.
Roy, I came across the same problem as you, and was even getting the same behavior when running that code snippet on an actual device (while running the code standalone, not in android, worked fine). I found this page and got it working, although only on the device, by using the following to figure out the Broadcast IP (instead of 239.255.255.250):
InetAddress getBroadcastAddress() throws IOException {
WifiManager wifi = mContext.getSystemService(Context.WIFI_SERVICE);
DhcpInfo dhcp = wifi.getDhcpInfo();
// handle null somehow
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
return InetAddress.getByAddress(quads);
}
Hope that helps:)
Does android provide such a discovery option?
Not that I am aware of, sorry.
This code snippet works fine on J2SE. However, on the Android emulator, I get a 'Time Out Exception' with response = 'null'
`DatagramSocket clientSocket = new DatagramSocket(8888);
clientSocket.setSoTimeout(20000);
/**
* SSDP is a text-based protocol based on the Hypertext Transfer Protocol (RFC 2616).
* However, it uses the User Datagram Protocol (UDP) as underlying transport protocol.
* Services are announced by the hosting system with multicast addressing to a
* specifically designated IP multicast address at port number 1900. In IPv4,
* the multicast address is 239.255.255.250.
*/
//getByName(host) //host the hostName to be resolved to an address or null.
InetAddress group = InetAddress.getByName("239.255.255.250");
//host can be null which means that an address of the loopback interface is returned.
if(group == null){
Log.d("Discovery","getByName(): returns address of loopback interface.");
}
byte[] sendData;
byte[] receiveData = new byte[128];
String sentence = "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "MX: 10\r\n"
+ "ST: ssdp:all\r\n"
+ "\r\n";
sendData = sentence.getBytes();
//public DatagramPacket (byte[] data, int length, InetAddress host, int port)
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, group, 1900);
try {
clientSocket.send(sendPacket);
} catch (Exception e) {
e.getMessage();
e.printStackTrace();
}
Log.d("Discovery","sent packet...");
while( true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
try
{
boolean isc = clientSocket.isConnected();
clientSocket.receive(receivePacket);
}
catch ( Exception Ex)
{
Log.d("Discovery","Time out Exception");
}
if (receivePacket.getAddress() == null)
{
Log.d("Discovery","receivePacket.getAddress() == null");
break;
}
Log.d("Discovery","Senders Address : " + receivePacket.getAddress().getHostAddress());
String controllerResponse = new String(receivePacket.getData());
} //end of while()
clientSocket.close(); `
For evaluation of SSDP in .NET this library may be useful
https://yortw.github.io/RSSDP/