I have an iOS 13.3 application running on the XCode iOS simulator. It communicates with a simple python tcpserver on a Raspberry PI running on a local network. The iOS code is based on //https://dev.to/bsorrentino/develop-a-textfield-validator-for-swiftui-7d3 which uses URLSession. I am getting a timeout in the iOS code after about 10 seconds. I've checked the network packets with tcpdump on the mac. The proper packets appear to be sent and received. The url used is http://10.0.0.119:60708 as the PI server does not handle https at this point. The python server receives a JWT, prepends the thread name and echos it back. The python snippet is as follows:
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
data = self.request.recv(4096).decode('utf-8')
if len(data) == 0:
break
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
print(response)
self.request.sendall(response.encode('utf-8'))
The error is:
2020-02-22 12:11:35.324596-0500 PIHome[64511:66647174] Task <2C1CE343-FB68-40CB-97C5-5E7967933838>.<2> finished with error [-1001] Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x600001046ca0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://10.0.0.119:60708/temperature, NSErrorFailingURLKey=http://10.0.0.119:60708/temperature, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
The tcpdump is as follows:
12:11:25.305647 IP 10.0.0.89.52915 > hastings.60708: Flags [S], seq 2969915581, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 2152442902 ecr 0,sackOK,eol], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0040 0000 4000 4006 25e9 0a00 0059 0a00 .#..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 50bd 0000 0000 b002 .w...$..P.......
0x0030: ffff 382f 0000 0204 05b4 0103 0306 0101 ..8/............
0x0040: 080a 804b ac16 0000 0000 0402 0000 ...K..........
12:11:25.312528 IP hastings.60708 > 10.0.0.89.52915: Flags [S.], seq 3390573497, ack 2969915582, win 28960, options [mss 1460,sackOK,TS val 3187848125 ecr 2152442902,nop,wscale 7], length 0
0x0000: 8c85 9048 25eb b827 ebc1 f24d 0800 4500 ...H%..'...M..E.
0x0010: 003c 0000 4000 4006 25ed 0a00 0077 0a00 .<..#.#.%....w..
0x0020: 0059 ed24 ceb3 ca18 0bb9 b105 50be a012 .Y.$........P...
0x0030: 7120 906f 0000 0204 05b4 0402 080a be02 q..o............
0x0040: b3bd 804b ac16 0103 0307 ...K......
12:11:25.312574 IP 10.0.0.89.52915 > hastings.60708: Flags [.], ack 1, win 2058, options [nop,nop,TS val 2152442909 ecr 3187848125], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0034 0000 4000 4006 25f5 0a00 0059 0a00 .4..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 50be ca18 0bba 8010 .w...$..P.......
0x0030: 080a 284b 0000 0101 080a 804b ac1d be02 ..(K.......K....
0x0040: b3bd ..
12:11:25.314030 IP 10.0.0.89.52915 > hastings.60708: Flags [P.], seq 1:269, ack 1, win 2058, options [nop,nop,TS val 2152442910 ecr 3187848125], length 268
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0140 0000 4000 4006 24e9 0a00 0059 0a00 .#..#.#.$....Y..
0x0020: 0077 ceb3 ed24 b105 50be ca18 0bba 8018 .w...$..P.......
0x0030: 080a 597f 0000 0101 080a 804b ac1e be02 ..Y........K....
0x0040: b3bd 504f 5354 202f 7465 6d70 6572 6174 ..POST./temperat
0x0050: 7572 6520 4854 5450 2f31 2e31 0d0a 486f ure.HTTP/1.1..Ho
0x0060: 7374 3a20 3130 2e30 2e30 2e31 3139 3a36 st:.10.0.0.119:6
0x0070: 3037 3038 0d0a 436f 6e74 656e 742d 5479 0708..Content-Ty
0x0080: 7065 3a20 6170 706c 6963 6174 696f 6e2f pe:.application/
0x0090: 6a73 6f6e 0d0a 436f 6e6e 6563 7469 6f6e json..Connection
0x00a0: 3a20 6b65 6570 2d61 6c69 7665 0d0a 4163 :.keep-alive..Ac
0x00b0: 6365 7074 3a20 6170 706c 6963 6174 696f cept:.applicatio
0x00c0: 6e2f 6a73 6f6e 0d0a 5573 6572 2d41 6765 n/json..User-Age
0x00d0: 6e74 3a20 5049 486f 6d65 2f31 2043 464e nt:.PIHome/1.CFN
0x00e0: 6574 776f 726b 2f31 3132 312e 322e 3120 etwork/1121.2.1.
0x00f0: 4461 7277 696e 2f31 392e 332e 300d 0a43 Darwin/19.3.0..C
0x0100: 6f6e 7465 6e74 2d4c 656e 6774 683a 2032 ontent-Length:.2
0x0110: 3139 0d0a 4163 6365 7074 2d4c 616e 6775 19..Accept-Langu
0x0120: 6167 653a 2065 6e2d 7573 0d0a 4163 6365 age:.en-us..Acce
0x0130: 7074 2d45 6e63 6f64 696e 673a 2067 7a69 pt-Encoding:.gzi
0x0140: 702c 2064 6566 6c61 7465 0d0a 0d0a p,.deflate....
12:11:25.314317 IP 10.0.0.89.52915 > hastings.60708: Flags [P.], seq 269:488, ack 1, win 2058, options [nop,nop,TS val 2152442910 ecr 3187848125], length 219
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 010f 0000 4000 4006 251a 0a00 0059 0a00 ....#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 51ca ca18 0bba 8018 .w...$..Q.......
0x0030: 080a e989 0000 0101 080a 804b ac1e be02 ...........K....
0x0040: b3bd 224c 6f67 696e 2073 7563 6365 7373 .."Login.success
0x0050: 6675 6c3a 6579 4a30 6558 4169 4f69 4a71 ful:eyJ0eXAiOiJq
0x0060: 6433 5169 4c43 4a68 6247 6369 4f69 4a49 d3QiLCJhbGciOiJI
0x0070: 557a 4931 4e69 4a39 2e65 794a 7a64 5749 UzI1NiJ9.eyJzdWI
0x0080: 694f 694a 5153 5568 7662 5755 6762 4739 iOiJQSUhvbWUgbG9
0x0090: 6e61 5734 694c 434a 3163 3256 7949 6a6f naW4iLCJ1c2VyIjo
0x00a0: 6963 476c 6f62 3231 6c4c 6e52 6862 6d52 icGlob21lLnRhbmR
0x00b0: 6f51 4752 6862 4756 354c 6e64 7a49 6977 oQGRhbGV5LndzIiw
0x00c0: 6961 5746 3049 6a6f 784e 5467 794d 7a6b iaWF0IjoxNTgyMzk
0x00d0: 784e 4467 314c 434a 6e63 6d39 3163 484d xNDg1LCJncm91cHM
0x00e0: 694f 6c73 6964 4746 755a 4767 6958 5830 iOlsidGFuZGgiXX0
0x00f0: 2e53 6770 6875 4d6a 6347 6f37 6648 6a6a .SgphuMjcGo7fHjj
0x0100: 7878 4736 5569 7770 6c67 754d 645a 6268 xxG6UiwplguMdZbh
0x0110: 6374 2d35 7a44 6344 6e64 4c59 22 ct-5zDcDndLY"
12:11:25.318063 IP hastings.60708 > 10.0.0.89.52915: Flags [.], ack 269, win 235, options [nop,nop,TS val 3187848130 ecr 2152442910], length 0
0x0000: 8c85 9048 25eb b827 ebc1 f24d 0800 4500 ...H%..'...M..E.
0x0010: 0034 4928 4000 4006 dccc 0a00 0077 0a00 .4I(#.#......w..
0x0020: 0059 ed24 ceb3 ca18 0bba b105 51ca 8010 .Y.$........Q...
0x0030: 00eb 2e58 0000 0101 080a be02 b3c2 804b ...X...........K
0x0040: ac1e ..
12:11:25.318064 IP hastings.60708 > 10.0.0.89.52915: Flags [P.], seq 1:280, ack 269, win 235, options [nop,nop,TS val 3187848131 ecr 2152442910], length 279
0x0000: 8c85 9048 25eb b827 ebc1 f24d 0800 4500 ...H%..'...M..E.
0x0010: 014b 4929 4000 4006 dbb4 0a00 0077 0a00 .KI)#.#......w..
0x0020: 0059 ed24 ceb3 ca18 0bba b105 51ca 8018 .Y.$........Q...
0x0030: 00eb cccc 0000 0101 080a be02 b3c3 804b ...............K
0x0040: ac1e 5468 7265 6164 2d31 343a 2050 4f53 ..Thread-14:.POS
0x0050: 5420 2f74 656d 7065 7261 7475 7265 2048 T./temperature.H
0x0060: 5454 502f 312e 310d 0a48 6f73 743a 2031 TTP/1.1..Host:.1
0x0070: 302e 302e 302e 3131 393a 3630 3730 380d 0.0.0.119:60708.
0x0080: 0a43 6f6e 7465 6e74 2d54 7970 653a 2061 .Content-Type:.a
0x0090: 7070 6c69 6361 7469 6f6e 2f6a 736f 6e0d pplication/json.
0x00a0: 0a43 6f6e 6e65 6374 696f 6e3a 206b 6565 .Connection:.kee
0x00b0: 702d 616c 6976 650d 0a41 6363 6570 743a p-alive..Accept:
0x00c0: 2061 7070 6c69 6361 7469 6f6e 2f6a 736f .application/jso
0x00d0: 6e0d 0a55 7365 722d 4167 656e 743a 2050 n..User-Agent:.P
0x00e0: 4948 6f6d 652f 3120 4346 4e65 7477 6f72 IHome/1.CFNetwor
0x00f0: 6b2f 3131 3231 2e32 2e31 2044 6172 7769 k/1121.2.1.Darwi
0x0100: 6e2f 3139 2e33 2e30 0d0a 436f 6e74 656e n/19.3.0..Conten
0x0110: 742d 4c65 6e67 7468 3a20 3231 390d 0a41 t-Length:.219..A
0x0120: 6363 6570 742d 4c61 6e67 7561 6765 3a20 ccept-Language:.
0x0130: 656e 2d75 730d 0a41 6363 6570 742d 456e en-us..Accept-En
0x0140: 636f 6469 6e67 3a20 677a 6970 2c20 6465 coding:.gzip,.de
0x0150: 666c 6174 650d 0a0d 0a flate....
12:11:25.318096 IP 10.0.0.89.52915 > hastings.60708: Flags [.], ack 280, win 2054, options [nop,nop,TS val 2152442914 ecr 3187848131], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0034 0000 4000 4006 25f5 0a00 0059 0a00 .4..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 52a5 ca18 0cd1 8010 .w...$..R.......
0x0030: 0806 2546 0000 0101 080a 804b ac22 be02 ..%F.......K."..
0x0040: b3c3 ..
12:11:25.321081 IP hastings.60708 > 10.0.0.89.52915: Flags [P.], seq 280:510, ack 488, win 243, options [nop,nop,TS val 3187848134 ecr 2152442910], length 230
0x0000: 8c85 9048 25eb b827 ebc1 f24d 0800 4500 ...H%..'...M..E.
0x0010: 011a 492a 4000 4006 dbe4 0a00 0077 0a00 ..I*#.#......w..
0x0020: 0059 ed24 ceb3 ca18 0cd1 b105 52a5 8018 .Y.$........R...
0x0030: 00f3 b091 0000 0101 080a be02 b3c6 804b ...............K
0x0040: ac1e 5468 7265 6164 2d31 343a 2022 4c6f ..Thread-14:."Lo
0x0050: 6769 6e20 7375 6363 6573 7366 756c 3a65 gin.successful:e
0x0060: 794a 3065 5841 694f 694a 7164 3351 694c yJ0eXAiOiJqd3QiL
0x0070: 434a 6862 4763 694f 694a 4955 7a49 314e CJhbGciOiJIUzI1N
0x0080: 694a 392e 6579 4a7a 6457 4969 4f69 4a51 iJ9.eyJzdWIiOiJQ
0x0090: 5355 6876 6257 5567 6247 396e 6157 3469 SUhvbWUgbG9naW4i
0x00a0: 4c43 4a31 6332 5679 496a 6f69 6347 6c6f LCJ1c2VyIjoicGlo
0x00b0: 6232 316c 4c6e 5268 626d 526f 5147 5268 b21lLnRhbmRoQGRh
0x00c0: 6247 5635 4c6e 647a 4969 7769 6157 4630 bGV5LndzIiwiaWF0
0x00d0: 496a 6f78 4e54 6779 4d7a 6b78 4e44 6731 IjoxNTgyMzkxNDg1
0x00e0: 4c43 4a6e 636d 3931 6348 4d69 4f6c 7369 LCJncm91cHMiOlsi
0x00f0: 6447 4675 5a47 6769 5858 302e 5367 7068 dGFuZGgiXX0.Sgph
0x0100: 754d 6a63 476f 3766 486a 6a78 7847 3655 uMjcGo7fHjjxxG6U
0x0110: 6977 706c 6775 4d64 5a62 6863 742d 357a iwplguMdZbhct-5z
0x0120: 4463 446e 644c 5922 DcDndLY"
12:11:25.321101 IP 10.0.0.89.52915 > hastings.60708: Flags [.], ack 510, win 2050, options [nop,nop,TS val 2152442917 ecr 3187848134], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0034 0000 4000 4006 25f5 0a00 0059 0a00 .4..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 52a5 ca18 0db7 8010 .w...$..R.......
0x0030: 0802 245e 0000 0101 080a 804b ac25 be02 ..$^.......K.%..
0x0040: b3c6 ..
12:11:35.324471 IP 10.0.0.89.52915 > hastings.60708: Flags [F.], seq 488, ack 510, win 2050, options [nop,nop,TS val 2152452893 ecr 3187848134], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0034 0000 4000 4006 25f5 0a00 0059 0a00 .4..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 52a5 ca18 0db7 8011 .w...$..R.......
0x0030: 0802 fd64 0000 0101 080a 804b d31d be02 ...d.......K....
0x0040: b3c6 ..
12:11:35.331969 IP hastings.60708 > 10.0.0.89.52915: Flags [F.], seq 510, ack 489, win 243, options [nop,nop,TS val 3187858144 ecr 2152452893], length 0
0x0000: 8c85 9048 25eb b827 ebc1 f24d 0800 4500 ...H%..'...M..E.
0x0010: 0034 492b 4000 4006 dcc9 0a00 0077 0a00 .4I+#.#......w..
0x0020: 0059 ed24 ceb3 ca18 0db7 b105 52a6 8011 .Y.$........R...
0x0030: 00f3 dd58 0000 0101 080a be02 dae0 804b ...X...........K
0x0040: d31d ..
12:11:35.332037 IP 10.0.0.89.52915 > hastings.60708: Flags [.], ack 511, win 2050, options [nop,nop,TS val 2152452899 ecr 3187858144], length 0
0x0000: b827 eb94 a718 8c85 9048 25eb 0800 4500 .'.......H%...E.
0x0010: 0034 0000 4000 4006 25f5 0a00 0059 0a00 .4..#.#.%....Y..
0x0020: 0077 ceb3 ed24 b105 52a6 ca18 0db8 8010 .w...$..R.......
0x0030: 0802 d643 0000 0101 080a 804b d323 be02 ...C.......K.#..
0x0040: dae0 ..
Is this simply a problem with https or is it something deeper?
This might be due to ATS, try to set the following keys in your application Info.plist
NSAppTransportSecurity : Dictionary {
NSAllowsArbitraryLoads : Boolean -> YES
NSAllowsArbitraryLoadsForMedia : Boolean -> YES
NSAllowsArbitraryLoadsInWebContent : Boolean -> YES
NSAllowsLocalNetworking : Boolean -> YES
Find more details on official Preventing Insecure Network Connections
Is there any practical difference in the results of these two little chunks of logic, if you are just checking for one specific condition and everything else is NOT X?
def country
if params[:ip_country_code] == "X"
{:api_key => 1}
else
{:api_key => 2}
end
end
vs.
def country
if params[:ip_country_code] == "X"
{:api_key => 1}
elsif params[:ip_country_code] != "X"
{:api_key => 2}
else
end
end
The difference if that using elsif generates one more comparison, therefore requiring a bit more work from the processor. You can disassemble it using following script:
code = <<~CODE
a = 4
if a == 4
puts "equal"
else
puts "not equal"
end
CODE
code2 = <<~CODE
a = 4
if a == 4
puts "equal"
elseif a != 4
puts "not equal"
end
CODE
puts RubyVM::InstructionSequence.compile(code).disasm
puts "\n\n----------------------\n\n"
puts RubyVM::InstructionSequence.compile(code2).disasm
Result for first one (if-else):
== disasm: #<ISeq:<compiled>#<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1#-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 putobject 4
0012 opt_eq <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0015 branchunless 26
0017 trace 1 ( 3)
0019 putself
0020 putstring "equal"
0022 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0025 leave ( 2)
0026 trace 1 ( 5)
0028 putself
0029 putstring "not equal"
0031 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0034 leave
While for the second (if-elsif):
== disasm: #<ISeq:<compiled>#<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1#-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 putobject 4
0012 opt_eq <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0015 branchunless 51
0017 trace 1 ( 3)
0019 putself
0020 putstring "equal"
0022 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0025 pop
0026 trace 1 ( 4)
0028 putself
0029 getlocal_OP__WC__0 2
0031 putobject 4
0033 opt_neq <callinfo!mid:!=, argc:1, ARGS_SIMPLE>, <callcache>, <callinfo!mid:==, argc:1, ARGS_SIMPLE>, <callcache>
0038 opt_send_without_block <callinfo!mid:elseif, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0041 pop
0042 trace 1 ( 5)
0044 putself
0045 putstring "not equal"
0047 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0050 leave ( 2)
0051 putnil ( 5)
0052 leave
As you see, second one generates more instructions so if done billions time, it will be slightly slower. I don't know if that's the "practicality" you meant.
In your case there will be even more overhead with accessing values from the hash. If you perform some really "heavy" operations in condition, it will be repeated twice and can have real impact on performance.
Case case
As asked in the comments, here's a version for case-based solution:
code3 = <<~CODE
a = 4
case a
when 4 then puts "equal"
else puts "not equal"
end
CODE
Result:
== disasm: #<ISeq:<compiled>#<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1#-1, kwrest: -1])
[ 2] a
0000 trace 1 ( 1)
0002 putobject 4
0004 setlocal_OP__WC__0 2
0006 trace 1 ( 2)
0008 getlocal_OP__WC__0 2
0010 dup
0011 opt_case_dispatch <cdhash>, 21
0014 dup ( 3)
0015 putobject 4
0017 checkmatch 2
0019 branchif 31
0021 pop ( 4)
0022 trace 1
0024 putself
0025 putstring "not equal"
0027 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0030 leave
0031 pop ( 5)
0032 trace 1 ( 3)
0034 putself
0035 putstring "equal"
0037 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0040 leave
Conclusion: this is only a bit longer that normal if-else and still much better that if-ifelse.
EDIT: I also noticed mistake in disassembled if-else, updated the answer.
if is good or two mutually exclusive choices.
elsif is usually used for multiple (or two not mutually exclusive) choices for different conditions.
multiple choices for the same condition are usually covered with with clause.
While there is no logical difference between those, the proper way to write this would be:
def country
value =
case params[:ip_country_code]
when "X" then 1
else 2
end
# or:
value =
if params[:ip_country_code] == 'X'
1
else
2
end
# or even with ternary:
value = params[:ip_country_code] == 'X' ? 1 : 2
{api_key: value}
end
I am working on a Ruby on Rails application which uses the WinRM library to access a remote Windows server. The transport supplied is :negotiate which will negotiate the authentication with the remote server.
The issue is the WinRM library expects a 401 HTTP status code so that it can send more data for authentication. However, a 200 HTTP status code is returned and the negotiate fails.
The backtrace is :
NoMethodError: undefined method `split' for nil:NilClass
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/http/transport.rb:226:in `init_auth'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/http/transport.rb:166:in `send_request'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/winrm_service.rb:489:in `send_message'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/winrm_service.rb:390:in `run_wql'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/command_executor.rb:186:in `os_version'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/command_executor.rb:145:in `code_page'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/command_executor.rb:72:in `block in open'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/command_executor.rb:218:in `retryable'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/winrm-1.7.3/lib/winrm/command_executor.rb:71:in `open'
from (irb):20
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/railties-4.2.1/lib/rails/commands/console.rb:110:in `start'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/railties-4.2.1/lib/rails/commands/console.rb:9:in `start'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:68:in `console'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/railties-4.2.1/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /home/cobalt/.rvm/gems/ruby-2.2.2/gems/railties-4.2.1/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'2.2.2 :021 >
The TCP Dump shows the below package exchanges
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
12:04:08.372376 IP d8b5d56cba65.53166 > pokcpeusap02.corp.absc.local.wsman: Flags [S], seq 2899844066, win 29200, options [mss 1460,sackOK,TS val 1316187676 ecr 0,nop,wscale 7], length 0
0x0000: 4500 003c 75fe 4000 4006 d486 0400 0005 E..<u.#.#.......
0x0010: 0acd e165 cfae 1761 acd8 1be2 0000 0000 ...e...a........
0x0020: a002 7210 f065 0000 0204 05b4 0402 080a ..r..e..........
0x0030: 4e73 6e1c 0000 0000 0103 0307 Nsn.........
12:04:08.421019 IP pokcpeusap02.corp.absc.local.wsman > d8b5d56cba65.53166: Flags [S.], seq 3702856093, ack 2899844067, win 8192, options [mss 1351,nop,wscale 8,sackOK,TS val 79780711 ecr 1316187676],
length 0
0x0000: 4500 003c 7f04 4000 7d06 8e80 0acd e165 E..<..#.}......e
0x0010: 0400 0005 1761 cfae dcb5 199d acd8 1be3 .....a..........
0x0020: a012 2000 754e 0000 0204 0547 0103 0308 ....uN.....G....
0x0030: 0402 080a 04c1 5b67 4e73 6e1c ......[gNsn.
12:04:08.421047 IP d8b5d56cba65.53166 > pokcpeusap02.corp.absc.local.wsman: Flags [.], ack 1, win 229, options [nop,nop,TS val 1316187725 ecr 79780711], length 0
0x0000: 4500 0034 75ff 4000 4006 d48d 0400 0005 E..4u.#.#.......
0x0010: 0acd e165 cfae 1761 acd8 1be3 dcb5 199e ...e...a........
0x0020: 8010 00e5 f05d 0000 0101 080a 4e73 6e4d .....]......NsnM
0x0030: 04c1 5b67 ..[g
12:04:08.421368 IP d8b5d56cba65.53166 > pokcpeusap02.corp.absc.local.wsman: Flags [P.], seq 1:340, ack 1, win 229, options [nop,nop,TS val 1316187725 ecr 79780711], length 339
0x0000: 4500 0187 7600 4000 4006 d339 0400 0005 E...v.#.#..9....
0x0010: 0acd e165 cfae 1761 acd8 1be3 dcb5 199e ...e...a........
0x0020: 8018 00e5 f1b0 0000 0101 080a 4e73 6e4d ............NsnM
0x0030: 04c1 5b67 504f 5354 202f 7773 6d61 6e20 ..[gPOST./wsman.
0x0040: 4854 5450 2f31 2e31 0d0a 4175 7468 6f72 HTTP/1.1..Author
0x0050: 697a 6174 696f 6e3a 204e 6567 6f74 6961 ization:.Negotia
0x0060: 7465 2054 6c52 4d54 564e 5455 4141 4241 te.TlRMTVNTUAABA
0x0070: 4141 414e 3449 4934 4151 4142 4141 6741 AAAN4II4AQABAAgA
0x0080: 4141 4141 4141 4141 4351 4141 4142 4462 AAAAAAAACQAAABDb
0x0090: 334a 775a 4468 694e 5751 314e 6d4e 6959 3JwZDhiNWQ1NmNiY
0x00a0: 5459 310d 0a43 6f6e 7465 6e74 2d54 7970 TY1..Content-Typ
0x00b0: 653a 2061 7070 6c69 6361 7469 6f6e 2f73 e:.application/s
0x00c0: 6f61 702b 786d 6c3b 6368 6172 7365 743d oap+xml;charset=
0x00d0: 5554 462d 380d 0a55 7365 722d 4167 656e UTF-8..User-Agen
0x00e0: 743a 2052 7562 7920 5769 6e52 4d20 436c t:.Ruby.WinRM.Cl
0x00f0: 6965 6e74 2028 322e 372e 312c 2072 7562 ient.(2.7.1,.rub
0x0100: 7920 322e 322e 3220 2832 3031 352d 3034 y.2.2.2.(2015-04
0x0110: 2d31 3329 290d 0a41 6363 6570 743a 202a -13))..Accept:.*
0x0120: 2f2a 0d0a 4461 7465 3a20 5475 652c 2030 /*..Date:.Tue,.0
0x0130: 3720 4d61 7220 3230 3137 2031 323a 3034 7.Mar.2017.12:04
0x0140: 3a30 3820 474d 540d 0a43 6f6e 7465 6e74 :08.GMT..Content
0x0150: 2d4c 656e 6774 683a 2030 0d0a 486f 7374 -Length:.0..Host
0x0160: 3a20 706f 6b63 7065 7573 6170 3032 2e63 :.pokcpeusap02.c
0x0170: 6f72 702e 6162 7363 2e6c 6f63 616c 3a35 orp.absc.local:5
0x0180: 3938 350d 0a0d 0a 985....
12:04:08.516497 IP pokcpeusap02.corp.absc.local.wsman > d8b5d56cba65.53166: Flags [P.], seq 1:39, ack 340, win 256, options [nop,nop,TS val 79780721 ecr 1316187725], length 38
0x0000: 4500 005a 7f05 4000 7d06 8e61 0acd e165 E..Z..#.}..a...e
0x0010: 0400 0005 1761 cfae dcb5 199e acd8 1d36 .....a.........6
0x0020: 8018 0100 11f4 0000 0101 080a 04c1 5b71 ..............[q
0x0030: 4e73 6e4d 4854 5450 2f31 2e31 2032 3030 NsnMHTTP/1.1.200
0x0040: 204f 4b0d 0a43 6f6e 7465 6e74 2d4c 656e .OK..Content-Len
0x0050: 6774 683a 2030 0d0a 0d0a gth:.0....
12:04:08.516541 IP d8b5d56cba65.53166 > pokcpeusap02.corp.absc.local.wsman: Flags [.], ack 39, win 229, options [nop,nop,TS val 1316187821 ecr 79780721], length 0
0x0000: 4500 0034 7601 4000 4006 d48b 0400 0005 E..4v.#.#.......
0x0010: 0acd e165 cfae 1761 acd8 1d36 dcb5 19c4 ...e...a...6....
0x0020: 8010 00e5 f05d 0000 0101 080a 4e73 6ead .....]......Nsn.
0x0030: 04c1 5b71 ..[q
What would be the issue? Why I don't get a 401 HTTP status code?
I havae managed to found the root cause of the issue. It turns out there is another service instead of WinRM srevice is listening to port 5985. Hence when a request is sent to that port, that service responded with a respone requiring Basic Authentication and the status code 200. The issue is fixed after starting WinRM service and make it listen at port 5985.
The detailed analysis can be found at Ruby WinRM undefined method `split' for nil:NilClass. It's really a good lesson to learn. Sometimes the issue is very simple and stupid, but to find out the issue would take much effort.
I have been working on an iOS reader app for a special kind of barcode used by Deutsche Bahn (german rail) for a while now. It is a variant of Aztec barcode that concatenates a DSA signature string and a zlib deflated payload.
I was stuck, when I learned that the AVMetadataMachineReadableCodeObject had no public method for reading the raw bytes contained in the barcode and the string methods always garbled the zlib-compressed data.
Luckily, this answer sent me in the right direction. The (private) bytes can be accessed with KVO, and as I don't currently expect to distribute the app on the App Store, that was perfect.
Despite my almost non-existent Swift and Objective-C knowledge I managed to get this to work, as you can see in the sample code. But the bytes from the barcode that are stored in NSData don't match the expected result! I suspected the zlib library I use (DeflateSwift) was not working, so I built a test case, which worked fine.
My question is: what am I doing wrong? Do I need to further process the raw bytes to get to the expected result (see below)? How raw exactly are the bytes that are stored in the AVMetadataMachineReadableCodeObject? Can anyone point me in the right direction? Any help is appreciated.
Here is my code (which is a sad mashup of Swift and Objective-C)
if let metadataObject = metadataObjects.first {
let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject;
let rawReadableObject = readableObject.valueForKeyPath("_internal.basicDescriptor")!["BarcodeRawData"] as? NSData;
if let rawBytes = rawReadableObject {
let barcodeData = rawBytes; // or use testData instead
let barcodeSplit:Int = 68;
let barcodeLength:Int = barcodeData.length;
let barcodeHeader:NSData = barcodeData.subdataWithRange(NSRange(location: 0, length: barcodeSplit))
let barcodeZlibContent:NSData = barcodeData.subdataWithRange(NSRange(location: barcodeSplit, length: (barcodeLength-barcodeSplit)))
let count = barcodeZlibContent.length / sizeof(UInt8)
var array = [UInt8](count: count, repeatedValue: 0)
barcodeZlibContent.getBytes(&array, length:count * sizeof(UInt8))
print("\(barcodeLength)kb")
print(barcodeHeader)
print(barcodeZlibContent)
var inflater = InflateStream()
var (inflated, err) = inflater.write(array, flush: true)
if err != nil{
fatalError("\(err!)")
}
if let ticketString = String(bytes: inflated, encoding: NSUTF8StringEncoding) {
print(ticketString)
} else {
print("not a valid UTF-8 sequence")
}
}
}
This is what I get
The bytes returned from AVMetadataMachineReadableCodeObject are
40 B4 FA 88 89 8A 88 88 98 E6 3E 20 09 10 0A 0E EF 25 ED AC DE C8 80 5A 6F 9D 21 9F 4A 6D 61 33 19 F3 12 10 8A 80 2B F0 C2 7C CE E0 AB 83 46 AF A6 42 79 FD E8 35 D4 8B 0B 00 00 00 00 03 13 3B A3 47 8E A9 C2 B4 DC 30 03 C2 89 32 8D A3 B0 D4 E6 2B 35 5B 7B 08 88 12 A0 AA A2 00 8E 22 20 31 95 10 1C 21 2A FF 78 2C BE 31 1B A2 12 B5 CF A3 87 9B 9B 59 EF 7B BC AC AE CA 88 C8 1C 02 E8 D2 B5 87 76 0D 93 77 8B FB 04 A2 B5 D1 F8 9A 67 D5 55 15 DA 61 13 91 EC 08 60 2D 9B 86 E1 94 35 C3 D8 A9 49 41 5B 3A 7C 59 A5 FD 9A E3 FE F8 3C 9F 3F 7B B2 59 DC 98 E3 5E 92 CC C0 21 11 EC AF BA D7 F4 5D DB FC BD A5 CA AF 99 08 28 E3 02 30 06 20 A8 00 88 43 8E A2 58 2D 87 24 33 40 18 C1 AE 50 04 08 91 7E 59 E1 F6 9B 87 E7 8A 67 AA 1B 3E FF FE EF 79 46 18 5A 23 03 B4 E9 1A 4F 2F 15 EA DC 46 F5 A9 67 AE B8 F7 16 0B F2 38 8B B3 96 35 34 AB D3 A6 0E 6C 77 9D 72 D5 85 7E 58 0B E0 25 69 2C AC 42 9C 13 0F 27 4F 13 72 4A 90 CB 1C ED 78 B3 60 F4 AD 4C FE 2B F4 51 A8 0D 60 CC DF 78 C7 65 78 CC E6 63 02 45 B1 F3 1F A8 ED 9E FE 63 00 00 00 00
Here is the sample barcode of a Deutsche Bahn ticket I used for testing.
This is what I need
When scanned with a proper barcode reader (I used bcTester 5) this yields the following bytes:
23 55 54 30 31 30 30 38 30 30 30 30 30 31 30 2C 02 14 1C 3D E9 2D CD 5E C4 C0 56 BD AE 61 3E 54 AD A1 B3 26 33 D2 02 14 40 75 03 D0 CF 9C C1 F5 70 58 BD 59 50 A7 AF C5 EB 0A F4 74 00 00 00 00 30 32 37 31 78 9C 65 50 CB 4E C3 30 10 E4 53 2C 71 43 4A D9 F5 2B 36 B7 84 04 52 01 55 51 40 1C 51 01 23 2A 42 0E 21 15 3F C7 8D 1F 63 36 11 52 2B 7C F1 78 76 76 66 BD F7 8F 4D 5D 54 C4 44 CE 10 05 D2 EB 78 5B AC 32 7B B4 77 C8 11 6B 62 C7 D6 79 AA EA AA 16 E1 B2 22 4D C4 01 AD 36 58 61 CA 6B 30 C6 E5 64 A0 B6 97 0F A6 A9 6F D6 71 DF C7 CF 3E 7F 37 93 66 8E C6 71 DE 92 4C C0 E1 22 0D FD 57 7A CB EE B6 CF EF 69 54 FD 66 44 05 31 D0 03 18 01 05 40 04 70 9C 51 46 AD 38 49 33 00 86 20 DD 42 88 04 22 5F A6 A1 DB F6 78 79 D4 79 95 76 1F 3F DF FD E7 98 86 16 B1 30 0B 65 D6 3C BD 2A 15 CE D8 AB E5 79 9D 47 7B DA 34 13 C7 34 73 5A 6B 0B 35 72 D9 5C 0D BB AE 53 AA E8 5F 86 B4 01 E9 25 8D 0D 50 8E 72 3C 39 3C B2 13 94 82 74 CE 2D C7 B3 41 8B ED 4C 9F F5 0B E2 85 6C 01 8C FE C7 B8 E9 87 8C D9 F1 90 28 A3 73 FE 05 6D DE 5F F1
As you can see, at offset 68 (78 9C) begins a valid zlib stream. If you split the data here and inflate the zlib data, it returns a string like this:
U_HEAD01005300802P9QAN-40501201514560DEDE0080ID0200180104840080BL020357031204GW3HEMP906012015060120151021193517S0010018Fernweh-Ticket natS00200012S0030001AS00900051-0-0S01200010S0140002S2S0150006BerlinS0160011NeumünsterS0210038B-Hbf 8:16 ICE794/HH-Hbf 10:16 IC2224S0230013Krull AndreaS026000213S0270019***************0484S0280013Andrea#Krull S031001006.01.2015S032001006.01.2015S035000511160S0360003271
Test NSData
If I build the byte array manually using the bytes returned from bcTester, everything works out as expected and the zlib data inflates correctly. Here is how I tested:
let testArray = [UInt8](arrayLiteral: 0x23, 0x55, 0x54, 0x30, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x2C, 0x02, 0x14, 0x1C, 0x3D, 0xE9, 0x2D, 0xCD, 0x5E, 0xC4, 0xC0, 0x56, 0xBD, 0xAE, 0x61, 0x3E, 0x54, 0xAD, 0xA1, 0xB3, 0x26, 0x33, 0xD2, 0x02, 0x14, 0x40, 0x75, 0x03, 0xD0, 0xCF, 0x9C, 0xC1, 0xF5, 0x70, 0x58, 0xBD, 0x59, 0x50, 0xA7, 0xAF, 0xC5, 0xEB, 0x0A, 0xF4, 0x74, 0x00, 0x00, 0x00, 0x00, 0x30, 0x32, 0x37, 0x31, 0x78, 0x9C, 0x65, 0x50, 0xCB, 0x4E, 0xC3, 0x30, 0x10, 0xE4, 0x53, 0x2C, 0x71, 0x43, 0x4A, 0xD9, 0xF5, 0x2B, 0x36, 0xB7, 0x84, 0x04, 0x52, 0x01, 0x55, 0x51, 0x40, 0x1C, 0x51, 0x01, 0x23, 0x2A, 0x42, 0x0E, 0x21, 0x15, 0x3F, 0xC7, 0x8D, 0x1F, 0x63, 0x36, 0x11, 0x52, 0x2B, 0x7C, 0xF1, 0x78, 0x76, 0x76, 0x66, 0xBD, 0xF7, 0x8F, 0x4D, 0x5D, 0x54, 0xC4, 0x44, 0xCE, 0x10, 0x05, 0xD2, 0xEB, 0x78, 0x5B, 0xAC, 0x32, 0x7B, 0xB4, 0x77, 0xC8, 0x11, 0x6B, 0x62, 0xC7, 0xD6, 0x79, 0xAA, 0xEA, 0xAA, 0x16, 0xE1, 0xB2, 0x22, 0x4D, 0xC4, 0x01, 0xAD, 0x36, 0x58, 0x61, 0xCA, 0x6B, 0x30, 0xC6, 0xE5, 0x64, 0xA0, 0xB6, 0x97, 0x0F, 0xA6, 0xA9, 0x6F, 0xD6, 0x71, 0xDF, 0xC7, 0xCF, 0x3E, 0x7F, 0x37, 0x93, 0x66, 0x8E, 0xC6, 0x71, 0xDE, 0x92, 0x4C, 0xC0, 0xE1, 0x22, 0x0D, 0xFD, 0x57, 0x7A, 0xCB, 0xEE, 0xB6, 0xCF, 0xEF, 0x69, 0x54, 0xFD, 0x66, 0x44, 0x05, 0x31, 0xD0, 0x03, 0x18, 0x01, 0x05, 0x40, 0x04, 0x70, 0x9C, 0x51, 0x46, 0xAD, 0x38, 0x49, 0x33, 0x00, 0x86, 0x20, 0xDD, 0x42, 0x88, 0x04, 0x22, 0x5F, 0xA6, 0xA1, 0xDB, 0xF6, 0x78, 0x79, 0xD4, 0x79, 0x95, 0x76, 0x1F, 0x3F, 0xDF, 0xFD, 0xE7, 0x98, 0x86, 0x16, 0xB1, 0x30, 0x0B, 0x65, 0xD6, 0x3C, 0xBD, 0x2A, 0x15, 0xCE, 0xD8, 0xAB, 0xE5, 0x79, 0x9D, 0x47, 0x7B, 0xDA, 0x34, 0x13, 0xC7, 0x34, 0x73, 0x5A, 0x6B, 0x0B, 0x35, 0x72, 0xD9, 0x5C, 0x0D, 0xBB, 0xAE, 0x53, 0xAA, 0xE8, 0x5F, 0x86, 0xB4, 0x01, 0xE9, 0x25, 0x8D, 0x0D, 0x50, 0x8E, 0x72, 0x3C, 0x39, 0x3C, 0xB2, 0x13, 0x94, 0x82, 0x74, 0xCE, 0x2D, 0xC7, 0xB3, 0x41, 0x8B, 0xED, 0x4C, 0x9F, 0xF5, 0x0B, 0xE2, 0x85, 0x6C, 0x01, 0x8C, 0xFE, 0xC7, 0xB8, 0xE9, 0x87, 0x8C, 0xD9, 0xF1, 0x90, 0x28, 0xA3, 0x73, 0xFE, 0x05, 0x6D, 0xDE, 0x5F, 0xF1)
let testData = NSData(bytes: testArray, length: testArray.count)
I solved this some time ago in Xamarin/C#, but the idea is the same for Swift too. The encodedData and ReadCode methods are taken form ZXing lib. Hope it helps.
It works well for reading and decoding both "small" and "large" ticket codes, but the default Aztec reader in iOS SDK is not good enough, so in the end we went on with the reader from Manateeworks. I can see now that it did not get any better with iOS 10 SDK.
public override void DidOutputMetadataObjects (AVCaptureMetadataOutput captureOutput, AVMetadataObject[] metadataObjects, AVCaptureConnection connection)
{
foreach (AVMetadataMachineReadableCodeObject metadata in metadataObjects) {
var d1 = (metadata.ValueForKey ((NSString)"_internal"));
var d2 = (d1.ValueForKey ((NSString)"basicDescriptor"));
var data = (d2.ValueForKey ((NSString)"BarcodeRawData"));
var str = data.ToString ().Trim ().Trim (new [] { '<', '>' }).Replace (" ", "");
var bitarray = new bool[str.Length * 4];
for (var i = 0; i < str.Length / 2; i++) {
int value = Convert.ToInt32 (str.Substring (i * 2, 2), 16);
bitarray [i * 8 + 0] = (value & 1) > 0;
bitarray [i * 8 + 1] = (value & 2) > 0;
bitarray [i * 8 + 2] = (value & 4) > 0;
bitarray [i * 8 + 3] = (value & 8) > 0;
bitarray [i * 8 + 4] = (value & 16) > 0;
bitarray [i * 8 + 5] = (value & 32) > 0;
bitarray [i * 8 + 6] = (value & 64) > 0;
bitarray [i * 8 + 7] = (value & 128) > 0;
}
var pabData = encodedData (bitarray);
parent.scanFinished (true, pabData);
}
}
enum ZXAztecTable
{
ZXAztecTableUpper,
ZXAztecTableBinary,
ZXAztecTableDigit
};
public byte[] encodedData (bool[] bitArray)
{
var result = new List<byte> ();
int endIndex = bitArray.Length;
ZXAztecTable latchTable = ZXAztecTable.ZXAztecTableUpper; // table most recently latched to
ZXAztecTable shiftTable = ZXAztecTable.ZXAztecTableUpper; // table to use for the next read
int index = 0;
while (index < endIndex) {
if (shiftTable == ZXAztecTable.ZXAztecTableBinary) {
if (endIndex - index < 5) {
break;
}
int length = ReadCode (bitArray, index, 5);
index += 5;
if (length == 0) {
if (endIndex - index < 11) {
break;
}
length = ReadCode (bitArray, index, 11) + 31;
index += 11;
}
for (int charCount = 0; charCount < length; charCount++) {
if (endIndex - index < 8) {
index = endIndex; // Force outer loop to exit
break;
}
byte code = (byte)ReadCode (bitArray, index, 8);
result.Add (code);
index += 8;
}
// Go back to whatever mode we had been in
shiftTable = latchTable;
} else {
int size = shiftTable == ZXAztecTable.ZXAztecTableDigit ? 4 : 5;
if (endIndex - index < size) {
break;
}
ReadCode (bitArray, index, size);
index += size;
latchTable = shiftTable;
shiftTable = ZXAztecTable.ZXAztecTableBinary;
}
}
return result.ToArray ();
}
public int ReadCode (bool[] bitArray, int startIndex, int length)
{
int res = 0;
for (int i = startIndex; i < startIndex + length; i++) {
res <<= 1;
if (bitArray [i]) {
res |= 0x01;
}
}
return res;
}
Although I had the same issue while working with Data Matrix code, I assume this answer will be helpful for those who encountered the same problem.
So, we managed to retrieve raw bytes from AVMetadataReadableMachineObject via KVO ("internalBasicDescriptor" "barcodeRawData") as Data and printed its description to console, as you did in example. The bytes are not what we expect to see and e.g. we cannot produce a readable string from it (or it is not even a text). The reason is that the code was generated using a particular encoding scheme.
In my case, Data Matrix use C40, X12, Edifact, Base256... encoding schemes. In case of Data Matrix codes, you can check the table from the official documentation https://www.gs1.org/docs/barcodes/GS1_DataMatrix_Guideline.pdf (p. 50). For instance, if we convert the first byte and get 231, it indicates that the code is encoded using base256.
QR, Aztec and other codes may use the same approach of encoding data (probably not the ones I mentioned). Thus, depending of your type you should search for encoding schemes (which are, in most cases, simple math formulas converting one integer to another). Consider, that a detailed documentation of encodation schemes may be increasingly limited thought the web.
So, the bytes returned by AVMetadataObject are correct, though encoded (you should actually try to understand how).
Lastly, from iOS 11.0 you can get raw bytes in a better way:
if let object = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
if object.type == AVMetadataObject.ObjectType.qr {
let descriptor = object.descriptor {
let rawBytes = descriptor.errorPayload
use .dataMatrix, .aztec, etc. instead of .qr (or you can even skip this line).
Thus, descriptor is basically CIBarcodeDescriptor, which has child classes so you can get more precise results (such as CIDataMatrixCodeDescriptor, CIQRCodeDescriptor, etc.) You can check some information on Apple Developer Website as well.