Flutter - How to Implement Network Service Discovery - flutter

I want to discover the deices which are running a specified service exposed to the local network, but I don't know how to.
For example I want local IP address and port number of the devices running service '_googlecast._tcp.'.
Is there any way to achieve this in Flutter ?
Thanks in advance

Check multicast DNS package: A Dart package to do service discovery over multicast DNS (mDNS), Bonjour, and Avahi.
Essentially, create a mDNS Client and get PTR record for the service, as:
const String name = '_googlecast._tcp.local';
final MDnsClient client = MDnsClient();
await client.start();
// Get the PTR recod for the service.
await for (PtrResourceRecord ptr in client
.lookup<PtrResourceRecord>(ResourceRecordQuery.serverPointer(name))) {
// Use the domainName from the PTR record to get the SRV record,
// which will have the port and local hostname.
// Note that duplicate messages may come through, especially if any
// other mDNS queries are running elsewhere on the machine.
await for (SrvResourceRecord srv in client.lookup<SrvResourceRecord>(
ResourceRecordQuery.service(ptr.domainName))) {
// Domain name will be something like "io.flutter.example#some-iphone.local._dartobservatory._tcp.local"
final String bundleId =
ptr.domainName; //.substring(0, ptr.domainName.indexOf('#'));
print('Dart observatory instance found at '
'${srv.target}:${srv.port} for "$bundleId".');
}
}
client.stop();
print('Done.');

Related

Flutter SocketException: Failed host lookup: 'xxxxxx.local'

I have a raspberry pi in my lan with the hostname 'xxx.local'. My phone is connected to the wifi but everytime I try to fetch data from my REST backend using the '.local' address i get this exception:
'SocketException (SocketException: Failed host lookup: 'xxx.local' (OS Error: No address associated with hostname, errno = 7))'
But it works fine when I try to connect to it via ssh or even when I try to fetch data using postman.
Is it possible that it has something to do with the mobile data, since it is deactivated because my test phone has no sim card inside. If yes, would it be possible to work without sim card?
The code where I try to fetch the data:
static Future<List<Device>> fetchDevices() async {
final response = await http.get('http://test-hub.local:9080/devices');
if (response.statusCode == 200) {
final data = json.decode(response.body);
print(data);
List<Device> responses =
data.map<Device>((j) => Device.fromJson(j)).toList();
print(responses);
return responses;
} else {
throw Exception(
'Failed to load Devices: ${response.statusCode} [${response.reasonPhrase}]');
}
}
I got stuck on this for a long time, The issue is that Android currently does not support mdns lookups (.local).
I don't know how you are getting your mdns address, but for people using the multicast_dns package you can fetch the ip address as described here. Then you can use the IP address for your http queries

Multicast between server and client with or without a router not knowing server IP in advance and possible diferent sub-net

I'm writing in Python software that runs on my Windows (and Linux) PC, while the PC is connected via LAN (with or without a router) to a second device.
The second device sends UDP multicast packets to a known multicast group address and port.
The software in the computer is configured to be part of the same multicast group.
This is working OK as long as both my computer and the server network configuration are on the same sub-net.
Now, most of the times I will don't know the IP of the device in advance and I'll be connecting my computer directly to the server point-to-point. (Imagine the software that comes with IP security cameras that allows you to discover or know the IP of the camera when connecting directly to them with out knowing it in advance and without being in the same sub-net). E.g my computer has IP 169.x.x.x/24 and the server has IP 10.1.1.100 but I do not know the server IP in advance.
For reasons out of my control, the device cannot be configured to be a DHCP server so it cannot assign IP to my computer and cannot use DNS.
How can I receive the UDP multicast packets without raw capture?
This is my current code for the socket configuration that is working when both the computer and the server have the same sub-net. Ex 10.1.1.100/16 and 10.1.1.60/16 but needs to work also as mentioned above.
class MulticastSocket(object):
"""Sends UDP packets to multicast addressses."""
def __init__(self, bind_ip=None):
self._create(bind_ip)
def _create(self, bind_ip):
self.bind_addr = bind_ip
# chosen arbitrary from IANA's Scoped Multicast Range
# https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml#unicast-prefix-based
self.multicast_group = '239.6.2.86'
self.multicast_port = 6286
"""Creates a multicast UDP socket"""
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
self._sock.settimeout(6)
ttl = 2
self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
self._sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(self.bind_addr))
membership_request = struct.pack('4s4s', socket.inet_aton(self.multicast_group),
socket.inet_aton(self.bind_addr))
self._sock.setsockopt(
socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, membership_request)
self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if sys.platform == 'linux':
bind_addr = self.multicast_group
else:
bind_addr = self.bind_addr if self.bind_addr else ''
self._sock.bind((bind_addr, self.multicast_port))
def get(self):
"""use to get the socket object to work with the select as select only accept sockets objects"""
return self._sock
def send(self, msg):
return self._sock.sendto(msg, (self.multicast_group, self.multicast_port))
def recv(self, len):
try:
response = self._sock.recvfrom(len)
return response
except socket.timeout:
return "", ""
def close(self):
self._sock.close()

WiFiP2PManager Connect WiFiP2PConfig - pass port number to client?

I've implemented a Xamarin app that successfully peers to another instance of itself running on another device using WiFiP2PManager, OnPeersAvailable and OnConnectionInfoAvailable (etc.).
My challenge now is I'd like the group owner to specify the PORT the client(s) will use to connect.
SERVER
var serverSocket = new ServerSocket(port); <<< PASS THIS PORT NUMBER TO THE CLIENT.
client = serverSocket.Accept();
CLIENT
client = new Socket();
InetSocketAddress socketAddress = new InetSocketAddress(address, port); <<< PORT PASSED FROM THE SERVER
client.Connect(socketAddress);
Is there any way I can pass additional information to the peer that it can use for connection, such as the port number?
Thanks
-John

