[racket] Sandbox, in a module, with a *shared* environment but *separate* I/O

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Thu Oct 27 20:32:12 EDT 2011

Tony,

You probably want to look at make-eval-factory and
make-base-eval-factory.  They are in scribble/eval rather than
racket/sandbox, I think mostly as a quirk of history.

Carl Eastlund

On Thu, Oct 27, 2011 at 7:32 PM, Tony Garnock-Jones <tonyg at ccs.neu.edu> wrote:
> I've managed to kludge together a solution that seems to do what I want.
> It seems that it's a shared *namespace* instance I want, with a fresh
> evaluator for each connection, and the only (?) control over namespaces
> for sandboxes is via sandbox-namespace-specs. It isn't the most elegant,
> but here's the code:
>
> ;;---
> #lang racket/base
>
> (require racket/tcp)
> (require racket/sandbox)
>
> (define e (make-base-namespace))
>
> (define (shell in out)
>  (printf "Accepted\n")
>  (fprintf out "Hello.\n")
>  (parameterize ((current-input-port in)
>                 (current-output-port out)
>                 (current-error-port out)
>                 (sandbox-input in)
>                 (sandbox-output out)
>                 (sandbox-error-output out)
>                 (current-namespace e)
>                 (sandbox-namespace-specs (list (lambda () e))))
>    (parameterize ((current-eval (make-evaluator '(begin))))
>      (read-eval-print-loop))
>    (fprintf out "\nGoodbye!\n")
>    (close-input-port in)
>    (close-output-port out)))
>
> (define s (tcp-listen 2322 4 #t))
> (printf "Accepting...\n")
> (let loop ()
>  (define-values (i o) (tcp-accept s))
>  (thread (lambda ()
>            (shell i o)))
>  (loop))
> ;;---
>
> Any suggestions people have for improving that are very welcome.
>
> Regards,
>  Tony
>
> On 2011-10-27 3:45 PM, Tony Garnock-Jones wrote:
>> Hi all,
>>
>> The example TCP-listening sandboxed REPLs given nearish the top of
>> http://docs.racket-lang.org/reference/Sandboxed_Evaluation.html differ
>> slightly: the one that only works from the toplevel shares a namespace
>> and evaluator between all the connections, but the one that works from a
>> module uses a fresh namespace and evaluator for each connection.
>>
>> How can I set things up so that
>>
>>  - a single "global environment" is shared between all connections, but
>>  - each connection gets its own input and output ports, connected
>>    to the socket?
>>
>> I'd like to be able to connect in one terminal, say "(define x 123)",
>> then connect in another terminal and have "x" result in "123". I'd also
>> like "(display 'hello)" to print to the issuing terminal rather than
>> going only to one or the other.
>>
>> Does this sound like a familiar problem? Have others solved this before?
>> I feel like I'm missing something about the distinction between
>> namespaces and evaluators...
>>
>> Regards,
>>   Tony



Posted on the users mailing list.