Coverage for aiocoap/defaults.py: 93%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

112 statements  

1# This file is part of the Python aiocoap library project. 

2# 

3# Copyright (c) 2012-2014 Maciej Wasilak <http://sixpinetrees.blogspot.com/>, 

4# 2013-2014 Christian Amsüss <c.amsuess@energyharvesting.at> 

5# 

6# aiocoap is free software, this file is published under the MIT license as 

7# described in the accompanying LICENSE file. 

8 

9"""This module contains helpers that inspect available modules and platform 

10specifics to give sane values to aiocoap defaults. 

11 

12All of this should eventually overridable by other libraries wrapping/using 

13aiocoap and by applications using aiocoap; however, these overrides do not 

14happen in the defaults module but where these values are actually accessed, so 

15this module is considered internal to aiocoap and not part of the API. 

16 

17The ``_missing_modules`` functions are helpers for inspecting what is 

18reasonable to expect to work. They can influence default values, but should not 

19be used in the rest of the code for feature checking (just raise the 

20ImportErrors) unless it's directly user-visible ("You configured OSCORE key 

21material, but OSCORE needs the following unavailable modules") or in the test 

22suite to decide which tests to skip. 

23""" 

24 

25import os 

26import socket 

27import sys 

28 

29def get_default_clienttransports(*, loop=None, use_env=True): 

30 """Return a list of transports that should be connected when a client 

31 context is created. 

32 

33 If an explicit ``AIOCOAP_CLIENT_TRANSPORT`` environment variable is set, it 

34 is read as a colon separated list of transport names. 

35 

36 By default, a DTLS mechanism will be picked if the required modules are 

37 available, and a UDP transport will be selected depending on whether the 

38 full udp6 transport is known to work. 

39 """ 

40 

41 if use_env and 'AIOCOAP_CLIENT_TRANSPORT' in os.environ: 

42 yield from os.environ['AIOCOAP_CLIENT_TRANSPORT'].split(':') 

43 return 

44 

45 if not oscore_missing_modules(): 

46 yield 'oscore' 

47 

48 if not dtls_missing_modules(): 

49 yield 'tinydtls' 

50 

51 yield 'tcpclient' 

52 yield 'tlsclient' 

53 if not ws_missing_modules(): 

54 yield 'ws' 

55 

56 if sys.platform != 'linux': 

57 # udp6 was never reported to work on anything but linux; would happily 

58 # add more platforms. 

59 yield 'simple6' 

60 return 

61 

62 # on android it seems that it's only the AI_V4MAPPED that causes trouble, 

63 # that should be managable in udp6 too. 

64 yield 'udp6' 

65 return 

66 

67def get_default_servertransports(*, loop=None, use_env=True): 

68 """Return a list of transports that should be connected when a server 

69 context is created. 

70 

71 If an explicit ``AIOCOAP_SERVER_TRANSPORT`` environment variable is set, it 

72 is read as a colon separated list of transport names. 

73 

74 By default, a DTLS mechanism will be picked if the required modules are 

75 available, and a UDP transport will be selected depending on whether the 

76 full udp6 transport is known to work. Both a simple6 and a simplesocketserver 

77 will be selected when udp6 is not available, and the simple6 will be used 

78 for any outgoing requests, which the simplesocketserver could serve but is worse 

79 at. 

80 """ 

81 

82 if use_env and 'AIOCOAP_SERVER_TRANSPORT' in os.environ: 

83 yield from os.environ['AIOCOAP_SERVER_TRANSPORT'].split(':') 

84 return 

85 

86 if not oscore_missing_modules(): 

87 yield 'oscore' 

88 

89 if not dtls_missing_modules(): 

90 if 'AIOCOAP_DTLSSERVER_ENABLED' in os.environ: 

91 yield 'tinydtls_server' 

92 yield 'tinydtls' 

93 

94 yield 'tcpserver' 

95 yield 'tcpclient' 

96 yield 'tlsserver' 

97 yield 'tlsclient' 

98 if not ws_missing_modules(): 

99 yield 'ws' 

100 