I not able to connect to ibm bluemix

This is the code that has been used. The IP that is used is on the same WiFi network to which my laptop is connected. Only the last digit is different.
#include <Ethernet.h>
#include<SPI.h>
#include <PubSubClient.h>
byte mac[] = { 0x12, 0xED, 0xBA, 0xFE, 0x2E, 0xED };
String macstr="12edbafe2eed";
byte ip[] = {192,16,1,1};
EthernetClient ethClient;
char servername[]="99elnd.messaging.internetofthings.ibmcloud.com";
PubSubClient client(servername, 1883,ethClient);
void setup()
{
Serial.begin(9600);
Serial.println("Arduino MQTT v.1.2");
Ethernet.begin(mac,ip);
}
void loop()
{
char clientStr[33];
String clientName = String("d:99elnd:arduno_mitul:12edbafe2ee2");
clientName.toCharArray(clientStr,33);
char token[] = "mituliot7450";
while (!client.connected()) {
Serial.println("Reconnecting client … ");
client.connect(clientStr, "use-token-auth", token);
}
String data = "{\"d\": {\"TEST\":";
data+=random(10);
data+="} }";
char jsonStr[33];
data.toCharArray(jsonStr,33);
char topicStr[33];
String topicName = String("iot-2/evt/status/fmt/json");
topicName.toCharArray(topicStr,33);
Serial.print("attempt to send");
Serial.print(jsonStr);
Serial.print("to");
Serial.println(topicStr);
if (client.publish(topicStr,jsonStr))
Serial.println("successfully sent");
else
Serial.println("unsuccessfully sent");
Serial.println("Disconnecting client … ");
client.disconnect();
delay(5000);
}
The serial monitor prints:
Arduino MQTT v.1.2
Reconnecting client …
Reconnecting client …
Reconnecting client …
Reconnecting client …
Reconnecting client …
Its slightly strange you are using 192,16,1,1 as your IP. Typically x.x.x.1 is the default gateway for a given network. If that is the case in your network, then there will be an IP conflict and your device will not have Internet connectivity. This appears to be the case as the credentials from your sketch do work, but there is no record of that device ever even attempting to connect prior to my testing.
You could use DHCP instead which is probably more portable as in the hello world client example here:
http://www.tweaking4all.com/hardware/arduino/arduino-ethernet-data-pull/
or try using the IP address of your laptop (while that is disconnected of course) if indeed your laptop is also using static IP assignment. I've found that, if the gateway and the DHCP server are one and the same device, it will not route traffic for an IP it has not supplied via DHCP, even if it is a valid and unused IP address. You have to limit the range of addresses the DHCP server can dish out in order to free up some to be used in static assignment.
Looks like maybe you are passing the wrong token for authentication - I see some authentication errors in the Watson-IoT log. Please confirm you are passing the correct authentication token that was generated when you registered the device.

How to configure exim to send mails to LAN without DNS

I am trying to configure exim to send mails directly over LAN without DNS, but I have no luck doing it...
On both ends there is a server with one Internet-facing interface and one local interface. I need to use the local interface.
When I telnet to port 25 from one server to another, it works like a charm. However, when I try to send mail via exim, it insist that I am trying to send the mail to myself.
I have added this router to server with local interface 11.11.0.1:
new_router:
driver = manualroute
domains = 11.11.0.2
transport = remote_smtp
route_list = * 11.11.0.1
and even forced the remote_smtp to use the correct interface:
remote_smtp:
driver = smtp
interface = 11.11.0.1
This is what I get if I try to send a mail form 11.11.0.1 to 11.11.0.2:
2014-03-16 22:11:38 1WPILK-0004YD-O1 == test#11.11.0.2 R=new_router defer (-1): remote host address is the local host
2014-03-16 22:11:39 1WPILK-0004YD-O1 Frozen
This should be the relevant part of the log:
--------> new_router router <--------
local_part=test domain=11.11.0.2
checking domains
11.11.0.2 in "11.11.0.2"? yes (matched "11.11.0.2")
calling new_router router
new_router router called for test#11.11.0.2
domain = 11.11.0.2
route_item = * 11.11.0.1
11.11.0.2 in "*"? yes (matched "*")
original list of hosts = "11.11.0.1" options =
expanded list of hosts = "11.11.0.1" options =
set transport remote_smtp
finding IP address for 11.11.0.1
calling host_find_byname
gethostbyname2(af=inet6) returned 1 (HOST_NOT_FOUND)
local host found for non-MX address
fully qualified name = 11.11.0.1
gethostbyname2 looked up these IP addresses:
name=11.11.0.1 address=11.11.0.1
LOG: MAIN
remote host address is the local host: 11.11.0.2
new_router router: defer for test#11.11.0.2
message: remote host address is the local host
added retry item for R:11.11.0.2: errno=-1 more_errno=0 flags=0
post-process test#11.11.0.2 (1)
LOG: MAIN
== test#11.11.0.2 R=new_router defer (-1): remote host address is the local host
Do you have any idea how to convince exim to not treat 11.11.0.2 as a local address?
Thanks,
Drasha
It seems your exim thinks 11.11.0.2 refers to your own machine, i.e. you have some configuration setting (local_interfaces, extra_local_interfaces or hosts_treat_as_local) that includes 11.11.0.2.
By default the manualroute router is intended to give you a remote host, but that can also be adjusted by adding
self = send
to your new_router configuration, although it would be better to fix the original problem instead of patching the symptoms as you might run into all kinds of other strange problems if you have messed up what is considered local hosts and not.
BTW, what does the command exim -bP | grep local show?