CoAP/coapthon/defines.py
2019-04-23 11:38:45 +02:00

304 lines
8.4 KiB
Python

import collections
import array
import struct
__author__ = 'Giacomo Tanganelli'
""" CoAP Parameters """
ACK_TIMEOUT = 2 # standard 2
SEPARATE_TIMEOUT = ACK_TIMEOUT / 2
ACK_RANDOM_FACTOR = 1.5
MAX_RETRANSMIT = 4
MAX_TRANSMIT_SPAN = ACK_TIMEOUT * (pow(2, (MAX_RETRANSMIT + 1)) - 1) * ACK_RANDOM_FACTOR
MAX_LATENCY = 120 # 2 minutes
PROCESSING_DELAY = ACK_TIMEOUT
MAX_RTT = (2 * MAX_LATENCY) + PROCESSING_DELAY
EXCHANGE_LIFETIME = MAX_TRANSMIT_SPAN + (2 * MAX_LATENCY) + PROCESSING_DELAY
DISCOVERY_URL = "/.well-known/core"
ALL_COAP_NODES = "224.0.1.187"
ALL_COAP_NODES_IPV6 = "FF00::FD"
MAX_PAYLOAD = 1024
MAX_NON_NOTIFICATIONS = 10
BLOCKWISE_SIZE = 1024
""" Message Format """
# number of bits used for the encoding of the CoAP version field.
VERSION_BITS = 2
# number of bits used for the encoding of the message type field.
TYPE_BITS = 2
# number of bits used for the encoding of the token length field.
TOKEN_LENGTH_BITS = 4
# number of bits used for the encoding of the request method/response code field.
CODE_BITS = 8
# number of bits used for the encoding of the message ID.
MESSAGE_ID_BITS = 16
# number of bits used for the encoding of the option delta field.
OPTION_DELTA_BITS = 4
# number of bits used for the encoding of the option delta field.
OPTION_LENGTH_BITS = 4
# One byte which indicates indicates the end of options and the start of the payload.
PAYLOAD_MARKER = 0xFF
# CoAP version supported by this Californium version.
VERSION = 1
# The lowest value of a request code.
REQUEST_CODE_LOWER_BOUND = 1
# The highest value of a request code.
REQUEST_CODE_UPPER_BOUND = 31
# The lowest value of a response code.
RESPONSE_CODE_LOWER_BOUND = 64
# The highest value of a response code.
RESPONSE_CODE_UPPER_BOUND = 191
corelinkformat = {
'ct': 'content_type',
'rt': 'resource_type',
'if': 'interface_type',
'sz': 'maximum_size_estimated',
'obs': 'observing'
}
# The integer.
INTEGER = 0
# The string.
STRING = 1
# The opaque.
OPAQUE = 2
# The unknown.
UNKNOWN = 3
# Cache modes
FORWARD_PROXY = 0
REVERSE_PROXY = 1
OptionItem = collections.namedtuple('OptionItem', 'number name value_type repeatable default')
class OptionRegistry(object):
"""
All CoAP options. Every option is represented as: (NUMBER, NAME, VALUE_TYPE, REPEATABLE, DEFAULT)
"""
def __init__(self):
pass
RESERVED = OptionItem(0, "Reserved", UNKNOWN, True, None)
IF_MATCH = OptionItem(1, "If-Match", OPAQUE, True, None)
URI_HOST = OptionItem(3, "Uri-Host", STRING, True, None)
ETAG = OptionItem(4, "ETag", OPAQUE, True, None)
IF_NONE_MATCH = OptionItem(5, "If-None-Match", OPAQUE, False, None)
OBSERVE = OptionItem(6, "Observe", INTEGER, False, 0)
URI_PORT = OptionItem(7, "Uri-Port", INTEGER, False, 5683)
LOCATION_PATH = OptionItem(8, "Location-Path", STRING, True, None)
URI_PATH = OptionItem(11, "Uri-Path", STRING, True, None)
CONTENT_TYPE = OptionItem(12, "Content-Type", INTEGER, False, 0)
MAX_AGE = OptionItem(14, "Max-Age", INTEGER, False, 60)
URI_QUERY = OptionItem(15, "Uri-Query", STRING, True, None)
ACCEPT = OptionItem(17, "Accept", INTEGER, False, 0)
LOCATION_QUERY = OptionItem(20,"Location-Query",STRING, True, None)
BLOCK2 = OptionItem(23, "Block2", INTEGER, False, None)
BLOCK1 = OptionItem(27, "Block1", INTEGER, False, None)
SIZE2 = OptionItem(28, "Size2", INTEGER, False, None)
PROXY_URI = OptionItem(35, "Proxy-Uri", STRING, False, None)
PROXY_SCHEME = OptionItem(39, "Proxy-Schema", STRING, False, None)
SIZE1 = OptionItem(60, "Size1", INTEGER, False, None)
NO_RESPONSE = OptionItem(258, "No-Response", INTEGER, False, None)
RM_MESSAGE_SWITCHING = OptionItem(65524, "Routing", OPAQUE, False, None)
LIST = {
0: RESERVED,
1: IF_MATCH,
3: URI_HOST,
4: ETAG,
5: IF_NONE_MATCH,
6: OBSERVE,
7: URI_PORT,
8: LOCATION_PATH,
11: URI_PATH,
12: CONTENT_TYPE,
14: MAX_AGE,
15: URI_QUERY,
17: ACCEPT,
20: LOCATION_QUERY,
23: BLOCK2,
27: BLOCK1,
28: SIZE2,
35: PROXY_URI,
39: PROXY_SCHEME,
60: SIZE1,
258: NO_RESPONSE,
65524: RM_MESSAGE_SWITCHING
}
@staticmethod
def get_option_flags(option_num):
"""
Get Critical, UnSafe, NoCacheKey flags from the option number
as per RFC 7252, section 5.4.6
:param option_num: option number
:return: option flags
:rtype: 3-tuple (critical, unsafe, no-cache)
"""
opt_bytes = array.array('B', '\0\0')
if option_num < 256:
s = struct.Struct("!B")
s.pack_into(opt_bytes, 0, option_num)
else:
s = struct.Struct("H")
s.pack_into(opt_bytes, 0, option_num)
critical = (opt_bytes[0] & 0x01) > 0
unsafe = (opt_bytes[0] & 0x02) > 0
nocache = ((opt_bytes[0] & 0x1e) == 0x1c)
return (critical, unsafe, nocache)
Types = {
'CON': 0,
'NON': 1,
'ACK': 2,
'RST': 3,
'None': None
}
CodeItem = collections.namedtuple('CodeItem', 'number name')
class Codes(object):
"""
CoAP codes. Every code is represented as (NUMBER, NAME)
"""
ERROR_LOWER_BOUND = 128
EMPTY = CodeItem(0, 'EMPTY')
GET = CodeItem(1, 'GET')
POST = CodeItem(2, 'POST')
PUT = CodeItem(3, 'PUT')
DELETE = CodeItem(4, 'DELETE')
CREATED = CodeItem(65, 'CREATED')
DELETED = CodeItem(66, 'DELETED')
VALID = CodeItem(67, 'VALID')
CHANGED = CodeItem(68, 'CHANGED')
CONTENT = CodeItem(69, 'CONTENT')
CONTINUE = CodeItem(95, 'CONTINUE')
BAD_REQUEST = CodeItem(128, 'BAD_REQUEST')
FORBIDDEN = CodeItem(131, 'FORBIDDEN')
NOT_FOUND = CodeItem(132, 'NOT_FOUND')
METHOD_NOT_ALLOWED = CodeItem(133, 'METHOD_NOT_ALLOWED')
NOT_ACCEPTABLE = CodeItem(134, 'NOT_ACCEPTABLE')
REQUEST_ENTITY_INCOMPLETE = CodeItem(136, 'REQUEST_ENTITY_INCOMPLETE')
PRECONDITION_FAILED = CodeItem(140, 'PRECONDITION_FAILED')
REQUEST_ENTITY_TOO_LARGE = CodeItem(141, 'REQUEST_ENTITY_TOO_LARGE')
UNSUPPORTED_CONTENT_FORMAT = CodeItem(143, 'UNSUPPORTED_CONTENT_FORMAT')
INTERNAL_SERVER_ERROR = CodeItem(160, 'INTERNAL_SERVER_ERROR')
NOT_IMPLEMENTED = CodeItem(161, 'NOT_IMPLEMENTED')
BAD_GATEWAY = CodeItem(162, 'BAD_GATEWAY')
SERVICE_UNAVAILABLE = CodeItem(163, 'SERVICE_UNAVAILABLE')
GATEWAY_TIMEOUT = CodeItem(164, 'GATEWAY_TIMEOUT')
PROXY_NOT_SUPPORTED = CodeItem(165, 'PROXY_NOT_SUPPORTED')
LIST = {
0: EMPTY,
1: GET,
2: POST,
3: PUT,
4: DELETE,
65: CREATED,
66: DELETE,
67: VALID,
68: CHANGED,
69: CONTENT,
95: CONTINUE,
128: BAD_REQUEST,
131: FORBIDDEN,
132: NOT_FOUND,
133: METHOD_NOT_ALLOWED,
134: NOT_ACCEPTABLE,
136: REQUEST_ENTITY_INCOMPLETE,
140: PRECONDITION_FAILED,
141: REQUEST_ENTITY_TOO_LARGE,
143: UNSUPPORTED_CONTENT_FORMAT,
160: INTERNAL_SERVER_ERROR,
161: NOT_IMPLEMENTED,
162: BAD_GATEWAY,
163: SERVICE_UNAVAILABLE,
164: GATEWAY_TIMEOUT,
165: PROXY_NOT_SUPPORTED
}
Content_types = {
"text/plain": 0,
"application/link-format": 40,
"application/xml": 41,
"application/octet-stream": 42,
"application/exi": 47,
"application/json": 50,
"application/cbor": 60
}
COAP_PREFACE = "coap://"
LOCALHOST = "127.0.0.1"
HC_PROXY_DEFAULT_PORT = 8080 # TODO there is a standard for this?
COAP_DEFAULT_PORT = 5683
DEFAULT_HC_PATH = "/"
BAD_REQUEST = 400 # "Bad Request" error code
NOT_IMPLEMENTED = 501 # "Not Implemented" error code
# Dictionary to map CoAP to HTTP requests code
CoAP_HTTP = {
"CREATED": "201",
"DELETED": "200",
"VALID": "304",
"CHANGED": "200",
"CONTENT": "200",
"BAD_REQUEST": "400",
"FORBIDDEN": "403",
"NOT_FOUND": "404",
"METHOD_NOT_ALLOWED": "400",
"NOT_ACCEPTABLE": "406",
"PRECONDITION_FAILED": "412",
"REQUEST_ENTITY_TOO_LARGE": "413",
"UNSUPPORTED_CONTENT_FORMAT": "415",
"INTERNAL_SERVER_ERROR": "500",
"NOT_IMPLEMENTED": "501",
"BAD_GATEWAY": "502",
"SERVICE_UNAVAILABLE": "503",
"GATEWAY_TIMEOUT": "504",
"PROXY_NOT_SUPPORTED": "502"
}