101 if sys.platform != 'linux': 

102 # udp6 was never reported to work on anything but linux; would happily 

103 # add more platforms. 

104 yield 'simple6' 

105 yield 'simplesocketserver' 

106 return 

107 

108 # on android it seems that it's only the AI_V4MAPPED that causes trouble, 

109 # that should be managable in udp6 too. 

110 yield 'udp6' 

111 return 

112 

113def has_reuse_port(*, use_env=True): 

114 """Return true if the platform indicates support for SO_REUSEPORT. 

115 

116 Can be overridden by explicitly setting ``AIOCOAP_REUSE_PORT`` to 1 or 

117 0.""" 

118 

119 if use_env and os.environ.get('AIOCOAP_REUSE_PORT'): 

120 return bool(int(os.environ['AIOCOAP_REUSE_PORT'])) 

121 

122 return hasattr(socket, 'SO_REUSEPORT') 

123 

124# FIXME: If there were a way to check for the extras defined in setup.py, or to link these lists to what is descibed there, that'd be great. 

125 

126def dtls_missing_modules(): 

127 """Return a list of modules that are missing in order to use the DTLS 

128 transport, or a false value if everything is present""" 

129 

130 missing = [] 

131 

132 try: 

133 from DTLSSocket import dtls # noqa: F401 

134 except ImportError: 

135 missing.append("DTLSSocket") 

136 

137 return missing 

138 

139def oscore_missing_modules(): 

140 """Return a list of modules that are missing in order to use OSCORE, or a 

141 false value if everything is present""" 

142 missing = [] 

143 try: 

144 import cbor2 # noqa: F401 

145 except ImportError: 

146 missing.append('cbor2') 

147 try: 

148 import cryptography # noqa: F401 

149 except ImportError: 

150 missing.append('cryptography') 

151 else: 

152 try: 

153 from cryptography.hazmat.primitives.ciphers.aead import AESCCM 

154 AESCCM(b"x" * 16, 8) 

155 except (cryptography.exceptions.UnsupportedAlgorithm, ImportError): 

156 missing.append('a version of OpenSSL that supports AES-CCM') 

157 try: 

158 import filelock # noqa: F401 

159 except ImportError: 

160 missing.append('filelock') 

161 

162 try: 

163 import ge25519 # noqa: F401 

164 except ImportError: 

165 missing.append('ge25519') 

166 

167 return missing 

168 

169def ws_missing_modules(): 

170 """Return a list of modules that are missing in order to user CoAP-over-WS, 

171 or a false value if everything is present""" 

172 missing = [] 

173 try: 

174 import websockets # noqa: F401 

175 except ImportError: 

176 missing.append('websockets') 

177 

178 return missing 

179 

180def linkheader_missing_modules(): 

181 """Return a list of moudles that are missing in order to use link_header 

182 functionaity (eg. running a resource directory), of a false value if 

183 everything is present.""" 

184 missing = [] 

185 try: 

186 import link_header # noqa: F401 

187 except ImportError: 

188 missing.append('LinkHeader') 

189 return missing 

190 

191def prettyprint_missing_modules(): 

192 """Return a list of modules that are missing in order to use pretty 

193 printing (ie. full aiocoap-client)""" 

194 missing = [] 

195 try: 

196 import link_header # noqa: F401 

197 except ImportError: 

198 missing.append('LinkHeader') 

199 try: 

200 import cbor2 # noqa: F401 

201 except ImportError: 

202 missing.append('cbor2') 

203 try: 

204 import termcolor # noqa: F401 

205 except ImportError: 

206 missing.append('termcolor') 

207 try: 

208 import pygments # noqa: F401 

209 except ImportError: 

210 missing.append('pygments') 

211 return missing 

212 

213 

214__all__ = [ 

215 'get_default_clienttransports', 

216 'get_default_servertransports', 

217 'has_reuse_port', 

218 'dtls_missing_modules', 

219 'oscore_missing_modules', 

220 'ws_missing_modules', 

221 'linkheader_missing_modules', 

222 'prettyprint_missing_modules', 

223 ]