Skip to content

Commit 798f5ff

Browse files
committed
feat: Add Windows compatibility
1 parent 019b4bd commit 798f5ff

File tree

4 files changed

+80
-28
lines changed

4 files changed

+80
-28
lines changed

rawsocketpy/util.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,56 @@
33

44
from __future__ import absolute_import
55
import socket
6-
import fcntl
76
import struct
87
import sys
98

10-
if sys.version_info >= (3, 0):
9+
if sys.platform == "win32":
10+
import psutil
1111

1212
def get_hw(ifname):
13-
"""Returns a bytearray containing the MAC address of the interface.
13+
addrs = psutil.net_if_addrs()
14+
if ifname not in addrs:
15+
raise ValueError(f"Interface '{ifname}' not found")
1416

15-
:param ifname: Interface name such as ``wlp2s0``
16-
:type ifname: str
17-
:rtype: str
18-
:rtype: bytearray
19-
"""
20-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
21-
info = fcntl.ioctl(
22-
s.fileno(), 0x8927, struct.pack("256s", bytearray(ifname[:15], "utf-8"))
23-
)
24-
return info[18:24]
17+
for snic in addrs[ifname]:
18+
if snic.family == psutil.AF_LINK:
19+
mac_str = snic.address.replace("-", ":")
20+
mac_bytes = bytearray(int(b, 16) for b in mac_str.split(":"))
21+
return mac_bytes
22+
23+
raise ValueError(f"No MAC address found for interface '{ifname}'")
2524

2625
else:
26+
import fcntl
2727

28-
def get_hw(ifname):
29-
"""Returns a unicode string containing the MAC address of the interface.
28+
if sys.version_info >= (3, 0):
3029

31-
:param ifname: Interface name such as ``wlp2s0``
32-
:type ifname: str
33-
:rtype: str
34-
"""
35-
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
36-
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack("256s", ifname[:15]))
37-
return info[18:24]
30+
def get_hw(ifname):
31+
"""Returns a bytearray containing the MAC address of the interface.
32+
33+
:param ifname: Interface name such as ``wlp2s0``
34+
:type ifname: str
35+
:rtype: str
36+
:rtype: bytearray
37+
"""
38+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
39+
info = fcntl.ioctl(
40+
s.fileno(), 0x8927, struct.pack("256s", bytearray(ifname[:15], "utf-8"))
41+
)
42+
return info[18:24]
43+
44+
else:
45+
46+
def get_hw(ifname):
47+
"""Returns a unicode string containing the MAC address of the interface.
48+
49+
:param ifname: Interface name such as ``wlp2s0``
50+
:type ifname: str
51+
:rtype: str
52+
"""
53+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
54+
info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack("256s", ifname[:15]))
55+
return info[18:24]
3856

3957

4058
def to_str(data, separator=":"):

requirements-win.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
psutil==7.1.0
2+
gevent==25.9.1

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
gevent==25.8.2
1+
gevent==25.9.1

test.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
2-
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
1+
#!/usr/bin/env python
2+
import argparse
33
import time
4+
import sys
5+
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
6+
47

58
def callback(handler, server):
69
print("Testing")
710
handler.setup()
811
handler.handle()
912
handler.finish()
1013

14+
1115
class LongTaskTest(RawRequestHandler):
1216
def handle(self):
1317
time.sleep(1)
@@ -17,11 +21,39 @@ def finish(self):
1721
print("End")
1822

1923
def setup(self):
20-
print("Begin")
24+
print("Begin")
25+
2126

2227
def main():
23-
rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
28+
parser = argparse.ArgumentParser(
29+
description="Run a RawAsyncServerCallback on a given network interface."
30+
)
31+
default_iface = "wlp2s0" if sys.platform == "linux" else "Ethernet"
32+
33+
parser.add_argument(
34+
"-i",
35+
"--interface",
36+
type=str,
37+
default=default_iface,
38+
help=f"Network interface to bind to (default: {default_iface})",
39+
)
40+
41+
parser.add_argument(
42+
"-p",
43+
"--protocol",
44+
type=lambda x: int(x, 0), # allows hex like 0xEEFA or decimal
45+
default=0xEEFA,
46+
help="EtherType / protocol number (default: 0xEEFA)",
47+
)
48+
args = parser.parse_args()
49+
rs = RawAsyncServerCallback(
50+
args.interface,
51+
args.protocol,
52+
LongTaskTest,
53+
callback,
54+
)
2455
rs.spin()
2556

26-
if __name__ == '__main__':
57+
58+
if __name__ == "__main__":
2759
main()

0 commit comments

Comments
 (0)