23 M_PLAIN =
"text/plain"
24 M_JSON =
"application/json"
27 from urllib.parse
import urlparse
29 from urlparse
import urlparse
32 import _webiopi.GPIO
as GPIO
37 return int(code/100) * 32 + (code%100)
41 FORMATS = {0:
"text/plain",
42 40:
"application/link-format",
43 41:
"application/xml",
44 42:
"application/octet-stream",
45 47:
"application/exi",
46 50:
"application/json"
53 for code
in COAPContentFormat.FORMATS:
54 if COAPContentFormat.FORMATS[code] == fmt:
63 if code
in COAPContentFormat.FORMATS:
64 return COAPContentFormat.FORMATS[code]
66 raise Exception(
"Unknown content format %d" % code)
70 OPTIONS = {1:
"If-Match",
103 TYPES = [
"CON",
"NON",
"ACK",
"RST"]
124 self.
host = p.hostname
126 self.
port = int(p.port)
130 delta = (byte & 0xF0) >> 4
132 return (delta, length)
136 result.append(
"Version: %s" % self.
version)
137 result.append(
"Type: %s" % self.
TYPES[self.
type])
138 result.append(
"Code: %s" % self.CODES[self.
code])
139 result.append(
"Id: %s" % self.
id)
140 result.append(
"Token: %s" % self.
token)
144 result.append(
"Uri-Path: %s" % self.
uri_path)
146 result.append(
"Payload: %s" % self.
payload)
148 return '\n'.join(result)
163 buff.append((value & 0xFF00) >> 8)
164 buff.append(value & 0x00FF)
173 delta = option - lastnumber
199 byte = (self.
version & 0x03) << 6
200 byte |= (self.
type & 0x03) << 4
202 token_len = min(len(self.
token), 8);
207 buff.append(self.
code)
208 buff.append((self.
id & 0xFF00) >> 8)
209 buff.append(self.
id & 0x00FF)
218 paths = self.uri_path.split(
"/")
221 if PYTHON_MAJOR >= 3:
225 lastnumber = self.
appendOption(buff, lastnumber, COAPOption.URI_PATH, data)
231 data.append((fmt_code & 0xFF00) >> 8)
232 data.append(fmt_code & 0x00FF)
233 lastnumber = self.
appendOption(buff, lastnumber, COAPOption.CONTENT_FORMAT, data)
238 if PYTHON_MAJOR >= 3:
239 data = self.payload.encode()
248 self.
version = (buff[0] & 0xC0) >> 6
249 self.
type = (buff[0] & 0x30) >> 4
250 token_length = buff[0] & 0x0F
253 self.
token = buff[index:index+token_length]
255 index += token_length
257 self.
id = (buff[2] << 8) | buff[3]
262 while index < len(buff)
and buff[index] != 0xFF:
268 delta += buff[index+offset]
272 delta += 255 + ((buff[index+offset] << 8) | buff[index+offset+1])
277 length += buff[index+offset]
282 length += 255 + ((buff[index+offset] << 8) | buff[index+offset+1])
286 valueBytes = buff[index+offset:index+offset+length]
288 if number
in [COAPOption.IF_MATCH, COAPOption.ETAG]:
291 elif number
in [COAPOption.URI_PORT, COAPOption.CONTENT_FORMAT, COAPOption.MAX_AGE, COAPOption.ACCEPT]:
298 if PYTHON_MAJOR >= 3:
299 value = valueBytes.decode()
301 value = str(valueBytes)
302 self.options.append({
'number': number,
'value': value})
303 index += offset + length
307 if len(buff) > index:
313 (number, value) = option.values()
314 if number == COAPOption.URI_PATH:
332 COAPMessage.__init__(self, msg_type, code, uri)
336 COAPRequest.__init__(self, COAPMessage.CON, COAPRequest.GET, uri)
340 COAPRequest.__init__(self, COAPMessage.CON, COAPRequest.POST, uri)
344 COAPRequest.__init__(self, COAPMessage.CON, COAPRequest.PUT, uri)
348 COAPRequest.__init__(self, COAPMessage.CON, COAPRequest.DELETE, uri)
358 128:
"4.00 Bad Request",
359 129:
"4.01 Unauthorized",
360 130:
"4.02 Bad Option",
361 131:
"4.03 Forbidden",
362 132:
"4.04 Not Found",
363 133:
"4.05 Method Not Allowed",
364 134:
"4.06 Not Acceptable",
365 140:
"4.12 Precondition Failed",
366 141:
"4.13 Request Entity Too Large",
367 143:
"4.15 Unsupported Content-Format",
368 160:
"5.00 Internal Server Error",
369 161:
"5.01 Not Implemented",
370 162:
"5.02 Bad Gateway",
371 163:
"5.03 Service Unavailable",
372 164:
"5.04 Gateway Timeout",
373 165:
"5.05 Proxying Not Supported"
392 PRECONDITION_FAILED = 140
393 ENTITY_TOO_LARGE = 141
394 UNSUPPORTED_CONTENT = 143
398 NOT_IMPLEMENTED = 161
400 SERVICE_UNAVAILABLE = 163
401 GATEWAY_TIMEOUT = 164
402 PROXYING_NOT_SUPPORTED = 165
405 COAPMessage.__init__(self)
409 self.
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
410 self.socket.settimeout(1.0)
411 self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
414 data = message.getBytes();
418 self.socket.sendto(data, (message.host, message.port))
419 data = self.socket.recv(1500)
421 response.parseByteArray(bytearray(data))
423 except socket.timeout:
428 logger = logging.getLogger(
"CoAP")
431 threading.Thread.__init__(self, name=
"COAPThread")
437 address_family = socket.AF_INET6
439 address_family = socket.AF_INET
441 self.
socket = socket.socket(address_family, socket.SOCK_DGRAM)
443 self.
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
444 self.socket.bind((
'', port))
445 self.socket.settimeout(1)
450 info(
"CoAP Server binded on coap://%s:%s/" % (self.
host, self.
port))
453 (request, client) = self.socket.recvfrom(1500)
454 requestBytes = bytearray(request)
456 coapRequest.parseByteArray(requestBytes)
461 responseBytes = coapResponse.getBytes()
462 self.socket.sendto(responseBytes, client)
463 self.logger.debug(
'"%s %s CoAP/%.1f" - %s (Client: %s)' % (coapRequest.CODES[coapRequest.code], coapRequest.uri_path, coapRequest.version, coapResponse.CODES[coapResponse.code], client[0]))
465 except socket.timeout
as e:
467 except Exception
as e:
471 info(
"CoAP Server stopped")
476 mreq = struct.pack(
"4sl", socket.inet_aton(self.
multicast_ip), socket.INADDR_ANY)
477 self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
485 if request.type == COAPMessage.CON:
486 response.type = COAPMessage.ACK
488 response.type = COAPMessage.NON
491 response.token = request.token
493 response.id = request.id
494 response.uri_path = request.uri_path
496 if request.code == COAPRequest.GET:
497 self.handler.do_GET(request, response)
498 elif request.code == COAPRequest.POST:
499 self.handler.do_POST(request, response)
500 elif request.code / 32 == 0:
501 response.code = COAPResponse.NOT_IMPLEMENTED
503 exception(Exception(
"Received CoAP Response : %s" % response))
511 (code, body, contentType) = self.handler.do_GET(request.uri_path[1:],
True)
513 response.code = COAPResponse.NOT_FOUND
515 response.code = COAPResponse.CONTENT
518 response.payload = body
519 response.content_format = COAPContentFormat.getCode(contentType)
520 except (GPIO.InvalidDirectionException, GPIO.InvalidChannelException, GPIO.SetupException)
as e:
521 response.code = COAPResponse.FORBIDDEN
522 response.payload =
"%s" % e
523 except Exception
as e:
524 response.code = COAPResponse.INTERNAL_ERROR
529 (code, body, contentType) = self.handler.do_POST(request.uri_path[1:], request.payload,
True)
531 response.code = COAPResponse.NOT_FOUND
533 response.code = COAPResponse.CHANGED
536 response.payload = body
537 response.content_format = COAPContentFormat.getCode(contentType)
538 except (GPIO.InvalidDirectionException, GPIO.InvalidChannelException, GPIO.SetupException)
as e:
539 response.code = COAPResponse.FORBIDDEN
540 response.payload =
"%s" % e
541 except Exception
as e:
542 response.code = COAPResponse.INTERNAL_ERROR
def getOptionHeaderExtension