Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Networking Timestamp (SO_TIMESTAMP, SO_TIMESTAMPNS, SO_TIMESTAMPING)

Linux Kernel offers a few ways to get timestamps for received (SO_TIMESTAMP, SO_TIMESTAMPNS, SO_TIMESTAMPING) or sent (SO_TIMESTAMPING) packets.

Kernel Doc: https://www.kernel.org/doc/Documentation/networking/timestamping.txt

Is there a way I can use that with Python? I don't see any SO_TIMESTAMP constant inside the Python sources. Tried 3.6.2 and GitHub master branch.

Right now, I can only use SIOCGSTAMP that gives me the timestamp of the last received packet and nothing seems available for sent packet timestamp.

like image 999
Jean-Francois Levesque Avatar asked Aug 04 '26 01:08

Jean-Francois Levesque


2 Answers

Finally, I have been able to get the SO_TIMESTAMPNS value like this:

SO_TIMESTAMPNS = 35
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))
s.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPNS, 1)
raw_data, ancdata, flags, address = s.recvmsg(65535, 1024)

ancdata[0][2] is the hardware timestamp as a timespec(ulong, ulong).

Does work on Linux but not on Mac OS X. Not tested on Windows.

like image 78
Jean-Francois Levesque Avatar answered Aug 05 '26 15:08

Jean-Francois Levesque


complete code, send and receive using python3

import struct
import time
import select
import socket
import sys
if(len(sys.argv)!=2):
    print("usage: ",sys.argv[0]," <send|receive>")
    sys.exit()
print(sys.argv[1]);
if(sys.argv[1]=='send'):
    MESSAGE = "Hello, World!"
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
    s.connect(('localhost', 10000))
    s.send(MESSAGE)
    time.sleep(0.0001)
    #time.sleep(5)
    s.send(MESSAGE)
    s.close()
else:
    SO_TIMESTAMPNS = 35
    #s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(3))

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setblocking(0)

    server.setsockopt(socket.SOL_SOCKET, SO_TIMESTAMPNS, 1)
    server.bind(('localhost', 10000))
    server.listen(5)
    inputs = [ server ]
    message_queues = {}
    outputs = []
    while inputs:
        print('\nwaiting for the next event')
        readable, writable, exceptional = select.select(inputs, outputs, inputs)
        for s in readable:
            if s is server:
                connection, client_address = s.accept()
                print('new connection from', client_address)
                connection.setblocking(0)
                inputs.append(connection)                
            else:
                raw_data, ancdata, flags, address = s.recvmsg(65535, 1024)
                print('received ', raw_data, '-',ancdata,'-',flags,'-',address)
                if(len(ancdata)>0):
                    #print(len(ancdata),len(ancdata[0]),ancdata[0][0],ancdata[0][1],ancdata[0][2])
                    #print('ancdata[0][2]:',type(ancdata[0][2])," - ",ancdata[0][2], " - ",len(ancdata[0][2]));
                    for i in ancdata:
                        print('ancdata: (cmsg_level, cmsg_type, cmsg_data)=(',i[0],",",i[1],", (",len(i[2]),") ",i[2],")");
                        if(i[0]!=socket.SOL_SOCKET or i[1]!=SO_TIMESTAMPNS):
                            continue
                        tmp=(struct.unpack("iiii",i[2]))
                        timestamp = tmp[0] + tmp[2]*1e-10
                        print("SCM_TIMESTAMPNS,", tmp, ", timestamp=",timestamp)
                if(not raw_data):
                    print('closing after reading no data')
                    # Stop listening for input on the connection
                    if s in outputs:
                        outputs.remove(s)
                    inputs.remove(s)
                    s.close()
like image 24
user2559936 Avatar answered Aug 05 '26 14:08

user2559936



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!