I am trying to develop an app that sends some broadcast messages and receives some answers from the other android devices. I am having some trouble receiving the UDP messages from the other devices. I should mention that this code worked on Gingerbread but on JellyBean it's not working anymore and I do not know what might be the problem.
Here is where I send the broadcast message (I know the other devices listen on port 5000) :
private void sendUDPMessage(String msg) {
try {
DatagramSocket clientSocket = new DatagramSocket();
clientSocket.setBroadcast(true);
InetAddress address = InetAddress.getByName(Utils.getBroadcastAddress());
byte[] sendData;
sendData = msg.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData,
sendData.length, address, 5000);
clientSocket.send(sendPacket);
clientSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
And here is where I receive it :
private void start_UDP()
{
try {
serverSocketUDP = new DatagramSocket(5000);
}
catch (Exception e) {
Log.i(LOGTAG, "Exception opening DatagramSocket UDP");
}
final byte[] receiveData = new byte[1024];
while(runningUDP) {
Log.d(LOGTAG, "Waiting for Broadcast request in ServerUDP.");
final DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocketUDP.receive(receivePacket);
byte[] sendData = new byte[1024];
InetAddress address = receivePacket.getAddress();
int port = receivePacket.getPort();
if(!receivePacket.getAddress().getHostAddress().equals(Utils.getLocalIpAddress()))
{
String req = new String(receivePacket.getData(), 0, receivePacket.getLength());
Log.d(LOGTAG, "Received UDP message : "+req+" from: "+receivePacket.getAddress().getHostAddress());
}
}// while ends
}//method ends
I should mention that these 2 functions are separate in 2 different threads so I can send and receive simultaneously.
I also acquire the following locks:
powerManager =(PowerManager)context.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK ,LOGTAG); // PARTIAL_WAKE_LOCK Only keeps CPU on
wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock(3, LOGTAG);
multicastLock = wifiManager.createMulticastLock(LOGTAG);
wakeLock.acquire();
multicastLock.acquire();
wifiLock.acquire();
And the permissions on the Manifest file :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
I have tested if the messages are sent using wireshark and tcpdump and they are sent. Moreover, what is even more strange, I receive the broadcast messages that I send (but I discard them because I dont need to process the messages sent from myself) but I dont receive the broadcast messages sent from the other devices (which should have the same format, only the source address would be different and the message contained, either way should not affect the broadcast message).
Please let me know if you have any ideas because I really ran out of anything else I could try. Any help would be appreciated. Thanks!
EDIT:
I have made some tests and even if when I run on each of the phones ifconfig wlan0 and it says something like
ifconfig wlan0
wlan0: ip 169.254.17.28 mask 255.255.0.0 flags [up broadcast multicast]
which means that the interface is active and the IP is set and can receive broadcast messages and multicast msgs but when I use
InetAddress in=InetAddress.getByName("169.254.17.28");
if (in.isReachable(1000))
Log.i(LOGTAG, "host is reachable");
else
Log.i(LOGTAG, "host is not reachable");
It shows in the logs host is not reachable.
This is where I turn on the Wi-fi
private void startWifiAdhoc() {
WifiManager wifiManager = (WifiManager)SharingFileService.context.getSystemService(Context.WIFI_SERVICE);
String command="";
if (condWifiAdhoc == false) {
condWifiAdhoc=true;
wifiInterface = Utils.getWifiInterface();
wifiManager.setWifiEnabled(true);
localIP = Utils.getLinkLocalAddress();
}
else
{
wifiManager.setWifiEnabled(true);
localIP = Utils.getLinkLocalAddress();
}
// Set wifi ad-hoc
command = context.getFilesDir().getPath()
+ "/iwconfig " + wifiInterface + " mode ad-hoc essid "
+ "mcp" + " channel " + "1" + " commit\n";
Log.i(LOGTAG, command);
Utils.rootExec(command);
Log.i(LOGTAG, "Ip address used :" + localIP);
command = context.getFilesDir().getPath()
+ "/ifconfig " + wifiInterface + " " + localIP
+ " netmask 255.255.0.0 up\n";
Log.i(LOGTAG, command);
Utils.rootExec(command);
}
I got this working by using a method described here to calculate the broadcast address: https://code.google.com/p/boxeeremote/wiki/AndroidUDP
Here's my receiver:
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
socket = new DatagramSocket(Constants.PORT, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while (true) {
Log.i(TAG,"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
Log.i(TAG, "Packet received from: " + packet.getAddress().getHostAddress());
String data = new String(packet.getData()).trim();
Log.i(TAG, "Packet received; data: " + data);
// Send the packet data back to the UI thread
Intent localIntent = new Intent(Constants.BROADCAST_ACTION)
// Puts the data into the Intent
.putExtra(Constants.EXTENDED_DATA_STATUS, data);
// Broadcasts the Intent to receivers in this app.
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
} catch (IOException ex) {
Log.i(TAG, "Oops" + ex.getMessage());
}
And here's my sender:
public void sendBroadcast(String messageStr) {
// Hack Prevent crash (sending should be done using an async task)
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
//Open a random port to send the package
DatagramSocket socket = new DatagramSocket();
socket.setBroadcast(true);
byte[] sendData = messageStr.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, getBroadcastAddress(), Constants.PORT);
socket.send(sendPacket);
System.out.println(getClass().getName() + "Broadcast packet sent to: " + getBroadcastAddress().getHostAddress());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.getMessage());
}
}
InetAddress getBroadcastAddress() throws IOException {
WifiManager wifi = (WifiManager) 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);
}
I came across your post when trying to solve a similar issue. Did you get your stuff working?
In my case, I had been trying to get a Nexus 7 (first gen with Jelly Bean 4.3) and Nexus One (Gingerbread 2.3.6) talking to each other via UDP. Initially my app, running on both devices, would successfully link up but only with one-way communication from the phone to the tablet. I had only one permission in place in the manifest: INTERNET. Communication from the tablet to the phone started working once I had added the ACCESS_NETWORK_STATE permission to the manifest.
So, for some reason, the Nexus 7 is happy with just the INTERNET permission for both sending and receiving UDP packets (well, my particular implementation of it, at least). The Nexus One will send with only the INTERNET permission but will not receive unless the ACCESS_NETWORK_STATE permission is given as well.
Your code looks similar to mine (I don't recognize your "UTILS." calls, however). In my case, though, for the purposes of testing, I've hard-coded the broadcast address (192.168.n.255). I'm on an access point while you're on an adhoc network. Perhaps that has some effect as well.
Related
I created a UDP Broadcast listener in my application and work great with all most device.
But does not work with these two f****g tablet, the application get stuck at :
"socket.receive(packet)"
The application is exactly the same and also android version is the same: Android 12.
My snipped code :
try {
//Keep a socket open to listen to all the UDP trafic that is destined for this port
val ip = getLocalIpAddress()?.split(".")
val broadcastIp = ip!![0] + "." + ip[1] + "." + ip[2] + ".255"
val inetAddress = InetAddress.getByName(broadcastIp)
val socket = DatagramSocket(9098, inetAddress)
socket.broadcast = true
while (true) {
val recvBuf = ByteArray(15000)
val packet = DatagramPacket(recvBuf, recvBuf.size)
//Receive a packet
socket.receive(packet)
//Packet received
val data = String(packet.data).trim { it <= ' ' }
count++
runOnUiThread {
txt?.append("Ricevo $count <------------$data\n")
sv!!.fullScroll(ScrollView.FOCUS_DOWN)
}
Log.d("Main", data)
}
} catch (err: Exception) {
err.printStackTrace()
}
Someone had the same issue with the new Samsung Devices???
The tablets are not rooted.
Thanks in advance.
I created a very simple application that only can receive UDP broadcast message, just to avoid other releated issue from my application.
On the older device with android 12 the UDP broadcast works correctly instead on the new Samsung device the UDP broadcast message does not work at all.
I am sending data from my development machine (Mac) via a Java socket client to android emulator which acts as the socket server. So basically I start android program first which opens socket port and waits for the data.
onStart calls two functions one to get IP, other to open server socket
#Override
protected void onStart() {
super.onStart();
getDeviceIpAddress();
new Thread(new start_siddhi_server()).start();
} //onStart
Code used to get IP is
public void getDeviceIpAddress() {
try {
//Loop through all the network interface devices
for (Enumeration<NetworkInterface> enumeration = NetworkInterface
.getNetworkInterfaces(); enumeration.hasMoreElements(); ) {
NetworkInterface networkInterface = enumeration.nextElement();
//Loop through all the ip addresses of the network interface devices
for (Enumeration<InetAddress> enumerationIpAddr = networkInterface.getInetAddresses(); enumerationIpAddr.hasMoreElements(); ) {
InetAddress inetAddress = enumerationIpAddr.nextElement();
//Filter out loopback address and other irrelevant ip addresses
if (!inetAddress.isLoopbackAddress() && inetAddress.getAddress().length == 4) {
//Print the device IP address into the text view
Log.d("ip address", inetAddress.getHostAddress());
}
}
}
} catch (SocketException e) {
Log.e("ERROR:", e.toString());
}
}
Code used to start server socket is
class start_siddhi_server implements Runnable {
#Override
public void run() {
Log.d("E", "starting siddhi server.........");
// Creating Siddhi Manager
SiddhiManager siddhiManager = new SiddhiManager();
String definition1 = " define stream temprature (room_no string, temp int);";
String query1 = "#info(name = 'query1') from temprature[temp >= 10] " +
"select room_no, temp " +
"insert into myOutputStream; ";
//Generating runtime
SiddhiAppRuntime siddhiAppRuntime = siddhiManager.createSiddhiAppRuntime(definition1 + query1);
//Adding callback to retrieve output events from query
siddhiAppRuntime.addCallback("myOutputStream", new StreamCallback() {
#Override
public void receive(Event[] events) {
// for loop for iterating each event
for (Event event : events) {
Log.d("complex event = ", " Temp is " + event.getData(1));
} //end of for
} // end of receive method
}); // end of callback
// getting input handler
InputHandler inputHandlerA = siddhiAppRuntime.getInputHandler("temprature");
// starting siddhi app
siddhiAppRuntime.start();
// starting server socket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(7000);
} catch (IOException e) {
e.printStackTrace();
}
Socket socket = null;
Log.d("E", " Siddhi server is waiting for sensor data.........");
while (true) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
if (socket.isConnected() == true) {
Log.d("E", "connection is successful........");
InputStreamReader isReader = null;
try {
isReader = new InputStreamReader(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
BufferedReader input = new BufferedReader(isReader);
String line;
try {
while ((line = input.readLine()) != null) {
String[] tupleData = line.split(",");
String[] sensor_value = new String[10];
int i = 0;
for (String tuple : tupleData) {
String[] tupleValue = tuple.split("=");
sensor_value[i] = tupleValue[1];
i += 1;
}// key pair of tuple ends
Integer patient_id = Integer.valueOf(sensor_value[0]);
Integer sensor_id = Integer.valueOf(sensor_value[1]);
Integer uid = Integer.valueOf(sensor_value[2]);
Long egtl = Long.valueOf(sensor_value[3]);
Long edtl = 0L;
// Long edtl = Long.valueOf(sensor_value[4]);
Integer value = Integer.valueOf(sensor_value[4]);
inputHandlerA.send(new Object[]{uid, value});
// Log.d("patient_id = ", String.valueOf(patient_id));
// Log.d("sensor_id = ", String.valueOf(sensor_id));
// Log.d("uid = ", String.valueOf(uid));
// Log.d("egtl = ", String.valueOf(egtl));
}//while
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} //socket.isConnected()
} //while (true)
} //run
} // runnig_server
Also, the permissions in manifest file are
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--The Paho Android Service needs the following permissions to work-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Case 1 .
when I run it using emulator I get the following IP
10.0.2.15
Result of ifconfig is same as well
generic_x86:/ $ ifconfig eth0
eth0 Link encap:UNSPEC Driver virtio_net
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::5054:ff:fe12:3456/64 Scope: Link
inet6 addr: fec0::5054:ff:fe12:3456/64 Scope: Site
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:3565 errors:0 dropped:0 overruns:0 frame:0
TX packets:4068 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1190457 TX bytes:971370
But the issue is that I am not able to send data to this port.
I have tried following IP's
10.0.2.1
10.0.2.2
10.0.2.15
localhostip
Case 2 .
But when I run the same code in Genymotion I get the following result
IP address: 192.168.56.101
When I send data to this IP it works.
What I am doing wrong?
How can I make it work for the android emulator?
I want to u the e android emulator as it is free 😀
Edit 1
the issue was solved by port forwarding
adb forward tcp:7000 tcp:7000
Now the problem is that I am not able to see network data in profiler in case I am using emulator
But in case I am using Genymotion , I am able to see the network data
You should add a port forwarding
adb forward tcp:7000 tcp:7000
and then use localhost:7000 to send data from your computer to the emulator.
The reason for this is that emulator creates a private virtual network (10.0.2.0) which is not bridged, so to be able to access it you have to forward ports.
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.
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/