b2g/simulator/packages/subprocess/lib/subprocess_worker_unix.js

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4 */
michael@0 5
michael@0 6 /*
michael@0 7 * ChromeWorker Object subprocess.jsm on Unix-like systems (Linux, Mac OS X, ...)
michael@0 8 * to process stdin/stdout/stderr on separate threads.
michael@0 9 *
michael@0 10 */
michael@0 11
michael@0 12 // Being a ChromeWorker object, implicitly uses the following:
michael@0 13 // Components.utils.import("resource://gre/modules/ctypes.jsm");
michael@0 14
michael@0 15 'use strict';
michael@0 16
michael@0 17 const BufferSize = 1024;
michael@0 18
michael@0 19 var libc = null;
michael@0 20 var libcFunc = {};
michael@0 21
michael@0 22
michael@0 23 /*
michael@0 24 struct pollfd {
michael@0 25 int fd; // file descriptor
michael@0 26 short events; // events to look for
michael@0 27 short revents; // events returned
michael@0 28 };
michael@0 29 */
michael@0 30
michael@0 31 var pollfd = new ctypes.StructType("pollfd",
michael@0 32 [ {'fd': ctypes.int},
michael@0 33 {'events': ctypes.short},
michael@0 34 {'revents': ctypes.short}
michael@0 35 ]);
michael@0 36
michael@0 37 var WriteBuffer = ctypes.uint8_t.array(BufferSize);
michael@0 38 var ReadBuffer = ctypes.char.array(BufferSize);
michael@0 39
michael@0 40
michael@0 41 const POLLIN = 0x0001;
michael@0 42 const POLLOUT = 0x0004;
michael@0 43
michael@0 44 const POLLERR = 0x0008; // some poll error occurred
michael@0 45 const POLLHUP = 0x0010; // file descriptor was "hung up"
michael@0 46 const POLLNVAL = 0x0020; // requested events "invalid"
michael@0 47
michael@0 48 const WNOHANG = 0x01;
michael@0 49
michael@0 50 const pid_t = ctypes.int32_t;
michael@0 51
michael@0 52 const INDEFINITE = -1;
michael@0 53 const NOWAIT = 0;
michael@0 54 const WAITTIME = 200 // wait time for poll() in ms
michael@0 55
michael@0 56 function initLibc(libName) {
michael@0 57 postMessage({msg: "debug", data: "initialising library with "+ libName});
michael@0 58
michael@0 59 libc = ctypes.open(libName);
michael@0 60
michael@0 61 libcFunc.pollFds = pollfd.array(1);
michael@0 62
michael@0 63 // int poll(struct pollfd fds[], nfds_t nfds, int timeout);
michael@0 64 libcFunc.poll = libc.declare("poll",
michael@0 65 ctypes.default_abi,
michael@0 66 ctypes.int,
michael@0 67 libcFunc.pollFds,
michael@0 68 ctypes.unsigned_int,
michael@0 69 ctypes.int);
michael@0 70
michael@0 71 //ssize_t write(int fd, const void *buf, size_t count);
michael@0 72 // NOTE: buf is declared as array of unsigned int8 instead of char to avoid
michael@0 73 // implicit charset conversion
michael@0 74 libcFunc.write = libc.declare("write",
michael@0 75 ctypes.default_abi,
michael@0 76 ctypes.int,
michael@0 77 ctypes.int,
michael@0 78 WriteBuffer,
michael@0 79 ctypes.int);
michael@0 80
michael@0 81 //int read(int fd, void *buf, size_t count);
michael@0 82 libcFunc.read = libc.declare("read",
michael@0 83 ctypes.default_abi,
michael@0 84 ctypes.int,
michael@0 85 ctypes.int,
michael@0 86 ReadBuffer,
michael@0 87 ctypes.int);
michael@0 88
michael@0 89 //int pipe(int pipefd[2]);
michael@0 90 libcFunc.pipefd = ctypes.int.array(2);
michael@0 91
michael@0 92 //int close(int fd);
michael@0 93 libcFunc.close = libc.declare("close",
michael@0 94 ctypes.default_abi,
michael@0 95 ctypes.int,
michael@0 96 ctypes.int);
michael@0 97
michael@0 98 //pid_t waitpid(pid_t pid, int *status, int options);
michael@0 99 libcFunc.waitpid = libc.declare("waitpid",
michael@0 100 ctypes.default_abi,
michael@0 101 pid_t,
michael@0 102 pid_t,
michael@0 103 ctypes.int.ptr,
michael@0 104 ctypes.int);
michael@0 105 }
michael@0 106
michael@0 107 function closePipe(pipe) {
michael@0 108 libcFunc.close(pipe);
michael@0 109 }
michael@0 110
michael@0 111 function writePipe(pipe, data) {
michael@0 112
michael@0 113 postMessage({msg: "debug", data: "trying to write to "+pipe});
michael@0 114
michael@0 115 let numChunks = Math.floor(data.length / BufferSize);
michael@0 116 let pData = new WriteBuffer();
michael@0 117
michael@0 118 for (var chunk = 0; chunk <= numChunks; chunk ++) {
michael@0 119 let numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize;
michael@0 120 for (var i=0; i < numBytes; i++) {
michael@0 121 pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256;
michael@0 122 }
michael@0 123
michael@0 124 let bytesWritten = libcFunc.write(pipe, pData, numBytes);
michael@0 125 if (bytesWritten != numBytes) {
michael@0 126 closePipe();
michael@0 127 libc.close();
michael@0 128 postMessage({ msg: "error", data: "error: wrote "+bytesWritten+" instead of "+numBytes+" bytes"});
michael@0 129 close();
michael@0 130 }
michael@0 131 }
michael@0 132 postMessage({msg: "info", data: "wrote "+data.length+" bytes of data"});
michael@0 133 }
michael@0 134
michael@0 135
michael@0 136 function readString(data, length, charset) {
michael@0 137 var string = '', bytes = [];
michael@0 138 for(var i = 0;i < length; i++) {
michael@0 139 if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data
michael@0 140 break;
michael@0 141
michael@0 142 bytes.push(data[i]);
michael@0 143 }
michael@0 144
michael@0 145 return bytes;
michael@0 146 }
michael@0 147
michael@0 148 function readPipe(pipe, charset, pid) {
michael@0 149 var p = new libcFunc.pollFds;
michael@0 150 p[0].fd = pipe;
michael@0 151 p[0].events = POLLIN | POLLERR | POLLHUP;
michael@0 152 p[0].revents = 0;
michael@0 153 var pollTimeout = WAITTIME;
michael@0 154 var exitCode = -1;
michael@0 155 var readCount = 0;
michael@0 156 var result, status = ctypes.int();
michael@0 157 result = 0;
michael@0 158
michael@0 159
michael@0 160 const i=0;
michael@0 161 while (true) {
michael@0 162 if (result == 0) {
michael@0 163 result = libcFunc.waitpid(pid, status.address(), WNOHANG);
michael@0 164 if (result > 0) {
michael@0 165 pollTimeout = NOWAIT;
michael@0 166 exitCode = parseInt(status.value);
michael@0 167 postMessage({msg: "debug", data: "waitpid signaled subprocess stop, exitcode="+status.value });
michael@0 168 }
michael@0 169 }
michael@0 170 var r = libcFunc.poll(p, 1, pollTimeout);
michael@0 171 if (r > 0) {
michael@0 172 if (p[i].revents & POLLIN) {
michael@0 173 postMessage({msg: "debug", data: "reading next chunk"});
michael@0 174 readCount = readPolledFd(p[i].fd, charset);
michael@0 175 if (readCount == 0) break;
michael@0 176 }
michael@0 177
michael@0 178 if (p[i].revents & POLLHUP) {
michael@0 179 postMessage({msg: "debug", data: "poll returned HUP"});
michael@0 180 break;
michael@0 181 }
michael@0 182 else if (p[i].revents & POLLERR) {
michael@0 183 postMessage({msg: "error", data: "poll returned error"});
michael@0 184 break;
michael@0 185 }
michael@0 186 else if (p[i].revents != POLLIN) {
michael@0 187 postMessage({msg: "error", data: "poll returned "+p[i]});
michael@0 188 break;
michael@0 189 }
michael@0 190 }
michael@0 191 else
michael@0 192 if (pollTimeout == 0 || r < 0) break;
michael@0 193 }
michael@0 194
michael@0 195 // continue reading until the buffer is empty
michael@0 196 while (readCount > 0) {
michael@0 197 readCount = readPolledFd(pipe, charset);
michael@0 198 }
michael@0 199
michael@0 200 libcFunc.close(pipe);
michael@0 201 postMessage({msg: "done", data: exitCode });
michael@0 202 libc.close();
michael@0 203 close();
michael@0 204 }
michael@0 205
michael@0 206 function readPolledFd(pipe, charset) {
michael@0 207 var line = new ReadBuffer();
michael@0 208 var r = libcFunc.read(pipe, line, BufferSize);
michael@0 209
michael@0 210 if (r > 0) {
michael@0 211 var c = readString(line, r, charset);
michael@0 212 postMessage({msg: "data", data: c, count: c.length});
michael@0 213 }
michael@0 214 return r;
michael@0 215 }
michael@0 216
michael@0 217 onmessage = function (event) {
michael@0 218 switch (event.data.msg) {
michael@0 219 case "init":
michael@0 220 initLibc(event.data.libc);
michael@0 221 break;
michael@0 222 case "read":
michael@0 223 initLibc(event.data.libc);
michael@0 224 readPipe(event.data.pipe, event.data.charset, event.data.pid);
michael@0 225 break;
michael@0 226 case "write":
michael@0 227 // data contents:
michael@0 228 // msg: 'write'
michael@0 229 // data: the data (string) to write
michael@0 230 // pipe: ptr to pipe
michael@0 231 writePipe(event.data.pipe, event.data.data);
michael@0 232 postMessage({msg: "info", data: "WriteOK"});
michael@0 233 break;
michael@0 234 case "close":
michael@0 235 postMessage({msg: "debug", data: "closing stdin\n"});
michael@0 236
michael@0 237 closePipe(event.data.pipe);
michael@0 238 postMessage({msg: "info", data: "ClosedOK"});
michael@0 239 break;
michael@0 240 case "stop":
michael@0 241 libc.close(); // do not use libc after this point
michael@0 242 close();
michael@0 243 break;
michael@0 244 default:
michael@0 245 throw("error: Unknown command"+event.data.msg+"\n");
michael@0 246 }
michael@0 247 return;
michael@0 248 };

mercurial