Repository navigation
Expand file tree
/
Copy pathBroadcast
More file actions
216 lines (150 loc) · 8.31 KB
/
Copy pathBroadcast
File metadata and controls
216 lines (150 loc) · 8.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
Using UDP broadcasting is the ultimate upgrade for an offline P2P application. It removes the need to manually type the server's static IP address into the client.
Instead, the server continuously shouts, "Hey, I am a P2P Server, here is my IP!" into the offline local airwaves, and any client on the same wireless network automatically hears it, extracts the server's IP, and establishes a secure TCP connection.
1. The Offline Auto-Discovering Server
This server script does two things simultaneously:
Spawns a background thread to broadcast its IP address over UDP port 5556 every 2 seconds.
Listens for direct TCP peer connections on TCP port 5555.
import socket
import subprocess
import re
import time
import threading
def get_wlan_ip():
try:
result = subprocess.run(['ip', '-o', '-4', 'addr', 'show'], capture_output=True, text=True, check=True)
for line in result.stdout.splitlines():
if ' wl' in line:
match = re.search(r'inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', line)
if match and match.group(1) != "127.0.0.1":
return match.group(1)
except Exception:
pass
return "127.0.0.1"
def udp_broadcast_beacon(server_ip, broadcast_port):
"""Continuously broadcasts the server's presence over the offline network."""
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Enable broadcasting privileges on this socket
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
print(f"[BEACON] UDP Broadcasting beacon active on port {broadcast_port}...")
# Send to the universal local subnet broadcast address
broadcast_address = ("255.255.255.255", broadcast_port)
message = f"P2P_SERVER_DISCOVER:{server_ip}".encode('utf-8')
try:
while True:
udp_socket.sendto(message, broadcast_address)
time.sleep(2) # Broadcast every 2 seconds
except KeyboardInterrupt:
pass
finally:
udp_socket.close()
def start_p2p_server(tcp_port=5555, udp_port=5556):
my_ip = get_wlan_ip()
print(f"[STARTING] Offline P2P Server initialized.")
print(f"[INFO] Detected local Static IP: {my_ip}")
# Start the discovery beacon in a separate background thread
beacon_thread = threading.Thread(target=udp_broadcast_beacon, args=(my_ip, udp_port), daemon=True)
beacon_thread.start()
# Setup the main TCP listening socket
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(('0.0.0.0', tcp_port))
tcp_server.listen(1)
print(f"[LISTENING] TCP Server listening for connections on port {tcp_port}...")
try:
while True:
conn, addr = tcp_server.accept()
print(f"[CONNECTED] Client successfully connected from: {addr}")
# Simple offline data handshake
data = conn.recv(1024).decode('utf-8')
print(f"[DATA RECEIVED] -> {data}")
conn.send("Handshake complete! Connected to Ubuntu server successfully.".encode('utf-8'))
conn.close()
print("[DISCONNECTED] Client transaction finished. Waiting for next peer...")
except KeyboardInterrupt:
print("\n[STOPPING] Shutting down P2P server.")
finally:
tcp_server.close()
if __name__ == "__main__":
start_p2p_server()
2. The Auto-Discovering Client
The client doesn't need to know the server's IP anymore. When booted up, it listens passively on UDP port 5556, grabs the server's static IP out of the airwaves, shuts down the listener, and instantly opens a direct TCP connection.
import socket
def discover_and_connect(tcp_port=5555, udp_port=5556):
# 1. Listen for the UDP broadcast beacon
udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Allow multiple apps to bind to the same broadcast port if needed
udp_client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind to all interfaces to listen for the broadcast
udp_client.bind(('', udp_port))
print(f"[DISCOVERING] Listening for offline server beacons on UDP port {udp_port}...")
server_ip = None
try:
while True:
data, addr = udp_client.recvfrom(1024)
message = data.decode('utf-8')
if message.startswith("P2P_SERVER_DISCOVER:"):
server_ip = message.split(":")[1]
print(f"[FOUND] Server detected automatically at IP: {server_ip}")
break # Stop listening to broadcasts once we have the IP
finally:
udp_client.close()
# 2. Connect to the discovered server via TCP
if server_ip:
tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
print(f"[CONNECTING] Establishing TCP connection to {server_ip}:{tcp_port}...")
tcp_client.connect((server_ip, tcp_port))
print("[SUCCESS] Pipeline established!")
tcp_client.send("Hello from the auto-discovered client device!".encode('utf-8'))
response = tcp_client.recv(1024).decode('utf-8')
print(f"[SERVER RESPONSE] {response}")
except Exception as e:
print(f"[ERROR] Connection failed: {e}")
finally:
tcp_client.close()
if __name__ == "__main__":
discover_and_connect()
💡 Why this works perfectly for Offline Wi-Fi
Zero Network Configuration: You don't need a DNS server or router interface. The 255.255.255.255 broadcast target addresses every hardware chip connected to that specific wireless ad-hoc or hotspot network profile.
Resilient: If you reconfigure your Ubuntu manual static IP tomorrow from 192.168.1.10 to 10.0.0.5, you don't need to rebuild or touch your client application code. It adapts instantly.
Would you like to build a multithreaded framework next so multiple clients can interact with your offline server simultaneously, or do you need to add file-sharing capabilities to this layout?
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Ah, there is the culprit! Because the device is owned by `root:root`, it completely ignores the `dialout` or `tty` groups. Your user account never stood a chance.
Since the system is being stubborn, we are going to use a **udev rule**. This tells Linux: *"The second this device plugs in, change its group to dialout and give it proper permissions automatically."*
Here is how to set it up permanently in under two minutes:
### Step 1: Create a Custom Udev Rule
Open a new rule file in your system's hardware configuration directory using `nano`:
```bash
sudo nano /etc/udev/rules.d/99-serial-fix.rules
```
### Step 2: Paste the Rule Logic
Paste the following two lines into the file. This covers both standard USB serial types (`ttyUSB` and `ttyACM`):
```text
KERNEL=="ttyUSB[0-9]*", MODE="0666", GROUP="dialout"
KERNEL=="ttyACM[0-9]*", MODE="0666", GROUP="dialout"
```
* **What this does:** It tells Linux that whenever a serial device loads up, force its permissions to `0666` (read/write for everyone) and assign it to the `dialout` group.
To save and exit Nano: Press **Ctrl+O**, then **Enter**, then **Ctrl+X**.
### Step 3: Reload the System Rules
Force Linux to read your new rule right away without rebooting:
```bash
sudo udevadm control --reload-rules
sudo udevadm trigger
```
---
### Step 4: Quick Reset
Unplug your USB serial device from the computer and plug it back in.
Now, if you run your python script, it will connect flawlessly. No `sudo`, no manual `chmod 777`, and it will persist every single time you reboot.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(
hostname="192.168.1.101",
username="raj",
password="your_password"
)
stdin, stdout, stderr = client.exec_command("sudo -S systemctl start tracking.service")
stdin.write("your_password\n")
stdin.flush()
print(stdout.read().decode())
print(stderr.read().decode())