code wiki / (root) / nx_escl_probe.nx

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}