Hello,
My application consists of a server daemon and a client library. The idea
is that any program can use this library to send commands to the server.
Everything works as I expect until I try to create a package. Both the
client code and the server code are in the same package called "app." I
run the server in a CMUCL REPL in one shell and I load the client bit in
another CMUCL top-level in a different shell.
I'll use the SHUT-DOWN command as an example here. The client side does
this
*(app:do-cmd '(:shut-down))
which sends a packet consisting of the keyword :SHUT-DOWN to the server.
The server then reads the packet and and performs some action based on the
first symbol in the packet,
(DEFUN do-cmd (cmd)
(CASE cmd
(:action-1 (do-action-1))
(:action-2 (do-action-2))
(:shut-down (do-shut-down))
(otherwise (log 'bad-command))))
When I (PRINT (SYMBOL-PACKAGE cmd)) right before the CASE I see that cmd is
interned in the COMMON-LISP-USER package, not the KEYWORD package which is
what I expected. Since the CASE is comparing the cmd to symbols in the
KEYWORD package, I get a lot of BAD-COMMAND entries in the log. I expected
cmd to be in the KEYWORD package because the symbol that was sent from the
client was a keyword.
> You are in a twisty maze...
> You hear furious typing in the near distance...
I just discovered that if I
*(in-package keyword)
*(app:server)
I can send commands from the client to the server and the server will carry
out the correct action.
How do I set up my program so that I can send the commands as keywords from
the client to the server? I could just add the (in-package keyword) and
(app:server) calls to the end of my source file and then when the file was
loaded it would launch the server but that doesn't seem to be the "right"
way to handle the problem.
Thanks for all your help.
--dennis
········@bellsouth.net writes:
> I'll use the SHUT-DOWN command as an example here. The client side does
> this
>
> *(app:do-cmd '(:shut-down))
>
> which sends a packet consisting of the keyword :SHUT-DOWN to the server.
Well it probably isn't sending the keyword (which is a symbol object)
over to the other process, but rather PRINTs the symbol to a string,
and sends that to the other process, which then READs the symbol back
from the string. When doing this, you have to ensure that both
processes have the same binding of *PACKAGE* when doing the printing
and the reading back, and you have to ensure that you use a printing
function that prints stuff in a way that is readable by READ, i.e. not
optimized to be read nicely by a human.
One nice way to ensure all of this is to use WITH-STANDARD-IO-SYNTAX
around your calls to write and read:
So in the one process you might be doing:
(with-standard-io-syntax (write cmd packet-stream))
and in the other you might be doing
(with-standard-io-syntax (read-from-string packet-stream))
or the equivalent on strings.
Another thing you might want to do though, in order to remove the most
obvious security whole from this process, is to bind *READ-EVAL* to
NIL inside the with-standard-io-syntax forms, i.e.
(with-standard-io-syntax
(let ((*read-eval* nil))
(write cmd packet-stream)))
and
(with-standard-io-syntax
(let ((*read-eval* nil))
(read-from-string packet-stream)))
Regs, Pierre.
--
Pierre R. Mai <····@acm.org> http://www.pmsf.de/pmai/
The most likely way for the world to be destroyed, most experts agree,
is by accident. That's where we come in; we're computer professionals.
We cause accidents. -- Nathaniel Borenstein
Pierre R. Mai wrote:
> Well it probably isn't sending the keyword (which is a symbol object)
> over to the other process, but rather PRINTs the symbol to a string,
<snip>
> function that prints stuff in a way that is readable by READ, i.e. not
> optimized to be read nicely by a human.
I am using FORMAT for writing and READ for reading the stream, my thoughts
being that anything that the reader understood, I could send very simply.
That would include vectors, arrays, and structures.
> One nice way to ensure all of this is to use WITH-STANDARD-IO-SYNTAX
Thanks for your comments. I'll spend tonight curled up with the Hyperspec
learing about WITH-STANDARD-IO-SYNTAX et al. :)
--dennis
········@bellsouth.net writes:
> Pierre R. Mai wrote:
>
> > Well it probably isn't sending the keyword (which is a symbol object)
> > over to the other process, but rather PRINTs the symbol to a string,
> <snip>
> > function that prints stuff in a way that is readable by READ, i.e. not
> > optimized to be read nicely by a human.
>
> I am using FORMAT for writing and READ for reading the stream, my thoughts
> being that anything that the reader understood, I could send very simply.
> That would include vectors, arrays, and structures.
Yes, that's the theory, but the printing functions you should use to
make that theory work are WRITE, or PRIN1/PRINT and maybe PPRINT, but
certainly not PRINC, and most likely not FORMAT: PRINC and FORMAT are
more or less intended to provide nicely formatted output for human
consumption, and not for READ's consumption. Furthermore as I wrote,
you need to make sure to bind the printer's and reader's control
variables to sensible values, something WITH-STANDARD-IO-SYNTAX can
help you with.
> > One nice way to ensure all of this is to use WITH-STANDARD-IO-SYNTAX
>
> Thanks for your comments. I'll spend tonight curled up with the Hyperspec
> learing about WITH-STANDARD-IO-SYNTAX et al. :)
Have fun...
Regs, Pierre.
--
Pierre R. Mai <····@acm.org> http://www.pmsf.de/pmai/
The most likely way for the world to be destroyed, most experts agree,
is by accident. That's where we come in; we're computer professionals.
We cause accidents. -- Nathaniel Borenstein