I have a raspberry pi, which is setup as a audio streaming server. I have used websockets and python as programming language. The client can listen to the live audio stream by connecting to the server hosted on raspberry pi. The system works well in localhost environment. Now, I want to access the server from the internet and by searching I got to know about STUN. I tried to use pystun but I couldn't get the proper port for NAT punching. So can anyone help me to implement STUN?
Note: server is listening at localhost:8000
Just Googling for STUN Python resulted in this:
https://pypi.python.org/pypi/pystun
Go to the bottom of that page and you'll find a link to the source code. Unpack it and the core STUN code is in the __init__.py file.
Back to your audio server. If it's a true client/server protocol and using only a single port for all communications, you don't need STUN per se. You just need to open a port on your NAT such that any client from the outside world can connect. If the protocol is more complicated (ports are dynamically negotiated in a peer to peer style), then you will need something like STUN on top of a signaling protocol service that is directly connected to the Internet.
NAT punching is used for peer-to-peer (P2P) communication and your audio streaming server seems to be a client-server implementation.
How and if this is going to work heavily depends on your NAT device (which kind of NAT is implemented). Chances are high that your NAT device has short timeouts and you need to punch holes for every client connection (from your raspberry pi).
As you stated you're using WebSockets and these are always TCP, pystun isn't going to work because pystun only supports UDP.
I'd suggest to create a port forwarding in your NAT device, tunnel your traffic using a P2P VPN or host your audio streaming server on a different network.
Related
I understand the upgrade handshake and then the creation of the WebSocket channel on a totally different socket, but I'm puzzled as to why this is not a problem when firewalls may block all traffic except that which is bound for 80 (or 443). It seems that the WebSocket traffic hosted at its own (non-80, non-443) port would get blocked -- but clearly WebSockets are mature and effective so I must be missing something. How does the WebSocket traffic on the non-80/non-443 port traverse firewalls? Is this related (no pun intended) to routing rules ESTABLISHED/RELATED? The following seems to come close to a solid answer:
https://stackoverflow.com/a/2291861/6100445
...that is, the WebSocket traffic is established in an outbound sense from the browser over HTTP and then established in an outbound sense from the WebSocket server over the new WebSocket port?
WebSockets are "designed to work over HTTP ports 443 and 80":
https://datatracker.ietf.org/doc/html/rfc6455
(also https://en.wikipedia.org/wiki/WebSocket)
But many tutorials launch separate WebSocket servers on totally different port numbers (e.g. 8001 is used commonly). A good example is the websockets package on PyPI, which uses port 8001 and flatly states WebSockets and HTTP servers should run on separate ports:
https://websockets.readthedocs.io/en/stable/intro/tutorial1.html
https://websockets.readthedocs.io/en/stable/faq/server.html#how-do-i-run-http-and-websocket-servers-on-the-same-port
A lot of material on the Web is hand-waving and glosses over some detail with statements like WebSockets "use the same port as HTTP and therefore get through firewalls" (I assume they mean the upgrade/handshake portion) but many other sources indicate that a WebSocket server (on the same computer as the HTTP server) should be established on a different port (I assume because the HTTP server is already bound to 80 (or 443), and this different non-80/non-443 port therefore carries the upgraded WebSocket traffic). The separate ports make sense from a TCP/IP socket binding perspective. What am I missing about how WebSockets use 80 (or 443) for the upgrade/handshake, a separate port for the WebSocket established traffic, yet still work through firewalls where the only traffic allowed is that which is destined for port 80 (or 443)?
I have an embedded system on which I can connect to internet. This embedded system must send sensor data to PC client.
I put a socket client using python on my PC. I put a socket server ( using C++ language on the embedded system because you can only use C++ ).
I can succesfully connect from my PC to the embedded system using the sockets and send and recieve whatever I want.
Now, the problem is I use local IP to connect to the system and both of them must be connected to the same Wifi router.
In the real application, I won't know where the embedded system is in the world. I need to get to it through internet, because it will be connectet to internet through 4g.
My question is, how can I connect to it through internet, if the embedded system is connected to internet using 4G?
Thank you
Realistically in typical situations, neither a PC nor an embedded device hanging off a 4g modem will likely have (or should be allowed) to have externally routable addresses.
What this practically means is that you need to bounce your traffic through a mutually visible relay in the cloud.
One very common way of doing that for IoT devices (which is basically to say, connected embedded devices) is to use MQTT. You'll find support in one form or another for most computing platforms with any sort of IP networking capability.
Of course there are many other schemes, too - you can do something with a RESTful API, or websockets (perhaps as an alternate mode of an MQTT broker), or various proprietary IoT solutions offered by the big cloud platforms.
It's also going to be really key that you wrap the traffic in SSL, so you'll need support for that in your embedded device, too. And you'll have to think about which CA certs you package, and what you do about time given its formal requirement as an input to SSL validation.
I think your problem is more easily solved if you reverse the roles of your embedded system and PC. If you are communicating to a device using IP protocols across cellular networks, it is much easier to have the device connect to a server on the PC rather than the other way around. Some networks/cellular modems do not allow server sockets and in any case, the IP address is usually dynamically allocated and therefore difficult to know. By having the device connect to a server, it "knows" the domain name (or IP address) and port to which it should make the connection. You just have to make sure that there is indeed a server program running at that host bound to some agreed upon port number. You can wake up the device to form the connection based on a number of criteria, e.g. time or amount of collected data, etc.
I've recently been learning electric circuitry using arduino and am looking to implement some changes to my Raspberry Pi application.
I used this outdated tutorial a few years ago to create my pi bluetooth receiver which is working well at the moment (https://www.instructables.com/id/Turn-your-Raspberry-Pi-into-a-Portable-Bluetooth-A/) but one downfall of this out-dated tutorial is that bluetooth connections have to be accepted via the screen (which is off because bluetooth speakers do not have screens).
My plan: use a button to accept bluetooth connections and use a flashing green LED to indicate a connection request.
How can I create a script that 'listens' for bluetooth pairing requests and run python code accordingly when its listening? With this, how can I connect to the bluetooth to accept a pair request?
I'm not too familiar with Raspberry Pi script placement, but am familiar with Python and know how I can connect to GPIO.
Thanks :)
What you are searching for is called a Bluetooth Agent. You need to use an official linux bluetooth protocol stack BlueZ. There is documentation describing the Agent API link. It uses DBus for communication. You need to invoke the following steps:
Create a bluetooth agent written in python and publish it at certain DBus object path. Your agent must implement org.bluez.Agent1 interface as described in Agent API doc.
Then you need to register this agent by calling RegisterAgent method from Agent API. Here you will provide the DBus path where your agent is located and also you will provide the capability in your case "DisplayYesNo" (LED as a display for pairing request, and button with some timeout for implementing Yes/No).
Also register your agent as a default agent by calling RequestDefaultAgent
Now if you try to pair with your device the appropriate function in your agent will be called (I think for your use case it will be RequestAuthorization) If you want to accept the pairing you will just return from this function, if you want to reject the pairing you must throw a DBus error inside this function.
As a starting point for you I would suggest you to look at this simple python Agent: https://github.com/pauloborges/bluez/blob/master/test/simple-agent
It implements all the functionality you need so just update it according to your needs.
Have fun :)
Have you tried using this Python library ? It lists Raspberry Pi support
Additionally, here's some info on listening for incoming Bluetooth connections:
Bluetooth programming in Python follows the socket programming model.
This is a concept that should be familiar to almost all network
programmers, and makes the transition from Internet programming to
Bluetooth programming much simpler. Example 3-2 and Example 3-3 show
how to establish a connection using an RFCOMM socket, transfer some
data, and disconnect.
import bluetooth
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
port = 1
server_sock.bind(("",port))
server_sock.listen(1)
client_sock,address = server_sock.accept()
print "Accepted connection from ",address
data = client_sock.recv(1024)
print "received [%s]" % data
client_sock.close()
server_sock.close()
An RFCOMM BluetoothSocket used to accept incoming connections must be
attached to operating system resources with the bind method. bind
takes in a tuple specifying the address of the local Bluetooth adapter
to use and a port number to listen on. Usually, there is only one
local Bluetooth adapter or it doesn't matter which one to use, so the
empty string indicates that any local Bluetooth adapter is acceptable.
Once a socket is bound, a call to listen puts the socket into
listening mode and it is then ready to accept incoming connections.
...
Source
I'm developing a simple Flask based server that can communicate with peer applications (other similar servers) on internet. The application can be behind a NAT. So I'm trying to resolve the external IP and port through a stun server by using pystun.
import stun
nat_type,external_ip,external_port=stun.get_ip_info()
The port returned is 54320. Problem is when I try http://external_ip:54320 the request is not reaching the Flask app. http://external_ip:5000 is also not working, 5000 being the internal port used (I know this should not work, but tried it anyways). There are no firewalls. I have run Flask with host="0.0.0.0".
to add.. i dont want to do explicit port mapping in the router.. is there a way flask can listen to a port that is accessible from external addresses and figure out external port through stun?
It is very difficult to host a server behind a NAT without doing an explicit port mapping. The NAT is also acting as a firewall. The node behind the NAT can make outbound TCP connections, but the NAT will block any inbound connections.
STUN doesn't help here because it only helps nodes behind NATs discover their own port mappings. To allow connection to be established after STUN, you typically have to do a hole punching step, which involves both endpoints simultaneously trying to connect to each other.
The one idea you could try is to use UPNP, which is a protocol that many NATs support for dynamically creating port mappings. There's some opens source libraries that might work.
But the easier solution is to just configure your NAT to have an explicitly port mapping. (e.g. port 50000 maps to your PC's internal IP address at a specific port).
I have a big problem, and I am having a hard time solving it. I have a custom made game controller, which outputs some data from it's sensors via serial communication and is connected to PC via serial port. I do the callculation of the current controller position in a Matlab script. I am building a web application that will display the data (position) of the device in a web browser, but can't seem to work out, how to connect my device to the browser. Matlab script sends all the position data to a UDP port with a sampling fequency of 100HZ (100 samples per second). I need to make a persistent connection between a web browser and my matlab script so I will be able to display the data. I am thinking about using web sockets API. but it does not "speak" UDP. So my idea was to somehow read the data with from UDP with a custom Python server and then create a websocket on that Python server and send data received via UDP port to web browser. Oh, and it would be nice if I could communicate in both directions. Will this work? Any ideas on how to do it? How is this usually done, I mean how can one connect let's say some temperature sensor to web browser to display data in real time?
Any answer will be gladly appreciated.
Thanks,
Leon
Note that although the WebSockets protocol is built on TCP sockets, the WebSockets protocol is not raw TCP sockets. A WebSockets connection has an HTTP friendly handshake (with some CORS functionality built-in). WebSockets are also message based (rather than streaming like TCP) so each message has a couple of bytes of framing headers.
You might look at websockify (disclaimer: I made websockify). Websockify is a python server that bridges/proxies between WebSockets and plain TCP sockets. I don't think it would be particularly difficult to adapt it to handle UDP sockets on the backend.
WebSockify (designed to be used together with the included include/websock.js front-end library) supports binary data even over the older Hixie versions of the protocol. This allows it to work with iOS (iPhone,iPad) devices which still only support the older version of the protocol.