source: ReferenceDesigns/w3_802.11/python/wlan_exp/transport/transport_eth_ip_udp_py.py

Last change on this file was 6320, checked in by chunter, 5 years ago

1.8.0 release wlan-exp

File size: 5.2 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3------------------------------------------------------------------------------
4Mango 802.11 Reference Design Experiments Framework
5    - Transport Unicast Ethernet IP/UDP Python Socket Implementation
6------------------------------------------------------------------------------
7License:   Copyright 2019 Mango Communications, Inc. All rights reserved.
8           Use and distribution subject to terms in LICENSE.txt
9------------------------------------------------------------------------------
10
11This module provides the unicast Ethernet IP/UDP transport based on the python
12socket class.
13
14Functions:
15    TransportEthIpUdpPy() -- Unicast Ethernet UDP transport based on python
16        sockets
17
18"""
19
20import re
21import time
22import socket
23
24from . import transport_eth_ip_udp as tp
25from . import exception as ex
26
27
28__all__ = ['TransportEthIpUdpPy']
29
30
31class TransportEthIpUdpPy(tp.TransportEthIpUdp):
32    """Class for Ethernet IP/UDP Transport class using Python libraries.
33       
34    Attributes:
35        See TransportEthIpUdp for all attributes
36    """
37    def __init__(self):
38        super(TransportEthIpUdpPy, self).__init__()
39   
40   
41    def send(self, payload, robust=True):
42        """Send a message over the transport.
43       
44        Args:
45            payload (bytes): Data to be sent over the socket
46            robust (bool):   Is a response required
47        """
48       
49        if robust:
50            self.hdr.response_required()
51        else:
52            self.hdr.response_not_required()
53       
54        self.hdr.set_length(len(payload))
55        self.hdr.increment()
56
57        # Assemble the packet from the transport header and payload
58        # The wlan_exp C assumes the bytes starting at 'payload' here are u32 aligned
59        #  in the full Ethernet packet. The transport header is 10 bytes by design,
60        #  which aligns the end of the transport header to a 4-byte boundary when
61        #  appended to a 14-byte Ethernet + 20-byte IP + 8-byte UDP header
62        # Different padding would be required here if the sizes of the headers
63        #  before the transport header change
64        data = bytes(self.hdr.serialize() + payload)       
65 
66        size = self.sock.sendto(data, (self.ip_address, self.unicast_port))
67       
68        if size != len(data):
69            print("Only {} of {} bytes of data sent".format(size, len(data)))
70
71
72    def receive(self, timeout=None):
73        """Return a response from the transport.
74
75        Args:
76            timeout (float):  Time (in float seconds) to wait before raising
77                an execption.  If no value is specified, then it will use the
78                default transport timeout (self.timeout)
79       
80        This function will block until a response is received or a timeout
81        occurs.  If a timeout occurs, it will raise a TransportError exception.
82        """
83        reply = b''
84
85        if timeout is None:
86            timeout  = self.timeout
87        else:
88            timeout += self.timeout         # Extend timeout to not run in to race conditions
89
90        received_resp = 0
91        start_time = time.time()
92       
93        while received_resp == 0:
94            recv_data = []
95           
96            try:
97                # Call the lowl-level socket recvfrom
98                #  Second return value is recv_addr, not used here
99                #  Size arg is set to larger than largest packet
100                (recv_data, _) = self.sock.recvfrom(10000)
101           
102            except socket.error as err:
103                expr = re.compile("timed out")
104                if not expr.match(str(err)):
105                    print("Failed to receive UDP packet.\nError message:\n{}".format(err))
106           
107            if len(recv_data) > 0:
108                hdr_len = self.hdr.sizeof()
109                # print("Received pkt from", recv_addr)
110                if (self.hdr.is_reply(recv_data[0:hdr_len])):
111                    reply = recv_data[hdr_len:]
112                    received_resp = 1
113           
114            if ((time.time() - start_time) > timeout ) and (received_resp == 0):
115                raise ex.TransportError(self, "Transport receive timed out.")
116
117        return reply
118
119
120    def receive_nb(self):
121        """Return a response from the transport.
122       
123        This function will not block and should be called in a polling loop
124        until a response is received.
125        """
126        reply = b''
127        recv_data = []
128
129        try:
130            # Call the lowl-level socket recvfrom
131            #  Second return value is recv_addr, not used here
132            #  Size arg is set to larger than largest packet
133            (recv_data, _) = self.sock.recvfrom(10000)
134        except socket.error as err:
135            expr = re.compile("timed out")
136            if not expr.match(str(err)):
137                print("Failed to receive UDP packet.\nError message:\n{}".format(err))
138       
139        if len(recv_data) > 0:
140            hdr_len = self.hdr.sizeof()
141            if (self.hdr.is_reply(recv_data[0:hdr_len])):
142                reply = recv_data[hdr_len:]
143           
144        return reply
145
146
147# End Class
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
Note: See TracBrowser for help on using the repository browser.