nx_escl_probe.nx source
↩ module page · 94 lines · 4634 B
1// nx_escl_probe.nx -- LIVE, READ-ONLY eSCL probe: does the real Brother speak the open scan standard?
2// Sends an HTTP GET /eSCL/ScannerCapabilities to 192.168.8.127:80 (reusing the sovereign TCP + HTTP-framing
3// primitives from nx_ipp_transport), and feeds the body to the gated nx_escl parser. A NEGATIVE result (no
4// eSCL) is an HONEST finding about this 2015-era MFP -- scan would then need WSD or a vendor path. READ-ONLY
5// (a GET) -> never-brick #26. license_tier: ORIGINAL ; genealogy_id: project-printer-management-ipp-sclass-2026-06-20
6
7import "nx_syscalls.nx"
8import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
9import "nx_ipp_transport.nx"
10import "nx_escl.nx"
11const K_MAGIC_1024: i64 = 1024
12const K_MAGIC_262144: i64 = 262144
13
14func p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
15func pn(v: i64) -> i64 {
16 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
17 var m: i64 = v
18 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
19 let t: *u8 = sys_mmap(24); var k: i64 = 0
20 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
21 let b: *u8 = sys_mmap(24); var i: i64 = 0
22 while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
23 sys_write(1, b, k); return 0
24}
25
26func main() -> i64 {
27 p("=== NISHI eSCL SCANNER PROBE (live, read-only GET) ===\n")
28 let a: i64 = 192
29 let b: i64 = 168
30 let c: i64 = 8
31 let d: i64 = 127
32 let port: i64 = 80
33 p("target http://"); pn(a); p("."); pn(b); p("."); pn(c); p("."); pn(d); p(":80/eSCL/ScannerCapabilities\n")
34
35 // build the HTTP GET request (reuse the transport's buffer writers)
36 let snd: *u8 = sys_mmap(K_MAGIC_1024)
37 var so: i64 = 0
38 so = nx_ipt_puts(snd, so, "GET /eSCL/ScannerCapabilities HTTP/1.1\r\nHost: ")
39 so = nx_ipt_puti(snd, so, a); snd[so] = 46 as u8; so = so + 1
40 so = nx_ipt_puti(snd, so, b); snd[so] = 46 as u8; so = so + 1
41 so = nx_ipt_puti(snd, so, c); snd[so] = 46 as u8; so = so + 1
42 so = nx_ipt_puti(snd, so, d)
43 so = nx_ipt_puts(snd, so, "\r\nAccept: application/xml, text/xml\r\nConnection: close\r\n\r\n")
44
45 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0)
46 if fd < 0 { p("socket() failed\n"); sys_exit(1); return 1 }
47 sys_set_socket_timeout(fd, 5)
48 let dest: *u8 = sys_mmap(16)
49 nx_ipt_sockaddr(dest, a, b, c, d, port)
50 if nx_connect_bounded(fd, dest, 16, NX_CONN_DEFAULT_MS) != 0 {
51 sys_close(fd)
52 p("RESULT: connect :80 FAILED -- the Brother's HTTP server is unreachable (reported, not swallowed).\n")
53 sys_exit(1); return 1
54 }
55 sys_write(fd, snd, so)
56
57 let resp: *u8 = sys_mmap(K_MAGIC_262144)
58 var total: i64 = 0
59 var keep: i64 = 1
60 while keep == 1 {
61 if total >= K_MAGIC_262144 { keep = 0 }
62 else {
63 let r: i64 = sys_read(fd, ((resp as i64) + total) as *u8, K_MAGIC_262144 - total)
64 if r <= 0 { keep = 0 }
65 else { total = total + r }
66 }
67 }
68 sys_close(fd)
69
70 let body: *u8 = sys_mmap(K_MAGIC_262144)
71 let out2: *i64 = sys_mmap(16) as *i64
72 let v: i64 = nx_ipt_extract_body(resp, total, body, K_MAGIC_262144, out2)
73 p("transport="); p(nx_ipt_verdict_name(v)); p(" http="); pn(out2[0]); p(" body_bytes="); pn(out2[1]); p("\n")
74 if v != NX_IPT_OK { p("RESULT: no clean HTTP response on :80 -- reported.\n"); sys_exit(0); return 0 }
75
76 let n: i64 = out2[1]
77 if nx_escl_find(body, n, "ScannerCapabilities" as *u8, 19) < 0 {
78 p("RESULT: response is NOT eSCL ScannerCapabilities.\n")
79 p("HONEST FINDING: this DCP-L2540DW does not expose eSCL at :80/eSCL/ScannerCapabilities (likely a\n")
80 p("pre-eSCL MFP). Scan on this unit needs WSD or the Brother path; eSCL stays the standard for modern\n")
81 p("scanners and our R0 protocol layer is ready for them. (A negative probe is a real result, not a bug.)\n")
82 sys_exit(0); return 0
83 }
84
85 p("RESULT: the Brother SPEAKS eSCL! parsing live capabilities (prefix-robust)...\n")
86 p(" MaxWidth = "); pn(nx_escl_caps_int(body, n, "MaxWidth>" as *u8, 9))
87 p(" MaxHeight = "); pn(nx_escl_caps_int(body, n, "MaxHeight>" as *u8, 10)); p("\n")
88 p(" color: grayscale="); pn(nx_escl_has(body, n, "Grayscale8" as *u8, 10))
89 p(" rgb24="); pn(nx_escl_has(body, n, "RGB24" as *u8, 5)); p("\n")
90 p(" formats: jpeg="); pn(nx_escl_has(body, n, "image/jpeg" as *u8, 10))
91 p(" pdf="); pn(nx_escl_has(body, n, "application/pdf" as *u8, 15)); p("\n")
92 p("NEXT: POST a ScanSettings job -> GET NextDocument -> decode JPEG (R2).\n")
93 sys_exit(0); return 0
94}