From: Andreas K. <and...@ac...> - 2006-08-10 21:31:34
|
comm::interp - Remote communication Generated from file './modules/comm/interp.man' by tcllib/doctools with format 'text' comm::interp(n) 0.1 comm "Remote communication" NAME ==== comm::interp - Linking communication channels to interpreters SYNOPSIS ======== package require Tcl 8.4 package require comm ?0.1? ::comm::comm::interp::protocol ?-option val...? cmds ?exeip? ::comm::comm::interp::safeBasic ?-option val...? ::comm::comm::interp::safe ?-option val...? ::comm::comm::interp::link comm ip DESCRIPTION =========== The package *comm::interp* is a supplement to the package *comm* providing facilities to easily link comm channels to Tcl interpreters. By default the scripts received by a comm channel are executed in the main interpreter of the receiving process, making for a very insecure model of execution. Something to be used only in a very secure and/or trusted environment. For everyone else this package was written, allowing the easy compartmentalization of execution, restriction to a safe environment, to specific commands, etc. Together with the ability of *comm* to create multiple channels, non-listening channels, local channels, etc. it is possible to handle a very wide range of security requirements. API === ::comm::comm::interp::protocol ?-option val...? cmds ?exeip? This command creates a new communication channel which understands only the commands listed as the keys of the dictionary cmds. The associated values are the actual commands executed in their lieu, in the interpreter exeip. This interpreter defaults to the main interpreter of the thread this command is executed in. To facilitate the above the command creates an internal interpreter which aliases the commands to the execution interpreter on the one hand, and is linked to the communication channel on the other hand. The command returns the path of the internal interpreter to enable the caller to perform additional intializations. Using an empty cmds mapping for example leaves us with an empty interpreter to be initialized at will. The options and their values coming before the cmds mapping are delegated to the new communication channel. The known options are -port, -local, and -silent, with the same meaning as explained in the documentation for the package *comm*. The option -listen is not recognized, as the new communication channel will always listen for incoming scripts, this cannot be deactivated. ::comm::comm::interp::safeBasic ?-option val...? This command a new communication channel which understands all the commands of a basic safe interpreter. The safe interpreter used for the execution of the received scripts is created by the command and returned as its result, to enable the caller to perform additional initialization at will. The term _basic_ means that the created interpreter is the plain result of invoking interp create -safe. The options and their values are delegated to the new communication channel. See comm::interp::protocol for the in-depth explanation of the recognized options. ::comm::comm::interp::safe ?-option val...? This command a new communication channel which understands all the commands of a safe interpreter crated by the *safe* package of the Tcl core. The safe interpreter used for the execution of the received scripts is created by the command using the command ::safe::interpCreate and returned as its result, to enable the caller to perform additional initialization at will. The options and their values are delegated to the new communication channel. See comm::interp::protocol for the in-depth explanation of the recognized options. ::comm::comm::interp::link comm ip This command takes an existing communication channel/object comm, and an existing interpreter ip and links them together. Afterward all scripts received by the channel are executed within the interpreter ip. This is the core functionality of this package, used by all preceding commands. It allows the most flexibility as both communication channel and executing interpreter can be created and configured at will. Thereas for the preceding commands the communication channel is restricted to a listener, and the interpreters are various forms of safe environments. SEE ALSO ======== comm KEYWORDS ======== communication, ipc, message, remote communication, rpc, socket COPYRIGHT ========= Copyright (c) 2006 Andreas Kupries. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: Hemang L. <hl...@ci...> - 2006-08-11 04:29:48
|
Hi Andreas, What is the main purpose of this library? If I understand correctly, it seems like a wrapper utility to create the (safe) interpreter and a comm channel within it. For example: ::comm::comm::interp::safe ?-option val...? can be coded as: set i [interp create -safe] $i eval { package require comm ::comm::comm new ?-option val...? } And comm::interp::link is probably same as "interp transfer {} <comm_chan> $i". At first, I thought this package provides safe interp restrictions on the commands sent over the comm wire and that the filtered set of remote commands received would still be executed in the main interpreter. However, on further thought, such a functionality (if developed) should not be called interp and your current approach of creating new interp for each channel looks reasonable. For comm::interp::safe and safeBasic commands you may also want to support optional ?exeip? argument. Also, for comm::interp::protocol API, will it internally create <exeip> or are users expected to create it before calling it? BTW, ::comm::comm::interp looks too long. You may want to drop one "comm" and call it ::comm::interp. Hemang. Andreas Kupries wrote: > comm::interp - Remote communication > Generated from file './modules/comm/interp.man' by tcllib/doctools with format > 'text' > comm::interp(n) 0.1 comm "Remote communication" > > NAME > ==== > > comm::interp - Linking communication channels to interpreters > > SYNOPSIS > ======== > > package require Tcl 8.4 > package require comm ?0.1? > > ::comm::comm::interp::protocol ?-option val...? cmds ?exeip? > ::comm::comm::interp::safeBasic ?-option val...? > ::comm::comm::interp::safe ?-option val...? > ::comm::comm::interp::link comm ip > > DESCRIPTION > =========== > > The package *comm::interp* is a supplement to the package *comm* providing > facilities to easily link comm channels to Tcl interpreters. By default the > scripts received by a comm channel are executed in the main interpreter of the > receiving process, making for a very insecure model of execution. Something to > be used only in a very secure and/or trusted environment. For everyone else this > package was written, allowing the easy compartmentalization of execution, > restriction to a safe environment, to specific commands, etc. Together with the > ability of *comm* to create multiple channels, non-listening channels, local > channels, etc. it is possible to handle a very wide range of security > requirements. > > API > === > > ::comm::comm::interp::protocol ?-option val...? cmds ?exeip? > > This command creates a new communication channel which understands only > the commands listed as the keys of the dictionary cmds. The associated > values are the actual commands executed in their lieu, in the > interpreter exeip. This interpreter defaults to the main interpreter of > the thread this command is executed in. > > To facilitate the above the command creates an internal interpreter > which aliases the commands to the execution interpreter on the one hand, > and is linked to the communication channel on the other hand. > > The command returns the path of the internal interpreter to enable the > caller to perform additional intializations. Using an empty cmds mapping > for example leaves us with an empty interpreter to be initialized at > will. > > The options and their values coming before the cmds mapping are > delegated to the new communication channel. The known options are -port, > -local, and -silent, with the same meaning as explained in the > documentation for the package *comm*. The option -listen is not > recognized, as the new communication channel will always listen for > incoming scripts, this cannot be deactivated. > > ::comm::comm::interp::safeBasic ?-option val...? > > This command a new communication channel which understands all the > commands of a basic safe interpreter. The safe interpreter used for the > execution of the received scripts is created by the command and returned > as its result, to enable the caller to perform additional initialization > at will. > > The term _basic_ means that the created interpreter is the plain result > of invoking interp create -safe. > > The options and their values are delegated to the new communication > channel. See comm::interp::protocol for the in-depth explanation of the > recognized options. > > ::comm::comm::interp::safe ?-option val...? > > This command a new communication channel which understands all the > commands of a safe interpreter crated by the *safe* package of the Tcl > core. The safe interpreter used for the execution of the received > scripts is created by the command using the command ::safe::interpCreate > and returned as its result, to enable the caller to perform additional > initialization at will. > > The options and their values are delegated to the new communication > channel. See comm::interp::protocol for the in-depth explanation of the > recognized options. > > ::comm::comm::interp::link comm ip > > This command takes an existing communication channel/object comm, and an > existing interpreter ip and links them together. Afterward all scripts > received by the channel are executed within the interpreter ip. > > This is the core functionality of this package, used by all preceding > commands. It allows the most flexibility as both communication channel > and executing interpreter can be created and configured at will. Thereas > for the preceding commands the communication channel is restricted to a > listener, and the interpreters are various forms of safe environments. > > SEE ALSO > ======== > > comm > > KEYWORDS > ======== > > communication, ipc, message, remote communication, rpc, socket > > COPYRIGHT > ========= > > Copyright (c) 2006 Andreas Kupries. > > -- > Andreas Kupries <and...@Ac...> > Developer @ http://www.ActiveState.com > Tel: +1 778-786-1122 > > > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > _______________________________________________ > Tcllib-devel mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcllib-devel > |
From: Andreas K. <aku...@sh...> - 2006-08-11 05:32:22
|
> Hi Andreas, > > What is the main purpose of this library? Convenience. I want simple commands to create the most common linkages of comm channels to restricted execution environments, instead of having to code the same things over and over for each service I choose to implement. > If I understand correctly, it seems like a wrapper utility to create > the (safe) interpreter and a comm channel within it. Basically yes. > For example: > ::comm::comm::interp::safe ?-option val...? > > can be coded as: > > set i [interp create -safe] > $i eval { > package require comm > ::comm::comm new ?-option val...? > } That works really only for trusted interpreters. It won't work for the 'protocol' linkage at all, because the protocol interpreter has _only_ the aliases, and nothing else, especially not 'comm' itself. It may work for the safe interpreter, with contortions. My implementation creates the comm channel in the current interpreter anmd then uses the 'comm event eval' hook to redirect execution into the restricted environment. That fully separates execution from communication and prevents the execution environment from being aware of how communication is done; it also has no way to tamper with the communication system, all influences will have to be approved through aliased commands. > And comm::interp::link is probably same as "interp transfer {} > <comm_chan> $i". A communication channel as managed by 'comm' is an object, not a transferable socket. Although it internally uses sockets. That is why the argument is named 'comm', not 'chan'. So no, no transfer. See also the explanation above. > At first, I thought this package provides safe interp restrictions on > the commands sent over the comm wire and that the filtered set of remote > commands received would still be executed in the main interpreter. It can be. If the 'exeip' for protocol is {}, aka current interpreter, and for the safe variants if the safe interp gets appropriate aliases. > However, on further thought, such a functionality (if developed) should > not be called interp i.e. instead of comm::interp you would like a different name comm::NAME better, with NAME ? > and your current approach of creating new interp > for each channel looks reasonable. > > For comm::interp::safe and safeBasic commands you may also want to > support optional ?exeip? argument. No. For 'protocol' I need it to immediately link the commands in the filtre interpreter to something sensible. In the 'safe*' links it is the callers responsibility to set aliases to somewhere else, if any. The 'protocol' stuff is intended for services with a fixed set of commands, and nothing else. Whereas 'safe*' stuff is more for implementing something like a remote console, or agent system, where some client sends some mobile code, i.e. agent, for execution and we want to contain it and its effects. > Also, for comm::interp::protocol API, > will it internally create <exeip> or are users expected to create it > before calling it? The command expects to get an existing interpreter. That can be {}, i.e. current, already existing, default. Or one newly created by the caller of 'protocol'. > BTW, ::comm::comm::interp looks too long. You may want to drop one > "comm" and call it ::comm::interp. "comm::comm::interp" is a typo. It should have been "comm::interp". > Hemang. > -- So long, Andreas Kupries <aku...@sh...> <http://www.purl.org/NET/akupries/> Developer @ <http://www.activestate.com/> ------------------------------------------------------------------------------- |
From: Hemang L. <hl...@ci...> - 2006-08-11 12:27:48
|
Hi Andreas, Thanks for the clarifications. Your original proposal looks good to me. You should try to document its internal working somewhere. Few minor comments: The name "exeip" looks confusing because of the "ip" string in it. How about calling it "exe_interp" instead. Also, is this a separate package or part of current comm package -- do I have to call "package require comm::interp" to use it my script or does it get automatically loaded when I do "package require comm". I would prefer the latter. Hemang. Andreas Kupries wrote: >> Hi Andreas, >> >> What is the main purpose of this library? >> > > Convenience. I want simple commands to create the most common linkages > of comm channels to restricted execution environments, instead of > having to code the same things over and over for each service I choose > to implement. > > >> If I understand correctly, it seems like a wrapper utility to create >> the (safe) interpreter and a comm channel within it. >> > > Basically yes. > > >> For example: >> > > >> ::comm::comm::interp::safe ?-option val...? >> >> can be coded as: >> >> set i [interp create -safe] >> $i eval { >> package require comm >> ::comm::comm new ?-option val...? >> } >> > > That works really only for trusted interpreters. It won't work for the > 'protocol' linkage at all, because the protocol interpreter has _only_ > the aliases, and nothing else, especially not 'comm' itself. It may > work for the safe interpreter, with contortions. > > My implementation creates the comm channel in the current interpreter > anmd then uses the 'comm event eval' hook to redirect execution into > the restricted environment. That fully separates execution from > communication and prevents the execution environment from being aware > of how communication is done; it also has no way to tamper with the > communication system, all influences will have to be approved through > aliased commands. > > >> And comm::interp::link is probably same as "interp transfer {} >> <comm_chan> $i". >> > > A communication channel as managed by 'comm' is an object, not a > transferable socket. Although it internally uses sockets. That is why > the argument is named 'comm', not 'chan'. > > So no, no transfer. See also the explanation above. > > >> At first, I thought this package provides safe interp restrictions on >> the commands sent over the comm wire and that the filtered set of remote >> commands received would still be executed in the main interpreter. >> > > It can be. If the 'exeip' for protocol is {}, aka current interpreter, > and for the safe variants if the safe interp gets appropriate aliases. > > > >> However, on further thought, such a functionality (if developed) should >> not be called interp >> > > i.e. instead of comm::interp you would like a different name > comm::NAME better, with NAME ? > > >> and your current approach of creating new interp >> for each channel looks reasonable. >> >> For comm::interp::safe and safeBasic commands you may also want to >> support optional ?exeip? argument. >> > > No. For 'protocol' I need it to immediately link the commands in the > filtre interpreter to something sensible. In the 'safe*' links it is > the callers responsibility to set aliases to somewhere else, if any. > > The 'protocol' stuff is intended for services with a fixed set of > commands, and nothing else. Whereas 'safe*' stuff is more for > implementing something like a remote console, or agent system, where > some client sends some mobile code, i.e. agent, for execution and we > want to contain it and its effects. > > > >> Also, for comm::interp::protocol API, >> will it internally create <exeip> or are users expected to create it >> before calling it? >> > > The command expects to get an existing interpreter. That can be {}, > i.e. current, already existing, default. Or one newly created by the > caller of 'protocol'. > > > >> BTW, ::comm::comm::interp looks too long. You may want to drop one >> "comm" and call it ::comm::interp. >> > > "comm::comm::interp" is a typo. It should have been "comm::interp". > > >> Hemang. >> >> > > |
From: Andreas K. <and...@ac...> - 2006-08-11 16:41:38
|
> Hi Andreas, > > Thanks for the clarifications. Your original proposal looks good to me. > You should try to document its internal working somewhere. Not sure about that. > Few minor comments: The name "exeip" looks confusing because of the "ip" > string in it. How about calling it "exe_interp" instead. Done. > Also, is this > a separate package or part of current comm package -- Yes. > do I have to call > "package require comm::interp" to use it my script Yes. > or does it get > automatically loaded when I do "package require comm". No. > I would prefer > the latter. I prefer the former actually, keep comm itself focused on the communication aspects, and use the proposed package for the linkage to useful execution environments. Back to the issue of naming, you disliked 'comm::interp'. Based on what the package does, or provides possible names could be comm::link (does linkage of comm to interps) and comm::safe (provides safe execution environments). Below is an updated manpage in text format. Changes: Fixed the comm::comm typo exeip -> exe_interp ip -> interp Factored description of options into separate section Updated the information about command results. Impl. actually returns [list $comm $interp], not $interp alone. Found that I need both so that I can delete them when I am done with them. [**] [**] I wonder if we should try to extend comm channels with client data instead. Would allow us to stash the created interps with the channel, could be configured to be deleted on channel destruction with some callback. Then we would have only one result for the commands above. ________________________________________________________________________________ ____ comm::interp(n) 0.1 comm "Remote communication" NAME ==== comm::interp - Linking communication channels to interpreters SYNOPSIS ======== package require Tcl 8.4 package require comm ?4.3? package require comm::interp ?0.1? ::comm::interp::protocol ?-option val...? cmds ?exe_interp? ::comm::interp::safeBasic ?-option val...? ::comm::interp::safe ?-option val...? ::comm::interp::link comm interp DESCRIPTION =========== The package *comm::interp* is a supplement to the package *comm* providing facilities to easily link comm channels to (restricted) Tcl interpreters. By default the scripts received by a comm channel are executed in the main interpreter of the receiving process, making for a very insecure model of execution. Something to be used only in a very secure and/or trusted environment. For everyone else this package was written, allowing the easy compartmentalization of execution, restriction to a safe environment, to specific commands, etc. Together with the ability of *comm* to create multiple channels, non-listening channels, local channels, etc. it is possible to handle a very wide range of security requirements. Note and remember that the communication channels provided by the package *comm* are objects, i.e. commands, and not Tcl channels. whenever we talk about channels we talk about objects, except where explicitly noted otherwise. API === ::comm::interp::protocol ?-option val...? cmds ?exe_interp? This command creates a new communication channel which understands exactly the commands listed as the keys of the dictionary cmds. The associated values are the actual commands executed in their lieu, in the existing interpreter exe_interp. This interpreter defaults to the current interpreter invoking the command. For any other interpreter it is the callers responsibility to create it. The command returns a 2-element list containing, in the given order, the fully qualified name of the communication channel, and the path of an internal interpreter used to connect comm channel and execution interpreter. This enables the caller to perform additional intializations of the internal interpreter, but is primarily done to allow proper deletion of both comm channel and interpreter when we are done. Regarding initializations, using an empty mapping for cmds for example will leave us with an empty interpreter to be initialized at will. The internal interpreter is set up such that it is empty of any and all commands, save for a set of aliases for the commands in the mapping cmds. As the script execution of the comm channel is directed into this interpreter this enforces the restriction of the protocol to the set of defined commands. For the options understood by this command see the section -> OPTIONS. ::comm::interp::safeBasic ?-option val...? This command creates a new communication channel which understands all the commands of a basic safe interpreter. The safe interpreter used for the execution of the received scripts is created by the command. The term _basic_ means that the created interpreter is the plain result of invoking interp create -safe. The command returns a 2-element list containing, in the given order, the fully qualified name of the communication channel, and the path of the created safe interpreter. This enables the caller to perform additional intializations of the safe interpreter, but is primarily done to allow proper deletion of both comm channel and interpreter when we are done. For the options understood by this command see the section -> OPTIONS. ::comm::interp::safe ?-option val...? This command a new communication channel which understands all the commands of a safe interpreter crated by the *safe* package of the Tcl core. The safe interpreter used for the execution of the received scripts is created by the command using the builtin command ::safe::interpCreate. The command returns a 2-element list containing, in the given order, the fully qualified name of the communication channel, and the path of the created safe interpreter. This enables the caller to perform additional intializations of the safe interpreter, but is primarily done to allow proper deletion of both comm channel and interpreter when we are done. For the options understood by this command see the section -> OPTIONS. ::comm::interp::link comm interp This command takes an existing communication channel comm as created by the package *comm*, and an existing interpreter interp and links them together. Afterward all scripts received by the channel are executed within the context of interp. This is the core functionality of this package, used by all preceding commands. It allows the most flexibility as both communication channel and the interpreter executing the received scripts can be created and configured at will. Thereas for the preceding commands the communication channel is created and restricted to be a listener, and the interpreters are various forms of safe environments, from the highly restricted protocol to the more open basic and extended safe interpreters. OPTIONS ======= All commands provided by this package taking any options understand the same set of options. They are -port, -local, and -silent, with the same meaning as explained in the documentation for the package *comm*. The option -listen is not recognized, as the new communication channels created by the commands (with the exception of ::comm::interp::link) are configured to always listen for incoming scripts, this cannot be deactivated. The options are always delegated to and processed by the new communication channel. SEE ALSO ======== comm KEYWORDS ======== communication, ipc, message, remote communication, rpc, socket COPYRIGHT ========= Copyright (c) 2006 Andreas Kupries. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: <dg...@ni...> - 2006-08-11 16:55:43
|
Quoting Andreas Kupries <and...@ac...>: > I prefer the former actually, keep comm itself focused on the communication > aspects, and use the proposed package for the linkage to useful execution > environments. I'm not a comm user, and I haven't carefully read all of these messages, but at arms length it sure looks like you're inventing a set of commands that would be good additions to the comm package itself, rather than another separate package. I think that means I'm agreeing with Hemang. That said, if more direct experience indicates this really should be a separate package from "comm", then give it a name separate from "comm" as well. This nested namespace stuff is anti-modular. Just IMHO. DGP |
From: Michael S. <sc...@un...> - 2006-08-11 17:04:48
|
dg...@ni... schrieb: > Quoting Andreas Kupries <and...@ac...>: >> I prefer the former actually, keep comm itself focused on the communication >> aspects, and use the proposed package for the linkage to useful execution >> environments. > > I'm not a comm user, and I haven't carefully read all > of these messages, but at arms length it sure looks like > you're inventing a set of commands that would be good > additions to the comm package itself, rather than another > separate package. I think that means I'm agreeing with > Hemang. I agree with Don and Hemang. Comm isn't really that much about communications, its mainly about remote code execution with a bit of communication thrown in, after all its a socket based replacement for send... You do not send plain messages, you send code. Michael |
From: Hemang L. <hl...@ci...> - 2006-08-11 17:43:05
|
Andreas Kupries wrote: > Back to the issue of naming, you disliked 'comm::interp'. > Ignore this part -- I was not sure about it did hence I had thought that the name was not appropriate. However, "comm::interp" looks fine to me now. > Factored description of options into separate section > Updated the information about command results. > Impl. actually returns [list $comm $interp], > not $interp alone. Found that I need both > so that I can delete them when I am done with > them. [**] > > > > [**] I wonder if we should try to extend comm channels with client data instead. > Would allow us to stash the created interps with the channel, could be > configured to be deleted on channel destruction with some callback. Then we > would have only one result for the commands above. > Few related questions: what happens if the user happens to delete the interp? Will it destroy the comm channel or the comm channel will exist but it will throw an error on the remote side. Similarly what happens if the comm channel is destroyed? Will it delete the interp or is it the user's responsibility to do cleanup? I think that protocol, safe and safeBasic should do both: create as well as delete the interp and comm channel (even when exe_interp is provided for protocol). Only the comm::interp::link API should be allowed to work with previously created interpreters. This will keep the design clean and simple. As for protocol API, is it possible to specify additional arguments for aliased commands? For example: interp alias <src> foo <dst> bar <comm_id> arg2 .. can this be specified as: comm::interp::protocol "foo {bar <comm_id> arg2 ..} foo2 bar2" What about callback hooks for comm channel? Are they executed in child interpreter or the main one. I guess since the comm object is linked to the child interpreter, everything will be evaluated in there. Hemang. |
From: Andreas K. <and...@ac...> - 2006-08-11 18:37:30
|
> Andreas Kupries wrote: > > > Back to the issue of naming, you disliked 'comm::interp'. > > > Ignore this part -- I was not sure about it did hence I had thought that > the name was not appropriate. However, "comm::interp" looks fine to me now. > > > Factored description of options into separate section > > Updated the information about command results. > > Impl. actually returns [list $comm $interp], > > not $interp alone. Found that I need both > > so that I can delete them when I am done with > > them. [**] > > > > > > > > [**] I wonder if we should try to extend comm channels with client > data instead. > > Would allow us to stash the created interps with the channel, could be > > configured to be deleted on channel destruction with some callback. Then we > > would have only one result for the commands above. > > > Few related questions: what happens if the user happens to delete the > interp? Will it destroy the comm channel or the comm channel will exist > but it will throw an error on the remote side. > Similarly what happens if the comm channel is destroyed? Will it delete > the interp or is it the user's responsibility to do cleanup? I think > that protocol, safe and safeBasic should do both: create as well as > delete the interp and comm channel (even when exe_interp is provided for > protocol). Only the comm::interp::link API should be allowed to work > with previously created interpreters. This will keep the design clean > and simple. Deletion and cleanup are an area where you can shoot yourself into the foot right now. Comm channel and interp are not linked to each other, none knows when the other is deleted. (1) Delete the comm channel. The interpreter stays around. It does nothing as nobody is sending scripts to it anymore. A leak. (2) Delete the interp. The comm channel stays around. Any incoming script will be directed to the missing interp, causing an error to be thrown. Without extending comm channels to know the interp I will have to wrap a snit class around the comm/interp combination for proper cleanup. However the multiple sugesstions to put this into 'comm' itself imply another route, that the comm channel does know the interp and deletes it with itself ... Looking over the comm manpage I find the work item Allow easier use of a slave interp for actual command execution (especially when operating in "not local" mode). My work here could serve as that, with tighter integration and knowledge between the various parts. Create a comm channel and link it directly to an execution environment. Possibly auto-created. Any internally/auto created interp are deleted with the channel. Some restricted visibility outside to allow for command definition and aliases ... > As for protocol API, is it possible to specify additional arguments for > aliased commands? Yes. > For example: > > interp alias <src> foo <dst> bar <comm_id> arg2 .. > > can this be specified as: > > comm::interp::protocol "foo {bar <comm_id> arg2 ..} foo2 bar2" The cmd mapping argument to protocol is a dictionary. It maps command names to _command_prefixes_. Which is what you want here. Examples. The trivial use case is protocol { Lookup lookup_name Register register_name Unregister unregister_name ... } Commands are mapped to commands. The advanced use case is protocol [list \ Lookup [list $theobject lookup otherarg] \ Register [list $theobject register otherarg] \ Unregister [list $theobject unregister otherarg] \ ] Commands are mapped to command prefixes containing additional arguments. > > What about callback hooks for comm channel? Are they executed in child > interpreter or the main one. I guess since the comm object is linked to > the child interpreter, everything will be evaluated in there. No. The only hook which goes to the execution environment is the 'eval' hook. I do not want the execution environment to do anything else than executing the incoming scripts. Authentication, lost connection, and all the other _management_ tasks are not things which I want the slave interpreter to see, or even influence in any way, shape, or form. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: Hemang L. <hl...@ci...> - 2006-08-11 19:36:58
|
Andreas Kupries wrote: > My work here could serve as that, with tighter integration and knowledge between > the various parts. > Create a comm channel and link it directly to an execution environment. Possibly > auto-created. Any > internally/auto created interp are deleted with the channel. Some restricted > visibility outside to allow for command definition and aliases ... > Yes: that sounds right. >> What about callback hooks for comm channel? Are they executed in child >> interpreter or the main one. I guess since the comm object is linked to >> the child interpreter, everything will be evaluated in there. >> > > No. The only hook which goes to the execution environment is the 'eval' hook. > I do not want the execution environment to do anything else than executing the > incoming scripts. Authentication, lost connection, and all the other > _management_ > tasks are not things which I want the slave interpreter to see, or even > influence > in any way, shape, or form. > I am not sure that these are restricted to management tasks. For example: I use 'eval' hook for debugging and lost connection hook to perform clean up. If these are not executed in exe_interp context then I would not have access to global variables, etc for debugging, right? The internal management tasks related to comm/interp functionality can be outside the execution environment but the user-registered hooks should be executed in the exe_interp context. Hemang. |
From: Andreas K. <and...@ac...> - 2006-08-11 20:36:26
|
> >> What about callback hooks for comm channel? Are they executed in child > >> interpreter or the main one. I guess since the comm object is linked to > >> the child interpreter, everything will be evaluated in there. > >> > > > > No. The only hook which goes to the execution environment is the > 'eval' hook. > > I do not want the execution environment to do anything else than > executing the > > incoming scripts. Authentication, lost connection, and all the other > > _management_ > > tasks are not things which I want the slave interpreter to see, or even > > influence > > in any way, shape, or form. > > > I am not sure that these are restricted to management tasks. For > example: I use 'eval' hook for debugging Debugging ... How ? > and lost connection hook to > perform clean up. So you have a backend which keeps state based on where a request originated from ? > If these are not executed in exe_interp context then I > would not have access to global variables, etc for debugging, right? It depends on what you are debugging, and how. Can you provide a trimmed example ? Also note that the visions for 'protocol' vs 'safe' are very different. This can affect our choices. > The internal management tasks related to comm/interp functionality can be > outside the execution environment but the user-registered hooks should > be executed in the exe_interp context. I am still not convinced. Maybe we have simply too different visions for what we want to do with this. When I wrote these commands I wanted to have convenient setup functionality specifically for and only for the eval hook. The other hooks simply did not enter the picture, they were out of scope. To put them into scope I need a very clear picture/vision on how they are used in such a situation. For now I will go back to the drawing board and see how the functionality can be integrated into the regular 'comm' package, i.e. what changes to syntax and setup are needed, what internals I have access to with that, etc. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: Hemang L. <hl...@ci...> - 2006-08-12 03:54:10
|
Andreas Kupries wrote: > > I am still not convinced. Maybe we have simply too different visions for what we > want to do with this. > > When I wrote these commands I wanted to have convenient setup functionality > specifically for and only for the eval hook. The other hooks simply did not > enter the picture, they were out of scope. To put them into scope I need a very > clear picture/vision on how they are used in such a situation. I have one server process and several client processes which are connected via comm channels. The server process is the master which hands off commands to execute on the client processes and keeps track of their execution progress in a global array. Each client is identified by a unique name and periodically sends signals to the server process to indicate its status. Sometimes a client process may get terminated either gracefully or abnormally say via kill command invoked by the user. The master process will know about it via "lost connection" hook and will perform cleanup. For debugging purposes, I use tcllib's logger package in the eval hook -- ${log}::debug API to print the name of the client, the status of global array for the corresponding client and the commands it has received over the comm channel. See below: # Setup event handler to do a cleanup whenever any socket # connection to the client process is lost. ::comm::comm hook lost "::foo::_cleanup \$id [list $client_id]" # Log all commands before evaluating them ::comm::comm hook eval {::foo::log::debug "Cmd eval: $buffer id: $client_id\n\[parray data($client_id)]"} # Log all command replies before evaluating them ::comm::comm hook reply {::foo::log::debug "Cmd reply: $buffer id: $client_id\n\[parray data($client_id)]"} With your proposal for comm/interp enhancements, I can use it to restrict the commands executed by the clients in the master process. I hope you get the idea. Hemang. |
From: Andreas K. <aku...@sh...> - 2006-08-12 06:31:08
|
> Andreas Kupries wrote: > > > > I am still not convinced. Maybe we have simply too different visions for what we > > want to do with this. > > > > When I wrote these commands I wanted to have convenient setup functionality > > specifically for and only for the eval hook. The other hooks simply did not > > enter the picture, they were out of scope. To put them into scope I need a very > > clear picture/vision on how they are used in such a situation. [explanation and examples snipped -- Thank you for them] I have now redone my proposal under the assumption that it becomes new features of comm itself ... This collapsed and removed most of the stuff in the original proposal. The new proposal basically provides communication channels with an option to set an interpreter for execution. This is the link command of the original proposal. The implementations of safeBasic and safe commands of the original become so trivial in the new scheme that providing special commands for them is not worthwhile. I.e. comm::comm new FOO -interp [interp create -safe] or comm::comm new FOO -interp [safe::interpCreate] The protocol command of the original proposal also reduces to 'create an empty interpreter and set aliases into it'. For the case of linking the aliases to a second interpreter 'interp alias' is still the best way of doing it, reducing this further to 'create an empty interp'. We can do a command for that, this is however quite general and unrelated to comm. Anybody with an idea where to place such command ? (Maybe a package "interp" ?) Still, the use case of linking the execution interpreter to a snit object may warrant a command to make this easier. Create empty interp, link to method in the object, specified through a list of names. Or a snit type ... snit::comm-listener, snit::comm, snit::listener, ... ? Here is the documentation of the new features of comm. Note that there is a second option to control the execution of event/hook scripts, for Hemang _______________________________________________________________________________ --- comm.man.orig 2005-10-03 21:03:19.000000000 -0700 +++ comm.man 2006-08-11 23:16:24.000000000 -0700 @@ -185,6 +185,9 @@ [lst_item "[option -local] [opt [arg 0|1]]"] [lst_item "[option -port] [opt [arg port]]"] [lst_item "[option -silent] [opt [arg 0|1]]"] + +[lst_item "[option -interp] [opt [arg interpreter]]"] +[lst_item "[option -ipevents] [opt [arg eventlist]]"] [list_end] [para] @@ -198,11 +201,12 @@ [para] -When [cmd config] changes the parameters of an existing channel, it -closes and reopens the listening socket. An automatically assigned -channel [emph id] will change when this happens. Recycling the socket -is done by invoking [cmd {::comm::comm abort}], which causes all -active sends to terminate. +When [cmd config] changes the parameters of an existing channel (with +the exception of [option -interp] and [option -ipevents]), it closes +and reopens the listening socket. An automatically assigned channel +[emph id] will change when this happens. Recycling the socket is done +by invoking [cmd {::comm::comm abort}], which causes all active sends +to terminate. [subsection {ID/PORT ASSIGNMENTS}] [para] @@ -238,6 +242,51 @@ attempts where the protocol negotiation phase failed, instead of throwing an error. +[subsection {EXECUTION ENVIRONMENT}] + +A communication channel in its default configuration will use the +current interpreter for the execution of all received scripts, and of +the event scripts associated with the various hooks. + +[para] + +This isecure setup can be changed by the user via the two options +[option -interp], and [option -ipevents]. + +[para] + +When [option -interp] is set all received scripts are executed in the +slave interpreter specified as the value of the option. This +interpreter is expected to exist before configuration. I.e. it is the +responsibility of the user to create it. However afterward the +communication channel takes ownership of this interpreter, and will +destroy it when the communication channel is destroyed. + +Note that reconfiguration of the communication channel to either a +different interpreter or the empty string will release the ownership +[emph without] destroying the previously configured interpreter. The +empty string has a special meaning, it restores the default behaviour +of executing received scripts in the current interpreter. + +[para] + +[emph {Also of note}] is that replies and callbacks (a special form of +reply) are [emph not] considered as received scripts. They are +trusted, part of the internal machinery of comm, and therefore always +executed in the current interpreter. + +[para] + +Even if an interpreter has been configured as the execution +environment for received scripts the event scripts associated with the +various hooks will by default still be executed in the current +interpreter. To change this use the option [option -ipevents] to +declare a list of the events whose scripts should be executed in the +declared interpreter as well. The contents of this option are ignored +if the communication channel is configured to execute received scripts +in the current interpreter. + + [subsection {REMOTE INTERPRETERS}] [para] _______________________________________________________________________________ -- So long, Andreas Kupries <aku...@sh...> <http://www.purl.org/NET/akupries/> Developer @ <http://www.activestate.com/> ------------------------------------------------------------------------------- |
From: Hemang L. <hl...@ci...> - 2006-08-12 20:22:13
|
Andreas Kupries wrote: > The new proposal basically provides communication channels with an > option to set an interpreter for execution. This is the link command > of the original proposal. The implementations of safeBasic and safe > commands of the original become so trivial in the new scheme that > providing special commands for them is not worthwhile. I.e. > > comm::comm new FOO -interp [interp create -safe] > or comm::comm new FOO -interp [safe::interpCreate] > Looks good. Just rename -ipevents option to -interp_events or -ievents. > The protocol command of the original proposal also reduces to 'create > an empty interpreter and set aliases into it'. For the case of linking > the aliases to a second interpreter 'interp alias' is still the best > way of doing it, reducing this further to 'create an empty interp'. We > can do a command for that, this is however quite general and unrelated > to comm. Anybody with an idea where to place such command ? (Maybe a > package "interp" ?) > Can you provide an example of how you intend to use this. As such, it could be just a sub-command "comm::comm link ..." but I can't say much without understanding how it is going to be used. > + > +This isecure setup can be changed by the user via the two options > Typo: isecure -> insecure. Hemang. |
From: Andreas K. <aku...@sh...> - 2006-08-14 06:46:06
|
> Andreas Kupries wrote: > > The new proposal basically provides communication channels with an > > option to set an interpreter for execution. This is the link command > > of the original proposal. The implementations of safeBasic and safe > > commands of the original become so trivial in the new scheme that > > providing special commands for them is not worthwhile. I.e. > > > > comm::comm new FOO -interp [interp create -safe] > > or comm::comm new FOO -interp [safe::interpCreate] > > > Looks good. Just rename -ipevents option to -interp_events or > -ievents. What is the problem with 'ip' ? > > The protocol command of the original proposal also reduces to 'create > > an empty interpreter and set aliases into it'. For the case of linking > > the aliases to a second interpreter 'interp alias' is still the best > > way of doing it, reducing this further to 'create an empty interp'. We > > can do a command for that, this is however quite general and unrelated > > to comm. Anybody with an idea where to place such command ? (Maybe a > > package "interp" ?) > > > Can you provide an example of how you intend to use this. As such, it > could be just a sub-command "comm::comm link ..." but I can't say much > without understanding how it is going to be used. The case of 'create an empty interpreter and set aliases into it', subcase 'the are aliases into the main interp, and a snit object' snit::type FOO { component comm constructor {...} { set comm [comm::comm new ${selfns}::comm \ -interp [XXXX $self {list of methods}]] return } } where XXXX is the command creating a an interpreter, clearing it of all commands, procedures, and namespaces, and then creating aliases for all methods in the list which redirect the commands to the newly created FOO instance. The other case, 'create an empty interp' is for the general case, where the aliases go into some other interpreter, and not an object. set empty [XXXX] set execution [interp create ...] interp alias $empty .... $execution ... ... comm::comm new FOO -interp $empty Here XXXX is the command to create an interpreter and clear it of all commands, procedures, and namespaces. > > + > > +This isecure setup can be changed by the user via the two options > > > Typo: isecure -> insecure. Fixed in my local copy. -- So long, Andreas Kupries <aku...@sh...> <http://www.purl.org/NET/akupries/> Developer @ <http://www.activestate.com/> ------------------------------------------------------------------------------- |
From: Jeff H. <je...@ac...> - 2006-08-14 16:24:07
|
Andreas Kupries wrote: > > Andreas Kupries wrote: > > > The new proposal basically provides communication channels with an > > > option to set an interpreter for execution. This is the link command > > > of the original proposal. The implementations of safeBasic and safe > > > commands of the original become so trivial in the new scheme that > > > providing special commands for them is not worthwhile. I.e. > > > > > > comm::comm new FOO -interp [interp create -safe] > > > or comm::comm new FOO -interp [safe::interpCreate] > > > > > Looks good. Just rename -ipevents option to -interp_events or > > -ievents. > > What is the problem with 'ip' ? 'ip' has different achronym connotations. Just using -events would work as well, since it is contextual. Jeff |
From: Andreas K. <and...@ac...> - 2006-08-14 16:27:47
|
> > > > comm::comm new FOO -interp [interp create -safe] > > > > or comm::comm new FOO -interp [safe::interpCreate] > > > > > > > Looks good. Just rename -ipevents option to -interp_events or > > > -ievents. > > > > What is the problem with 'ip' ? > > 'ip' has different achronym connotations. Just using -events would work as > well, since it is contextual. Of the three -interp_events, -ievents, and -events I like the last one best. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: Hemang L. <hl...@ci...> - 2006-08-14 19:57:59
|
Andreas Kupries wrote: > > What is the problem with 'ip' ? > Maybe it's just me: when I see ip I think of internet protocol, intellectual property, etc but never "interp". Just -events is fine with me. > >>> The protocol command of the original proposal also reduces to 'create >>> an empty interpreter and set aliases into it'. For the case of linking >>> the aliases to a second interpreter 'interp alias' is still the best >>> way of doing it, reducing this further to 'create an empty interp'. We >>> can do a command for that, this is however quite general and unrelated >>> to comm. Anybody with an idea where to place such command ? (Maybe a >>> package "interp" ?) >>> >>> >> Can you provide an example of how you intend to use this. As such, it >> could be just a sub-command "comm::comm link ..." but I can't say much >> without understanding how it is going to be used. >> [thanks for the examples] Ok, now I understand and agree that it is completely unrelated to comm package. One possibility is to extend the [interp create] itself to support a -empty option. It already supports -safe option and a -empty option would restrict it even further by creating an empty interpreter. Hemang. |
From: Andreas K. <and...@ac...> - 2006-08-14 20:09:33
|
> Andreas Kupries wrote: > > > > What is the problem with 'ip' ? > > > Maybe it's just me: when I see ip I think of internet protocol, > intellectual property, etc but never "interp". I see. I could see the second, forgot the first. > Just -events is fine with me. Ok. That it will be. > >>> The protocol command of the original proposal also reduces to 'create > >>> an empty interpreter and set aliases into it'. For the case of linking > >>> the aliases to a second interpreter 'interp alias' is still the best > >>> way of doing it, reducing this further to 'create an empty interp'. We > >>> can do a command for that, this is however quite general and unrelated > >>> to comm. Anybody with an idea where to place such command ? (Maybe a > >>> package "interp" ?) > >>> > >>> > >> Can you provide an example of how you intend to use this. As such, it > >> could be just a sub-command "comm::comm link ..." but I can't say much > >> without understanding how it is going to be used. > >> > [thanks for the examples] > > Ok, now I understand and agree that it is completely unrelated to comm > package. One possibility is to extend the [interp create] itself to > support a -empty option. It already supports -safe option and a -empty > option would restrict it even further by creating an empty interpreter. True. However right now I wish to keep this in pure Tcl. Moving stuff like that into the core can come later. ... I guess it will be an "interp" package in Tcllib. Maybe with overloading the core command, in anticipiation of the move you proposed. Yes. -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |
From: Andreas K. <aku...@sh...> - 2006-08-17 04:32:57
|
> > Andreas Kupries wrote: > > > > > > What is the problem with 'ip' ? > > > > > Maybe it's just me: when I see ip I think of internet protocol, > > intellectual property, etc but never "interp". > > I see. I could see the second, forgot the first. > > > Just -events is fine with me. > > Ok. That it will be. The new options -interp and -events have been implemented, and the testsuite extended as well. Package version is now 4.3.1. -- So long, Andreas Kupries <aku...@sh...> <http://www.purl.org/NET/akupries/> Developer @ <http://www.activestate.com/> ------------------------------------------------------------------------------- |
From: Andreas K. <and...@ac...> - 2006-08-17 20:54:30
|
One of the services I wanted to put into Tcllib, based on the 'safe' comm foundation is the primitive nameserver I did years ago, see http://www.oche.de/~akupries/soft/pool/f_net_ns_server.tcl.html Except when I started the docs/spec for the new implementation I found myself quickly on the road to complexity, because of a number of questions I came up with in need answers ... For now the doc/spec is quite incomplete and actually more a set of notes I started to make to organize my thoughts and get something coherent out of of whatever notions are tumbling through my subconscious. Below is the relevant section of the spec to be. Question is, how far should I go in complexity. What is the most simple yet general use case ? In the worst case I could even do a series of services with different complexities and data models ... Gods, now I have started thinking about pluggability, one API, different databases underneath ... Stop! ... ______________________________________________________________ The simplest database, relationally speaking, would be a table table { name : string id : list (host port) } This leaves the structure and semantics of 'name' to the clients of the service. Not the client objects, but the users of these objects. Is this the application name ? Example: Tkcon The name of a service provided ? Example: log Do we allow multiple ids per name ? I.e. do we want 'name' to be a unique key or not ? What about situation where we have multiple instances of a service or application, but 'name' has to be unique. Registration then either disallows the multiple instances, or the name gets internal structure to distinguish between instances. When we have structure it starts to make sense to make it explicit, i.e. instead of storing a string representation we break it apart and store components explicitly. And now we have begun sliding down the slippery slope of complexity. Actually, before writing the last sentence, a different thought bubbled up out of my subconscious, that I am apparently re-inventing LDAP, where the stored records have complex structure with many keyes, attributes, possibly nesting, and can be searched for by any component. That made me realize that my questions had put me really well on the road to higher complexity. Still. What would we use in the Tcl world as records ? My guess would be nested dictionaries. ______________________________________________________________ -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 > -----Original Message----- > From: tcl...@li... > [mailto:tcl...@li...]On Behalf Of Andreas > Kupries > Sent: Wednesday, August 16, 2006 9:28 PM > To: Hemang Lavana; Tcllib Devel > Subject: Re: [Tcllib-devel] A proposed new package ... Asking for > comments. > > > > > > Andreas Kupries wrote: > > > > > > > > What is the problem with 'ip' ? > > > > > > > Maybe it's just me: when I see ip I think of internet protocol, > > > intellectual property, etc but never "interp". > > > > I see. I could see the second, forgot the first. > > > > > Just -events is fine with me. > > > > Ok. That it will be. > > The new options -interp and -events have been implemented, and the > testsuite extended as well. Package version is now 4.3.1. > > -- > So long, > Andreas Kupries <aku...@sh...> > <http://www.purl.org/NET/akupries/> > Developer @ <http://www.activestate.com/> > ---------------------------------------------------------------------- > --------- > > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > _______________________________________________ > Tcllib-devel mailing list > Tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcllib-devel |
From: Michael S. <sc...@un...> - 2006-08-18 11:45:39
|
Andreas Kupries schrieb: > One of the services I wanted to put into Tcllib, based on the 'safe' comm > foundation > is the primitive nameserver I did years ago, see > > http://www.oche.de/~akupries/soft/pool/f_net_ns_server.tcl.html > > Except when I started the docs/spec for the new implementation I found myself > quickly on the road to complexity, because of a number of questions I came up > with in need answers ... For now the doc/spec is quite incomplete and actually > more a set of notes I started to make to organize my thoughts and get something > coherent out of of whatever notions are tumbling through my subconscious. Keep it basically simple. What would be the main usecase? comm services which need to detect each other? > > Actually, before writing the last sentence, a different > thought bubbled up out of my subconscious, that I am > apparently re-inventing LDAP, where the stored records have > complex structure with many keyes, attributes, possibly > nesting, and can be searched for by any component. That made > me realize that my questions had put me really well on the > road to higher complexity. Your basically not only solving similar problems to LDAP/X.500, you also dabble in the field of UDDI (http://en.wikipedia.org/wiki/Universal_Description_Discovery_and_Integration) or even the naming conventions/name discovery used by things like DBUS or Apples Bonjour/Rendevouzs. > Still. What would we use in the Tcl world as records ? My > guess would be nested dictionaries. Yes to nested dictionaries for storing the records. Michael |
From: Andreas K. <and...@ac...> - 2006-08-18 16:56:45
|
> Andreas Kupries schrieb: > > One of the services I wanted to put into Tcllib, based on the 'safe' comm > > foundation > > is the primitive nameserver I did years ago, see > > > > http://www.oche.de/~akupries/soft/pool/f_net_ns_server.tcl.html > > > > Except when I started the docs/spec for the new implementation I > found myself > > quickly on the road to complexity, because of a number of questions > I came up > > with in need answers ... For now the doc/spec is quite incomplete > and actually > > more a set of notes I started to make to organize my thoughts and > get something > > coherent out of of whatever notions are tumbling through my subconscious. > > Keep it basically simple. What would be the main usecase? comm services > which need to detect each other? That is what I use the old service for at home (popeyemon to discover popeye [1]). [1] popeye is my pop client (See Pool package) popeyemon is a small monitor application (also in Pool) for it. It uses the log output of popeye to drive its UI ... That log system is the ancestor of 'log' in Tcllib. > > Actually, before writing the last sentence, a different > > thought bubbled up out of my subconscious, that I am > > apparently re-inventing LDAP, where the stored records have > > complex structure with many keyes, attributes, possibly > > nesting, and can be searched for by any component. That made > > me realize that my questions had put me really well on the > > road to higher complexity. > > Your basically not only solving similar problems to LDAP/X.500, you also > dabble in the field of UDDI > (http://en.wikipedia.org/wiki/Universal_Description_Discovery_and_Integration) Huh. > or even the naming conventions/name discovery used by things like DBUS > or Apples Bonjour/Rendevouzs. I should note that I use TCP here. Bonjour/Rendevouzs is UDP, so for a Tcl binding to that you need either tclUDP, or ceptcl. Any takers ? Sidenote: The TCP port the server will use will be '[phonecode <packagename-without-colons>] % 65536'. The modulo is needed as port numbers are apparently 'short'. > > Still. What would we use in the Tcl world as records ? My > > guess would be nested dictionaries. > > Yes to nested dictionaries for storing the records. > > Michael -- Andreas Kupries <and...@Ac...> Developer @ http://www.ActiveState.com Tel: +1 778-786-1122 |