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.

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

mercurial