direct-io.hg

changeset 1696:466bdc820e84

bitkeeper revision 1.1041.13.1 (40eb0eb2uTenw4RI9fetIsxTLmIHyQ)

Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno-ia64.bk
author iap10@labyrinth.cl.cam.ac.uk
date Tue Jul 06 20:42:26 2004 +0000 (2004-07-06)
parents 55d2aa0544ae 57c047484acc
children b8ad289cb612
files .rootkeys docs/HOWTOs/XenDebugger-HOWTO linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c linux-2.4.26-xen-sparse/arch/xen/kernel/process.c linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c tools/examples/xmdefaults tools/examples/xmnetbsd tools/libxutil/Makefile tools/libxutil/allocate.h tools/libxutil/file_stream.h tools/libxutil/gzip_stream.c tools/libxutil/gzip_stream.h tools/libxutil/kernel_stream.h tools/libxutil/string_stream.c tools/libxutil/string_stream.h tools/libxutil/sys_net.h tools/libxutil/sys_string.h tools/misc/nsplitd/Makefile tools/misc/nsplitd/nsplitd.c tools/python/xen/util/ip.py tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendMigrate.py tools/python/xen/xend/XendRoot.py tools/python/xen/xend/packing.py tools/python/xen/xend/server/SrvBase.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/SrvDomainDir.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/channel.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/cstruct.py tools/python/xen/xend/server/domain.py tools/python/xen/xend/server/messages.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/sxp.py tools/python/xen/xm/create.py tools/python/xen/xm/help.py tools/python/xen/xm/main.py tools/python/xen/xm/opts.py tools/python/xen/xm/shutdown.py tools/xfrd/Make.xfrd tools/xfrd/Makefile tools/xfrd/connection.c tools/xfrd/connection.h tools/xfrd/debug.h tools/xfrd/enum.c tools/xfrd/enum.h tools/xfrd/hash_table.c tools/xfrd/hash_table.h tools/xfrd/lexis.c tools/xfrd/lexis.h tools/xfrd/lzi_stream.c tools/xfrd/lzi_stream.h tools/xfrd/marshal.c tools/xfrd/marshal.h tools/xfrd/select.c tools/xfrd/select.h tools/xfrd/sxpr.c tools/xfrd/sxpr.h tools/xfrd/xdr.c tools/xfrd/xdr.h tools/xfrd/xen_domain.c tools/xfrd/xen_domain.h tools/xfrd/xfrd.c tools/xfrd/xfrd.h tools/xfrd/xfrdClient.py xen/arch/x86/Makefile xen/arch/x86/Rules.mk xen/arch/x86/apic.c xen/arch/x86/boot/x86_32.S xen/arch/x86/boot/x86_64.S xen/arch/x86/domain.c xen/arch/x86/domain_page.c xen/arch/x86/entry.S xen/arch/x86/irq.c xen/arch/x86/mm.c xen/arch/x86/mpparse.c xen/arch/x86/process.c xen/arch/x86/rwlock.c xen/arch/x86/setup.c xen/arch/x86/smpboot.c xen/arch/x86/time.c xen/arch/x86/trampoline.S xen/arch/x86/traps.c xen/arch/x86/usercopy.c xen/arch/x86/x86_32/domain_page.c xen/arch/x86/x86_32/entry.S xen/arch/x86/x86_32/mm.c xen/arch/x86/x86_32/usercopy.c xen/arch/x86/x86_32/xen.lds xen/arch/x86/x86_64/entry.S xen/arch/x86/x86_64/usercopy.c xen/arch/x86/x86_64/xen.lds xen/arch/x86/xen.lds xen/include/asm-x86/config.h xen/include/asm-x86/irq.h
line diff
     1.1 --- a/.rootkeys	Thu Jul 01 23:45:24 2004 +0000
     1.2 +++ b/.rootkeys	Tue Jul 06 20:42:26 2004 +0000
     1.3 @@ -201,6 +201,8 @@ 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/mis
     1.4  3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
     1.5  3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c
     1.6  40c9c469kT0H9COWzA4XzPBjWK0WsA tools/misc/netfix
     1.7 +4022a73cEKvrYe_DVZW2JlAxobg9wg tools/misc/nsplitd/Makefile
     1.8 +4022a73cKms4Oq030x2JBzUB426lAQ tools/misc/nsplitd/nsplitd.c
     1.9  3f870808_8aFBAcZbWiWGdgrGQyIEw tools/misc/p4perf.h
    1.10  3f5ef5a2ir1kVAthS14Dc5QIRCEFWg tools/misc/xen-clone
    1.11  3f5ef5a2dTZP0nnsFoeq2jRf3mWDDg tools/misc/xen-clone.README
    1.12 @@ -239,6 +241,7 @@ 40c9c4686jruMyZIqiaZRMiMoqMJtg tools/pyt
    1.13  40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py
    1.14  40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py
    1.15  40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py
    1.16 +40e9808elkoRulOo1GxRTp5ulJGVNw tools/python/xen/xend/packing.py
    1.17  40c9c468DCpMe542varOolW1Xc68ew tools/python/xen/xend/server/SrvBase.py
    1.18  40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py
    1.19  40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py
    1.20 @@ -257,7 +260,6 @@ 40c9c4692hckPol_EK0EGB16ZyDsyQ tools/pyt
    1.21  40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
    1.22  40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
    1.23  40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
    1.24 -40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py
    1.25  40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
    1.26  40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
    1.27  40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
    1.28 @@ -265,6 +267,7 @@ 40c9c469ZqILEQ8x6yWy0_51jopiCg tools/pyt
    1.29  40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
    1.30  40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
    1.31  40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
    1.32 +40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py
    1.33  40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py
    1.34  40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py
    1.35  40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py
    1.36 @@ -274,6 +277,32 @@ 4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xen
    1.37  403a3edbVpV2E_wq1zeEkJ_n4Uu2eg tools/xentrace/xentrace.c
    1.38  403a3edblCUrzSj0mmKhO5HOPrOrSQ tools/xentrace/xentrace_format
    1.39  4050c413NtuyIq5lsYJV4P7KIjujXw tools/xentrace/xentrace_format.1
    1.40 +40e9808eHO3QprCFKg9l2JJzgt2voA tools/xfrd/Make.xfrd
    1.41 +40e9808epTR4zWrYjGUnaaynK20Q5A tools/xfrd/Makefile
    1.42 +40e9808eysqT4VNDlJFqsZB2rdg4Qw tools/xfrd/connection.c
    1.43 +40e9808eyXfJUi4E0C3WSgrEXqQ1sQ tools/xfrd/connection.h
    1.44 +40e9808eULGwffNOE4kBrAfZ9YAVMA tools/xfrd/debug.h
    1.45 +40e9808eyjiahG5uF6AMelNVujBzCg tools/xfrd/enum.c
    1.46 +40e9808eZpbdn9q2KSSMGCNvY_ZgpQ tools/xfrd/enum.h
    1.47 +40e9808easXCzzAZQodEfKAhgUXSPA tools/xfrd/hash_table.c
    1.48 +40e9808e94BNXIVVKBFHC3rnkvwtJg tools/xfrd/hash_table.h
    1.49 +40e9808epW9iHcLXuO3QfUfLzB7onw tools/xfrd/lexis.c
    1.50 +40e9808egccMhCizayQRGtpBA3L5MQ tools/xfrd/lexis.h
    1.51 +40e9808ePADCSKL1YgGCt2TbYPnYkw tools/xfrd/lzi_stream.c
    1.52 +40e9808eDNAdpF71o5teYb9DTT-PRw tools/xfrd/lzi_stream.h
    1.53 +40e9808eQxi0EzTcPJtosrzxEIjA-Q tools/xfrd/marshal.c
    1.54 +40e9808etg13xfRm0Lqd8vY-jHOoTg tools/xfrd/marshal.h
    1.55 +40e9808eCsmywryb036TdtRMJHDMmQ tools/xfrd/select.c
    1.56 +40e9808e99OcM547cKMTfmCVSoWVAw tools/xfrd/select.h
    1.57 +40e9808e5_PLdodqVOSx0b4T_f5aeg tools/xfrd/sxpr.c
    1.58 +40e9808e0O4sHZtkDv5hlSqjYcdQAQ tools/xfrd/sxpr.h
    1.59 +40e9808eF3NVldqRNS5IHM8gbFAvpw tools/xfrd/xdr.c
    1.60 +40e9808ezXzoRHm7pybXU69NtnjimA tools/xfrd/xdr.h
    1.61 +40e9808edpUtf4bJ8IbqClPJj_OvbA tools/xfrd/xen_domain.c
    1.62 +40e9808eHviFFIwdUKOA234uIeifjA tools/xfrd/xen_domain.h
    1.63 +40e9808eIFeV-MDCNyVTNt5NfMPKeQ tools/xfrd/xfrd.c
    1.64 +40e9808eGIbOoSNJRiwWK2C3mjGWaA tools/xfrd/xfrd.h
    1.65 +40e9808eHXvs_5eggj9McD_J90mhNw tools/xfrd/xfrdClient.py
    1.66  3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
    1.67  3ddb79bcbOVHh38VJzc97-JEGD4dJQ xen/Makefile
    1.68  3ddb79bcWnTwYsQRWl_PaneJfa6p0w xen/Rules.mk
    1.69 @@ -285,8 +314,7 @@ 3ddb79bcSC_LvnmFlX-T5iTgaR0SKg xen/arch/
    1.70  40e42bdbNu4MjI750THP_8J1S-Sa0g xen/arch/x86/boot/x86_64.S
    1.71  3ddb79bcUrk2EIaM5VsT6wUudH1kkg xen/arch/x86/delay.c
    1.72  40e34414WiQO4h2m3tcpaCPn7SyYyg xen/arch/x86/dom0_ops.c
    1.73 -3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/domain_page.c
    1.74 -3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/entry.S
    1.75 +3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/domain.c
    1.76  3ddb79bcY5zW7KhvI9gvfuPi3ZumEg xen/arch/x86/extable.c
    1.77  3fe443fdDDb0Sw6NQBCk4GQapayfTA xen/arch/x86/flushtlb.c
    1.78  3ddb79bcesE5E-lS4QhRhlqXxqj9cA xen/arch/x86/i387.c
    1.79 @@ -294,7 +322,6 @@ 3ddb79bcCAq6IpdkHueChoVTfXqEQQ xen/arch/
    1.80  3ddb79bcBit4xJXbwtX0kb1hh2uO1Q xen/arch/x86/idle0_task.c
    1.81  3ddb79bcKIkRR0kqWaJhe5VUDkMdxg xen/arch/x86/io_apic.c
    1.82  3ddb79bdqfIcjkz_h9Hvtp8Tk_19Zw xen/arch/x86/irq.c
    1.83 -3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/mm.c
    1.84  3ddb79bdS4UeWWXDH-FaBKqcpMFcnw xen/arch/x86/mpparse.c
    1.85  3f12cff65EV3qOG2j37Qm0ShgvXGRw xen/arch/x86/nmi.c
    1.86  3ddb79bdHe6_Uij4-glW91vInNtBYQ xen/arch/x86/pci-irq.c
    1.87 @@ -303,7 +330,6 @@ 3ddb79bdeJ7_86z03yTAPIeeywOg3Q xen/arch/
    1.88  3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/x86/pci-x86.h
    1.89  40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/x86/pdb-linux.c
    1.90  4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/x86/pdb-stub.c
    1.91 -3ddb79bc1_2bAt67x9MFCP4AZrQnvQ xen/arch/x86/process.c
    1.92  3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c
    1.93  3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c
    1.94  405b8599xI_PoEr3zZoJ2on-jdn7iw xen/arch/x86/shadow.c
    1.95 @@ -312,8 +338,14 @@ 3ddb79bcfUN3-UBCPzX26IU8bq-3aw xen/arch/
    1.96  3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c
    1.97  3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
    1.98  3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
    1.99 -3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/usercopy.c
   1.100 -3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/xen.lds
   1.101 +3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c
   1.102 +3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S
   1.103 +3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c
   1.104 +3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
   1.105 +3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
   1.106 +40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
   1.107 +40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
   1.108 +40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
   1.109  3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
   1.110  3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c
   1.111  4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c
     2.1 --- a/docs/HOWTOs/XenDebugger-HOWTO	Thu Jul 01 23:45:24 2004 +0000
     2.2 +++ b/docs/HOWTOs/XenDebugger-HOWTO	Tue Jul 06 20:42:26 2004 +0000
     2.3 @@ -77,7 +77,7 @@ Serial Port Configuration
     2.4    one stream (without the high bit) is the console and 
     2.5    one stream (with the high bit stripped) is the pdb communication.
     2.6  
     2.7 -  See:  xeno.bk/tools/nsplitd
     2.8 +  See:  xeno.bk/tools/misc/nsplitd
     2.9  
    2.10    nsplitd configuration
    2.11    ---------------------
    2.12 @@ -107,7 +107,7 @@ Serial Port Configuration
    2.13    characters received.
    2.14  
    2.15    You can connect to the nsplitd using
    2.16 -  'tools/xenctl/lib/console_client.py <host> <port>'
    2.17 +  'tools/misc/xencons <host> <port>'
    2.18  
    2.19  GDB 6.0
    2.20    pdb has been tested with gdb 6.0.  It should also work with
     3.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h	Thu Jul 01 23:45:24 2004 +0000
     3.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/common.h	Tue Jul 06 20:42:26 2004 +0000
     3.3 @@ -19,7 +19,7 @@
     3.4  #define ASSERT(_p) \
     3.5      if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
     3.6      __LINE__, __FILE__); *(int*)0=0; }
     3.7 -#define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \
     3.8 +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
     3.9                             __FILE__ , __LINE__ , ## _a )
    3.10  #else
    3.11  #define ASSERT(_p) ((void)0)
     4.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c	Thu Jul 01 23:45:24 2004 +0000
     4.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/backend/interface.c	Tue Jul 06 20:42:26 2004 +0000
     4.3 @@ -217,7 +217,7 @@ int blkif_disconnect(blkif_be_disconnect
     4.4          blkif->status = DISCONNECTING;
     4.5          blkif->disconnect_rspid = rsp_id;
     4.6          wmb(); /* Let other CPUs see the status change. */
     4.7 -        free_irq(blkif->irq, NULL);
     4.8 +        free_irq(blkif->irq, blkif);
     4.9          blkif_deschedule(blkif);
    4.10          blkif_put(blkif);
    4.11      }
     5.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c	Thu Jul 01 23:45:24 2004 +0000
     5.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/blkif/frontend/main.c	Tue Jul 06 20:42:26 2004 +0000
     5.3 @@ -616,7 +616,7 @@ static void blkif_status_change(blkif_fe
     5.4  
     5.5              printk(KERN_INFO "VBD driver recovery in progress\n");
     5.6              
     5.7 -            /* Prevent new requests being issued until we've fixed things up. */
     5.8 +            /* Prevent new requests being issued until we fix things up. */
     5.9              spin_lock_irq(&io_request_lock);
    5.10              recovery = 1;
    5.11              blkif_state = BLKIF_STATE_DISCONNECTED;
     6.1 --- a/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Thu Jul 01 23:45:24 2004 +0000
     6.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c	Tue Jul 06 20:42:26 2004 +0000
     6.3 @@ -266,7 +266,7 @@ int netif_disconnect(netif_be_disconnect
     6.4          netif->disconnect_rspid = rsp_id;
     6.5          wmb(); /* Let other CPUs see the status change. */
     6.6          netif_stop_queue(netif->dev);
     6.7 -        free_irq(netif->irq, NULL);
     6.8 +        free_irq(netif->irq, netif);
     6.9          netif_deschedule(netif);
    6.10          netif_put(netif);
    6.11      }
     7.1 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c	Thu Jul 01 23:45:24 2004 +0000
     7.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/process.c	Tue Jul 06 20:42:26 2004 +0000
     7.3 @@ -115,7 +115,7 @@ void cpu_idle (void)
     7.4      }
     7.5  }
     7.6  
     7.7 -void machine_restart(char * __unused)
     7.8 +void machine_restart(char *__unused)
     7.9  {
    7.10      /* We really want to get pending console data out before we die. */
    7.11      extern void xencons_force_flush(void);
    7.12 @@ -128,7 +128,11 @@ void machine_halt(void)
    7.13      /* We really want to get pending console data out before we die. */
    7.14      extern void xencons_force_flush(void);
    7.15      xencons_force_flush();
    7.16 -    HYPERVISOR_shutdown();
    7.17 +    for ( ; ; ) /* loop without wasting cpu cycles */
    7.18 +    {
    7.19 +        HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_pending = 0;
    7.20 +        HYPERVISOR_block();
    7.21 +    }
    7.22  }
    7.23  
    7.24  void machine_power_off(void)
     8.1 --- a/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c	Thu Jul 01 23:45:24 2004 +0000
     8.2 +++ b/linux-2.4.26-xen-sparse/arch/xen/kernel/setup.c	Tue Jul 06 20:42:26 2004 +0000
     8.3 @@ -8,6 +8,8 @@
     8.4   * This file handles the architecture-dependent parts of initialization
     8.5   */
     8.6  
     8.7 +#define __KERNEL_SYSCALLS__
     8.8 +static int errno;
     8.9  #include <linux/errno.h>
    8.10  #include <linux/sched.h>
    8.11  #include <linux/kernel.h>
    8.12 @@ -30,6 +32,7 @@
    8.13  #include <linux/highmem.h>
    8.14  #include <linux/bootmem.h>
    8.15  #include <linux/seq_file.h>
    8.16 +#include <linux/reboot.h>
    8.17  #include <asm/processor.h>
    8.18  #include <linux/console.h>
    8.19  #include <linux/module.h>
    8.20 @@ -1148,10 +1151,10 @@ void __init cpu_init (void)
    8.21  
    8.22  #include <asm/suspend.h>
    8.23  
    8.24 -/* Treat multiple suspend requests as a single one. */
    8.25 -static int suspending;
    8.26 +/* Ignore multiple shutdown requests. */
    8.27 +static int shutting_down = -1;
    8.28  
    8.29 -static void suspend_task(void *unused)
    8.30 +static void __do_suspend(void)
    8.31  {
    8.32      /* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
    8.33      extern void blkdev_suspend(void);
    8.34 @@ -1220,7 +1223,7 @@ static void suspend_task(void *unused)
    8.35  
    8.36      HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
    8.37  
    8.38 -    suspending = 0; 
    8.39 +    shutting_down = -1; 
    8.40  
    8.41      memcpy(&start_info, &suspend_record->resume_info, sizeof(start_info));
    8.42  
    8.43 @@ -1272,25 +1275,78 @@ static void suspend_task(void *unused)
    8.44          free_page((unsigned long)suspend_record);
    8.45  }
    8.46  
    8.47 -static struct tq_struct suspend_tq;
    8.48 +static int shutdown_process(void *__unused)
    8.49 +{
    8.50 +    static char *envp[] = { "HOME=/", "TERM=linux", 
    8.51 +                            "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
    8.52 +    static char *restart_argv[]  = { "/sbin/shutdown", "-r", "now", NULL };
    8.53 +    static char *poweroff_argv[] = { "/sbin/halt",     "-p",        NULL };
    8.54 +
    8.55 +    extern asmlinkage long sys_reboot(int magic1, int magic2,
    8.56 +                                      unsigned int cmd, void *arg);
    8.57 +
    8.58 +    daemonize();
    8.59 +
    8.60 +    switch ( shutting_down )
    8.61 +    {
    8.62 +    case CMSG_SHUTDOWN_POWEROFF:
    8.63 +        if ( execve("/sbin/halt", poweroff_argv, envp) < 0 )
    8.64 +        {
    8.65 +            sys_reboot(LINUX_REBOOT_MAGIC1,
    8.66 +                       LINUX_REBOOT_MAGIC2,
    8.67 +                       LINUX_REBOOT_CMD_POWER_OFF,
    8.68 +                       NULL);
    8.69 +        }
    8.70 +        break;
    8.71 +
    8.72 +    case CMSG_SHUTDOWN_REBOOT:
    8.73 +        if ( execve("/sbin/shutdown", restart_argv, envp) < 0 )
    8.74 +        {
    8.75 +            sys_reboot(LINUX_REBOOT_MAGIC1,
    8.76 +                       LINUX_REBOOT_MAGIC2,
    8.77 +                       LINUX_REBOOT_CMD_RESTART,
    8.78 +                       NULL);
    8.79 +        }
    8.80 +        break;
    8.81 +    }
    8.82 +
    8.83 +    return 0;
    8.84 +}
    8.85 +
    8.86 +static void __shutdown_handler(void *unused)
    8.87 +{
    8.88 +    int err;
    8.89 +
    8.90 +    if ( shutting_down != CMSG_SHUTDOWN_SUSPEND )
    8.91 +    {
    8.92 +        err = kernel_thread(shutdown_process, NULL, CLONE_FS | CLONE_FILES);
    8.93 +        if ( err < 0 )
    8.94 +            printk(KERN_ALERT "Error creating shutdown process!\n");
    8.95 +        else
    8.96 +            shutting_down = -1; /* could try again */
    8.97 +    }
    8.98 +    else
    8.99 +    {
   8.100 +        __do_suspend();
   8.101 +    }
   8.102 +}
   8.103  
   8.104  static void shutdown_handler(ctrl_msg_t *msg, unsigned long id)
   8.105  {
   8.106 -    if ( msg->subtype != CMSG_SHUTDOWN_SUSPEND )
   8.107 +    static struct tq_struct shutdown_tq;
   8.108 +
   8.109 +    if ( (shutting_down == -1) &&
   8.110 +         ((msg->subtype == CMSG_SHUTDOWN_POWEROFF) ||
   8.111 +          (msg->subtype == CMSG_SHUTDOWN_REBOOT) ||
   8.112 +          (msg->subtype == CMSG_SHUTDOWN_SUSPEND)) )
   8.113      {
   8.114 -        extern void ctrl_alt_del(void);
   8.115 -        ctrl_if_send_response(msg);
   8.116 -        ctrl_alt_del();
   8.117 -    }
   8.118 -    else if ( !suspending )
   8.119 -    {
   8.120 -	suspending = 1;
   8.121 -	suspend_tq.routine = suspend_task;
   8.122 -	schedule_task(&suspend_tq);	
   8.123 +        shutting_down = msg->subtype;
   8.124 +        shutdown_tq.routine = __shutdown_handler;
   8.125 +        schedule_task(&shutdown_tq);
   8.126      }
   8.127      else
   8.128      {
   8.129 -	printk(KERN_ALERT"Ignore queued suspend request\n");
   8.130 +	printk("Ignore spurious shutdown request\n");
   8.131      }
   8.132  
   8.133      ctrl_if_send_response(msg);
     9.1 --- a/tools/examples/xmdefaults	Thu Jul 01 23:45:24 2004 +0000
     9.2 +++ b/tools/examples/xmdefaults	Tue Jul 06 20:42:26 2004 +0000
     9.3 @@ -2,17 +2,23 @@
     9.4  #============================================================================
     9.5  # Python defaults setup for 'xm create'.
     9.6  # Edit this file to reflect the configuration of your system.
     9.7 -# This file expects the variable 'vmid' to be set.
     9.8  #============================================================================
     9.9  
    9.10 -try:
    9.11 -    vmid = int(vmid) # convert to integer
    9.12 -except:
    9.13 -    raise ValueError, "Variable 'vmid' must be an integer"
    9.14 +# Define script variables here.
    9.15 +# xm_vars is defined automatically, use xm_vars.var() to define a variable.
    9.16  
    9.17 -if vmid <= 0:
    9.18 -    raise ValueError, "Variable 'vmid' must be greater than 0" 
    9.19 +def vmid_check(var, val):
    9.20 +    val = int(val)
    9.21 +    if val <= 0:
    9.22 +        raise ValueError
    9.23 +    return val
    9.24 +    
    9.25 +xm_vars.var('vmid',
    9.26 +            use="Virtual machine id. Integer greater than 0.",
    9.27 +            check=vmid_check)
    9.28  
    9.29 +# This checks the script variables.
    9.30 +xm_vars.check()
    9.31  
    9.32  #----------------------------------------------------------------------------
    9.33  # Kernel image file.
    9.34 @@ -87,6 +93,6 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
    9.35  #----------------------------------------------------------------------------
    9.36  # Set according to whether you want the domain  restarted when it exits.
    9.37  # The default is False.
    9.38 -#restart = True
    9.39 +#autorestart = True
    9.40  
    9.41  #============================================================================
    10.1 --- a/tools/examples/xmnetbsd	Thu Jul 01 23:45:24 2004 +0000
    10.2 +++ b/tools/examples/xmnetbsd	Tue Jul 06 20:42:26 2004 +0000
    10.3 @@ -2,24 +2,23 @@
    10.4  #============================================================================
    10.5  # Python defaults setup for 'xm create'.
    10.6  # Edit this file to reflect the configuration of your system.
    10.7 -# This file expects the variable 'vmid' to be set.
    10.8  #============================================================================
    10.9  
   10.10 -def config_usage ():
   10.11 -    print >>sys.stderr,"""
   10.12 -The config file '%s' requires the following variable to be defined:
   10.13 - vmid             -- Numeric identifier for the new domain, used to calculate
   10.14 -                     the VM's IP address and root partition. E.g. -Dvmid=1
   10.15 -""" % config_file
   10.16 -
   10.17 +# Define script variables here.
   10.18 +# xm_vars is defined automatically, use xm_vars.var() to define a variable.
   10.19  
   10.20 -try:
   10.21 -    vmid = int(vmid) # convert to integer
   10.22 -except:
   10.23 -    raise ValueError, "Variable 'vmid' must be an integer"
   10.24 +def vmid_check(var, val):
   10.25 +    val = int(val)
   10.26 +    if val <= 0:
   10.27 +        raise ValueError
   10.28 +    return val
   10.29 +    
   10.30 +xm_vars.var('vmid',
   10.31 +            use="Virtual machine id. Integer greater than 0.",
   10.32 +            check=vmid_check)
   10.33  
   10.34 -if vmid <= 0:
   10.35 -    raise ValueError, "Variable 'vmid' must be greater than 0" 
   10.36 +# This checks the script variables.
   10.37 +xm_vars.check()
   10.38  
   10.39  #----------------------------------------------------------------------------
   10.40  # Kernel image file.
   10.41 @@ -97,6 +96,6 @@ extra = "4 VMID=%d bootdev=xennet0" % vm
   10.42  #----------------------------------------------------------------------------
   10.43  # Set according to whether you want the domain  restarted when it exits.
   10.44  # The default is False.
   10.45 -#restart = True
   10.46 +#autorestart = True
   10.47  
   10.48  #============================================================================
    11.1 --- a/tools/libxutil/Makefile	Thu Jul 01 23:45:24 2004 +0000
    11.2 +++ b/tools/libxutil/Makefile	Tue Jul 06 20:42:26 2004 +0000
    11.3 @@ -8,7 +8,7 @@ LIB_SRCS += allocate.c
    11.4  LIB_SRCS += file_stream.c
    11.5  LIB_SRCS += gzip_stream.c
    11.6  LIB_SRCS += iostream.c
    11.7 -LIB_SRCS += sys_net.c
    11.8 +#LIB_SRCS += sys_net.c
    11.9  LIB_SRCS += sys_string.c
   11.10  
   11.11  LIB_OBJS := $(LIB_SRCS:.c=.o)
    12.1 --- a/tools/libxutil/allocate.h	Thu Jul 01 23:45:24 2004 +0000
    12.2 +++ b/tools/libxutil/allocate.h	Tue Jul 06 20:42:26 2004 +0000
    12.3 @@ -16,8 +16,8 @@
    12.4   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    12.5   */
    12.6  
    12.7 -#ifndef _XEN_LIB_ALLOCATE_H_
    12.8 -#define _XEN_LIB_ALLOCATE_H_
    12.9 +#ifndef _XUTIL_ALLOCATE_H_
   12.10 +#define _XUTIL_ALLOCATE_H_
   12.11  
   12.12  /** Allocate memory for a given type, and cast. */
   12.13  #define ALLOCATE(ctype) (ctype *)allocate(sizeof(ctype))
   12.14 @@ -33,7 +33,7 @@ extern void memzero(void *p, int size);
   12.15  typedef void AllocateFailedFn(int size, int type);
   12.16  extern AllocateFailedFn *allocate_failed_fn;
   12.17  
   12.18 -#endif /* _XEN_LIB_ALLOCATE_H_ */
   12.19 +#endif /* _XUTIL_ALLOCATE_H_ */
   12.20  
   12.21  
   12.22  
    13.1 --- a/tools/libxutil/file_stream.h	Thu Jul 01 23:45:24 2004 +0000
    13.2 +++ b/tools/libxutil/file_stream.h	Tue Jul 06 20:42:26 2004 +0000
    13.3 @@ -16,8 +16,8 @@
    13.4   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    13.5   */
    13.6  
    13.7 -#ifndef _XEN_LIB_FILE_STREAM_H_
    13.8 -#define _XEN_LIB_FILE_STREAM_H_
    13.9 +#ifndef _XUTIL_FILE_STREAM_H_
   13.10 +#define _XUTIL_FILE_STREAM_H_
   13.11  
   13.12  #ifndef __KERNEL__
   13.13  #include "iostream.h"
   13.14 @@ -32,4 +32,4 @@ extern IOStream get_stream_stdin(void);
   13.15  
   13.16  extern int file_stream_setvbuf(IOStream *io, char *buf, int mode, size_t size);
   13.17  #endif
   13.18 -#endif /* !_XEN_LIB_FILE_STREAM_H_ */
   13.19 +#endif /* !_XUTIL_FILE_STREAM_H_ */
    14.1 --- a/tools/libxutil/gzip_stream.c	Thu Jul 01 23:45:24 2004 +0000
    14.2 +++ b/tools/libxutil/gzip_stream.c	Tue Jul 06 20:42:26 2004 +0000
    14.3 @@ -1,4 +1,3 @@
    14.4 -/* $Id: gzip_stream.c,v 1.4 2003/09/30 15:22:53 mjw Exp $ */
    14.5  /*
    14.6   * Copyright (C) 2003 Hewlett-Packard Company.
    14.7   *
    15.1 --- a/tools/libxutil/gzip_stream.h	Thu Jul 01 23:45:24 2004 +0000
    15.2 +++ b/tools/libxutil/gzip_stream.h	Tue Jul 06 20:42:26 2004 +0000
    15.3 @@ -1,4 +1,3 @@
    15.4 -#/* $Id: gzip_stream.h,v 1.3 2003/09/30 15:22:53 mjw Exp $ */
    15.5  /*
    15.6   * Copyright (C) 2003 Hewlett-Packard Company.
    15.7   *
    15.8 @@ -17,8 +16,8 @@
    15.9   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   15.10   */
   15.11  
   15.12 -#ifndef _SP_GZIP_STREAM_H_
   15.13 -#define _SP_GZIP_STREAM_H_
   15.14 +#ifndef _XUTIL_GZIP_STREAM_H_
   15.15 +#define _XUTIL_GZIP_STREAM_H_
   15.16  
   15.17  #ifndef __KERNEL__
   15.18  #include "iostream.h"
   15.19 @@ -28,4 +27,4 @@ extern IOStream *gzip_stream_new(gzFile 
   15.20  extern IOStream *gzip_stream_fopen(const char *file, const char *flags);
   15.21  extern IOStream *gzip_stream_fdopen(int fd, const char *flags);
   15.22  #endif
   15.23 -#endif /* !_SP_FILE_STREAM_H_ */
   15.24 +#endif /* !_XUTIL_GZIP_STREAM_H_ */
    16.1 --- a/tools/libxutil/kernel_stream.h	Thu Jul 01 23:45:24 2004 +0000
    16.2 +++ b/tools/libxutil/kernel_stream.h	Tue Jul 06 20:42:26 2004 +0000
    16.3 @@ -16,8 +16,8 @@
    16.4   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    16.5   */
    16.6  
    16.7 -#ifndef _XEN_LIB_KERNEL_STREAM_H_
    16.8 -#define _XEN_LIB_KERNEL_STREAM_H_
    16.9 +#ifndef _XUTIL_KERNEL_STREAM_H_
   16.10 +#define _XUTIL_KERNEL_STREAM_H_
   16.11  
   16.12  #ifdef __KERNEL__
   16.13  #include "iostream.h"
   16.14 @@ -26,4 +26,4 @@ extern IOStream get_stream_kernel(void);
   16.15  #define get_stream_stdout get_stream_kernel
   16.16  
   16.17  #endif /* __KERNEL__ */
   16.18 -#endif /* !_XEN_LIB_KERNEL_STREAM_H_ */
   16.19 +#endif /* !_XUTIL_KERNEL_STREAM_H_ */
    17.1 --- a/tools/libxutil/string_stream.c	Thu Jul 01 23:45:24 2004 +0000
    17.2 +++ b/tools/libxutil/string_stream.c	Tue Jul 06 20:42:26 2004 +0000
    17.3 @@ -25,8 +25,6 @@
    17.4  #include "string_stream.h"
    17.5  #include "allocate.h"
    17.6  
    17.7 -static int string_print(IOStream *io, const char *msg, va_list args);
    17.8 -static int string_getc(IOStream *io);
    17.9  static int string_error(IOStream *io);
   17.10  static int string_close(IOStream *io);
   17.11  static void string_free(IOStream *io);
   17.12 @@ -49,45 +47,6 @@ static inline StringData *get_string_dat
   17.13      return (StringData*)io->data;
   17.14  }
   17.15  
   17.16 -/** Read a character from a string stream.
   17.17 - *
   17.18 - * @param io string stream
   17.19 - * @return character read, IOSTREAM_EOF if no more input
   17.20 - */
   17.21 -static int string_getc(IOStream *io){
   17.22 -    StringData *data = get_string_data(io);
   17.23 -    int c = IOSTREAM_EOF;
   17.24 -    char *s = data->in;
   17.25 -
   17.26 -    if(s && s < data->end){
   17.27 -        c = (unsigned)*s;
   17.28 -        data->in = s+1;
   17.29 -    }
   17.30 -    return c;
   17.31 -}
   17.32 -
   17.33 -/** Print to a string stream.
   17.34 - * Formats the data to an internal buffer and prints it.
   17.35 - * The formatted data must fit into the internal buffer.
   17.36 - *
   17.37 - * @param io string stream
   17.38 - * @param format print format
   17.39 - * @param args print arguments
   17.40 - * @return result of the print
   17.41 - */
   17.42 -static int string_print(IOStream *io, const char *msg, va_list args){
   17.43 -    StringData *data = get_string_data(io);
   17.44 -    int k = data->end - data->out;
   17.45 -    int n = vsnprintf(data->out, k, (char*)msg, args);
   17.46 -    if(n < 0 || n > k ){
   17.47 -        n = k;
   17.48 -        IOStream_close(io);
   17.49 -    } else {
   17.50 -        data->out += n;
   17.51 -    }
   17.52 -    return n;
   17.53 -}
   17.54 -
   17.55  /** Test if a string stream has an error.
   17.56   *
   17.57   * @param io string stream
   17.58 @@ -118,7 +77,7 @@ static int string_close(IOStream *io){
   17.59   */
   17.60  static void string_free(IOStream *io){
   17.61      StringData *data = get_string_data(io);
   17.62 -    zero(data, sizeof(*data));
   17.63 +    memzero(data, sizeof(*data));
   17.64      deallocate(data);
   17.65  }
   17.66  
   17.67 @@ -139,13 +98,13 @@ IOMethods *string_stream_get_methods(voi
   17.68   */
   17.69  void string_stream_init(IOStream *io, StringData *data, char *s, int n){
   17.70      if(data && io){
   17.71 -        zero(data, sizeof(*data));
   17.72 +        memzero(data, sizeof(*data));
   17.73          data->string = (char*)s;
   17.74          data->in = data->string;
   17.75          data->out = data->string;
   17.76          data->size = n;
   17.77          data->end = data->string + n;
   17.78 -        zero(io, sizeof(*io));
   17.79 +        memzero(io, sizeof(*io));
   17.80          io->methods = &string_methods;
   17.81          io->data = data;
   17.82      }
    18.1 --- a/tools/libxutil/string_stream.h	Thu Jul 01 23:45:24 2004 +0000
    18.2 +++ b/tools/libxutil/string_stream.h	Tue Jul 06 20:42:26 2004 +0000
    18.3 @@ -1,4 +1,3 @@
    18.4 -/* $Id: string_stream.h,v 1.1 2003/08/22 14:25:48 mjw Exp $ */
    18.5  /*
    18.6   * Copyright (C) 2001, 2002 Hewlett-Packard Company.
    18.7   *
    18.8 @@ -17,8 +16,8 @@
    18.9   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   18.10   */
   18.11  
   18.12 -#ifndef _SP_STRING_STREAM_H_
   18.13 -#define _SP_STRING_STREAM_H_
   18.14 +#ifndef _XUTIL_STRING_STREAM_H_
   18.15 +#define _XUTIL_STRING_STREAM_H_
   18.16  
   18.17  #include "iostream.h"
   18.18  
   18.19 @@ -43,4 +42,4 @@ extern IOMethods *string_stream_get_meth
   18.20  extern IOStream *string_stream_new(char *s, int n);
   18.21  extern void string_stream_init(IOStream *stream, StringData *data, char *s, int n);
   18.22  
   18.23 -#endif /* !_SP_STRING_STREAM_H_ */
   18.24 +#endif /* !_XUTIL_STRING_STREAM_H_ */
    19.1 --- a/tools/libxutil/sys_net.h	Thu Jul 01 23:45:24 2004 +0000
    19.2 +++ b/tools/libxutil/sys_net.h	Tue Jul 06 20:42:26 2004 +0000
    19.3 @@ -16,8 +16,8 @@
    19.4   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    19.5   */
    19.6  
    19.7 -#ifndef _XEN_LIB_SYS_NET_H_
    19.8 -#define _XEN_LIB_SYS_NET_H_
    19.9 +#ifndef _XUTIL_SYS_NET_H_
   19.10 +#define _XUTIL_SYS_NET_H_
   19.11  /** @file
   19.12   *
   19.13   * Replacement for standard network includes.
   19.14 @@ -72,7 +72,7 @@ extern int inet_aton(const char *address
   19.15  extern char *mac_ntoa(const unsigned char *macaddr);
   19.16  extern int mac_aton(const char *addr, unsigned char *macaddr);
   19.17  
   19.18 -#endif /* !_SP_SYS_NET_H_ */
   19.19 +#endif /* !_XUTIL_SYS_NET_H_ */
   19.20  
   19.21  
   19.22  
    20.1 --- a/tools/libxutil/sys_string.h	Thu Jul 01 23:45:24 2004 +0000
    20.2 +++ b/tools/libxutil/sys_string.h	Tue Jul 06 20:42:26 2004 +0000
    20.3 @@ -16,8 +16,8 @@
    20.4   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    20.5   */
    20.6  
    20.7 -#ifndef _XEN_LIB_SYS_STRING_H_
    20.8 -#define _XEN_LIB_SYS_STRING_H_
    20.9 +#ifndef _XUTIL_SYS_STRING_H_
   20.10 +#define _XUTIL_SYS_STRING_H_
   20.11  /** @file
   20.12   * Replacement for standard string includes.
   20.13   * Works in user or kernel code.
   20.14 @@ -88,4 +88,4 @@ static inline size_t strnlen(const char 
   20.15  extern int convert_atoul(const char *s, unsigned long *v);
   20.16  extern int path_concat(char *s, char *t, char **val);
   20.17  
   20.18 -#endif /* !_XEN_LIB_SYS_STRING_H_ */
   20.19 +#endif /* !_XUTIL_SYS_STRING_H_ */
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/misc/nsplitd/Makefile	Tue Jul 06 20:42:26 2004 +0000
    21.3 @@ -0,0 +1,22 @@
    21.4 +
    21.5 +CC     = gcc
    21.6 +CFLAGS = -Wall -O3
    21.7 +CFILES = $(wildcard *.c)
    21.8 +
    21.9 +HDRS     = $(wildcard *.h)
   21.10 +OBJS     = $(patsubst %.c,%.o,$(wildcard *.c))
   21.11 +
   21.12 +TARGET   = nsplitd
   21.13 +
   21.14 +all: $(TARGET)
   21.15 +
   21.16 +install: all
   21.17 +
   21.18 +clean:
   21.19 +	$(RM) *.o $(TARGET) *~
   21.20 +
   21.21 +$(TARGET): $(OBJS)
   21.22 +	$(CC) $(CFLAGS) -o $@ $^
   21.23 +
   21.24 +%.o: %.c $(HDRS) Makefile
   21.25 +	$(CC) $(CFLAGS) -c -o $@ $<
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/misc/nsplitd/nsplitd.c	Tue Jul 06 20:42:26 2004 +0000
    22.3 @@ -0,0 +1,686 @@
    22.4 +/*
    22.5 + *	nsplitd.c
    22.6 + *	---------
    22.7 + *
    22.8 + * $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $
    22.9 + *
   22.10 + * Copyright (c) 1995, University of Cambridge Computer Laboratory,
   22.11 + * Copyright (c) 1995, Richard Black, All Rights Reserved.
   22.12 + *
   22.13 + *
   22.14 + * A complete re-implementation of DME's nsplitd for use from inetd
   22.15 + *
   22.16 + */
   22.17 +
   22.18 +/* The basic stream comes in (via inetd) and we then conenct to
   22.19 + * somewhere else providing a loop-through service, except we offer
   22.20 + * two other ports for connection - one of which gets a second channel
   22.21 + * using the top bit to distinguish, and the other is a master control
   22.22 + * port (normally used for gdb) which gets complete exclusive access
   22.23 + * for its duration.
   22.24 + *
   22.25 + * Originally designed for multiplexing a xwcons/telnet with a gdb
   22.26 + * post-mortem debugging session.
   22.27 + *
   22.28 + * Here is a picture:
   22.29 + *
   22.30 + * 					    port0 (from inetd)
   22.31 + *      8-bit connection     	       	   /
   22.32 + * 	   made by us	   <----> nsplitd <-----gdbport (default port0+2)
   22.33 + * 	to host:port/tcp		  |\
   22.34 + * 					  | port1 (default port0+1)
   22.35 + *                                         \
   22.36 + *                                          control (default port0+3)
   22.37 + *
   22.38 + * If port1 is explicitly disabled (through a command-line option) then
   22.39 + * port0 becomes 8-bit clean.
   22.40 + */
   22.41 +
   22.42 +/*
   22.43 + * N.B.: We do NOT support 8 bit stdin/stdout usage on a
   22.44 + * /dev/... because to do that right involves much messing with ioctl
   22.45 + * and TIOC... etc.  If you want to do that sort of thing then the
   22.46 + * right way to do it is to chain this onto wconsd (which does know
   22.47 + * about and understand all the ioctl and TIOC grief).
   22.48 + */
   22.49 +
   22.50 +#include <sys/types.h>
   22.51 +#include <stdarg.h>
   22.52 +#include <stdio.h>
   22.53 +#include <stdlib.h>
   22.54 +#include <assert.h>
   22.55 +#include <errno.h>
   22.56 +#include <unistd.h>
   22.57 +#include <ctype.h>
   22.58 +#include <netdb.h>
   22.59 +#include <string.h>
   22.60 +
   22.61 +#include <sys/time.h>
   22.62 +#include <sys/signal.h>
   22.63 +#include <sys/socket.h>
   22.64 +#include <netinet/in.h>
   22.65 +#include <netinet/tcp.h>
   22.66 +#include <arpa/inet.h>
   22.67 +#include <sys/ioctl.h>
   22.68 +#include <syslog.h>
   22.69 +
   22.70 +#ifndef FALSE
   22.71 +#define FALSE 0
   22.72 +#endif
   22.73 +#ifndef TRUE
   22.74 +#define TRUE 1
   22.75 +#endif
   22.76 +
   22.77 +#ifndef LOG_DAEMON
   22.78 +#define LOG_DAEMON 0
   22.79 +#endif
   22.80 +
   22.81 +#define DB(x)  /* ((x), fflush(stderr)) */
   22.82 +
   22.83 +extern char *optarg;
   22.84 +
   22.85 +extern int optind, opterr, optopt;
   22.86 +
   22.87 +static char *prog_name;
   22.88 +
   22.89 +static void usage(void)
   22.90 +{
   22.91 +    fprintf(stderr, "This program (%s) should be run via inetd (tcp)\n\n",
   22.92 +	    prog_name);
   22.93 +    fprintf(stderr, "usage: %s [-h<highport>][-g<gdbport>]"
   22.94 +	    "[-c<ctlport>][-8] host:service\n",
   22.95 +	    prog_name);
   22.96 +    exit(1);
   22.97 +}
   22.98 +
   22.99 +static void fault(char *format, ...)
  22.100 +{
  22.101 +    va_list		ap;
  22.102 +    char		logbuf[1024];
  22.103 +
  22.104 +    va_start(ap, format);
  22.105 +    fprintf(stderr, "%s: ", prog_name);
  22.106 +    vfprintf(stderr, format, ap);
  22.107 +    fflush(stderr);
  22.108 +    va_end(ap);
  22.109 +    
  22.110 +    /* XXX This is a bit dubious, but there is no vsyslog */
  22.111 +    va_start(ap, format);
  22.112 +    vsprintf(logbuf, format, ap);
  22.113 +    syslog(LOG_ERR, logbuf);
  22.114 +    va_end(ap);
  22.115 +    exit(1);
  22.116 +}
  22.117 +
  22.118 +static int getservice(char *name, unsigned short *port)
  22.119 +{
  22.120 +    struct servent		*se;
  22.121 +
  22.122 +    if (!name) return -1;
  22.123 +
  22.124 +    if (isdigit(name[0]))
  22.125 +	*port = atoi(name);
  22.126 +    else
  22.127 +    {
  22.128 +	if (!(se = getservbyname(name, "tcp")))
  22.129 +	    return -1;
  22.130 +	*port = ntohs(se->s_port);
  22.131 +    }
  22.132 +    return 0;
  22.133 +}
  22.134 +
  22.135 +/* 
  22.136 + *  connect_host: connect to ("name", "port")
  22.137 + */
  22.138 +static int connect_host (char *name, unsigned int port)
  22.139 +{
  22.140 +    int			fd;
  22.141 +    struct hostent	*hostent;
  22.142 +    struct sockaddr_in	sin;
  22.143 +    int			on;
  22.144 +    
  22.145 +    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  22.146 +	fault("socket");
  22.147 +    
  22.148 +    if (!(hostent = gethostbyname(name)))
  22.149 +	fault("gethostbyname: %s: %s\n", name, strerror(errno));
  22.150 +    
  22.151 +    memset(&sin, 0, sizeof(sin));
  22.152 +    sin.sin_family = AF_INET;
  22.153 +    sin.sin_port   = htons (port);
  22.154 +    memcpy(&sin.sin_addr.s_addr, hostent->h_addr, sizeof(struct in_addr));
  22.155 +    
  22.156 +    if (connect(fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
  22.157 +	fault("connect: %s:%u: %s\n", name, port, strerror(errno));
  22.158 +    
  22.159 +    on = 1;
  22.160 +    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
  22.161 +	syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
  22.162 +
  22.163 +    on = 1;
  22.164 +    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
  22.165 +	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  22.166 +
  22.167 +    return fd;
  22.168 +}
  22.169 +
  22.170 +/*
  22.171 + * open a tcp socket and start listening for connections on it
  22.172 + */
  22.173 +static int startlistening(unsigned short port)
  22.174 +{
  22.175 +    int			fd, on;
  22.176 +    struct sockaddr_in	sin;
  22.177 +
  22.178 +    if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  22.179 +	fault("socket");
  22.180 +    
  22.181 +    on = 1;
  22.182 +    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0)
  22.183 +      syslog(LOG_WARNING, "setsockopt (SO_REUSEADDR): %m");
  22.184 +
  22.185 +    memset(&sin, 0, sizeof(sin));
  22.186 +    sin.sin_family      = AF_INET;
  22.187 +    sin.sin_port        = htons (port);
  22.188 +    sin.sin_addr.s_addr = INADDR_ANY;
  22.189 +    if (bind(fd, &sin, sizeof(sin)) < 0)
  22.190 +	fault("bind: %u: %s\n", port, strerror(errno));
  22.191 +    
  22.192 +    if (listen(fd, 1) < 0)
  22.193 +	fault("listen: %s\n", strerror(errno));
  22.194 +    
  22.195 +    return fd;
  22.196 +}
  22.197 +
  22.198 +static void noblock(int fd)
  22.199 +{
  22.200 +    int on=1;
  22.201 +    
  22.202 +    if (ioctl(fd, FIONBIO, &on) < 0)
  22.203 +	fault("ioctl: FIONBIO: %s\n", strerror(errno));
  22.204 +}
  22.205 +
  22.206 +
  22.207 +/* You might not believe this, but fd_sets don't have to be a 32-bit
  22.208 + * integer.  In particular, in glibc2 it is an array of unsigned
  22.209 + * longs.  Hence, this hacked up FD_SET_rjb() that works out if it
  22.210 + * would have been a nop. */
  22.211 +#define FD_SET_rjb(fd, setp) \
  22.212 +do {						\
  22.213 +    if ((fd) != 32)				\
  22.214 +	FD_SET((fd), (setp));			\
  22.215 +} while(0)
  22.216 +
  22.217 +#define FD_ISSET_rjb(fd, setp) (((fd) != 32)? FD_ISSET((fd), (setp)) : 0)
  22.218 +
  22.219 +#define MAXSIZE	256
  22.220 +
  22.221 +/* -----------------------------------------------------------------
  22.222 + * The main bit of the algorithm. Note we use 32 to mean not connected
  22.223 + * because this gives us 1<<32 == 0. We could have done this one
  22.224 + * character at a time, but that would have been very inefficient and
  22.225 + * not the unix way.  */
  22.226 +static int debug;
  22.227 +
  22.228 +static void doit(int actl, int acto, int lish, int lisg, int lisc)
  22.229 +{
  22.230 +    int		acth, actg, actc;
  22.231 +    int		gdbmode = FALSE;
  22.232 +    char	gibuf[MAXSIZE], oibuf[MAXSIZE];
  22.233 +    char	libuf[MAXSIZE], lobuf[MAXSIZE];
  22.234 +    char	hibuf[MAXSIZE], hobuf[MAXSIZE];
  22.235 +    char	ctlbuf[MAXSIZE];
  22.236 +    fd_set	rdfs, wrfs, exfs;
  22.237 +    int		gicc, oicc, licc, locc, hicc, hocc, ctlcc;
  22.238 +    char	*giptr, *oiptr, *liptr, *loptr, *hiptr, *hoptr;
  22.239 +    int		rc, fromlen;
  22.240 +    struct sockaddr_in		from;
  22.241 +    
  22.242 +    gicc = oicc = licc = locc = hicc = hocc = ctlcc = 0;
  22.243 +    acth = actg = actc = 32;			/* XXX yummy */
  22.244 +
  22.245 +    noblock(actl);
  22.246 +    noblock(acto);
  22.247 +
  22.248 +    for(;;)
  22.249 +    {
  22.250 +	FD_ZERO(&rdfs);
  22.251 +	FD_ZERO(&wrfs);
  22.252 +	FD_ZERO(&exfs);
  22.253 +
  22.254 +	/* always take input from the control port (if it's connected) */
  22.255 +	FD_SET_rjb(actc, &rdfs);
  22.256 +
  22.257 +	if (gdbmode)
  22.258 +	{
  22.259 +	    if (oicc)
  22.260 +		FD_SET_rjb(actg, &wrfs);
  22.261 +	    else
  22.262 +		FD_SET_rjb(acto, &rdfs);
  22.263 +	    
  22.264 +	    if (gicc)
  22.265 +		FD_SET_rjb(acto, &wrfs);
  22.266 +	    else
  22.267 +		FD_SET_rjb(actg, &rdfs);
  22.268 +	}
  22.269 +	else
  22.270 +	{
  22.271 +	    /* There is no such thing as oibuf because its been split into
  22.272 +	     * lobuf and hobuf
  22.273 +	     */
  22.274 +	    if (locc || hocc)
  22.275 +	    {
  22.276 +		if (locc)
  22.277 +		    FD_SET_rjb(actl, &wrfs);
  22.278 +		if (hocc)
  22.279 +		    FD_SET_rjb(acth, &wrfs);
  22.280 +	    }
  22.281 +	    else
  22.282 +		FD_SET_rjb(acto, &rdfs);
  22.283 +	    
  22.284 +	    if (licc)
  22.285 +		FD_SET_rjb(acto, &wrfs);
  22.286 +	    else
  22.287 +		FD_SET_rjb(actl, &rdfs);
  22.288 +	    
  22.289 +	    if (hicc)
  22.290 +		FD_SET_rjb(acto, &wrfs);
  22.291 +	    else
  22.292 +		FD_SET_rjb(acth, &rdfs);
  22.293 +	}
  22.294 +	
  22.295 +	if (acth == 32 && lish>=0)	FD_SET_rjb(lish, &rdfs);
  22.296 +	if (actg == 32)			FD_SET_rjb(lisg, &rdfs);
  22.297 +	if (actc == 32)			FD_SET_rjb(lisc, &rdfs);
  22.298 +
  22.299 +	/* now make exfs the union of the read and write fd sets, plus
  22.300 +	 * "actl" */
  22.301 +	{
  22.302 +	    int i;
  22.303 +	    exfs = rdfs;
  22.304 +	    for(i=0; i<32; i++)  /* XXX we only copy fd numbers up to 31 */
  22.305 +		if (FD_ISSET(i, &wrfs))
  22.306 +		    FD_SET_rjb(i, &exfs);
  22.307 +	    FD_SET_rjb(actl, &exfs);
  22.308 +	}
  22.309 +
  22.310 +	/* XXX AND: can't print something of type fd_set as %x - it
  22.311 +         * might be an array */
  22.312 +	DB(fprintf(stderr, "%s: before select: %08x %08x %08x\n",
  22.313 +		   prog_name, rdfs, wrfs, exfs));
  22.314 +	
  22.315 +	if (select(32, &rdfs, &wrfs, &exfs, NULL) < 0)
  22.316 +	    fault("select: %s\n", strerror(errno));
  22.317 +	
  22.318 +	DB(fprintf(stderr, "%s: after  select: %08x %08x %08x\n",
  22.319 +		   prog_name, rdfs, wrfs, exfs));
  22.320 +	
  22.321 +	/* XXX it appears that a non-blocking socket may not show up
  22.322 +	 * correctly in exfs but instead goes readable with no data in
  22.323 +	 * it. Thus we check for zero and goto the appropriate close
  22.324 +	 * method.  */
  22.325 +
  22.326 +	/* Deal with exceptions */
  22.327 +	if (FD_ISSET_rjb(actg, &exfs))
  22.328 +	{
  22.329 +	exfs_actg:
  22.330 +	    close(actg);
  22.331 +	    gdbmode = FALSE;
  22.332 +	    oicc = 0;
  22.333 +	    oiptr = oibuf;
  22.334 +	    actg = 32;
  22.335 +	    continue;		/* because assumptions changed */
  22.336 +	}
  22.337 +	if (FD_ISSET_rjb(acth, &exfs))
  22.338 +	{
  22.339 +	exfs_acth:
  22.340 +	    close(acth);
  22.341 +	    hicc = hocc = 0;
  22.342 +	    hiptr = hibuf;
  22.343 +	    hoptr = hibuf;
  22.344 +	    acth = 32;
  22.345 +	    continue;		/* because assumptions changed */
  22.346 +	}
  22.347 +	if (FD_ISSET_rjb(actl, &exfs) ||
  22.348 +	    FD_ISSET_rjb(acto, &exfs))
  22.349 +	{
  22.350 +	exfs_actl:
  22.351 +	exfs_acto:
  22.352 +	    /* Thats all folks ... */
  22.353 +	    break;
  22.354 +	}
  22.355 +	if (FD_ISSET_rjb(actc, &exfs))
  22.356 +	{
  22.357 +	exfs_ctl:
  22.358 +	    close(actc);
  22.359 +	    actc = 32;
  22.360 +	    ctlcc = 0;
  22.361 +	    continue;
  22.362 +	}
  22.363 +
  22.364 +	/* Deal with reading */
  22.365 +	if (FD_ISSET_rjb(acto, &rdfs))
  22.366 +	{
  22.367 +	    if ((oicc = read(acto, oiptr = oibuf, MAXSIZE)) < 0)
  22.368 +		fault("read acto: %d: %s\n", oicc, strerror(errno));
  22.369 +	    if (!oicc) goto exfs_acto;
  22.370 +	    
  22.371 +	    if (!gdbmode)
  22.372 +	    {
  22.373 +		int t;
  22.374 +
  22.375 +		assert((locc == 0) && (hocc == 0));
  22.376 +		loptr = lobuf;
  22.377 +		hoptr = hobuf;
  22.378 +		
  22.379 +		if (lish>=0) {
  22.380 +		    for(t=0; t<oicc; t++)
  22.381 +			if (oibuf[t] & 0x80)
  22.382 +			    hobuf[hocc++] = oibuf[t] & 0x7f;
  22.383 +			else
  22.384 +			    lobuf[locc++] = oibuf[t];
  22.385 +		} else {
  22.386 +		    for (t=0; t<oicc; t++)
  22.387 +			lobuf[locc++] = oibuf[t];
  22.388 +		}
  22.389 +		/* If no high connection scratch that */
  22.390 +		if (acth == 32)
  22.391 +		    hocc=0;
  22.392 +	    }
  22.393 +	}
  22.394 +	if (FD_ISSET_rjb(actl, &rdfs))
  22.395 +	{
  22.396 +	    if ((licc = read(actl, liptr = libuf, MAXSIZE)) < 0)
  22.397 +		fault("read actl: %d: %s\n", licc, strerror(errno));
  22.398 +	    if (!licc) goto exfs_actl;
  22.399 +	}
  22.400 +	if (FD_ISSET_rjb(acth, &rdfs))
  22.401 +	{
  22.402 +	    int t;
  22.403 +	    
  22.404 +	    if ((hicc = read(acth, hiptr = hibuf, MAXSIZE)) < 0)
  22.405 +		fault("read acth: %d: %s\n", hicc, strerror(errno));
  22.406 +	    if (!hicc) goto exfs_acth;
  22.407 +	    for(t=0; t<hicc; t++)
  22.408 +		hibuf[t] |= 0x80;
  22.409 +	}
  22.410 +	if (FD_ISSET_rjb(actg, &rdfs))
  22.411 +	{
  22.412 +	    if ((gicc = read(actg, giptr = gibuf, MAXSIZE)) < 0)
  22.413 +		fault("read actg: %d: %s\n", gicc, strerror(errno));
  22.414 +	    if (debug) write(1, giptr, gicc);		/* XXX */
  22.415 +	    if (!gicc) goto exfs_actg;
  22.416 +	}
  22.417 +	if (FD_ISSET_rjb(actc, &rdfs))
  22.418 +	{
  22.419 +	    if ((ctlcc = read(actc, ctlbuf, MAXSIZE)) < 0)
  22.420 +		fault("read actc: %d: %s\n", ctlcc, strerror(errno));
  22.421 +	    if (debug) write(1, ctlbuf, gicc);
  22.422 +	    if (!ctlcc) goto exfs_ctl;
  22.423 +	    if (ctlbuf[0] == 'r') /* reset command */
  22.424 +	    {
  22.425 +		syslog(LOG_INFO, "reset command read, exiting");
  22.426 +		if (debug) write(1, "reseting\n", sizeof("reseting\n"));
  22.427 +		break;
  22.428 +	    }
  22.429 +	}
  22.430 +	
  22.431 +	/* Deal with writing */
  22.432 +	if (FD_ISSET_rjb(actg, &wrfs))
  22.433 +	{
  22.434 +	    /* We must be in gdb mode so send oi buffer data */
  22.435 +	    assert(gdbmode);
  22.436 +	    if (debug) write(2, oiptr, oicc);		/* XXX */
  22.437 +	    if ((rc = write(actg, oiptr, oicc)) <= 0)
  22.438 +		fault("write actg: %d: %s\n", rc, strerror(errno));
  22.439 +	    oiptr += rc;
  22.440 +	    oicc  -= rc;
  22.441 +	}
  22.442 +	if (FD_ISSET_rjb(actl, &wrfs))
  22.443 +	{
  22.444 +	    if ((rc = write(actl, loptr, locc)) <= 0)
  22.445 +		fault("write actl: %d: %s\n", rc, strerror(errno));
  22.446 +	    loptr += rc;
  22.447 +	    locc  -= rc;
  22.448 +	}
  22.449 +	if (FD_ISSET_rjb(acth, &wrfs))
  22.450 +	{
  22.451 +	    if ((rc = write(acth, hoptr, hocc)) <= 0)
  22.452 +		fault("write acth: %d: %s\n", rc, strerror(errno));
  22.453 +	    hoptr += rc;
  22.454 +	    hocc  -= rc;
  22.455 +	}
  22.456 +	if (FD_ISSET_rjb(acto, &wrfs))
  22.457 +	{
  22.458 +	    /* If in gdb mode send gdb input, otherwise send low data
  22.459 +	       preferentially */
  22.460 +	    if (gdbmode)
  22.461 +	    {
  22.462 +		assert(gicc);
  22.463 +		if ((rc = write(acto, giptr, gicc)) <= 0)
  22.464 +		    fault("write acto: %d: %s\n", rc, strerror(errno));
  22.465 +		giptr += rc;
  22.466 +		gicc  -= rc;
  22.467 +	    }
  22.468 +	    else
  22.469 +	    {
  22.470 +		if (licc)
  22.471 +		{
  22.472 +		    if ((rc = write(acto, liptr, licc)) <= 0)
  22.473 +			fault("write acto: %d: %s\n", rc, strerror(errno));
  22.474 +		    liptr += rc;
  22.475 +		    licc  -= rc;
  22.476 +		}
  22.477 +		else
  22.478 +		{
  22.479 +		    assert(hicc);
  22.480 +		    if ((rc = write(acto, hiptr, hicc)) <= 0)
  22.481 +			fault("write acto: %d: %s\n", rc, strerror(errno));
  22.482 +		    hiptr += rc;
  22.483 +		    hicc  -= rc;
  22.484 +		}
  22.485 +	    }
  22.486 +	}
  22.487 +	
  22.488 +	/* Deals with new connections */
  22.489 +	if ((acth == 32) && lish>=0 && (FD_ISSET_rjb(lish, &rdfs)))
  22.490 +	{
  22.491 +	    fromlen = sizeof(from);
  22.492 +	    if ((acth = accept(lish, &from, &fromlen)) < 0)
  22.493 +	    {
  22.494 +		syslog(LOG_WARNING, "accept: %m");
  22.495 +		acth = 32;
  22.496 +	    }
  22.497 +	    else
  22.498 +	    {
  22.499 +		noblock(acth);
  22.500 +		hicc = hocc = 0;
  22.501 +		syslog(LOG_INFO, "highbit client peer is %s:%u\n",
  22.502 +		       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
  22.503 +	    }
  22.504 +	}
  22.505 +	
  22.506 +	if ((actg == 32) && (FD_ISSET_rjb(lisg, &rdfs)))
  22.507 +	{
  22.508 +	    fromlen = sizeof(from);
  22.509 +	    if ((actg = accept(lisg, &from, &fromlen)) < 0)
  22.510 +	    {
  22.511 +		syslog(LOG_WARNING, "accept: %m");
  22.512 +		actg = 32;
  22.513 +	    }
  22.514 +	    else
  22.515 +	    {
  22.516 +		noblock(actg);
  22.517 +		gicc = 0;
  22.518 +		gdbmode = TRUE;
  22.519 +		syslog(LOG_INFO, "gdb client peer is %s:%u\n",
  22.520 +		       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
  22.521 +	    }
  22.522 +	}
  22.523 +
  22.524 +	if ((actc == 32) && (FD_ISSET_rjb(lisc, &rdfs)))
  22.525 +	{
  22.526 +	    fromlen = sizeof(from);
  22.527 +	    if ((actc = accept(lisc, &from, &fromlen)) < 0)
  22.528 +	    {
  22.529 +		syslog(LOG_WARNING, "accept (ctl): %m");
  22.530 +		actc = 32;
  22.531 +	    }
  22.532 +	    else
  22.533 +	    {
  22.534 +		noblock(actc);
  22.535 +		syslog(LOG_INFO, "ctl client peer is %s:%u\n",
  22.536 +		       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
  22.537 +	    }
  22.538 +	}
  22.539 +	    
  22.540 +	/* Back to top of loop */
  22.541 +    }
  22.542 +    
  22.543 +    /* We are bailing because one of the primary connections has gone
  22.544 +     * away. We close these all explicitly here because that way the
  22.545 +     * timeout on reusing the port numbers is smnaller. */
  22.546 +    
  22.547 +    close(acth);
  22.548 +    close(actg);
  22.549 +    /* XXX AND: why are we closing all these "character counts" ?? */
  22.550 +    close(gicc);
  22.551 +    close(oicc);
  22.552 +    close(licc);
  22.553 +    close(locc);
  22.554 +    close(hicc);
  22.555 +    close(hocc);
  22.556 +}
  22.557 +
  22.558 +/*
  22.559 + * ------------------------------------------------------------
  22.560 + */
  22.561 +int main(int argc, char **argv)
  22.562 +{
  22.563 +    /* In general, suffix "l" is low channel, "h" is high channel, "g"
  22.564 +     * is gdb channel, "c" is control channel and "o" is output channel.
  22.565 +     */
  22.566 +    struct sockaddr_in		from;
  22.567 +    int				infd = 0, outfd;
  22.568 +    unsigned short		portl, porth, portg, portc, porto;
  22.569 +    int				on = 1, c;
  22.570 +    char			*outname, *outservice;
  22.571 +    int				fromlen;
  22.572 +    int				lish, lisg, lisc;
  22.573 +#if 0
  22.574 +    FILE			*newerr;
  22.575 +#endif /* 0 */
  22.576 +    
  22.577 +    prog_name = argv[0];
  22.578 +
  22.579 +    if (isatty(infd))
  22.580 +	usage();
  22.581 +
  22.582 +    /* Here, then not just a simple idiot. */
  22.583 +
  22.584 +    signal(SIGPIPE, SIG_IGN);
  22.585 +
  22.586 +    openlog(prog_name, LOG_PID, LOG_DAEMON);
  22.587 +
  22.588 +    fromlen = sizeof(from);
  22.589 +    if (getsockname(infd, &from, &fromlen) < 0)
  22.590 +	fault("getsockname: %s", strerror(errno));
  22.591 +    if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
  22.592 +	fault("not an inet socket (family=%d)\n", from.sin_family);
  22.593 +    
  22.594 +    portl = ntohs(from.sin_port);
  22.595 +    porth = portl+1;
  22.596 +    portg = porth+1;
  22.597 +    portc = portg+1;
  22.598 +
  22.599 +    fromlen = sizeof(from);
  22.600 +    if (getpeername(infd, &from, &fromlen) < 0)
  22.601 +	fault("getpeername: %s", strerror(errno));
  22.602 +    if ((fromlen != sizeof(from)) || (from.sin_family != AF_INET))
  22.603 +	fault("not an inet socket (family=%d)\n", from.sin_family);
  22.604 +
  22.605 +    syslog(LOG_INFO, "on port %u peer is %s:%u\n", portl,
  22.606 +	   inet_ntoa(from.sin_addr), ntohs(from.sin_port));
  22.607 +    
  22.608 +    if (setsockopt(infd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
  22.609 +	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  22.610 +
  22.611 +    /* from here on, we map stderr to output on the connection so we can
  22.612 +     * report errors to the remote user.
  22.613 +     */
  22.614 +#if 0
  22.615 +    if (!(newerr = fdopen(infd, "w")))
  22.616 +	syslog(LOG_WARNING, "fdopen: %m");
  22.617 +    else
  22.618 +	*stderr = *newerr;
  22.619 +#endif
  22.620 +	
  22.621 +    while((c = getopt(argc, argv, "d8h:g:c:")) != EOF)
  22.622 +    {
  22.623 +	switch(c)
  22.624 +	{
  22.625 +	case 'd':
  22.626 +	    debug++;
  22.627 +	    break;
  22.628 +	    
  22.629 +	case 'h':
  22.630 +	    /* high bit port */
  22.631 +	    if (getservice(optarg, &porth) < 0)
  22.632 +		fault("getservice failed (high port '%s')\n", optarg);
  22.633 +	    break;
  22.634 +	    
  22.635 +	case 'g':
  22.636 +	    /* gdb port */
  22.637 +	    if (getservice(optarg, &portg) < 0)
  22.638 +		fault("getservice failed (gdb port '%s')\n", optarg);
  22.639 +	    break;
  22.640 +
  22.641 +	case 'c':
  22.642 +	    /* control port */
  22.643 +	    if (getservice(optarg, &portc) < 0)
  22.644 +		fault("getservice failed (control port '%s')\n", optarg);
  22.645 +	    break;
  22.646 +
  22.647 +	case '8':
  22.648 +	    /* 8-bit clean; no high port */
  22.649 +	    porth=0;
  22.650 +	    break;
  22.651 +
  22.652 +	default:
  22.653 +	    fault("bad argument list!\n");
  22.654 +	}
  22.655 +    }
  22.656 +    
  22.657 +    if (argc != optind + 1)
  22.658 +	fault("unparsed arguments (%d!=%d)\n", argc, optind+1);
  22.659 +
  22.660 +    outname = argv[optind];
  22.661 +    if (!(outservice = strchr(outname, ':')))
  22.662 +	fault("output arg '%s' doesn't contain ':'\n", outname);
  22.663 +    *outservice++ = 0;
  22.664 +    if (getservice(outservice, &porto) < 0)
  22.665 +	fault("getservice failed (output port '%s')\n", outservice);
  22.666 +    
  22.667 +    /* Time to start the sockets */
  22.668 +
  22.669 +    if (porth) {
  22.670 +	lish  = startlistening(porth);
  22.671 +    } else {
  22.672 +	lish  = -1;
  22.673 +    }
  22.674 +    lisg  = startlistening(portg);
  22.675 +    lisc  = startlistening(portc);
  22.676 +    
  22.677 +    outfd = connect_host(outname, porto);
  22.678 +    
  22.679 +    doit(infd, outfd, lish, lisg, lisc);
  22.680 +
  22.681 +    syslog(LOG_INFO, "terminating normally\n");
  22.682 +
  22.683 +    fclose(stderr);
  22.684 +
  22.685 +    closelog();
  22.686 +    exit(0); 
  22.687 +}
  22.688 +
  22.689 +/* End $Id: nsplitd.c,v 2.6 1998/09/17 14:28:37 sde1000 Exp $ */
    23.1 --- a/tools/python/xen/util/ip.py	Thu Jul 01 23:45:24 2004 +0000
    23.2 +++ b/tools/python/xen/util/ip.py	Tue Jul 06 20:42:26 2004 +0000
    23.3 @@ -3,7 +3,7 @@ import re
    23.4  import socket
    23.5  import struct
    23.6  
    23.7 -def readlines(fd):
    23.8 +def _readlines(fd):
    23.9      """Version of readlines safe against EINTR.
   23.10      """
   23.11      import errno
   23.12 @@ -21,7 +21,7 @@ def readlines(fd):
   23.13          lines.append(line)
   23.14      return lines
   23.15  
   23.16 -def readline(fd):
   23.17 +def _readline(fd):
   23.18      """Version of readline safe against EINTR.
   23.19      """
   23.20      while 1:
   23.21 @@ -42,11 +42,14 @@ as it may have been moved onto the bridg
   23.22  NBE_BRIDGE = 'nbe-br'
   23.23  
   23.24  def get_current_ipaddr(dev='eth0'):
   23.25 -    """Return a string containing the primary IP address for the given
   23.26 -    network interface (default 'eth0').
   23.27 +    """Get the primary IP address for the given network interface.
   23.28 +
   23.29 +    dev     network interface (default eth0)
   23.30 +
   23.31 +    returns interface address as a string
   23.32      """
   23.33      fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   23.34 -    lines = readlines(fd)
   23.35 +    lines = _readlines(fd)
   23.36      for line in lines:
   23.37          m = re.search( '^\s+inet addr:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   23.38                         line )
   23.39 @@ -57,11 +60,14 @@ def get_current_ipaddr(dev='eth0'):
   23.40      return None
   23.41  
   23.42  def get_current_ipmask(dev='eth0'):
   23.43 -    """Return a string containing the primary IP netmask for the given
   23.44 -    network interface (default 'eth0').
   23.45 +    """Get the primary IP netmask for a network interface.
   23.46 +
   23.47 +    dev     network interface (default eth0)
   23.48 +
   23.49 +    returns interface netmask as a string
   23.50      """
   23.51      fd = os.popen( '/sbin/ifconfig ' + dev + ' 2>/dev/null' )
   23.52 -    lines = readlines(fd)
   23.53 +    lines = _readlines(fd)
   23.54      for line in lines:
   23.55          m = re.search( '^.+Mask:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*',
   23.56                         line )
   23.57 @@ -72,11 +78,14 @@ def get_current_ipmask(dev='eth0'):
   23.58      return None
   23.59  
   23.60  def get_current_ipgw(dev='eth0'):
   23.61 -    """Return a string containing the IP gateway for the given
   23.62 -    network interface (default 'eth0').
   23.63 +    """Get the IP gateway for a network interface.
   23.64 +
   23.65 +    dev     network interface (default eth0)
   23.66 +
   23.67 +    returns gateway address as a string
   23.68      """
   23.69      fd = os.popen( '/sbin/route -n' )
   23.70 -    lines = readlines(fd)
   23.71 +    lines = _readlines(fd)
   23.72      for line in lines:
   23.73          m = re.search( '^\S+\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' +
   23.74                         '\s+\S+\s+\S*G.*' + dev + '.*', line )
   23.75 @@ -88,24 +97,46 @@ def get_current_ipgw(dev='eth0'):
   23.76  
   23.77  def inet_aton(addr):
   23.78      """Convert an IP addr in IPv4 dot notation into an int.
   23.79 +
   23.80 +    addr    IP address as a string
   23.81 +
   23.82 +    returns integer
   23.83      """
   23.84      b = socket.inet_aton(addr)
   23.85      return struct.unpack('!I', b)[0]
   23.86  
   23.87  def inet_ntoa(n):
   23.88      """Convert an int into an IP addr in IPv4 dot notation.
   23.89 +
   23.90 +    n       IP address
   23.91 +
   23.92 +    returns string
   23.93      """
   23.94      b = struct.pack('!I', n)
   23.95      return socket.inet_ntoa(b)
   23.96  
   23.97  def add_offset_to_ip(addr, offset):
   23.98      """Add a numerical offset to an IP addr in IPv4 dot notation.
   23.99 +
  23.100 +    addr    IP address
  23.101 +    offset  offset to add
  23.102 +
  23.103 +    returns new address
  23.104      """
  23.105      n = inet_aton(addr)
  23.106      n += offset
  23.107      return inet_ntoa(n)
  23.108  
  23.109  def check_subnet( ip, network, netmask ):
  23.110 +    """Check if an IP address is in the subnet defined by
  23.111 +    a network address and mask'.
  23.112 +
  23.113 +    ip      IP adress
  23.114 +    network network address
  23.115 +    netmask network mask
  23.116 +    
  23.117 +    returns 1 if it is in the subnet, 0 if not
  23.118 +    """
  23.119      n_ip = inet_aton(ip)
  23.120      n_net = inet_aton(network)
  23.121      n_mask = inet_aton(netmask)
    24.1 --- a/tools/python/xen/xend/XendClient.py	Thu Jul 01 23:45:24 2004 +0000
    24.2 +++ b/tools/python/xen/xend/XendClient.py	Tue Jul 06 20:42:26 2004 +0000
    24.3 @@ -1,6 +1,11 @@
    24.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    24.5  """Client API for the HTTP interface on xend.
    24.6  Callable as a script - see main().
    24.7 +
    24.8 +This API is the 'control-plane' for xend.
    24.9 +The 'data-plane' is done separately. For example, consoles
   24.10 +are accessed via sockets on xend, but the list of consoles
   24.11 +is accessible via this API.
   24.12  """
   24.13  import sys
   24.14  import httplib
   24.15 @@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse):
   24.16  
   24.17  
   24.18  def sxprio(sxpr):
   24.19 +    """Convert an sxpr to a string.
   24.20 +    """
   24.21      io = StringIO()
   24.22      sxp.show(sxpr, out=io)
   24.23      print >> io
   24.24 @@ -80,6 +87,12 @@ def eventurl(location, root, id=''):
   24.25      return urljoin(location, root, 'event/', id)
   24.26  
   24.27  def xend_request(url, method, data=None):
   24.28 +    """Make a request to xend.
   24.29 +
   24.30 +    url    xend request url
   24.31 +    method http method: POST or GET
   24.32 +    data   request argument data (dict)
   24.33 +    """
   24.34      urlinfo = urlparse.urlparse(url)
   24.35      (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
   24.36      if DEBUG: print url, urlinfo
   24.37 @@ -122,20 +135,37 @@ def xend_request(url, method, data=None)
   24.38      return val
   24.39  
   24.40  def xend_get(url, args=None):
   24.41 +    """Make a xend request using GET.
   24.42 +    Requests using GET are 'safe' and may be repeated without
   24.43 +    nasty side-effects.
   24.44 +    """
   24.45      return xend_request(url, "GET", args)
   24.46  
   24.47  def xend_call(url, data):
   24.48 +    """Make xend request using POST.
   24.49 +    Requests using POST potentially cause side-effects and should
   24.50 +    not be repeated unless it really is wanted to do the side
   24.51 +    effect again.
   24.52 +    """
   24.53      return xend_request(url, "POST", data)
   24.54  
   24.55  class Xend:
   24.56  
   24.57 +    """Default location of the xend server."""
   24.58      SRV_DEFAULT = "localhost:8000"
   24.59 +
   24.60 +    """Default path to the xend root on the server."""
   24.61      ROOT_DEFAULT = "/xend/"
   24.62  
   24.63      def __init__(self, srv=None, root=None):
   24.64          self.bind(srv, root)
   24.65  
   24.66      def bind(self, srv=None, root=None):
   24.67 +        """Bind to a given server.
   24.68 +
   24.69 +        srv  server location (host:port)
   24.70 +        root server xend root path
   24.71 +        """
   24.72          if srv is None: srv = self.SRV_DEFAULT
   24.73          if root is None: root = self.ROOT_DEFAULT
   24.74          if not root.endswith('/'): root += '/'
   24.75 @@ -195,9 +225,10 @@ class Xend:
   24.76          return xend_call(self.domainurl(id),
   24.77                           {'op'      : 'pause'})
   24.78  
   24.79 -    def xend_domain_shutdown(self, id):
   24.80 +    def xend_domain_shutdown(self, id, reason):
   24.81          return xend_call(self.domainurl(id),
   24.82 -                         {'op'      : 'shutdown'})
   24.83 +                         {'op'      : 'shutdown',
   24.84 +                          'reason'  : reason })
   24.85  
   24.86      def xend_domain_destroy(self, id):
   24.87          return xend_call(self.domainurl(id),
    25.1 --- a/tools/python/xen/xend/XendDomain.py	Thu Jul 01 23:45:24 2004 +0000
    25.2 +++ b/tools/python/xen/xend/XendDomain.py	Tue Jul 06 20:42:26 2004 +0000
    25.3 @@ -5,8 +5,11 @@
    25.4   Needs to be persistent for one uptime.
    25.5  """
    25.6  import sys
    25.7 +import traceback
    25.8  
    25.9  from twisted.internet import defer
   25.10 +defer.Deferred.debug = 1
   25.11 +from twisted.internet import reactor
   25.12  
   25.13  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   25.14  
   25.15 @@ -28,10 +31,19 @@ eserver = EventServer.instance()
   25.16  class XendDomain:
   25.17      """Index of all domains. Singleton.
   25.18      """
   25.19 -    
   25.20 +
   25.21 +    """Path to domain database."""
   25.22      dbpath = "domain"
   25.23 +
   25.24 +    """Table of domain info indexed by domain id."""
   25.25      domain = {}
   25.26      
   25.27 +    """Table of configs for domain restart, indexed by domain id."""
   25.28 +    restarts = {}
   25.29 +
   25.30 +    """Table of delayed calls."""
   25.31 +    schedule = {}
   25.32 +    
   25.33      def __init__(self):
   25.34          self.xconsole = XendConsole.instance()
   25.35          # Table of domain info indexed by domain id.
   25.36 @@ -49,6 +61,53 @@ class XendDomain:
   25.37          print 'XendDomain> virq', val
   25.38          self.reap()
   25.39  
   25.40 +    def schedule_later(self, _delay, _name, _fn, *args):
   25.41 +        """Schedule a function to be called later (if not already scheduled).
   25.42 +
   25.43 +        _delay delay in seconds
   25.44 +        _name  schedule name
   25.45 +        _fn    function
   25.46 +        args   arguments
   25.47 +        """
   25.48 +        if self.schedule.get(_name): return
   25.49 +        self.schedule[_name] = reactor.callLater(_delay, _fn, *args)
   25.50 +        
   25.51 +    def schedule_cancel(self, name):
   25.52 +        """Cancel a scheduled function call.
   25.53 +        
   25.54 +        name schedule name to cancel
   25.55 +        """
   25.56 +        callid = self.schedule.get(name)
   25.57 +        if not callid:
   25.58 +            return
   25.59 +        if callid.active():
   25.60 +            callid.cancel()
   25.61 +        del self.schedule[name]
   25.62 +
   25.63 +    def reap_schedule(self, delay=0):
   25.64 +        """Schedule reap to be called later.
   25.65 +
   25.66 +        delay delay in seconds
   25.67 +        """
   25.68 +        self.schedule_later(delay, 'reap', self.reap)
   25.69 +
   25.70 +    def reap_cancel(self):
   25.71 +        """Cancel any scheduled reap.
   25.72 +        """
   25.73 +        self.schedule_cancel('reap')
   25.74 +
   25.75 +    def refresh_schedule(self, delay=0):
   25.76 +        """Schedule refresh to be called later.
   25.77 +        
   25.78 +        delay delay in seconds
   25.79 +        """
   25.80 +        self.schedule_later(delay, 'refresh', self.refresh)
   25.81 +
   25.82 +    def refresh_cancel(self):
   25.83 +        """Cancel any scheduled refresh.
   25.84 +        """
   25.85 +        self.schedule_cancel('refresh')
   25.86 +
   25.87      def rm_all(self):
   25.88          """Remove all domain info. Used after reboot.
   25.89          """
   25.90 @@ -145,6 +204,7 @@ class XendDomain:
   25.91          """Look for domains that have crashed or stopped.
   25.92          Tidy them up.
   25.93          """
   25.94 +        self.reap_cancel()
   25.95          print 'XendDomain>reap>'
   25.96          domlist = xc.domain_getinfo()
   25.97          casualties = []
   25.98 @@ -158,12 +218,14 @@ class XendDomain:
   25.99          for d in casualties:
  25.100              id = str(d['dom'])
  25.101              print 'XendDomain>reap> died id=', id, d
  25.102 -            self.domain_destroy(id, refresh=0)
  25.103 +            self.final_domain_destroy(id)
  25.104          print 'XendDomain>reap<'
  25.105  
  25.106      def refresh(self):
  25.107          """Refresh domain list from Xen.
  25.108          """
  25.109 +        self.refresh_cancel()
  25.110 +        print 'XendDomain>refresh>'
  25.111          domlist = xc.domain_getinfo()
  25.112          # Index the domlist by id.
  25.113          # Add entries for any domains we don't know about.
  25.114 @@ -184,7 +246,7 @@ class XendDomain:
  25.115                  d.update(dominfo)
  25.116              else:
  25.117                  self._delete_domain(d.id)
  25.118 -        self.reap()
  25.119 +        self.reap_schedule(1)
  25.120  
  25.121      def refresh_domain(self, id):
  25.122          """Refresh information for a single domain.
  25.123 @@ -267,21 +329,70 @@ class XendDomain:
  25.124          """Shutdown domain (nicely).
  25.125  
  25.126          id     domain id
  25.127 -        reason shutdown type: poweroff, reboot, halt
  25.128 +        reason shutdown type: poweroff, reboot, suspend, halt
  25.129          """
  25.130          dom = int(id)
  25.131          if dom <= 0:
  25.132              return 0
  25.133 +        self.domain_restart_schedule(id, reason)
  25.134          eserver.inject('xend.domain.shutdown', [id, reason])
  25.135 +        if reason == 'halt':
  25.136 +            reason = 'poweroff'
  25.137          val = xend.domain_shutdown(dom, reason)
  25.138 -        self.refresh()
  25.139 +        self.refresh_schedule()
  25.140          return val
  25.141 -    
  25.142 -    def domain_destroy(self, id, refresh=1):
  25.143 -        """Terminate domain immediately.
  25.144 +
  25.145 +    def domain_restart_schedule(self, id, reason):
  25.146 +        """Schedule a restart for a domain if it needs one.
  25.147 +
  25.148 +        id     domain id
  25.149 +        reason shutdown reason
  25.150 +        """
  25.151 +        if id in self.restarts:
  25.152 +            # Don't schedule if already there.
  25.153 +            return
  25.154 +        restart = 0
  25.155 +        if reason in ['poweroff', 'reboot']:
  25.156 +            dominfo = self.domain.get(id)
  25.157 +            if dominfo and (dominfo.autorestart or reason == 'reboot'):
  25.158 +                restart = 1
  25.159 +                # Clear autorestart flag to avoid multiple restarts.
  25.160 +                dominfo.autorestart = 0
  25.161 +            
  25.162 +        if restart:
  25.163 +            self.restarts[id] = dominfo.config
  25.164 +            
  25.165 +    def domain_restart_cancel(self, id):
  25.166 +        """Cancel any restart scheduled for a domain.
  25.167  
  25.168          id domain id
  25.169 -        refresh send a domain destroy event if true
  25.170 +        """
  25.171 +        dominfo = self.domain.get(id)
  25.172 +        if dominfo:
  25.173 +            dominfo.autorestart = 0
  25.174 +        if id in self.restarts:
  25.175 +            del self.restarts[id]
  25.176 +
  25.177 +    def domain_restarts(self):
  25.178 +        """Execute any scheduled domain restarts for domains that have gone.
  25.179 +        """
  25.180 +        for id in self.restarts.keys():
  25.181 +            if id in self.domain:
  25.182 +                # Don't execute restart for domains still running.
  25.183 +                continue
  25.184 +            config = self.restarts[id]
  25.185 +            # Remove it from the restarts.
  25.186 +            del self.restarts[id]
  25.187 +            try:
  25.188 +                self.domain_create(config)
  25.189 +            except:
  25.190 +                print >>sys.stderr, "XendDomain> Exception restarting domain"
  25.191 +                traceback.print_exc(sys.stderr)
  25.192 +        
  25.193 +    def final_domain_destroy(self, id):
  25.194 +        """Final destruction of a domain..
  25.195 +
  25.196 +        id domain id
  25.197          """
  25.198          dom = int(id)
  25.199          if dom <= 0:
  25.200 @@ -292,15 +403,26 @@ class XendDomain:
  25.201              val = dominfo.destroy()
  25.202          else:
  25.203              val = xc.domain_destroy(dom=dom)
  25.204 -        if refresh: self.refresh()
  25.205          return val       
  25.206  
  25.207 +    def domain_destroy(self, id):
  25.208 +        """Terminate domain immediately.
  25.209 +        Camcels any restart for the domain.
  25.210 +
  25.211 +        id domain id
  25.212 +        """
  25.213 +        self.domain_restart_cancel(id)
  25.214 +        val = self.final_domain_destroy(id)
  25.215 +        self.refresh_schedule()
  25.216 +        return val
  25.217 +
  25.218      def domain_migrate(self, id, dst):
  25.219          """Start domain migration.
  25.220  
  25.221          id domain id
  25.222          """
  25.223          # Need a cancel too?
  25.224 +        # Don't forget to cancel restart for it.
  25.225          pass
  25.226  
  25.227      def domain_save(self, id, dst, progress=0):
    26.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Jul 01 23:45:24 2004 +0000
    26.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Tue Jul 06 20:42:26 2004 +0000
    26.3 @@ -15,6 +15,7 @@ import sys
    26.4  import os
    26.5  
    26.6  from twisted.internet import defer
    26.7 +defer.Deferred.debug = 1
    26.8  
    26.9  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
   26.10  import xen.util.ip
   26.11 @@ -291,6 +292,9 @@ def vm_restore(src, progress=0):
   26.12      if dom < 0:
   26.13          raise VmError('restore failed')
   26.14      vmconfig = sxp.from_string(d['vmconfig'])
   26.15 +    if not vmconfig:
   26.16 +        raise VmError('bad vmconfig s-expression')
   26.17 +    vmconfig = vmconfig[0]
   26.18      vm.config = sxp.child_value(vmconfig, 'config')
   26.19      deferred = vm.dom_configure(dom)
   26.20      def vifs_cb(val, vm):
   26.21 @@ -362,6 +366,8 @@ class XendDomainInfo:
   26.22          self.state = self.STATE_OK
   26.23          #todo: set to migrate info if migrating
   26.24          self.migrate = None
   26.25 +        #Whether to auto-restart
   26.26 +        self.autorestart = 0
   26.27  
   26.28      def setdom(self, dom):
   26.29          self.dom = int(dom)
   26.30 @@ -417,7 +423,9 @@ class XendDomainInfo:
   26.31          self.config = config
   26.32          try:
   26.33              self.name = sxp.child_value(config, 'name')
   26.34 -            self.memory = int(sxp.child_value(config, 'memory', '128'))
   26.35 +            self.memory = int(sxp.child_value(config, 'memory') or '128')
   26.36 +            if sxp.child(config, 'autorestart'):
   26.37 +                self.autorestart = 1
   26.38              self.configure_backends()
   26.39              image = sxp.child_value(config, 'image')
   26.40              image_name = sxp.name(image)
   26.41 @@ -426,14 +434,18 @@ class XendDomainInfo:
   26.42                  raise VmError('unknown image type: ' + image_name)
   26.43              image_handler(self, image)
   26.44              deferred = self.configure()
   26.45 +            def cbok(x):
   26.46 +                print 'vm_create> cbok', x
   26.47 +                return x
   26.48 +            def cberr(err):
   26.49 +                self.destroy()
   26.50 +                return err
   26.51 +            deferred.addCallback(cbok)
   26.52 +            deferred.addErrback(cberr)
   26.53          except StandardError, ex:
   26.54              # Catch errors, cleanup and re-raise.
   26.55              self.destroy()
   26.56              raise
   26.57 -        def cbok(x):
   26.58 -            print 'vm_create> cbok', x
   26.59 -            return x
   26.60 -        deferred.addCallback(cbok)
   26.61          print 'vm_create<'
   26.62          return deferred
   26.63  
   26.64 @@ -445,7 +457,7 @@ class XendDomainInfo:
   26.65          """
   26.66          devices = []
   26.67          for d in sxp.children(self.config, 'device'):
   26.68 -            dev = sxp.child0(d)
   26.69 +            dev = sxp.child(d)
   26.70              if dev is None: continue
   26.71              if name == sxp.name(dev):
   26.72                  devices.append(dev)
   26.73 @@ -576,7 +588,7 @@ class XendDomainInfo:
   26.74          if self.recreate: return
   26.75          memory = self.memory
   26.76          name = self.name
   26.77 -        cpu = int(sxp.child_value(self.config, 'cpu', '-1'))
   26.78 +        cpu = int(sxp.child_value(self.config, 'cpu') or '-1')
   26.79          print 'init_domain>', memory, name, cpu
   26.80          dom = xc.domain_create(mem_kb= memory * 1024, name= name, cpu= cpu)
   26.81          if dom <= 0:
   26.82 @@ -641,7 +653,7 @@ class XendDomainInfo:
   26.83          devices = sxp.children(self.config, 'device')
   26.84          index = {}
   26.85          for d in devices:
   26.86 -            dev = sxp.child0(d)
   26.87 +            dev = sxp.child(d)
   26.88              if dev is None:
   26.89                  raise VmError('invalid device')
   26.90              dev_name = sxp.name(dev)
   26.91 @@ -660,7 +672,7 @@ class XendDomainInfo:
   26.92          """Set configuration flags if the vm is a backend for netif of blkif.
   26.93          """
   26.94          for c in sxp.children(self.config, 'backend'):
   26.95 -            name = sxp.name(sxp.child0(c))
   26.96 +            name = sxp.name(sxp.child(c))
   26.97              if name == 'blkif':
   26.98                  self.blkif_backend = 1
   26.99              elif name == 'netif':
  26.100 @@ -706,6 +718,10 @@ class XendDomainInfo:
  26.101              self.name = d['name']
  26.102              self.memory = d['memory']/1024
  26.103              deferred = self.configure()
  26.104 +            def cberr(err):
  26.105 +                self.destroy()
  26.106 +                return err
  26.107 +            deferred.addErrback(cberr)
  26.108          except StandardError, ex:
  26.109              self.destroy()
  26.110              raise
  26.111 @@ -738,7 +754,7 @@ def vm_image_linux(vm, image):
  26.112      """
  26.113      kernel = sxp.child_value(image, "kernel")
  26.114      cmdline = ""
  26.115 -    ip = sxp.child_value(image, "ip", "dhcp")
  26.116 +    ip = sxp.child_value(image, "ip") or "dhcp"
  26.117      if ip:
  26.118          cmdline += " ip=" + ip
  26.119      root = sxp.child_value(image, "root")
  26.120 @@ -747,7 +763,7 @@ def vm_image_linux(vm, image):
  26.121      args = sxp.child_value(image, "args")
  26.122      if args:
  26.123          cmdline += " " + args
  26.124 -    ramdisk = sxp.child_value(image, "ramdisk", '')
  26.125 +    ramdisk = sxp.child_value(image, "ramdisk") or ''
  26.126      vifs = vm.config_devices("vif")
  26.127      vm.create_domain("linux", kernel, ramdisk, cmdline, len(vifs))
  26.128      return vm
  26.129 @@ -764,7 +780,7 @@ def vm_image_netbsd(vm, image):
  26.130      #todo: Same as for linux. Is that right? If so can unify them.
  26.131      kernel = sxp.child_value(image, "kernel")
  26.132      cmdline = ""
  26.133 -    ip = sxp.child_value(image, "ip", "dhcp")
  26.134 +    ip = sxp.child_value(image, "ip") or "dhcp"
  26.135      if ip:
  26.136          cmdline += "ip=" + ip
  26.137      root = sxp.child_value(image, "root")
  26.138 @@ -793,7 +809,7 @@ def vm_dev_vif(vm, val, index):
  26.139      defer = make_vif(vm.dom, vif, vmac, vm.recreate)
  26.140      def fn(id):
  26.141          dev = xend.netif_dev(vm.dom, vif)
  26.142 -        devid = sxp.attribute(val, 'id')
  26.143 +        devid = sxp.child_value(val, 'id')
  26.144          if devid:
  26.145              dev.setprop('id', devid)
  26.146          bridge = sxp.child_value(val, "bridge")
  26.147 @@ -820,7 +836,7 @@ def vm_dev_vbd(vm, val, index):
  26.148      dev = sxp.child_value(val, 'dev')
  26.149      if not dev:
  26.150          raise VmError('vbd: Missing dev')
  26.151 -    mode = sxp.child_value(val, 'mode', 'r')
  26.152 +    mode = sxp.child_value(val, 'mode') or 'r'
  26.153      defer = make_disk(vm.dom, uname, dev, mode, vm.recreate)
  26.154      def fn(vbd):
  26.155          dev = xend.blkif_dev(vm.dom, vdev)
  26.156 @@ -922,7 +938,7 @@ def vm_field_vnet(vm, config, val, index
  26.157          if id is None:
  26.158              raise VmError('vnet: missing vif id')
  26.159          dev = vm.get_device_by_id('vif', id)
  26.160 -        #vnet = sxp.child_value(v, 'vnet', 1)
  26.161 +        #vnet = sxp.child_value(v, 'vnet') or '1'
  26.162          #mac = sxp.child_value(dev, 'mac')
  26.163          #vif = sxp.child_value(dev, 'vif')
  26.164          #vnet_bridge(vnet, mac, vm.dom, 0)
    27.1 --- a/tools/python/xen/xend/XendMigrate.py	Thu Jul 01 23:45:24 2004 +0000
    27.2 +++ b/tools/python/xen/xend/XendMigrate.py	Tue Jul 06 20:42:26 2004 +0000
    27.3 @@ -2,22 +2,125 @@
    27.4  
    27.5  import sys
    27.6  import socket
    27.7 +import time
    27.8 +
    27.9 +from twisted.internet import reactor
   27.10 +from twisted.internet import defer
   27.11 +defer.Deferred.debug = 1
   27.12 +from twisted.internet.protocol import Protocol
   27.13 +from twisted.internet.protocol import ClientFactory
   27.14  
   27.15  import sxp
   27.16  import XendDB
   27.17  import EventServer; eserver = EventServer.instance()
   27.18  
   27.19 +from xen.xend.packing import SxpPacker, SxpUnpacker
   27.20 +from xen.xend import XendDomain
   27.21 +xd = XendDomain.instance()
   27.22 +
   27.23 +
   27.24 +XFRD_PORT = 8002
   27.25 +
   27.26 +XFR_PROTO_MAJOR = 1
   27.27 +XFR_PROTO_MINOR = 0
   27.28 +
   27.29 +class Migrate(Protocol):
   27.30 +
   27.31 +    def __init__(self, minfo):
   27.32 +        self.packer = None
   27.33 +        self.unpacker = None
   27.34 +        self.minfo = minfo
   27.35 +
   27.36 +    def connectionMade(self):
   27.37 +        self.packer = SxpPacker(self.transport)
   27.38 +        self.unpacker = SxpPacker()
   27.39 +        # Send hello.
   27.40 +        self.packer.pack(['xfr.hello', XFR_PROTO_MAJOR, XFR_PROTO_MINOR])
   27.41 +        # Send migrate.
   27.42 +        vmconfig = self.minfo.vmconfig()
   27.43 +        if not vmconfig:
   27.44 +            self.loseConnection()
   27.45 +            return
   27.46 +        self.packer.pack(['xfr.migrate',
   27.47 +                          self.minfo.src_dom,
   27.48 +                          vmconfig,
   27.49 +                          self.minfo.dst_host,
   27.50 +                          self.minfo.dst_port])
   27.51 +
   27.52 +    def connectionLost(self, reason):
   27.53 +        self.minfo.closed(reason)
   27.54 +
   27.55 +    def dataReceived(self, data):
   27.56 +        try:
   27.57 +            self.unpacker.reset(data)
   27.58 +            val = self.unpacker.unpack()
   27.59 +            print 'dataReceived>', 'val=', val
   27.60 +            op = val[0]
   27.61 +            op.replace('.', '_')
   27.62 +            if op.startwith('xfr_'):
   27.63 +                fn = getattr(self, op, self.unknown)
   27.64 +            else:
   27.65 +                fn = self.unknown
   27.66 +            fn(val)
   27.67 +        except Exception, ex:
   27.68 +            print 'dataReceived>', ex
   27.69 +            pass
   27.70 +
   27.71 +    def unknown(self, val):
   27.72 +        print 'unknown>', val
   27.73 +
   27.74 +    def xfr_progress(self, val):
   27.75 +        print 'xfr_progress>', val
   27.76 +
   27.77 +    def xfr_error(self, val):
   27.78 +        # If we get an error with non-zero code the migrate failed.
   27.79 +        # An error with code zero indicates hello success.
   27.80 +        err = int(val[1])
   27.81 +        if not err: return
   27.82 +        self.minfo.error(err);
   27.83 +        self.loseConnection()
   27.84 +
   27.85 +    def xfr_ok(self, val):
   27.86 +        # An ok indicates migrate completed successfully, and contains
   27.87 +        # the new domain id on the remote system.
   27.88 +        dom = int(val[1])
   27.89 +        self.minfo.ok(dom)
   27.90 +        self.loseConnection()
   27.91 +
   27.92 +class MigrateClientFactory(ClientFactory):
   27.93 +
   27.94 +    def __init__(self, minfo):
   27.95 +        ClientFactory.__init__(self)
   27.96 +        self.minfo = minfo
   27.97 +
   27.98 +    def startedConnecting(self, connector):
   27.99 +        print 'Started to connect', 'self=', self, 'connector=', connector
  27.100 +
  27.101 +    def buildProtocol(self, addr):
  27.102 +        print 'buildProtocol>', addr
  27.103 +        return Migrate(self.minfo)
  27.104 +
  27.105 +    def clientConnectionLost(self, connector, reason):
  27.106 +        print 'clientConnectionLost>', 'connector=', connector, 'reason=', reason
  27.107 +
  27.108 +    def clientConnectionFailed(self, connector, reason):
  27.109 +        print 'clientConnectionFailed>', 'connector=', connector, 'reason=', reason
  27.110 +
  27.111 +
  27.112  class XendMigrateInfo:
  27.113  
  27.114      # states: begin, active, failed, succeeded?
  27.115  
  27.116 -    def __init__(self, id, dom, dst):
  27.117 +    def __init__(self, id, dom, host, port):
  27.118          self.id = id
  27.119          self.state = 'begin'
  27.120          self.src_host = socket.gethostname()
  27.121          self.src_dom = dom
  27.122          self.dst_host = dst
  27.123 +        self.dst_port = port
  27.124          self.dst_dom = None
  27.125 +        self.start = 0
  27.126 +        self.deferred = defer.Deferred()
  27.127          
  27.128      def set_state(self, state):
  27.129          self.state = state
  27.130 @@ -29,12 +132,33 @@ class XendMigrateInfo:
  27.131          sxpr = ['migrate', ['id', self.id], ['state', self.state] ]
  27.132          sxpr_src = ['src', ['host', self.src_host], ['domain', self.src_dom] ]
  27.133          sxpr.append(sxpr_src)
  27.134 -        sxpr_dst = ['dst', ['host', self.dst] ]
  27.135 +        sxpr_dst = ['dst', ['host', self.dst_host] ]
  27.136          if self.dst_dom:
  27.137              sxpr_dst.append(['domain', self.dst_dom])
  27.138          sxpr.append(sxpr_dst)
  27.139          return sxpr
  27.140 -    
  27.141 +
  27.142 +    def vmconfig(self):
  27.143 +        dominfo = xd.domain_get(self.dom)
  27.144 +        if dominfo:
  27.145 +            val = return sxp.to_string(dominfo)
  27.146 +        else:
  27.147 +            val = None
  27.148 +        return None
  27.149 +
  27.150 +    def error(self, err):
  27.151 +        self.state = 'error'
  27.152 +
  27.153 +    def ok(self, dom):
  27.154 +        self.state = 'ok'
  27.155 +        self.dst_dom = dom
  27.156 +
  27.157 +    def close(self):
  27.158 +        if self.state =='ok':
  27.159 +            eserver.inject('xend.migrate.ok', self.sxpr())
  27.160 +        else:
  27.161 +            self.state = 'error'
  27.162 +            eserver.inject('xend.migrate.error', self.sxpr())
  27.163  
  27.164  class XendMigrate:
  27.165      # Represents migration in progress.
  27.166 @@ -84,15 +208,15 @@ class XendMigrate:
  27.167      def migrate_get(self, id):
  27.168          return self.migrate.get(id)
  27.169      
  27.170 -    def migrate_begin(self, dom, dst):
  27.171 +    def migrate_begin(self, dom, host):
  27.172          # Check dom for existence, not migrating already.
  27.173 -        # Create migrate info, tell xend to migrate it?
  27.174 -        # - or fork migrate command ourselves?
  27.175          # Subscribe to migrate notifications (for updating).
  27.176          id = self.nextid()
  27.177 -        info = XenMigrateInfo(id, dom, dst)
  27.178 +        info = XenMigrateInfo(id, dom, host, XFRD_PORT)
  27.179          self._add_migrate(id, info)
  27.180 -        return id
  27.181 +        mcf = MigrateClientFactory(info)
  27.182 +        reactor.connectTCP('localhost', XFRD_PORT, mcf)
  27.183 +        return info.deferred
  27.184  
  27.185  def instance():
  27.186      global inst
    28.1 --- a/tools/python/xen/xend/XendRoot.py	Thu Jul 01 23:45:24 2004 +0000
    28.2 +++ b/tools/python/xen/xend/XendRoot.py	Tue Jul 06 20:42:26 2004 +0000
    28.3 @@ -145,7 +145,7 @@ class XendRoot:
    28.4          val	default value (optional, defaults to None)
    28.5          returns value
    28.6          """
    28.7 -        return sxp.child_value(self.config, name, val=val)
    28.8 +        return sxp.child_value(self.config, name) or val
    28.9  
   28.10  def instance():
   28.11      global inst
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tools/python/xen/xend/packing.py	Tue Jul 06 20:42:26 2004 +0000
    29.3 @@ -0,0 +1,329 @@
    29.4 +
    29.5 +# XDR-style packer/unpacker for sxpr.
    29.6 +#
    29.7 +# string -> [STRING] [len:u16] <len bytes>
    29.8 +# atom   -> [ATOM]   [len:u16] <len bytes>
    29.9 +# int    -> [UINT]   [value]
   29.10 +# list   -> [LIST]   {1 elt}* 0
   29.11 +# null   -> [NULL]
   29.12 +# none   -> [NONE]
   29.13 +# bool   -> [BOOL]   { 0:u8 | 1:u8 }
   29.14 +#
   29.15 +# types packed as u16.
   29.16 +#
   29.17 +# So (a b c) -> [LIST] 1 a 1 b 1 c 0
   29.18 +#    ()      -> [LIST] 0
   29.19 +
   29.20 +import struct
   29.21 +
   29.22 +try:
   29.23 +    from cStringIO import StringIO as _StringIO
   29.24 +except ImportError:
   29.25 +    from StringIO import StringIO as _StringIO
   29.26 +
   29.27 +import types
   29.28 +
   29.29 +class Error(Exception):
   29.30 +    
   29.31 +    def __init__(self, msg):
   29.32 +        self.msg = msg
   29.33 +        
   29.34 +    def __repr__(self):
   29.35 +        return repr(self.msg)
   29.36 +    
   29.37 +    def __str__(self):
   29.38 +        return str(self.msg)
   29.39 +
   29.40 +
   29.41 +class ConversionError(Error):
   29.42 +    pass
   29.43 +
   29.44 +BOOL_SIZE   = 1
   29.45 +BOOL_FMT    = '>B'
   29.46 +
   29.47 +BYTE_SIZE   = 1
   29.48 +BYTE_FMT    = '>b'
   29.49 +UBYTE_FMT   = '>B'
   29.50 +
   29.51 +SHORT_SIZE  = 2
   29.52 +SHORT_FMT   = '>h'
   29.53 +USHORT_FMT  = '>H'
   29.54 +
   29.55 +INT_SIZE   =  4
   29.56 +INT_FMT    = '>l'
   29.57 +UINT_FMT   = '>L'
   29.58 +
   29.59 +NONE_CODE   = 0
   29.60 +NULL_CODE   = 1
   29.61 +INT_CODE    = 2
   29.62 +STRING_CODE = 3
   29.63 +ATOM_CODE   = 4
   29.64 +BOOL_CODE   = 5
   29.65 +LIST_CODE   = 10
   29.66 +
   29.67 +class Packer:
   29.68 +    
   29.69 +    def __init__(self, io=None):
   29.70 +        self.reset(io=io)
   29.71 +
   29.72 +    def reset(self, io=None):
   29.73 +        if io is None:
   29.74 +            io = _StringIO()
   29.75 +        self.io = io
   29.76 +
   29.77 +    def get_buffer(self):
   29.78 +        return self.io.getvalue()
   29.79 +
   29.80 +    def get_io(self):
   29.81 +        return self.io
   29.82 +
   29.83 +    def struct_pack(self, fmt, x):
   29.84 +        try:
   29.85 +            self.io.write(struct.pack(fmt, x))
   29.86 +        except struct.error, msg:
   29.87 +            raise ConversionError, msg
   29.88 +
   29.89 +    def pack_none(self):
   29.90 +        pass
   29.91 +    
   29.92 +    def pack_bool(self, x):
   29.93 +        # { '1' | '0' }
   29.94 +        print 'bool>', x
   29.95 +        if x:
   29.96 +            self.io.write('\1')
   29.97 +        else:
   29.98 +            self.io.write('\0')
   29.99 +
  29.100 +    def pack_byte(self, x):
  29.101 +        self.struct_pack(BYTE_FMT, x & 0xff)
  29.102 +
  29.103 +    def pack_char(self, x):
  29.104 +        print 'char>', x
  29.105 +        self.io.write(x)
  29.106 +        
  29.107 +    def pack_ubyte(self, x):
  29.108 +        print 'ubyte>', x
  29.109 +        self.struct_pack(UBYTE_FMT, x & 0xff)
  29.110 +
  29.111 +    def pack_ushort(self, x):
  29.112 +        print 'ushort>', x
  29.113 +        self.struct_pack(USHORT_FMT, x & 0xffff)
  29.114 +        
  29.115 +    def pack_short(self, x):
  29.116 +        print 'short>', x
  29.117 +        self.struct_pack(SHORT_FMT, x & 0xffff)
  29.118 +
  29.119 +    def pack_uint(self, x):
  29.120 +        print 'uint>', x
  29.121 +        self.struct_pack(UINT_FMT, x)
  29.122 +        
  29.123 +    def pack_int(self, x):
  29.124 +        print 'int>', x
  29.125 +        self.struct_pack(INT_FMT, x)
  29.126 +
  29.127 +    def pack_uhyper(self, x):
  29.128 +        print 'uhyper>', x
  29.129 +        self.pack_uint(x>>32 & 0xffffffffL)
  29.130 +        self.pack_uint(x & 0xffffffffL)
  29.131 +
  29.132 +    pack_hyper = pack_uhyper
  29.133 +
  29.134 +    def pack_fstring(self, n, x):
  29.135 +        print 'fstring>', x
  29.136 +        self.io.write(x)
  29.137 +
  29.138 +    pack_fopaque = pack_fstring
  29.139 +
  29.140 +    def pack_string(self, x):
  29.141 +        print 'string>', x
  29.142 +        n = len(x)
  29.143 +        self.pack_ushort(n)
  29.144 +        self.pack_fstring(n, x)
  29.145 +
  29.146 +    pack_opaque = pack_string
  29.147 +    pack_bytes = pack_string
  29.148 +
  29.149 +    def pack_list(self, x, pack_item):
  29.150 +        print 'list>', x
  29.151 +        # { '1' <item> }* '0'
  29.152 +        for item in x:
  29.153 +            self.pack_bool(1)
  29.154 +            pack_item(item)
  29.155 +        self.pack_bool(0)
  29.156 +
  29.157 +    def pack_farray(self, x, pack_item):
  29.158 +        # <item>*
  29.159 +        # Can pass n and check length - but is it worth it?
  29.160 +        print 'farray>', list
  29.161 +        for item in x:
  29.162 +            pack_item(item)
  29.163 +
  29.164 +    def pack_array(self, x, pack_item):
  29.165 +        # n <item>*n
  29.166 +        print 'array>', x
  29.167 +        self.pack_uint(len(x))
  29.168 +        self.pack_farray(x, pack_item)
  29.169 +
  29.170 +class Unpacker:
  29.171 +
  29.172 +    def __init__(self, data):
  29.173 +        self.reset(data)
  29.174 +
  29.175 +    def reset(self, data):
  29.176 +        if isinstance(data, types.StringType):
  29.177 +            data = _StringIO(data)
  29.178 +        self.io = data
  29.179 +
  29.180 +    def get_bytes(self, n):
  29.181 +        if n < 0:
  29.182 +            raise ConversionError('negative byte count')
  29.183 +        data = self.io.read(n)
  29.184 +        return data
  29.185 +
  29.186 +    def struct_unpack(self, fmt, n):
  29.187 +        data = self.get_bytes(n)
  29.188 +        try:
  29.189 +            return struct.unpack(fmt, data)[0]
  29.190 +        except struct.error, msg:
  29.191 +            raise ConversionError, msg
  29.192 +       
  29.193 +    def unpack_none(self):
  29.194 +        return None
  29.195 +
  29.196 +    def unpack_bool(self):
  29.197 +        return self.struct_unpack(BOOL_FMT, BOOL_SIZE)
  29.198 +
  29.199 +    def unpack_char(self):
  29.200 +        return self.get_bytes(1)[0]
  29.201 +
  29.202 +    def unpack_byte(self):
  29.203 +        return self.struct_unpack(BYTE_FMT, BYTE_SIZE)
  29.204 +    
  29.205 +    def unpack_ubyte(self):
  29.206 +        return self.struct_unpack(UBYTE_FMT, BYTE_SIZE)
  29.207 +    
  29.208 +    def unpack_ushort(self):
  29.209 +        return self.struct_unpack(USHORT_FMT, SHORT_SIZE)
  29.210 +
  29.211 +    def unpack_short(self):
  29.212 +        return self.struct_unpack(SHORT_FMT, SHORT_SIZE)
  29.213 +        
  29.214 +    def unpack_uint(self):
  29.215 +        x = self.struct_unpack(UINT_FMT, UINT_SIZE)
  29.216 +        try:
  29.217 +            return int(x)
  29.218 +        except OverflowError:
  29.219 +            return x
  29.220 +
  29.221 +    def unpack_int(self):
  29.222 +        return self.struct_unpack(INT_FMT, INT_SIZE)
  29.223 +
  29.224 +    def unpack_uhyper(self):
  29.225 +        hi = self.unpack_uint()
  29.226 +        lo = self.unpack_uint()
  29.227 +        return long(hi)<<32 | lo
  29.228 +
  29.229 +    def unpack_hyper(self):
  29.230 +        x = self.unpack_uhyper()
  29.231 +        if x >= 0x8000000000000000L:
  29.232 +            x = x - 0x10000000000000000L
  29.233 +        return x
  29.234 +
  29.235 +    def unpack_fstring(self, n):
  29.236 +        return self.get_bytes(n)
  29.237 +
  29.238 +    unpack_fopaque = unpack_fstring
  29.239 +
  29.240 +    def unpack_string(self):
  29.241 +        n = self.unpack_ushort()
  29.242 +        return self.unpack_fstring(n)
  29.243 +
  29.244 +    unpack_opaque = unpack_string
  29.245 +    unpack_bytes = unpack_string
  29.246 +
  29.247 +    def unpack_list(self, unpack_item):
  29.248 +        list = []
  29.249 +        while self.unpack_bool():
  29.250 +            list.append(unpack_item())
  29.251 +        return list
  29.252 +
  29.253 +    def unpack_farray(self, n, unpack_item):
  29.254 +        list = []
  29.255 +        for i in range(n):
  29.256 +            list.append(unpack_item())
  29.257 +        return list
  29.258 +
  29.259 +    def unpack_array(self, unpack_item):
  29.260 +        n = self.unpack_ushort()
  29.261 +        return self.unpack_farray(n, unpack_item)
  29.262 +
  29.263 +class SxpPacker(Packer):
  29.264 +
  29.265 +    pack_code = Packer.pack_ushort
  29.266 +
  29.267 +    def pack(self, x):
  29.268 +        if isinstance(x, types.NoneType):
  29.269 +            self.pack_code(NONE_CODE)
  29.270 +            self.pack_none()
  29.271 +        elif isinstance(x, types.IntType):
  29.272 +            self.pack_code(INT_CODE)
  29.273 +            self.pack_int(x)
  29.274 +        elif isinstance(x, types.StringType):
  29.275 +            self.pack_code(STRING_CODE)
  29.276 +            self.pack_string(x)
  29.277 +        elif isinstance(x, types.ListType):
  29.278 +            self.pack_code(LIST_CODE)
  29.279 +            self.pack_list(x, self.pack)
  29.280 +        else:
  29.281 +           raise Error('invalid type ' + str(type(x)))
  29.282 +
  29.283 +class SxpUnpacker(Unpacker):
  29.284 +
  29.285 +    unpack_code = Unpacker.unpack_ushort
  29.286 +
  29.287 +    def unpack(self):
  29.288 +        code = self.unpack_code()
  29.289 +        if code == NONE_CODE:
  29.290 +            val = self.unpack_none()
  29.291 +        elif code == INT_CODE:
  29.292 +            val = self.unpack_int()
  29.293 +        elif code == BOOL_CODE:
  29.294 +            val = self.unpack_bool()
  29.295 +        elif code == STRING_CODE:
  29.296 +            val = self.unpack_string()
  29.297 +        elif code == ATOM_CODE:
  29.298 +            val = self.unpack_string()
  29.299 +        elif code == LIST_CODE:
  29.300 +            val = self.unpack_list(self.unpack)
  29.301 +        else:
  29.302 +            raise Error('invalid code ' + str(code))
  29.303 +        return val
  29.304 +
  29.305 +def main():
  29.306 +    d = "['vfarm', ['@', ['name', 'vfarm1']], ['memory', 1024], ['image', 'splinux'], ['args', 'root=/dev/nfs ip=dhcp'], [ 1, -1, 1000000]]"
  29.307 +    print"> len=", len(d), "d=", d
  29.308 +    obj = ['vfarm', ['@', ['name', 'vfarm1']],
  29.309 +           ['memory', 1024],
  29.310 +           ['image', 'splinux'],
  29.311 +           ['args', 'root=/dev/nfs ip=dhcp'],
  29.312 +           [ 1, -1, 1000000] ]
  29.313 +    print "> obj=", obj
  29.314 +    pack = SxpPacker()
  29.315 +    pack.pack(obj)
  29.316 +    data = pack.get_buffer()
  29.317 +    print "> len=", len(data), "data=", data
  29.318 +    unpack = SxpUnpacker(data)
  29.319 +    obj_unpack = unpack.unpack()
  29.320 +    print "> obj=", obj_unpack
  29.321 +    #obj = [100,101,102, 999.00234, { 'a': 1, 'b': 2 } ]
  29.322 +    #pack.reset()
  29.323 +    #pack.pack_item(obj)
  29.324 +    #data = pack.get_buffer()
  29.325 +    #print "> obj=", obj
  29.326 +    #print "> len=", len(data), "data=", data
  29.327 +    #unpack.reset(data)
  29.328 +    #obj_unpack = unpack.unpack_item()
  29.329 +    #print "> obj=", obj_unpack
  29.330 +    
  29.331 +if __name__ == "__main__":
  29.332 +    main()
    30.1 --- a/tools/python/xen/xend/server/SrvBase.py	Thu Jul 01 23:45:24 2004 +0000
    30.2 +++ b/tools/python/xen/xend/server/SrvBase.py	Tue Jul 06 20:42:26 2004 +0000
    30.3 @@ -8,6 +8,7 @@ import types
    30.4  import StringIO
    30.5  
    30.6  from twisted.internet import defer
    30.7 +defer.Deferred.debug = 1
    30.8  from twisted.internet import reactor
    30.9  from twisted.web import error
   30.10  from twisted.web import resource
    31.1 --- a/tools/python/xen/xend/server/SrvDaemon.py	Thu Jul 01 23:45:24 2004 +0000
    31.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py	Tue Jul 06 20:42:26 2004 +0000
    31.3 @@ -23,6 +23,7 @@ from twisted.internet import reactor
    31.4  from twisted.internet import protocol
    31.5  from twisted.internet import abstract
    31.6  from twisted.internet import defer
    31.7 +defer.Deferred.debug = 1
    31.8  
    31.9  from xen.lowlevel import xu
   31.10  
    32.1 --- a/tools/python/xen/xend/server/SrvDomain.py	Thu Jul 01 23:45:24 2004 +0000
    32.2 +++ b/tools/python/xen/xend/server/SrvDomain.py	Tue Jul 06 20:42:26 2004 +0000
    32.3 @@ -27,7 +27,11 @@ class SrvDomain(SrvDir):
    32.4          return val
    32.5  
    32.6      def op_shutdown(self, op, req):
    32.7 -        val = self.xd.domain_shutdown(self.dom.id)
    32.8 +        #val = self.xd.domain_shutdown(self.dom.id)
    32.9 +        fn = FormFn(self.xd.domain_shutdown,
   32.10 +                    [['dom', 'int'],
   32.11 +                     ['reason', 'str']])
   32.12 +        val = fn(req.args, {'dom': self.dom.id})
   32.13          req.setResponseCode(202)
   32.14          req.setHeader("Location", "%s/.." % req.prePathURL())
   32.15          return val
    33.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py	Thu Jul 01 23:45:24 2004 +0000
    33.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py	Tue Jul 06 20:42:26 2004 +0000
    33.3 @@ -1,5 +1,6 @@
    33.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    33.5  
    33.6 +import traceback
    33.7  from StringIO import StringIO
    33.8  
    33.9  from twisted.protocols import http
   33.10 @@ -24,6 +25,7 @@ class SrvDomainDir(SrvDir):
   33.11          val = None
   33.12          try:
   33.13              dom = self.xd.domain_get(x)
   33.14 +            if not dom: raise KeyError('No such domain')
   33.15              val = SrvDomain(dom)
   33.16          except KeyError, ex:
   33.17              print 'SrvDomainDir>', ex
   33.18 @@ -38,6 +40,9 @@ class SrvDomainDir(SrvDir):
   33.19          return v
   33.20  
   33.21      def op_create(self, op, req):
   33.22 +        """Create a domain.
   33.23 +        Expects the domain config in request parameter 'config' in SXP format.
   33.24 +        """
   33.25          ok = 0
   33.26          try:
   33.27              configstring = req.args.get('config')[0]
   33.28 @@ -48,7 +53,8 @@ class SrvDomainDir(SrvDir):
   33.29              config = pin.get_val()
   33.30              ok = 1
   33.31          except Exception, ex:
   33.32 -            print 'op_create>', ex
   33.33 +            print 'op_create> Exception in config', ex
   33.34 +            traceback.print_exc()
   33.35          if not ok:
   33.36              req.setResponseCode(http.BAD_REQUEST, "Invalid configuration")
   33.37              return "Invalid configuration"
   33.38 @@ -57,19 +63,20 @@ class SrvDomainDir(SrvDir):
   33.39                                     "Invalid configuration")
   33.40          try:
   33.41              deferred = self.xd.domain_create(config)
   33.42 -            deferred.addCallback(self._cb_op_create, configstring, req)
   33.43 +            deferred.addCallback(self._op_create_cb, configstring, req)
   33.44 +            deferred.addErrback(self._op_create_err, req)
   33.45              return deferred
   33.46          except Exception, ex:
   33.47 -            raise
   33.48 -            #return ['err', str(ex) ]
   33.49 -            #req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
   33.50 -            #return str(ex)
   33.51 +            print 'op_create> Exception creating domain:'
   33.52 +            traceback.print_exc()
   33.53 +            req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
   33.54 +            return str(ex)
   33.55              #return error.ErrorPage(http.BAD_REQUEST,
   33.56              #                       "Error creating domain",
   33.57              #                       str(ex))
   33.58                                     
   33.59  
   33.60 -    def _cb_op_create(self, dominfo, configstring, req):
   33.61 +    def _op_create_cb(self, dominfo, configstring, req):
   33.62          """Callback to handle deferred domain creation.
   33.63          """
   33.64          dom = dominfo.id
   33.65 @@ -89,7 +96,16 @@ class SrvDomainDir(SrvDir):
   33.66              out.close()
   33.67              return val
   33.68  
   33.69 +    def _op_create_err(self, err, req):
   33.70 +        """Callback to handle errors in deferred domain creation.
   33.71 +        """
   33.72 +        print 'op_create> Deferred Exception creating domain:', err
   33.73 +        req.setResponseCode(http.BAD_REQUEST, "Error creating domain")
   33.74 +        return str(err)
   33.75 +
   33.76      def op_restore(self, op, req):
   33.77 +        """Restore a domain from file.
   33.78 +        """
   33.79          fn = FormFn(self.xd.domain_restore,
   33.80                      [['file', 'str']])
   33.81          val = fn(req.args)
   33.82 @@ -131,6 +147,8 @@ class SrvDomainDir(SrvDir):
   33.83              req.write('</ul>')
   33.84  
   33.85      def form(self, req):
   33.86 +        """Generate the form(s) for domain dir operations.
   33.87 +        """
   33.88          req.write('<form method="post" action="%s" enctype="multipart/form-data">'
   33.89                    % req.prePathURL())
   33.90          req.write('<button type="submit" name="op" value="create">Create Domain</button>')
    34.1 --- a/tools/python/xen/xend/server/blkif.py	Thu Jul 01 23:45:24 2004 +0000
    34.2 +++ b/tools/python/xen/xend/server/blkif.py	Tue Jul 06 20:42:26 2004 +0000
    34.3 @@ -1,4 +1,7 @@
    34.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    34.5 +
    34.6  from twisted.internet import defer
    34.7 +defer.Deferred.debug = 1
    34.8  
    34.9  from xen.xend import sxp
   34.10  from xen.xend import PrettyPrint
   34.11 @@ -18,53 +21,78 @@ class BlkifControllerFactory(controller.
   34.12          self.majorTypes = [ CMSG_BLKIF_BE ]
   34.13  
   34.14          self.subTypes = {
   34.15 -            CMSG_BLKIF_BE_CREATE     : self.recv_be_create,
   34.16 -            CMSG_BLKIF_BE_CONNECT    : self.recv_be_connect,
   34.17 -            CMSG_BLKIF_BE_VBD_CREATE : self.recv_be_vbd_create,
   34.18 -            CMSG_BLKIF_BE_VBD_GROW   : self.recv_be_vbd_grow,
   34.19              CMSG_BLKIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
   34.20              }
   34.21          self.attached = 1
   34.22          self.registerChannel()
   34.23  
   34.24      def createInstance(self, dom, recreate=0):
   34.25 -        d = self.addDeferred()
   34.26 +        """Create a block device controller for a domain.
   34.27 +
   34.28 +        dom      domain
   34.29 +        recreate if true it's a recreate (after xend restart)
   34.30 +        """
   34.31 +        d = defer.Deferred()
   34.32          blkif = self.getInstanceByDom(dom)
   34.33          if blkif:
   34.34 -            self.callDeferred(blkif)
   34.35 +            d.callback(blkif)
   34.36          else:
   34.37              blkif = BlkifController(self, dom)
   34.38              self.addInstance(blkif)
   34.39              if recreate:
   34.40 -                self.callDeferred(blkif)
   34.41 +                d.callback(blkif)
   34.42              else:
   34.43 -                blkif.send_be_create()
   34.44 +                d1 = defer.Deferred()
   34.45 +                d1.addCallback(self.respond_be_create, d)
   34.46 +                d1.addErrback(d.errback)
   34.47 +                blkif.send_be_create(response=d1)
   34.48          return d
   34.49  
   34.50      def getDomainDevices(self, dom):
   34.51 +        """Get the block devices for a domain.
   34.52 +
   34.53 +        dom domain
   34.54 +
   34.55 +        returns devices
   34.56 +        """
   34.57          blkif = self.getInstanceByDom(dom)
   34.58          return (blkif and blkif.getDevices()) or []
   34.59  
   34.60      def getDomainDevice(self, dom, vdev):
   34.61 +        """Get a block device from a domain.
   34.62 +
   34.63 +        dom  domain
   34.64 +        vdev device index
   34.65 +
   34.66 +        returns device
   34.67 +        """
   34.68          blkif = self.getInstanceByDom(dom)
   34.69          return (blkif and blkif.getDevice(vdev)) or None
   34.70  
   34.71      def setControlDomain(self, dom, recreate=0):
   34.72 +        """Set the back-end block device controller domain.
   34.73 +
   34.74 +        dom      domain
   34.75 +        recreate if true it's a recreate (after xend restart)
   34.76 +        """
   34.77          if self.dom == dom: return
   34.78          self.deregisterChannel()
   34.79          if not recreate:
   34.80              self.attached = 0
   34.81          self.dom = dom
   34.82          self.registerChannel()
   34.83 -        #
   34.84 -        #if xend.blkif.be_port:
   34.85 -        #    xend.blkif.recovery = True
   34.86 -        #xend.blkif.be_port = xend.main.port_from_dom(dom)
   34.87  
   34.88      def getControlDomain(self):
   34.89 +        """Get the back-end block device controller domain.
   34.90 +        """
   34.91          return self.dom
   34.92  
   34.93      def reattachDevice(self, dom, vdev):
   34.94 +        """Reattach a device (on changing control domain).
   34.95 +
   34.96 +        dom  domain
   34.97 +        vdev device index
   34.98 +        """
   34.99          blkif = self.getInstanceByDom(dom)
  34.100          if blkif:
  34.101              blkif.reattachDevice(vdev)
  34.102 @@ -83,17 +111,20 @@ class BlkifControllerFactory(controller.
  34.103          return attached
  34.104                           
  34.105      def reattached(self):
  34.106 +        """Notify all block interface we have been reattached
  34.107 +        (after changing control domain).
  34.108 +        """
  34.109          for blkif in self.getInstances():
  34.110              blkif.reattached()
  34.111  
  34.112 -    def recv_be_create(self, msg, req):
  34.113 -        #print 'recv_be_create>'
  34.114 +    def respond_be_create(self, msg, d):
  34.115 +        print 'respond_be_create>'
  34.116          val = unpackMsg('blkif_be_create_t', msg)
  34.117          blkif = self.getInstanceByDom(val['domid'])
  34.118 -        self.callDeferred(blkif)
  34.119 +        d.callback(blkif)
  34.120      
  34.121 -    def recv_be_connect(self, msg, req):
  34.122 -        #print 'recv_be_create>'
  34.123 +    def respond_be_connect(self, msg):
  34.124 +        print 'respond_be_connect>', self
  34.125          val = unpackMsg('blkif_be_connect_t', msg)
  34.126          blkif = self.getInstanceByDom(val['domid'])
  34.127          if blkif:
  34.128 @@ -101,25 +132,30 @@ class BlkifControllerFactory(controller.
  34.129          else:
  34.130              pass
  34.131      
  34.132 -    def recv_be_vbd_create(self, msg, req):
  34.133 -        #print 'recv_be_vbd_create>'
  34.134 +    def respond_be_vbd_create(self, msg, d):
  34.135 +        print 'recv_be_vbd_create>', self
  34.136          val = unpackMsg('blkif_be_vbd_create_t', msg)
  34.137          blkif = self.getInstanceByDom(val['domid'])
  34.138          if blkif:
  34.139 -            blkif.send_be_vbd_grow(val['vdevice'])
  34.140 +            d1 = defer.Deferred()
  34.141 +            d1.addCallback(self.respond_be_vbd_grow, d)
  34.142 +            if d: d1.addErrback(d.errback)
  34.143 +            blkif.send_be_vbd_grow(val['vdevice'], response=d1)
  34.144          else:
  34.145              pass
  34.146      
  34.147 -    def recv_be_vbd_grow(self, msg, req):
  34.148 -        #print 'recv_be_vbd_grow>'
  34.149 +    def respond_be_vbd_grow(self, msg, d):
  34.150 +        print 'recv_be_vbd_grow>', self
  34.151          val = unpackMsg('blkif_be_vbd_grow_t', msg)
  34.152          # Check status?
  34.153          if self.attached:
  34.154 -            self.callDeferred(0)
  34.155 +            if d:
  34.156 +                d.callback(0)
  34.157          else:
  34.158              self.reattachDevice(val['domid'], val['vdevice'])
  34.159  
  34.160      def recv_be_driver_status_changed(self, msg, req):
  34.161 +        print 'recv_be_driver_status_changed>', self, req
  34.162          val = unpackMsg('blkif_be_driver_status_changed_t', msg)
  34.163          status = val['status']
  34.164          if status == BLKIF_DRIVER_STATUS_UP and not self.attached:
  34.165 @@ -147,7 +183,6 @@ class BlkDev(controller.Dev):
  34.166          return val
  34.167  
  34.168      def destroy(self):
  34.169 -        print 'BlkDev>destroy>', self.vdev
  34.170          PrettyPrint.prettyprint(self.sxpr())
  34.171          self.controller.send_be_vbd_destroy(self.vdev)
  34.172          
  34.173 @@ -157,7 +192,6 @@ class BlkifController(controller.Control
  34.174      """
  34.175      
  34.176      def __init__(self, factory, dom):
  34.177 -        #print 'BlkifController> dom=', dom
  34.178          controller.Controller.__init__(self, factory, dom)
  34.179          self.devices = {}
  34.180  
  34.181 @@ -172,7 +206,6 @@ class BlkifController(controller.Control
  34.182          self.attached = 1
  34.183          self.evtchn = None
  34.184          self.registerChannel()
  34.185 -        #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
  34.186  
  34.187      def sxpr(self):
  34.188          val = ['blkif', ['dom', self.dom]]
  34.189 @@ -182,11 +215,6 @@ class BlkifController(controller.Control
  34.190                          self.evtchn['port2']])
  34.191          return val
  34.192  
  34.193 -    def lostChannel(self):
  34.194 -        print 'BlkifController>lostChannel>', 'dom=', self.dom
  34.195 -        #self.destroyDevices()
  34.196 -        controller.Controller.lostChannel(self)
  34.197 -
  34.198      def getDevices(self):
  34.199          return self.devices.values()
  34.200  
  34.201 @@ -201,26 +229,32 @@ class BlkifController(controller.Control
  34.202  
  34.203      def attachDevice(self, vdev, mode, segment, recreate=0):
  34.204          """Attach a device to the specified interface.
  34.205 +
  34.206 +        vdev     device index
  34.207 +        mode     read/write mode
  34.208 +        segment  segment
  34.209 +        recreate if true it's being recreated (after xend restart)
  34.210 +
  34.211 +        returns deferred
  34.212          """
  34.213 -        #print 'BlkifController>attach_device>', self.dom, vdev, mode, segment
  34.214          dev = self.addDevice(vdev, mode, segment)
  34.215          if not dev: return -1
  34.216 +        d = defer.Deferred()
  34.217          if recreate:
  34.218 -            d = defer.Deferred()
  34.219              d.callback(self)
  34.220          else:
  34.221 -            self.send_be_vbd_create(vdev)
  34.222 -            d = self.factory.addDeferred()
  34.223 +            d1 = defer.Deferred()
  34.224 +            d1.addCallback(self.factory.respond_be_vbd_create, d)
  34.225 +            d1.addErrback(d.errback)
  34.226 +            self.send_be_vbd_create(vdev, response=d1)
  34.227          return d
  34.228  
  34.229      def destroy(self):
  34.230 -        print 'BlkifController>destroy> dom=', self.dom
  34.231          def cb_destroy(val):
  34.232              self.send_be_destroy()
  34.233 -        d = self.factory.addDeferred()
  34.234 +        d = defer.Deferred()
  34.235          d.addCallback(cb_destroy)
  34.236 -        self.send_be_disconnect()
  34.237 -        #self.destroyDevices()
  34.238 +        self.send_be_disconnect(response=d)
  34.239  
  34.240      def destroyDevices(self):
  34.241          for dev in self.getDevices():
  34.242 @@ -232,7 +266,9 @@ class BlkifController(controller.Control
  34.243          self.attached = 0
  34.244          for dev in self.devices.values():
  34.245              dev.attached = 0
  34.246 -            self.send_be_vbd_create(vdev)
  34.247 +            d1 = defer.Deferred()
  34.248 +            d1.addCallback(self.factory.respond_be_vbd_create, None)
  34.249 +            self.send_be_vbd_create(vdev, response=d1)
  34.250  
  34.251      def reattachDevice(self, vdev):
  34.252          """Reattach a device, when the back-end control domain has changed.
  34.253 @@ -273,51 +309,47 @@ class BlkifController(controller.Control
  34.254                          'blkif_handle' : val['handle'],
  34.255                          'evtchn'       : self.evtchn['port1'],
  34.256                          'shmem_frame'  : val['shmem_frame'] })
  34.257 -        self.factory.writeRequest(msg)
  34.258 -        pass
  34.259 +        d = defer.Deferred()
  34.260 +        d.addCallback(self.factory.respond_be_connect)
  34.261 +        self.factory.writeRequest(msg, response=d)
  34.262  
  34.263 -    #def recv_fe_interface_status_changed(self, msg, req):
  34.264 -    #    (hnd, status, chan) = unpackMsg('blkif_fe_interface_status_changed_t', msg)
  34.265 -    #    print 'recv_fe_interface_status_changed>', hnd, status, chan
  34.266 -    #   pass
  34.267 -
  34.268 -    def send_fe_interface_status_changed(self):
  34.269 +    def send_fe_interface_status_changed(self, response=None):
  34.270          msg = packMsg('blkif_fe_interface_status_changed_t',
  34.271                        { 'handle' : 0,
  34.272                          'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
  34.273                          'evtchn' : self.evtchn['port2'] })
  34.274 -        self.writeRequest(msg)
  34.275 +        self.writeRequest(msg, response=response)
  34.276  
  34.277 -    def send_be_create(self):
  34.278 +    def send_be_create(self, response=None):
  34.279          msg = packMsg('blkif_be_create_t',
  34.280                        { 'domid'        : self.dom,
  34.281                          'blkif_handle' : 0 })
  34.282 -        self.factory.writeRequest(msg)
  34.283 +        self.factory.writeRequest(msg, response=response)
  34.284  
  34.285 -    def send_be_disconnect(self):
  34.286 +    def send_be_disconnect(self, response=None):
  34.287          print '>BlkifController>send_be_disconnect>', 'dom=', self.dom
  34.288          msg = packMsg('blkif_be_disconnect_t',
  34.289                        { 'domid'        : self.dom,
  34.290                          'blkif_handle' : 0 })
  34.291 -        self.factory.writeRequest(msg)
  34.292 +        self.factory.writeRequest(msg, response=response)
  34.293  
  34.294 -    def send_be_destroy(self):
  34.295 +    def send_be_destroy(self, response=None):
  34.296          print '>BlkifController>send_be_destroy>', 'dom=', self.dom
  34.297          msg = packMsg('blkif_be_destroy_t',
  34.298                        { 'domid'        : self.dom,
  34.299                          'blkif_handle' : 0 })
  34.300 -        self.factory.writeRequest(msg)
  34.301 +        self.factory.writeRequest(msg, response=response)
  34.302  
  34.303 -    def send_be_vbd_create(self, vdev):
  34.304 +    def send_be_vbd_create(self, vdev, response=None):
  34.305          dev = self.devices[vdev]
  34.306          msg = packMsg('blkif_be_vbd_create_t',
  34.307                        { 'domid'        : self.dom,
  34.308                          'blkif_handle' : 0,
  34.309                          'vdevice'      : dev.vdev,
  34.310                          'readonly'     : dev.readonly() })
  34.311 -        self.factory.writeRequest(msg)
  34.312 +        self.factory.writeRequest(msg, response=response)
  34.313          
  34.314 -    def send_be_vbd_grow(self, vdev):
  34.315 +    def send_be_vbd_grow(self, vdev, response=None):
  34.316          dev = self.devices[vdev]
  34.317          msg = packMsg('blkif_be_vbd_grow_t',
  34.318                        { 'domid'                : self.dom,
  34.319 @@ -326,9 +358,9 @@ class BlkifController(controller.Control
  34.320                          'extent.device'        : dev.device,
  34.321                          'extent.sector_start'  : dev.start_sector,
  34.322                          'extent.sector_length' : dev.nr_sectors })
  34.323 -        self.factory.writeRequest(msg)
  34.324 +        self.factory.writeRequest(msg, response=response)
  34.325  
  34.326 -    def send_be_vbd_destroy(self, vdev):
  34.327 +    def send_be_vbd_destroy(self, vdev, response=None):
  34.328          print '>BlkifController>send_be_vbd_destroy>', 'dom=', self.dom, 'vdev=', vdev
  34.329          PrettyPrint.prettyprint(self.sxpr())
  34.330          dev = self.devices[vdev]
  34.331 @@ -337,5 +369,5 @@ class BlkifController(controller.Control
  34.332                          'blkif_handle'         : 0,
  34.333                          'vdevice'              : dev.vdev })
  34.334          del self.devices[vdev]
  34.335 -        self.factory.writeRequest(msg)
  34.336 +        self.factory.writeRequest(msg, response=response)
  34.337      
    35.1 --- a/tools/python/xen/xend/server/channel.py	Thu Jul 01 23:45:24 2004 +0000
    35.2 +++ b/tools/python/xen/xend/server/channel.py	Tue Jul 06 20:42:26 2004 +0000
    35.3 @@ -1,3 +1,5 @@
    35.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    35.5 +
    35.6  import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
    35.7  from xen.lowlevel import xu
    35.8  from messages import msgTypeName
    35.9 @@ -24,14 +26,11 @@ class ChannelFactory:
   35.10          self.notifier = xu.notifier()
   35.11      
   35.12      def addChannel(self, channel):
   35.13 -        """Add a channel.
   35.14 +        """Add a channel. Registers with the notifier.
   35.15          """
   35.16          idx = channel.idx
   35.17          self.channels[idx] = channel
   35.18          self.notifier.bind(idx)
   35.19 -        # Try to wake it up
   35.20 -        #self.notifier.unmask(idx)
   35.21 -        #channel.notify()
   35.22  
   35.23      def getChannel(self, idx):
   35.24          """Get the channel with the given index (if any).
   35.25 @@ -40,6 +39,7 @@ class ChannelFactory:
   35.26  
   35.27      def delChannel(self, idx):
   35.28          """Remove the channel with the given index (if any).
   35.29 +        Deregisters with the notifier.
   35.30          """
   35.31          if idx in self.channels:
   35.32              del self.channels[idx]
   35.33 @@ -174,9 +174,9 @@ class VirqChannel(BaseChannel):
   35.34          """Close the channel. Calls lostChannel(self) on all its clients and
   35.35          channelClosed() on the factory.
   35.36          """
   35.37 -        for c in self.clients:
   35.38 +        for c in self.clients[:]:
   35.39              c.lostChannel(self)
   35.40 -        del self.clients
   35.41 +        self.clients = []
   35.42          BaseChannel.close(self)
   35.43  
   35.44      def registerClient(self, client):
   35.45 @@ -238,7 +238,7 @@ class Channel(BaseChannel):
   35.46          """
   35.47          if self.closed: return
   35.48          self.closed = 1
   35.49 -        for d in self.devs:
   35.50 +        for d in self.devs[:]:
   35.51              d.lostChannel()
   35.52          self.factory.channelClosed(self)
   35.53          self.devs = []
   35.54 @@ -288,6 +288,8 @@ class Channel(BaseChannel):
   35.55                     self.getRemotePort()))
   35.56  
   35.57      def handleNotification(self):
   35.58 +        """Process outstanding messages in repsonse to notification on the port.
   35.59 +        """
   35.60          if self.closed:
   35.61              print 'handleNotification> Notification on closed channel', self
   35.62              return
   35.63 @@ -299,6 +301,8 @@ class Channel(BaseChannel):
   35.64              self.notify()
   35.65  
   35.66      def notify(self):
   35.67 +        """Notify the other end of the port that messages have been processed.
   35.68 +        """
   35.69          if self.closed: return
   35.70          self.port.notify()
   35.71  
    36.1 --- a/tools/python/xen/xend/server/console.py	Thu Jul 01 23:45:24 2004 +0000
    36.2 +++ b/tools/python/xen/xend/server/console.py	Tue Jul 06 20:42:26 2004 +0000
    36.3 @@ -1,3 +1,4 @@
    36.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    36.5  
    36.6  from twisted.internet import reactor
    36.7  from twisted.internet import protocol
    36.8 @@ -12,11 +13,6 @@ import controller
    36.9  from messages import *
   36.10  from params import *
   36.11  
   36.12 -"""Telnet binary option."""
   36.13 -TRANSMIT_BINARY = '0'
   36.14 -WILL = chr(251)
   36.15 -IAC = chr(255)
   36.16 -
   36.17  class ConsoleProtocol(protocol.Protocol):
   36.18      """Asynchronous handler for a console TCP socket.
   36.19      """
   36.20 @@ -36,19 +32,12 @@ class ConsoleProtocol(protocol.Protocol)
   36.21              self.loseConnection()
   36.22              return
   36.23          else:
   36.24 -            # KAF: A nice quiet successful connect. Don't bother with telnet
   36.25 -            # control sequence -- telnet is not the appropriate protocol here. 
   36.26 +            # KAF: A nice quiet successful connect.
   36.27              #self.transport.write("Connected to console %d on domain %d\n"
   36.28              #                     % (self.idx, self.controller.dom))
   36.29 -            #self.setTelnetTransmitBinary()
   36.30              eserver.inject('xend.console.connect',
   36.31                             [self.idx, self.addr[0], self.addr[1]])
   36.32  
   36.33 -    def setTelnetTransmitBinary(self):
   36.34 -        """Send the sequence to set the telnet TRANSMIT-BINARY option.
   36.35 -        """
   36.36 -        self.write(IAC + WILL + TRANSMIT_BINARY)
   36.37 -
   36.38      def dataReceived(self, data):
   36.39          if self.controller.handleInput(self, data):
   36.40              self.loseConnection()
   36.41 @@ -104,11 +93,15 @@ class ConsoleController(controller.Contr
   36.42      output and the connected TCP sockets to post console input.
   36.43      """
   36.44  
   36.45 +    STATUS_NEW       = 'new'
   36.46 +    STATUS_CLOSED    = 'closed'
   36.47 +    STATUS_CONNECTED = 'connected'
   36.48 +    STATUS_LISTENING = 'listening'
   36.49 +
   36.50      def __init__(self, factory, dom, console_port):
   36.51 -        #print 'ConsoleController> dom=', dom, type(dom)
   36.52          controller.Controller.__init__(self, factory, dom)
   36.53          self.majorTypes = [ CMSG_CONSOLE ]
   36.54 -        self.status = "new"
   36.55 +        self.status = self.STATUS_NEW
   36.56          self.addr = None
   36.57          self.conn = None
   36.58          self.rbuf = xu.buffer()
   36.59 @@ -118,7 +111,6 @@ class ConsoleController(controller.Contr
   36.60          self.registerChannel()
   36.61          self.listener = None
   36.62          self.listen()
   36.63 -        #print 'ConsoleController<', 'dom=', self.dom, 'idx=', self.idx
   36.64  
   36.65      def sxpr(self):
   36.66          val =['console',
   36.67 @@ -136,29 +128,31 @@ class ConsoleController(controller.Contr
   36.68          return not (self.closed() or self.rbuf.empty())
   36.69  
   36.70      def closed(self):
   36.71 -        return self.status == 'closed'
   36.72 +        return self.status == self.STATUS_CLOSED
   36.73  
   36.74      def connected(self):
   36.75 -        return self.status == 'connected'
   36.76 +        return self.status == self.STATUS_CONNECTED
   36.77  
   36.78      def close(self):
   36.79 -        try:
   36.80 -            #print 'ConsoleController> close dom=', self.dom
   36.81 -            self.status = "closed"
   36.82 -            if self.conn:
   36.83 -                self.conn.loseConnection()
   36.84 -            self.listener.stopListening()
   36.85 -            self.deregisterChannel()
   36.86 -            self.lostChannel()
   36.87 -        except Exception, ex:
   36.88 -            print 'ConsoleController>close>', ex
   36.89 -            raise
   36.90 +        """Close the console controller.
   36.91 +        """
   36.92 +        self.lostChannel()
   36.93 +
   36.94 +    def lostChannel(self):
   36.95 +        """The channel to the domain has been lost.
   36.96 +        Cleanup: disconnect TCP connections and listeners, notify the controller.
   36.97 +        """
   36.98 +        self.status = self.STATUS_CLOSED
   36.99 +        if self.conn:
  36.100 +            self.conn.loseConnection()
  36.101 +        self.listener.stopListening()
  36.102 +        controller.Controller.lostChannel(self)
  36.103  
  36.104      def listen(self):
  36.105          """Listen for TCP connections to the console port..
  36.106          """
  36.107          if self.closed(): return
  36.108 -        self.status = "listening"
  36.109 +        self.status = self.STATUS_LISTENING
  36.110          if self.listener:
  36.111              #self.listener.startListening()
  36.112              pass
  36.113 @@ -167,15 +161,25 @@ class ConsoleController(controller.Contr
  36.114              self.listener = reactor.listenTCP(self.console_port, f)
  36.115  
  36.116      def connect(self, addr, conn):
  36.117 +        """Connect a TCP connection to the console.
  36.118 +        Fails if closed or already connected.
  36.119 +
  36.120 +        addr peer address
  36.121 +        conn connection
  36.122 +
  36.123 +        returns 0 if ok, negative otherwise
  36.124 +        """
  36.125          if self.closed(): return -1
  36.126          if self.connected(): return -1
  36.127          self.addr = addr
  36.128          self.conn = conn
  36.129 -        self.status = "connected"
  36.130 +        self.status = self.STATUS_CONNECTED
  36.131          self.handleOutput()
  36.132          return 0
  36.133  
  36.134      def disconnect(self):
  36.135 +        """Disconnect the TCP connection to the console.
  36.136 +        """
  36.137          if self.conn:
  36.138              self.conn.loseConnection()
  36.139          self.addr = None
  36.140 @@ -183,15 +187,29 @@ class ConsoleController(controller.Contr
  36.141          self.listen()
  36.142  
  36.143      def requestReceived(self, msg, type, subtype):
  36.144 -        #print '***Console', self.dom, msg.get_payload()
  36.145 +        """Receive console data from the console channel.
  36.146 +
  36.147 +        msg     console message
  36.148 +        type    major message type
  36.149 +        subtype minor message typ
  36.150 +        """
  36.151          self.rbuf.write(msg.get_payload())
  36.152          self.handleOutput()
  36.153          
  36.154      def responseReceived(self, msg, type, subtype):
  36.155 +        """Handle a response to a request written to the console channel.
  36.156 +        Just ignore it because the return values are not interesting.
  36.157 +
  36.158 +        msg     console message
  36.159 +        type    major message type
  36.160 +        subtype minor message typ
  36.161 +        """
  36.162          pass
  36.163  
  36.164      def produceRequests(self):
  36.165 -        # Send as much pending console data as there is room for.
  36.166 +        """Write pending console data to the console channel.
  36.167 +        Writes as much to the channel as it can.
  36.168 +        """
  36.169          work = 0
  36.170          while not self.wbuf.empty() and self.channel.writeReady():
  36.171              msg = xu.message(CMSG_CONSOLE, 0, 0)
  36.172 @@ -201,7 +219,12 @@ class ConsoleController(controller.Contr
  36.173  
  36.174      def handleInput(self, conn, data):
  36.175          """Handle some external input aimed at the console.
  36.176 -        Called from a TCP connection (conn).
  36.177 +        Called from a TCP connection (conn). Ignores the input
  36.178 +        if the calling connection (conn) is not the one connected
  36.179 +        to the console (self.conn).
  36.180 +
  36.181 +        conn connection
  36.182 +        data input data
  36.183          """
  36.184          if self.closed(): return -1
  36.185          if conn != self.conn: return 0
  36.186 @@ -215,18 +238,14 @@ class ConsoleController(controller.Contr
  36.187          Sends it to the connected console (if any).
  36.188          """
  36.189          if self.closed():
  36.190 -            #print 'Console>handleOutput> closed'
  36.191              return -1
  36.192          if not self.conn:
  36.193 -            #print 'Console>handleOutput> not connected'
  36.194              return 0
  36.195          while not self.rbuf.empty():
  36.196              try:
  36.197 -                #print 'Console>handleOutput> writing...'
  36.198                  bytes = self.conn.write(self.rbuf.peek())
  36.199                  if bytes > 0:
  36.200                      self.rbuf.discard(bytes)
  36.201              except socket.error, error:
  36.202                  pass
  36.203 -        #print 'Console>handleOutput<'
  36.204          return 0
    37.1 --- a/tools/python/xen/xend/server/controller.py	Thu Jul 01 23:45:24 2004 +0000
    37.2 +++ b/tools/python/xen/xend/server/controller.py	Tue Jul 06 20:42:26 2004 +0000
    37.3 @@ -1,10 +1,50 @@
    37.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    37.5 +
    37.6  from twisted.internet import defer
    37.7 +defer.Deferred.debug = 1
    37.8  
    37.9  import channel
   37.10  from messages import msgTypeName
   37.11  
   37.12 +DEBUG=0
   37.13 +
   37.14 +class OutOfOrderError(RuntimeError):
   37.15 +    """Error reported when a response arrives out of order.
   37.16 +    """
   37.17 +    pass
   37.18 +
   37.19 +class Responder:
   37.20 +    """Handler for a response to a message.
   37.21 +    """
   37.22 +
   37.23 +    def __init__(self, mid, deferred):
   37.24 +        """Create a responder.
   37.25 +
   37.26 +        mid      message id of response to handle
   37.27 +        deferred deferred object holding the callbacks
   37.28 +        """
   37.29 +        self.mid = mid
   37.30 +        self.deferred = deferred
   37.31 +
   37.32 +    def responseReceived(self, msg):
   37.33 +        if self.deferred.called: return
   37.34 +        self.deferred.callback(msg)
   37.35 +
   37.36 +    def error(self, err):
   37.37 +        if self.deferred.called: return
   37.38 +        self.deferred.errback(err)
   37.39 +
   37.40  class CtrlMsgRcvr:
   37.41      """Abstract class for things that deal with a control interface to a domain.
   37.42 +
   37.43 +    Instance variables:
   37.44 +
   37.45 +    dom       : the domain we are a control interface for
   37.46 +    majorTypes: list of major message types we are interested in
   37.47 +    subTypes  : mapping of message subtypes to methods
   37.48 +    
   37.49 +    channel   : channel to the domain
   37.50 +    idx       : channel index
   37.51      """
   37.52  
   37.53  
   37.54 @@ -15,50 +55,140 @@ class CtrlMsgRcvr:
   37.55          self.dom = None
   37.56          self.channel = None
   37.57          self.idx = None
   37.58 +        self.responders = []
   37.59 +        # Timeout (in seconds) for deferreds.
   37.60 +        self.timeout = 10
   37.61 +
   37.62 +    def setTimeout(self, timeout):
   37.63 +        self.timeout = timeout
   37.64  
   37.65      def requestReceived(self, msg, type, subtype):
   37.66 +        """Dispatch a request to handlers.
   37.67 +
   37.68 +        msg     message
   37.69 +        type    major message type
   37.70 +        subtype minor message type
   37.71 +        """
   37.72 +        msgid = msg.get_header()['id']
   37.73 +        if DEBUG:
   37.74 +            print 'requestReceived>', self, msgid, msgTypeName(type, subtype)
   37.75          method = self.subTypes.get(subtype)
   37.76          if method:
   37.77              method(msg, 1)
   37.78 -        else:
   37.79 +        elif DEBUG:
   37.80              print ('requestReceived> No handler: Message type %s %d:%d'
   37.81                     % (msgTypeName(type, subtype), type, subtype)), self
   37.82          
   37.83      def responseReceived(self, msg, type, subtype):
   37.84 +        """Dispatch a response to handlers.
   37.85 +
   37.86 +        msg     message
   37.87 +        type    major message type
   37.88 +        subtype minor message type
   37.89 +        """
   37.90 +        msgid = msg.get_header()['id']
   37.91 +        if DEBUG:
   37.92 +            print 'responseReceived>', self, msgid, msgTypeName(type, subtype)
   37.93 +        if self.callResponders(msg):
   37.94 +            return
   37.95          method = self.subTypes.get(subtype)
   37.96          if method:
   37.97              method(msg, 0)
   37.98 -        else:
   37.99 +        elif DEBUG:
  37.100              print ('responseReceived> No handler: Message type %s %d:%d'
  37.101                     % (msgTypeName(type, subtype), type, subtype)), self
  37.102  
  37.103 +    def addResponder(self, mid, deferred):
  37.104 +        """Add a responder for a message id.
  37.105 +        The deferred is called with callback(msg) when a response
  37.106 +        with the given message id arrives. Responses are expected
  37.107 +        to arrive in order of message id. When a response arrives,
  37.108 +        waiting responders for messages with lower id have errback
  37.109 +        called with an OutOfOrder error.
  37.110 +
  37.111 +        mid      message id of response expected
  37.112 +        deferred a Deferred to handle the response
  37.113 +
  37.114 +        returns Responder
  37.115 +        """
  37.116 +        if self.timeout > 0:
  37.117 +            deferred.setTimeout(self.timeout)
  37.118 +        resp = Responder(mid, deferred)
  37.119 +        self.responders.append(resp)
  37.120 +        return resp
  37.121 +
  37.122 +    def callResponders(self, msg):
  37.123 +        """Call any waiting responders for a response message.
  37.124 +
  37.125 +        msg     response message
  37.126 +        
  37.127 +        returns 1 if there was a responder for the message, 0 otherwise
  37.128 +        """
  37.129 +        hdr = msg.get_header()
  37.130 +        mid = hdr['id']
  37.131 +        handled = 0
  37.132 +        while self.responders:
  37.133 +            resp = self.responders[0]
  37.134 +            if resp.mid > mid:
  37.135 +                break
  37.136 +            self.responders.pop()
  37.137 +            if resp.mid < mid:
  37.138 +                print 'handleResponse> Out of order:', resp.mid, mid
  37.139 +                resp.error(OutOfOrderError())
  37.140 +            else:
  37.141 +                handled = 1
  37.142 +                resp.responseReceived(msg)
  37.143 +                break
  37.144 +        return handled
  37.145 +
  37.146      def lostChannel(self):
  37.147 +        """Called when the channel to the domain is lost.
  37.148 +        """
  37.149          pass
  37.150      
  37.151      def registerChannel(self):
  37.152 -        #print 'CtrlMsgRcvr>registerChannel>', self
  37.153 +        """Register interest in our major message types with the
  37.154 +        channel to our domain.
  37.155 +        """
  37.156          self.channel = self.channelFactory.domChannel(self.dom)
  37.157          self.idx = self.channel.getIndex()
  37.158          if self.majorTypes:
  37.159              self.channel.registerDevice(self.majorTypes, self)
  37.160          
  37.161      def deregisterChannel(self):
  37.162 -        #print 'CtrlMsgRcvr>deregisterChannel>', self
  37.163 +        """Deregister interest in our major message types with the
  37.164 +        channel to our domain.
  37.165 +        """
  37.166          if self.channel:
  37.167              self.channel.deregisterDevice(self)
  37.168              del self.channel
  37.169  
  37.170      def produceRequests(self):
  37.171 +        """Produce any queued requests.
  37.172 +
  37.173 +        return number produced
  37.174 +        """
  37.175          return 0
  37.176  
  37.177 -    def writeRequest(self, msg):
  37.178 +    def writeRequest(self, msg, response=None):
  37.179 +        """Write a request to the channel.
  37.180 +
  37.181 +        msg      message
  37.182 +        response Deferred to handle the response (optional)
  37.183 +        """
  37.184          if self.channel:
  37.185 +            if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg
  37.186 +            if response:
  37.187 +                self.addResponder(msg.get_header()['id'], response)
  37.188              self.channel.writeRequest(msg)
  37.189          else:
  37.190              print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
  37.191  
  37.192      def writeResponse(self, msg):
  37.193 +        """Write a response to the channel.
  37.194 +        """
  37.195          if self.channel:
  37.196 +            if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg
  37.197              self.channel.writeResponse(msg)
  37.198          else:
  37.199              print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
  37.200 @@ -66,6 +196,12 @@ class CtrlMsgRcvr:
  37.201  class ControllerFactory(CtrlMsgRcvr):
  37.202      """Abstract class for factories creating controllers.
  37.203      Maintains a table of instances.
  37.204 +
  37.205 +    Instance variables:
  37.206 +
  37.207 +    instances : mapping of index to controller instance
  37.208 +    dlist     : list of deferreds
  37.209 +    dom       : domain
  37.210      """
  37.211  
  37.212      def __init__(self):
  37.213 @@ -73,55 +209,46 @@ class ControllerFactory(CtrlMsgRcvr):
  37.214          self.instances = {}
  37.215          self.dlist = []
  37.216          self.dom = 0
  37.217 -        # Timeout (in seconds) for deferreds.
  37.218 -        self.timeout = 10
  37.219          
  37.220      def addInstance(self, instance):
  37.221 +        """Add a controller instance (under its index).
  37.222 +        """
  37.223          self.instances[instance.idx] = instance
  37.224  
  37.225      def getInstance(self, idx):
  37.226 +        """Get a controller instance from its index.
  37.227 +        """
  37.228          return self.instances.get(idx)
  37.229  
  37.230      def getInstances(self):
  37.231 +        """Get a list of all controller instances.
  37.232 +        """
  37.233          return self.instances.values()
  37.234  
  37.235      def getInstanceByDom(self, dom):
  37.236 +        """Get the controller instance for the given domain.
  37.237 +        """
  37.238          for inst in self.instances.values():
  37.239              if inst.dom == dom:
  37.240                  return inst
  37.241          return None
  37.242  
  37.243      def delInstance(self, instance):
  37.244 -        #print 'ControllerFactory>delInstance>', instance.idx
  37.245 +        """Delete an instance from the table.
  37.246 +        """
  37.247          if instance.idx in self.instances:
  37.248 -            #print 'ControllerFactory>delInstance> remove', instance.idx
  37.249              del self.instances[instance.idx]
  37.250  
  37.251      def createInstance(self, dom, recreate=0):
  37.252 +        """Create an instance. Define in a subclass.
  37.253 +        """
  37.254          raise NotImplementedError()
  37.255  
  37.256      def instanceClosed(self, instance):
  37.257 -        #print 'ControllerFactory>instanceClosed>', instance.idx, instance
  37.258 +        """Callback called when an instance is closed (usually by the instance).
  37.259 +        """
  37.260          self.delInstance(instance)
  37.261  
  37.262 -    def addDeferred(self):
  37.263 -        d = defer.Deferred()
  37.264 -        if self.timeout > 0:
  37.265 -            # The deferred will error if not called before timeout.
  37.266 -            d.setTimeout(self.timeout)
  37.267 -        self.dlist.append(d)
  37.268 -        return d
  37.269 -
  37.270 -    def callDeferred(self, *args):
  37.271 -        if self.dlist:
  37.272 -            d = self.dlist.pop(0)
  37.273 -            d.callback(*args)
  37.274 -
  37.275 -    def errDeferred(self, *args):
  37.276 -        if self.dlist:
  37.277 -            d = self.dlist.pop(0)
  37.278 -            d.errback(*args)
  37.279 -
  37.280  class Controller(CtrlMsgRcvr):
  37.281      """Abstract class for a device controller attached to a domain.
  37.282      """
  37.283 @@ -134,15 +261,20 @@ class Controller(CtrlMsgRcvr):
  37.284          self.idx = None
  37.285  
  37.286      def close(self):
  37.287 -        self.deregisterChannel()
  37.288 +        """Close the controller.
  37.289 +        """
  37.290          self.lostChannel()
  37.291  
  37.292      def lostChannel(self):
  37.293 -        #print 'Controller>lostChannel>', self, self.factory
  37.294 +        """The controller channel has been lost.
  37.295 +        """
  37.296 +        self.deregisterChannel()
  37.297          self.factory.instanceClosed(self)
  37.298  
  37.299  class Dev:
  37.300 -
  37.301 +    """Abstract class for a device attached to a device controller.
  37.302 +    """
  37.303 +    
  37.304      def __init__(self, controller):
  37.305          self.controller = controller
  37.306          self.props = {}
  37.307 @@ -160,9 +292,6 @@ class Dev:
  37.308          if k in self.props:
  37.309              del self.props[k]
  37.310  
  37.311 -    #def __repr__(self):
  37.312 -    #    return str(self.sxpr())
  37.313 -
  37.314      def sxpr(self):
  37.315          raise NotImplementedError()
  37.316  
    38.1 --- a/tools/python/xen/xend/server/cstruct.py	Thu Jul 01 23:45:24 2004 +0000
    38.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.3 @@ -1,269 +0,0 @@
    38.4 -import struct
    38.5 -
    38.6 -class Struct:
    38.7 -
    38.8 -    maxDepth = 10
    38.9 -
   38.10 -    base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
   38.11 -
   38.12 -    sizes = {'B': 1,
   38.13 -            'H': 2,
   38.14 -            'I': 4,
   38.15 -            'L': 4,
   38.16 -            'Q': 8,
   38.17 -            'c': 1,
   38.18 -            'h': 2,
   38.19 -            'i': 4,
   38.20 -            'l': 4,
   38.21 -            'q': 8,
   38.22 -            'x': 1,
   38.23 -            }
   38.24 -
   38.25 -    formats = {
   38.26 -        'int8'          : 'B',
   38.27 -        'int16'         : 'H',
   38.28 -        'int32'         : 'I',
   38.29 -        'int64'         : 'Q',
   38.30 -        'u8'            : 'B',
   38.31 -        'u16'           : 'H',
   38.32 -        'u32'           : 'I',
   38.33 -        'u64'           : 'Q'
   38.34 -        }
   38.35 -
   38.36 -    def typedef(self, name, val):
   38.37 -        self.formats[name] = val
   38.38 -
   38.39 -    def struct(self, name, *f):
   38.40 -        self.typedef(name, StructInfo(self, f))
   38.41 -        
   38.42 -    def getType(self, name):
   38.43 -        return self.formats[name]
   38.44 -
   38.45 -    def format(self, ty):
   38.46 -        d = 0
   38.47 -        f = ty
   38.48 -        while d < self.maxDepth:
   38.49 -            d += 1
   38.50 -            f = self.formats[f]
   38.51 -            if isinstance(f, StructInfo):
   38.52 -                return f.format()
   38.53 -            if f in self.base:
   38.54 -                return f
   38.55 -        return -1
   38.56 -
   38.57 -    def alignedformat(self, ty):
   38.58 -        fmt = self.format(ty)
   38.59 -        #print 'alignedformat> %s |%s|' %(ty, fmt)
   38.60 -        afmt = self.align(fmt)
   38.61 -        #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
   38.62 -        return afmt
   38.63 -
   38.64 -    def align(self, fmt):
   38.65 -        n1 = 0
   38.66 -        afmt = ''
   38.67 -        for a in fmt:
   38.68 -            n2 = self.getSize(a)
   38.69 -            m = n1 % n2
   38.70 -            if m:
   38.71 -                d = (n2 - m)
   38.72 -                afmt += 'x' * d
   38.73 -                n1 += d
   38.74 -            afmt += a
   38.75 -            n1 += n2
   38.76 -        return afmt
   38.77 -
   38.78 -    def fmtsize(self, fmt):
   38.79 -        s = 0
   38.80 -        for f in fmt:
   38.81 -            s += self.getSize(f)
   38.82 -        return s
   38.83 -
   38.84 -    def getSize(self, f):
   38.85 -        return self.sizes[f]
   38.86 -
   38.87 -    def pack(self, ty, data):
   38.88 -        return self.getType(ty).pack(data)
   38.89 -
   38.90 -    def unpack(self, ty, data):
   38.91 -        return self.getType(ty).unpack(data)
   38.92 -
   38.93 -    def show(self):
   38.94 -        l = self.formats.keys()
   38.95 -        l.sort()
   38.96 -        for v in l:
   38.97 -            print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
   38.98 -
   38.99 -
  38.100 -class StructInfo:
  38.101 -
  38.102 -    def __init__(self, s, f):
  38.103 -        self.fmt = None
  38.104 -        self.structs = s
  38.105 -        self.fields = f
  38.106 -
  38.107 -    def alignedformat(self):
  38.108 -        if self.afmt: return self.afmt
  38.109 -        self.afmt = self.structs.align(self.format())
  38.110 -        return self.afmt
  38.111 -    
  38.112 -    def format(self):
  38.113 -        if self.fmt: return self.fmt
  38.114 -        fmt = ""
  38.115 -        for (ty, name) in self.fields:
  38.116 -            fmt += self.formatString(ty)
  38.117 -        self.fmt = fmt
  38.118 -        return fmt
  38.119 -
  38.120 -    def formatString(self, ty):
  38.121 -        if ty in self.fields:
  38.122 -            ty = self.fields[ty]
  38.123 -        return self.structs.format(ty)
  38.124 -
  38.125 -    def pack(self, *args):
  38.126 -        return struct.pack(self.alignedformat(), *args)
  38.127 -
  38.128 -    def unpack(self, data):
  38.129 -        return struct.unpack(self.alignedformat(), data)
  38.130 -
  38.131 -types = Struct()
  38.132 -
  38.133 -types.typedef('short'         , 'h')
  38.134 -types.typedef('int'           , 'i')
  38.135 -types.typedef('long'          , 'l')
  38.136 -types.typedef('unsigned short', 'H')
  38.137 -types.typedef('unsigned int'  , 'I')
  38.138 -types.typedef('unsigned long' , 'L')
  38.139 -types.typedef('domid_t'       , 'u64')
  38.140 -types.typedef('blkif_vdev_t'  , 'u16')
  38.141 -types.typedef('blkif_pdev_t'  , 'u16')
  38.142 -types.typedef('blkif_sector_t', 'u64')
  38.143 -
  38.144 -types.struct('u8[6]',
  38.145 -             ('u8', 'a1'),
  38.146 -             ('u8', 'a2'),
  38.147 -             ('u8', 'a3'),
  38.148 -             ('u8', 'a4'),
  38.149 -             ('u8', 'a5'),
  38.150 -             ('u8', 'a6'))
  38.151 -             
  38.152 -types.struct('blkif_fe_interface_status_changed_t',
  38.153 -    ('unsigned int',    'handle'),
  38.154 -    ('unsigned int',    'status'),
  38.155 -    ('unsigned int',    'evtchn'))
  38.156 -
  38.157 -types.struct('blkif_fe_driver_status_changed_t',
  38.158 -    ('unsigned int',    'status'),
  38.159 -    ('unsigned int',    'nr_interfaces'))
  38.160 -
  38.161 -types.struct('blkif_fe_interface_connect_t',
  38.162 -    ('unsigned int' ,   'handle'),
  38.163 -    ('unsigned long',   'shmem_frame'))
  38.164 -
  38.165 -types.struct('blkif_fe_interface_disconnect_t',
  38.166 -    ('unsigned int',   'handle'))
  38.167 -
  38.168 -types.struct('blkif_extent_t',
  38.169 -    ('blkif_pdev_t'  , 'device'),
  38.170 -    ('blkif_sector_t', 'sector_start'),
  38.171 -    ('blkif_sector_t', 'sector_length'))
  38.172 -
  38.173 -types.struct('blkif_be_create_t', 
  38.174 -    ('domid_t'     ,   'domid'),
  38.175 -    ('unsigned int',   'blkif_handle'),
  38.176 -    ('unsigned int',   'status'))
  38.177 -             
  38.178 -types.struct('blkif_be_destroy_t',
  38.179 -    ('domid_t'     ,   'domid'),
  38.180 -    ('unsigned int',   'blkif_handle'),
  38.181 -    ('unsigned int',   'status'))
  38.182 -
  38.183 -types.struct('blkif_be_connect_t',
  38.184 -    ('domid_t'      ,  'domid'),
  38.185 -    ('unsigned int' ,  'blkif_handle'),
  38.186 -    ('unsigned int' ,  'evtchn'),
  38.187 -    ('unsigned long',  'shmem_frame'),
  38.188 -    ('unsigned int' ,  'status'))
  38.189 -
  38.190 -types.struct('blkif_be_disconnect_t',
  38.191 -    ('domid_t'     ,   'domid'),
  38.192 -    ('unsigned int',   'blkif_handle'),
  38.193 -    ('unsigned int',   'status'))
  38.194 -
  38.195 -types.struct('blkif_be_vbd_create_t', 
  38.196 -    ('domid_t'     ,   'domid'),         #Q
  38.197 -    ('unsigned int',   'blkif_handle'),  #I
  38.198 -    ('blkif_vdev_t',   'vdevice'),       #H
  38.199 -    ('int'         ,   'readonly'),      #i
  38.200 -    ('unsigned int',   'status'))        #I
  38.201 -
  38.202 -types.struct('blkif_be_vbd_destroy_t', 
  38.203 -    ('domid_t'     ,   'domid'),
  38.204 -    ('unsigned int',   'blkif_handle'),
  38.205 -    ('blkif_vdev_t',   'vdevice'),
  38.206 -    ('unsigned int',   'status'))
  38.207 -
  38.208 -types.struct('blkif_be_vbd_grow_t', 
  38.209 -    ('domid_t'       , 'domid'),         #Q
  38.210 -    ('unsigned int'  , 'blkif_handle'),  #I
  38.211 -    ('blkif_vdev_t'  , 'vdevice'),       #H   
  38.212 -    ('blkif_extent_t', 'extent'),        #HQQ
  38.213 -    ('unsigned int'  , 'status'))        #I
  38.214 -
  38.215 -types.struct('blkif_be_vbd_shrink_t', 
  38.216 -    ('domid_t'     ,   'domid'),
  38.217 -    ('unsigned int',   'blkif_handle'),
  38.218 -    ('blkif_vdev_t',   'vdevice'),
  38.219 -    ('unsigned int',   'status'))
  38.220 -
  38.221 -types.struct('blkif_be_driver_status_changed_t',
  38.222 -    ('unsigned int',   'status'),
  38.223 -    ('unsigned int',   'nr_interfaces'))
  38.224 -
  38.225 -types.struct('netif_fe_interface_status_changed_t',
  38.226 -    ('unsigned int',   'handle'),
  38.227 -    ('unsigned int',   'status'),
  38.228 -    ('unsigned int',   'evtchn'),
  38.229 -    ('u8[6]',          'mac'))
  38.230 -
  38.231 -types.struct('netif_fe_driver_status_changed_t',
  38.232 -    ('unsigned int',   'status'),
  38.233 -    ('unsigned int',   'nr_interfaces'))
  38.234 -
  38.235 -types.struct('netif_fe_interface_connect_t',
  38.236 -    ('unsigned int',   'handle'),
  38.237 -    ('unsigned long',  'tx_shmem_frame'),
  38.238 -    ('unsigned long',  'rx_shmem_frame'))
  38.239 -
  38.240 -types.struct('netif_fe_interface_disconnect_t',
  38.241 -    ('unsigned int',   'handle'))
  38.242 -
  38.243 -types.struct('netif_be_create_t', 
  38.244 -    ('domid_t'     ,   'domid'),
  38.245 -    ('unsigned int',   'netif_handle'),
  38.246 -    ('u8[6]'       ,   'mac'),
  38.247 -    ('unsigned int',   'status'))
  38.248 -
  38.249 -types.struct('netif_be_destroy_t',
  38.250 -    ('domid_t'     ,   'domid'),
  38.251 -    ('unsigned int',   'netif_handle'),
  38.252 -    ('unsigned int',   'status'))
  38.253 -
  38.254 -types.struct('netif_be_connect_t', 
  38.255 -    ('domid_t'      ,  'domid'),
  38.256 -    ('unsigned int' ,  'netif_handle'),
  38.257 -    ('unsigned int' ,  'evtchn'),
  38.258 -    ('unsigned long',  'tx_shmem_frame'),
  38.259 -    ('unsigned long',  'rx_shmem_frame'),
  38.260 -    ('unsigned int' ,  'status'))
  38.261 -
  38.262 -types.struct('netif_be_disconnect_t',
  38.263 -    ('domid_t'     ,   'domid'),
  38.264 -    ('unsigned int',   'netif_handle'),
  38.265 -    ('unsigned int',   'status'))
  38.266 -
  38.267 -types.struct('netif_be_driver_status_changed_t',
  38.268 -    ('unsigned int',   'status'),
  38.269 -    ('unsigned int',   'nr_interfaces'))
  38.270 -
  38.271 -if 1 or __name__ == "__main__":
  38.272 -    types.show()
    39.1 --- a/tools/python/xen/xend/server/domain.py	Thu Jul 01 23:45:24 2004 +0000
    39.2 +++ b/tools/python/xen/xend/server/domain.py	Tue Jul 06 20:42:26 2004 +0000
    39.3 @@ -1,3 +1,5 @@
    39.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    39.5 +
    39.6  import channel
    39.7  import controller
    39.8  from messages import *
    39.9 @@ -7,11 +9,23 @@ class DomainControllerFactory(controller
   39.10      """
   39.11  
   39.12      def createInstance(self, dom):
   39.13 +        """Create a domain controller.
   39.14 +
   39.15 +        dom domain
   39.16 +
   39.17 +        returns domain controller
   39.18 +        """
   39.19          d = DomainController(self, dom)
   39.20          self.addInstance(d)
   39.21          return d
   39.22      
   39.23      def getInstanceByDom(self, dom):
   39.24 +        """Get a domain controller for a domain, creating if necessary.
   39.25 +
   39.26 +        dom domain
   39.27 +
   39.28 +        returns domain controller
   39.29 +        """
   39.30          for inst in self.instances.values():
   39.31              if inst.dom == dom:
   39.32                  return inst
   39.33 @@ -21,8 +35,11 @@ class DomainControllerFactory(controller
   39.34  
   39.35  class DomainController(controller.Controller):
   39.36      """Generic controller for a domain.
   39.37 +    Used for domain shutdown.
   39.38      """
   39.39  
   39.40 +    """Map shutdown reasons to the message type to use.
   39.41 +    """
   39.42      reasons = {'poweroff' : 'shutdown_poweroff_t',
   39.43                 'reboot'   : 'shutdown_reboot_t',
   39.44                 'suspend'  : 'shutdown_suspend_t' }
   39.45 @@ -34,6 +51,10 @@ class DomainController(controller.Contro
   39.46          print 'DomainController>', self, self.channel, self.idx
   39.47  
   39.48      def shutdown(self, reason):
   39.49 +        """Shutdown a domain.
   39.50 +
   39.51 +        reason shutdown reason
   39.52 +        """
   39.53          msgtype = self.reasons.get(reason)
   39.54          if not msgtype:
   39.55              raise ValueError('invalid reason:' + reason)
    40.1 --- a/tools/python/xen/xend/server/messages.py	Thu Jul 01 23:45:24 2004 +0000
    40.2 +++ b/tools/python/xen/xend/server/messages.py	Tue Jul 06 20:42:26 2004 +0000
    40.3 @@ -148,6 +148,9 @@ netif_formats = {
    40.4  msg_formats.update(netif_formats)
    40.5  
    40.6  #============================================================================
    40.7 +# Domain shutdown message types.
    40.8 +#============================================================================
    40.9 +
   40.10  CMSG_SHUTDOWN = 6
   40.11  
   40.12  CMSG_SHUTDOWN_POWEROFF  = 0
   40.13 @@ -176,8 +179,23 @@ msg_formats.update(shutdown_formats)
   40.14  class Msg:
   40.15      pass
   40.16  
   40.17 +_next_msgid = 0
   40.18 +
   40.19 +def nextid():
   40.20 +    global _next_msgid
   40.21 +    return ++_next_msgid
   40.22 +
   40.23  def packMsg(ty, params):
   40.24 -    if DEBUG: print '>packMsg', ty, params
   40.25 +    """Pack a message.
   40.26 +    Any 'mac' parameter is passed in as an int[6] array and converted.
   40.27 +
   40.28 +    ty     message type name
   40.29 +    params message parameter dict
   40.30 +
   40.31 +    returns xu message
   40.32 +    """
   40.33 +    msgid = nextid()
   40.34 +    if DEBUG: print '>packMsg', msgid, ty, params
   40.35      (major, minor) = msg_formats[ty]
   40.36      args = {}
   40.37      for (k, v) in params.items():
   40.38 @@ -189,11 +207,19 @@ def packMsg(ty, params):
   40.39      if DEBUG:
   40.40          for (k, v) in args.items():
   40.41              print 'packMsg>', k, v, type(v)
   40.42 -    msgid = 0
   40.43      msg = xu.message(major, minor, msgid, args)
   40.44      return msg
   40.45  
   40.46  def unpackMsg(ty, msg):
   40.47 +    """Unpack a message.
   40.48 +    Any mac addresses in the message are converted to int[6] array
   40.49 +    in the return dict.
   40.50 +
   40.51 +    ty  message type
   40.52 +    msg xu message
   40.53 +
   40.54 +    returns parameter dict
   40.55 +    """
   40.56      args = msg.get_payload()
   40.57      mac = [0, 0, 0, 0, 0, 0]
   40.58      macs = []
   40.59 @@ -208,10 +234,19 @@ def unpackMsg(ty, msg):
   40.60          args['mac'] = mac
   40.61          for k in macs:
   40.62              del args[k]
   40.63 -    if DEBUG: print '<unpackMsg', ty, args
   40.64 +    if DEBUG:
   40.65 +        msgid = msg.get_header()['id']
   40.66 +        print '<unpackMsg', msgid, ty, args
   40.67      return args
   40.68  
   40.69  def msgTypeName(ty, subty):
   40.70 +    """Convert a message type, subtype pair (ints) to a message type name (string).
   40.71 +
   40.72 +    ty    integer message type
   40.73 +    subty integer message subtype
   40.74 +
   40.75 +    returns message type name (or None)
   40.76 +    """
   40.77      for (name, info) in msg_formats.items():
   40.78          if info[0] == ty and info[1] == subty:
   40.79              return name
    41.1 --- a/tools/python/xen/xend/server/netif.py	Thu Jul 01 23:45:24 2004 +0000
    41.2 +++ b/tools/python/xen/xend/server/netif.py	Tue Jul 06 20:42:26 2004 +0000
    41.3 @@ -1,6 +1,9 @@
    41.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    41.5 +
    41.6  import random
    41.7  
    41.8  from twisted.internet import defer
    41.9 +defer.Deferred.debug = 1
   41.10  
   41.11  from xen.xend import sxp
   41.12  from xen.xend import PrettyPrint
   41.13 @@ -21,8 +24,8 @@ class NetifControllerFactory(controller.
   41.14          self.majorTypes = [ CMSG_NETIF_BE ]
   41.15  
   41.16          self.subTypes = {
   41.17 -            CMSG_NETIF_BE_CREATE : self.recv_be_create,
   41.18 -            CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
   41.19 +            #CMSG_NETIF_BE_CREATE : self.recv_be_create,
   41.20 +            #CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
   41.21              CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
   41.22              }
   41.23          self.attached = 1
   41.24 @@ -30,8 +33,12 @@ class NetifControllerFactory(controller.
   41.25  
   41.26      def createInstance(self, dom, recreate=0):
   41.27          """Create or find the network interface controller for a domain.
   41.28 +
   41.29 +        dom      domain
   41.30 +        recreate if true this is a recreate (xend restarted)
   41.31 +
   41.32 +        returns netif controller
   41.33          """
   41.34 -        #print 'netif>createInstance> dom=', dom
   41.35          netif = self.getInstanceByDom(dom)
   41.36          if netif is None:
   41.37              netif = NetifController(self, dom)
   41.38 @@ -39,15 +46,31 @@ class NetifControllerFactory(controller.
   41.39          return netif
   41.40  
   41.41      def getDomainDevices(self, dom):
   41.42 +        """Get the network device controllers for a domain.
   41.43 +
   41.44 +        dom  domain
   41.45 +        
   41.46 +        returns netif controller
   41.47 +        """
   41.48          netif = self.getInstanceByDom(dom)
   41.49          return (netif and netif.getDevices()) or []
   41.50  
   41.51      def getDomainDevice(self, dom, vif):
   41.52 +        """Get a virtual network interface device for a domain.
   41.53 +
   41.54 +        dom domain
   41.55 +        vif virtual interface index
   41.56 +
   41.57 +        returns NetDev
   41.58 +        """
   41.59          netif = self.getInstanceByDom(dom)
   41.60          return (netif and netif.getDevice(vif)) or None
   41.61          
   41.62      def setControlDomain(self, dom, recreate=0):
   41.63          """Set the 'back-end' device driver domain.
   41.64 +
   41.65 +        dom      domain
   41.66 +        recreate if true this is a recreate (xend restarted)
   41.67          """
   41.68          if self.dom == dom: return
   41.69          self.deregisterChannel()
   41.70 @@ -55,19 +78,13 @@ class NetifControllerFactory(controller.
   41.71              self.attached = 0
   41.72          self.dom = dom
   41.73          self.registerChannel()
   41.74 -        #
   41.75 -        #if xend.netif.be_port.remote_dom != 0:
   41.76 -        #    xend.netif.recovery = True
   41.77 -        #    xend.netif.be_port = xend.main.port_from_dom(dom)
   41.78 -        #
   41.79  
   41.80      def getControlDomain(self):
   41.81 +        """Get the domain id of the back-end control domain.
   41.82 +        """
   41.83          return self.dom
   41.84  
   41.85 -    def recv_be_create(self, msg, req):
   41.86 -        self.callDeferred(0)
   41.87 -    
   41.88 -    def recv_be_connect(self, msg, req):
   41.89 +    def respond_be_connect(self, msg):
   41.90          val = unpackMsg('netif_be_connect_t', msg)
   41.91          dom = val['domid']
   41.92          vif = val['netif_handle']
   41.93 @@ -75,7 +92,7 @@ class NetifControllerFactory(controller.
   41.94          if netif:
   41.95              netif.send_interface_connected(vif)
   41.96          else:
   41.97 -            print "recv_be_connect> unknown vif=", vif
   41.98 +            print "respond_be_connect> unknown vif=", vif
   41.99              pass
  41.100  
  41.101      def recv_be_driver_status_changed(self, msg, req):
  41.102 @@ -88,23 +105,6 @@ class NetifControllerFactory(controller.
  41.103                  netif.reattach_devices()
  41.104              self.attached = 1
  41.105  
  41.106 -##         pl = msg.get_payload()
  41.107 -##         status = pl['status']
  41.108 -##         if status == NETIF_DRIVER_STATUS_UP:
  41.109 -##             if xend.netif.recovery:
  41.110 -##                 print "New netif backend now UP, notifying guests:"
  41.111 -##                 for netif_key in interface.list.keys():
  41.112 -##                     netif = interface.list[netif_key]
  41.113 -##                     netif.create()
  41.114 -##                     print "  Notifying %d" % netif.dom
  41.115 -##                     msg = xu.message(
  41.116 -##                         CMSG_NETIF_FE,
  41.117 -##                         CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
  41.118 -##                         { 'handle' : 0, 'status' : 1 })
  41.119 -##                     netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
  41.120 -##                 print "Done notifying guests"
  41.121 -##                 recovery = False
  41.122 -                
  41.123  class NetDev(controller.Dev):
  41.124      """Info record for a network device.
  41.125      """
  41.126 @@ -130,9 +130,13 @@ class NetDev(controller.Dev):
  41.127          return val
  41.128  
  41.129      def get_vifname(self):
  41.130 +        """Get the virtual interface device name.
  41.131 +        """
  41.132          return "vif%d.%d" % (self.controller.dom, self.vif)
  41.133  
  41.134      def get_mac(self):
  41.135 +        """Get the MAC address as a string.
  41.136 +        """
  41.137          return ':'.join(map(lambda x: "%x" % x, self.mac))
  41.138  
  41.139      def vifctl_params(self):
  41.140 @@ -141,23 +145,31 @@ class NetDev(controller.Dev):
  41.141                   'ipaddr': self.ipaddr }
  41.142  
  41.143      def up(self, bridge=None, ipaddr=[]):
  41.144 +        """Bring the device up.
  41.145 +
  41.146 +        bridge ethernet bridge to connect to
  41.147 +        ipaddr list of ipaddrs to filter using iptables
  41.148 +        """
  41.149          self.bridge = bridge
  41.150          self.ipaddr = ipaddr
  41.151          Vifctl.up(self.get_vifname(), **self.vifctl_params())
  41.152  
  41.153      def down(self):
  41.154 +        """Bring the device down.
  41.155 +        """
  41.156          Vifctl.down(self.get_vifname(), **self.vifctl_params())
  41.157  
  41.158      def destroy(self):
  41.159 +        """Destroy the device's resources and disconnect from the back-end
  41.160 +        device controller.
  41.161 +        """
  41.162          def cb_destroy(val):
  41.163              self.controller.send_be_destroy(self.vif)
  41.164 -        print 'NetDev>destroy>', 'vif=', self.vif
  41.165 -        PrettyPrint.prettyprint(self.sxpr())
  41.166          self.down()
  41.167 -        d = self.controller.factory.addDeferred()
  41.168 +        #d = self.controller.factory.addDeferred()
  41.169 +        d = defer.Deferred()
  41.170          d.addCallback(cb_destroy)
  41.171 -        self.controller.send_be_disconnect(self.vif)
  41.172 -        #self.controller.send_be_destroy(self.vif)
  41.173 +        self.controller.send_be_disconnect(self.vif, response=d)
  41.174          
  41.175  
  41.176  class NetifController(controller.Controller):
  41.177 @@ -165,7 +177,6 @@ class NetifController(controller.Control
  41.178      """
  41.179      
  41.180      def __init__(self, factory, dom):
  41.181 -        #print 'NetifController> dom=', dom
  41.182          controller.Controller.__init__(self, factory, dom)
  41.183          self.devices = {}
  41.184          
  41.185 @@ -178,21 +189,23 @@ class NetifController(controller.Control
  41.186                  self.recv_fe_interface_connect,
  41.187              }
  41.188          self.registerChannel()
  41.189 -        #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
  41.190  
  41.191      def sxpr(self):
  41.192          val = ['netif', ['dom', self.dom]]
  41.193          return val
  41.194      
  41.195      def randomMAC(self):
  41.196 -        # VIFs get a random MAC address with a "special" vendor id.
  41.197 -        # 
  41.198 -        # NB. The vendor is currently an "obsolete" one that used to belong
  41.199 -        # to DEC (AA-00-00). Using it is probably a bit rude :-)
  41.200 -        # 
  41.201 -        # NB2. The first bit of the first random octet is set to zero for
  41.202 -        # all dynamic MAC addresses. This may allow us to manually specify
  41.203 -        # MAC addresses for some VIFs with no fear of clashes.
  41.204 +        """Generate a random MAC address.
  41.205 +
  41.206 +        Uses OUI (Organizationally Unique Identifier) AA:00:00, an
  41.207 +        unassigned one that used to belong to DEC. The OUI list is
  41.208 +        available at 'standards.ieee.org'.
  41.209 +
  41.210 +        The remaining 3 fields are random, with the first bit of the first
  41.211 +        random field set 0.
  41.212 +
  41.213 +        returns array of 6 ints
  41.214 +        """
  41.215          mac = [ 0xaa, 0x00, 0x00,
  41.216                  random.randint(0x00, 0x7f),
  41.217                  random.randint(0x00, 0xff),
  41.218 @@ -200,29 +213,46 @@ class NetifController(controller.Control
  41.219          return mac
  41.220  
  41.221      def lostChannel(self):
  41.222 -        print 'NetifController>lostChannel>', 'dom=', self.dom
  41.223 -        #self.destroyDevices()
  41.224 +        """Method called when the channel has been lost.
  41.225 +        """
  41.226          controller.Controller.lostChannel(self)
  41.227  
  41.228      def getDevices(self):
  41.229 +        """Get a list of the devices.
  41.230 +        """
  41.231          return self.devices.values()
  41.232  
  41.233      def getDevice(self, vif):
  41.234 +        """Get a device.
  41.235 +
  41.236 +        vif device index
  41.237 +
  41.238 +        returns device (or None)
  41.239 +        """
  41.240          return self.devices.get(vif)
  41.241  
  41.242      def addDevice(self, vif, vmac):
  41.243 +        """Add a network interface. If vmac is None a random MAC is
  41.244 +        assigned. If specified, vmac must be a string of the form
  41.245 +        XX:XX:XX:XX:XX where X is hex digit.
  41.246 +
  41.247 +        vif device index
  41.248 +        vmac device MAC 
  41.249 +
  41.250 +        returns device
  41.251 +        """
  41.252          if vmac is None:
  41.253              mac = self.randomMAC()
  41.254          else:
  41.255              mac = [ int(x, 16) for x in vmac.split(':') ]
  41.256          if len(mac) != 6: raise ValueError("invalid mac")
  41.257 -        #print "attach_device>", "vif=", vif, "mac=", mac
  41.258          dev = NetDev(self, vif, mac)
  41.259          self.devices[vif] = dev
  41.260          return dev
  41.261  
  41.262      def destroy(self):
  41.263 -        print 'NetifController>destroy>', 'dom=', self.dom
  41.264 +        """Destroy the controller and all devices.
  41.265 +        """
  41.266          self.destroyDevices()
  41.267          
  41.268      def destroyDevices(self):
  41.269 @@ -237,20 +267,19 @@ class NetifController(controller.Control
  41.270          @param vmac mac address (string)
  41.271          """
  41.272          self.addDevice(vif, vmac)
  41.273 +        d = defer.Deferred()
  41.274          if recreate:
  41.275 -            d = defer.Deferred()
  41.276              d.callback(self)
  41.277          else:
  41.278 -            d = self.factory.addDeferred()
  41.279 -            self.send_be_create(vif)
  41.280 +            self.send_be_create(vif, response=d)
  41.281          return d
  41.282  
  41.283      def reattach_devices(self):
  41.284          """Reattach all devices when the back-end control domain has changed.
  41.285          """
  41.286 -        d = self.factory.addDeferred()
  41.287 +        #d = self.factory.addDeferred()
  41.288          self.send_be_create(vif)
  41.289 -        self.attach_fe_devices(0)
  41.290 +        self.attach_fe_devices()
  41.291  
  41.292      def attach_fe_devices(self):
  41.293          for dev in self.devices.values():
  41.294 @@ -279,38 +308,39 @@ class NetifController(controller.Control
  41.295                          'evtchn'         : dev.evtchn['port1'],
  41.296                          'tx_shmem_frame' : val['tx_shmem_frame'],
  41.297                          'rx_shmem_frame' : val['rx_shmem_frame'] })
  41.298 -        self.factory.writeRequest(msg)
  41.299 +        d = defer.Deferred()
  41.300 +        d.addCallback(self.factory.respond_be_connect)
  41.301 +        self.factory.writeRequest(msg, response=d)
  41.302  
  41.303 -    def send_interface_connected(self, vif):
  41.304 +    def send_interface_connected(self, vif, response=None):
  41.305          dev = self.devices[vif]
  41.306          msg = packMsg('netif_fe_interface_status_changed_t',
  41.307                        { 'handle' : dev.vif,
  41.308                          'status' : NETIF_INTERFACE_STATUS_CONNECTED,
  41.309                          'evtchn' : dev.evtchn['port2'],
  41.310                          'mac'    : dev.mac })
  41.311 -        self.writeRequest(msg)
  41.312 +        self.writeRequest(msg, response=response)
  41.313  
  41.314 -    def send_be_create(self, vif):
  41.315 +    def send_be_create(self, vif, response=None):
  41.316          dev = self.devices[vif]
  41.317          msg = packMsg('netif_be_create_t',
  41.318                        { 'domid'        : self.dom,
  41.319                          'netif_handle' : dev.vif,
  41.320                          'mac'          : dev.mac })
  41.321 -        self.factory.writeRequest(msg)
  41.322 +        self.factory.writeRequest(msg, response=response)
  41.323  
  41.324 -    def send_be_disconnect(self, vif):
  41.325 +    def send_be_disconnect(self, vif, response=None):
  41.326          dev = self.devices[vif]
  41.327          msg = packMsg('netif_be_disconnect_t',
  41.328                        { 'domid'        : self.dom,
  41.329                          'netif_handle' : dev.vif })
  41.330 -        self.factory.writeRequest(msg)
  41.331 +        self.factory.writeRequest(msg, response=response)
  41.332  
  41.333 -    def send_be_destroy(self, vif):
  41.334 -        print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
  41.335 +    def send_be_destroy(self, vif, response=None):
  41.336          PrettyPrint.prettyprint(self.sxpr())
  41.337          dev = self.devices[vif]
  41.338          del self.devices[vif]
  41.339          msg = packMsg('netif_be_destroy_t',
  41.340                        { 'domid'        : self.dom,
  41.341                          'netif_handle' : vif })
  41.342 -        self.factory.writeRequest(msg)
  41.343 +        self.factory.writeRequest(msg, response=response)
    42.1 --- a/tools/python/xen/xend/sxp.py	Thu Jul 01 23:45:24 2004 +0000
    42.2 +++ b/tools/python/xen/xend/sxp.py	Tue Jul 06 20:42:26 2004 +0000
    42.3 @@ -21,56 +21,19 @@ from StringIO import StringIO
    42.4  __all__ = [
    42.5      "mime_type", 
    42.6      "ParseError", 
    42.7 -    "Parser", 
    42.8 -    "atomp", 
    42.9 -    "show", 
   42.10 -    "show_xml", 
   42.11 -    "elementp", 
   42.12 +    "Parser",
   42.13 +    "show",
   42.14      "name", 
   42.15 -    "attributes", 
   42.16 -    "attribute", 
   42.17      "children", 
   42.18      "child", 
   42.19 -    "child_at", 
   42.20 -    "child0", 
   42.21 -    "child1", 
   42.22 -    "child2", 
   42.23 -    "child3", 
   42.24 -    "child4", 
   42.25      "child_value",
   42.26 -    "has_id", 
   42.27 -    "with_id", 
   42.28 -    "child_with_id", 
   42.29 -    "elements", 
   42.30      "to_string",
   42.31      "from_string",
   42.32 -    "all_from_string",
   42.33      "parse", 
   42.34      ]
   42.35  
   42.36  mime_type = "application/sxp"
   42.37  
   42.38 -escapes = {
   42.39 -    'a': '\a',
   42.40 -    'b': '\b',
   42.41 -    't': '\t',
   42.42 -    'n': '\n',
   42.43 -    'v': '\v',
   42.44 -    'f': '\f',
   42.45 -    'r': '\r',
   42.46 -    '\\': '\\',
   42.47 -    '\'': '\'',
   42.48 -    '\"': '\"'}
   42.49 -
   42.50 -k_list_open  = "("
   42.51 -k_list_close = ")"
   42.52 -k_attr_open  = "@"
   42.53 -k_eval       = "!"
   42.54 -
   42.55 -escapes_rev = {}
   42.56 -for k in escapes:
   42.57 -    escapes_rev[escapes[k]] = k
   42.58 -
   42.59  class ParseError(StandardError):
   42.60  
   42.61      def __init__(self, parser, value):
   42.62 @@ -86,7 +49,6 @@ class ParserState:
   42.63          self.parent = parent
   42.64          self.buf = ''
   42.65          self.val = []
   42.66 -        self.delim = None
   42.67          self.fn = fn
   42.68  
   42.69      def push(self, fn):
   42.70 @@ -95,28 +57,19 @@ class ParserState:
   42.71  class Parser:
   42.72  
   42.73      def __init__(self):
   42.74 -        self.error = sys.stderr
   42.75          self.reset()
   42.76  
   42.77      def reset(self):
   42.78 -        self.val = []
   42.79          self.eof = 0
   42.80 -        self.err = 0
   42.81          self.line_no = 0
   42.82          self.char_no = 0
   42.83 -        self.state = None
   42.84 +        self.state = self.start_state = ParserState(self.state_start)
   42.85  
   42.86      def push_state(self, fn):
   42.87          self.state = self.state.push(fn)
   42.88  
   42.89      def pop_state(self):
   42.90 -        val = self.state
   42.91          self.state = self.state.parent
   42.92 -        if self.state and self.state.fn == self.state_start:
   42.93 -            # Return to start state - produce the value.
   42.94 -            self.val += self.state.val
   42.95 -            self.state.val = []
   42.96 -        return val
   42.97  
   42.98      def in_class(self, c, s):
   42.99          return s.find(c) >= 0
  42.100 @@ -136,12 +89,6 @@ class Parser:
  42.101      def in_printable_class(self, c):
  42.102          return self.in_class(c, string.printable)
  42.103  
  42.104 -    def set_error_stream(self, error):
  42.105 -        self.error = error
  42.106 -
  42.107 -    def has_error(self):
  42.108 -        return self.err > 0
  42.109 -
  42.110      def at_eof(self):
  42.111          return self.eof
  42.112  
  42.113 @@ -166,439 +113,131 @@ class Parser:
  42.114             self.char_no += 1 
  42.115  
  42.116          if self.state is None:
  42.117 -            self.begin_start(None)
  42.118 +            self.state = ParserState(self.state_start)
  42.119 +
  42.120          self.state.fn(c)
  42.121  
  42.122      def ready(self):
  42.123 -        return len(self.val) > 0
  42.124 +        return len(self.start_state.val) > 0
  42.125  
  42.126      def get_val(self):
  42.127 -        v = self.val[0]
  42.128 -        self.val = self.val[1:]
  42.129 +        v = self.start_state.val[0]
  42.130 +        self.start_state.val = self.start_state.val[1:]
  42.131          return v
  42.132  
  42.133      def get_all(self):
  42.134 -        return self.val
  42.135 -
  42.136 -    def begin_start(self, c):
  42.137 -        self.state = ParserState(self.state_start)
  42.138 +        return self.start_state.val
  42.139  
  42.140 -    def end_start(self):
  42.141 -        self.val += self.state.val
  42.142 -        self.pop_state()
  42.143 -    
  42.144      def state_start(self, c):
  42.145 -        if self.at_eof():
  42.146 -            self.end_start()
  42.147 -        elif self.in_space_class(c):
  42.148 +        if self.at_eof() or self.in_space_class(c):
  42.149              pass
  42.150          elif self.in_comment_class(c):
  42.151 -            self.begin_comment(c)
  42.152 -        elif c == k_list_open:
  42.153 -            self.begin_list(c)
  42.154 -        elif c == k_list_close:
  42.155 +            self.push_state(self.state_comment)
  42.156 +        elif c == '(':
  42.157 +            self.push_state(self.state_list)
  42.158 +        elif c == ')':
  42.159              raise ParseError(self, "syntax error: "+c)
  42.160          elif self.in_string_quote_class(c):
  42.161 -            self.begin_string(c)
  42.162 +            self.push_state(self.state_string)
  42.163 +            self.state.buf = c
  42.164          elif self.in_printable_class(c):
  42.165 -            self.begin_atom(c)
  42.166 +            self.push_state(self.state_atom)
  42.167 +            self.state.buf = c
  42.168          elif c == chr(4):
  42.169              # ctrl-D, EOT: end-of-text.
  42.170              self.input_eof()
  42.171          else:
  42.172              raise ParseError(self, "invalid character: code %d" % ord(c))
  42.173  
  42.174 -    def begin_comment(self, c):
  42.175 -        self.push_state(self.state_comment)
  42.176 -        self.state.buf += c
  42.177 -
  42.178 -    def end_comment(self):
  42.179 -        self.pop_state()
  42.180 -    
  42.181      def state_comment(self, c):
  42.182          if c == '\n' or self.at_eof():
  42.183 -            self.end_comment()
  42.184 -        else:
  42.185 -            self.state.buf += c
  42.186 +            self.pop_state()
  42.187  
  42.188 -    def begin_string(self, c):
  42.189 -        self.push_state(self.state_string)
  42.190 -        self.state.delim = c
  42.191 -
  42.192 -    def end_string(self):
  42.193 -        val = self.state.buf
  42.194 -        self.state.parent.val.append(val)
  42.195 -        self.pop_state()
  42.196 -        
  42.197      def state_string(self, c):
  42.198          if self.at_eof():
  42.199              raise ParseError(self, "unexpected EOF")
  42.200 -        elif c == self.state.delim:
  42.201 -            self.end_string()
  42.202 -        elif c == '\\':
  42.203 -            self.push_state(self.state_escape)
  42.204 +        self.state.buf += c
  42.205 +        # Look out for non-escaped end delimiter
  42.206 +        if self.state.buf[0] == c and self.state.buf[-2] != '\\':
  42.207 +            try: # parse escape sequences but fall back to something simple
  42.208 +                val = eval(compile(self.state.buf,'','eval'))
  42.209 +            except:
  42.210 +                val = self.state.buf[1:-1] # just strip the delimiters
  42.211 +            self.state.parent.val.append(val)
  42.212 +            self.pop_state()
  42.213 +    
  42.214 +    def state_atom(self, c):
  42.215 +        if (self.at_eof() or
  42.216 +            self.is_separator(c) or
  42.217 +            self.in_space_class(c) or
  42.218 +            self.in_comment_class(c)):
  42.219 +            val = self.state.buf
  42.220 +            self.state.parent.val.append(val)
  42.221 +            self.pop_state()
  42.222 +            if not self.at_eof():
  42.223 +                self.input_char(c)
  42.224          else:
  42.225              self.state.buf += c
  42.226  
  42.227 -    def state_escape(self, c):
  42.228 -        if self.at_eof():
  42.229 -            raise ParseError(self, "unexpected EOF")
  42.230 -        d = escapes.get(c)
  42.231 -        if d:
  42.232 -            self.state.parent.buf += d
  42.233 -            self.pop_state()
  42.234 -        elif c == 'x':
  42.235 -            self.state.fn = self.state_hex
  42.236 -            self.state.val = 0
  42.237 -        else:
  42.238 -            self.state.fn = self.state_octal
  42.239 -            self.state.val = 0
  42.240 -            self.input_char(c)
  42.241 -
  42.242 -    def state_octal(self, c):
  42.243 -        def octaldigit(c):
  42.244 -            self.state.val *= 8
  42.245 -            self.state.val += ord(c) - ord('0')
  42.246 -            self.state.buf += c
  42.247 -            if self.state.val < 0 or self.state.val > 0xff:
  42.248 -                raise ParseError(self, "invalid octal escape: out of range " + self.state.buf)
  42.249 -            if len(self.state.buf) == 3:
  42.250 -               octaldone()
  42.251 -               
  42.252 -        def octaldone():
  42.253 -            d = chr(self.state.val)
  42.254 -            self.state.parent.buf += d
  42.255 -            self.pop_state()
  42.256 -            
  42.257 -        if self.at_eof():
  42.258 -            raise ParseError(self, "unexpected EOF")
  42.259 -        elif '0' <= c <= '7':
  42.260 -            octaldigit(c)
  42.261 -        elif len(self.buf):
  42.262 -            octaldone()
  42.263 -            self.input_char(c)
  42.264 -
  42.265 -    def state_hex(self, c):
  42.266 -        def hexdone():
  42.267 -            d = chr(self.state.val)
  42.268 -            self.state.parent.buf += d
  42.269 -            self.pop_state()
  42.270 -            
  42.271 -        def hexdigit(c, d):
  42.272 -            self.state.val *= 16
  42.273 -            self.state.val += ord(c) - ord(d)
  42.274 -            self.state.buf += c
  42.275 -            if self.state.val < 0 or self.state.val > 0xff:
  42.276 -                raise ParseError(self, "invalid hex escape: out of range " + self.state.buf)
  42.277 -            if len(self.state.buf) == 2:
  42.278 -                hexdone()
  42.279 -            
  42.280 -        if self.at_eof():
  42.281 -            raise ParseError(self, "unexpected EOF")
  42.282 -        elif '0' <= c <= '9':
  42.283 -            hexdigit(c, '0')
  42.284 -        elif 'A' <= c <= 'F':
  42.285 -            hexdigit(c, 'A')
  42.286 -        elif 'a' <= c <= 'f':
  42.287 -            hexdigit(c, 'a')
  42.288 -        elif len(buf):
  42.289 -            hexdone()
  42.290 -            self.input_char(c)
  42.291 -
  42.292 -    def begin_atom(self, c):
  42.293 -        self.push_state(self.state_atom)
  42.294 -        self.state.buf = c
  42.295 -
  42.296 -    def end_atom(self):
  42.297 -        val = self.state.buf
  42.298 -        self.state.parent.val.append(val)
  42.299 -        self.pop_state()
  42.300 -    
  42.301 -    def state_atom(self, c):
  42.302 -        if self.at_eof():
  42.303 -            self.end_atom()
  42.304 -        elif (self.is_separator(c) or
  42.305 -              self.in_space_class(c) or
  42.306 -              self.in_comment_class(c)):
  42.307 -            self.end_atom()
  42.308 -            self.input_char(c)
  42.309 -        else:
  42.310 -            self.state.buf += c
  42.311 -
  42.312 -    def begin_list(self, c):
  42.313 -        self.push_state(self.state_list)
  42.314 -
  42.315 -    def end_list(self):
  42.316 -        val = self.state.val
  42.317 -        self.state.parent.val.append(val)
  42.318 -        self.pop_state()
  42.319 -
  42.320      def state_list(self, c):
  42.321          if self.at_eof():
  42.322              raise ParseError(self, "unexpected EOF")
  42.323 -        elif c == k_list_close:
  42.324 -            self.end_list()
  42.325 +        elif c == ')':
  42.326 +            val = self.state.val
  42.327 +            self.state.parent.val.append(val)
  42.328 +            self.pop_state()
  42.329          else:
  42.330              self.state_start(c)
  42.331  
  42.332 -def atomp(sxpr):
  42.333 -    """Check if an sxpr is an atom.
  42.334 -    """
  42.335 -    if sxpr.isalnum() or sxpr == '@':
  42.336 -        return 1
  42.337 -    for c in sxpr:
  42.338 -        if c in string.whitespace: return 0
  42.339 -        if c in '"\'\\(){}[]<>$#&%^': return 0
  42.340 -        if c in string.ascii_letters: continue
  42.341 -        if c in string.digits: continue
  42.342 -        if c in '.-_:/~': continue
  42.343 -        return 0
  42.344 -    return 1
  42.345 -    
  42.346  def show(sxpr, out=sys.stdout):
  42.347      """Print an sxpr in bracketed (lisp-style) syntax.
  42.348      """
  42.349      if isinstance(sxpr, types.ListType):
  42.350 -        out.write(k_list_open)
  42.351 -        i = 0
  42.352 +        out.write('(')
  42.353          for x in sxpr:
  42.354 -            if i: out.write(' ')
  42.355              show(x, out)
  42.356 -            i += 1
  42.357 -        out.write(k_list_close)
  42.358 -    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
  42.359 -        out.write(sxpr)
  42.360 +            out.write(' ')
  42.361 +        out.write(')')
  42.362      else:
  42.363 -        #out.write("'" + str(sxpr) + "'")
  42.364          out.write(repr(str(sxpr)))
  42.365  
  42.366 -def show_xml(sxpr, out=sys.stdout):
  42.367 -    """Print an sxpr in XML syntax.
  42.368 -    """
  42.369 -    if isinstance(sxpr, types.ListType):
  42.370 -        element = name(sxpr)
  42.371 -        out.write('<%s' % element)
  42.372 -        for attr in attributes(sxpr):
  42.373 -            out.write(' %s=%s' % (attr[0], attr[1]))
  42.374 -        out.write('>')
  42.375 -        i = 0
  42.376 -        for x in children(sxpr):
  42.377 -            if i: out.write(' ')
  42.378 -            show_xml(x, out)
  42.379 -            i += 1
  42.380 -        out.write('</%s>' % element)
  42.381 -    elif isinstance(sxpr, types.StringType) and atomp(sxpr):
  42.382 -        out.write(sxpr)
  42.383 -    else:
  42.384 -        out.write(str(sxpr))
  42.385 -
  42.386 -def elementp(sxpr, elt=None):
  42.387 -    """Check if an sxpr is an element of the given type.
  42.388 -
  42.389 -    sxpr sxpr
  42.390 -    elt  element type
  42.391 -    """
  42.392 -    return (isinstance(sxpr, types.ListType)
  42.393 -            and len(sxpr)
  42.394 -            and (None == elt or sxpr[0] == elt))
  42.395 -
  42.396  def name(sxpr):
  42.397 -    """Get the element name of an sxpr.
  42.398 -    If the sxpr is not an element (i.e. it's an atomic value) its name
  42.399 -    is None.
  42.400 -
  42.401 -    sxpr
  42.402 -
  42.403 -    returns name (None if not an element).
  42.404 -    """
  42.405 -    val = None
  42.406 -    if isinstance(sxpr, types.StringType):
  42.407 -        val = sxpr
  42.408 -    elif isinstance(sxpr, types.ListType) and len(sxpr):
  42.409 -        val = sxpr[0]
  42.410 -    return val
  42.411 -
  42.412 -def attributes(sxpr):
  42.413 -    """Get the attribute list of an sxpr.
  42.414 -
  42.415 -    sxpr
  42.416 -
  42.417 -    returns attribute list
  42.418 +    """Get the element name of an sxpr, or None if a bad sxpr.
  42.419      """
  42.420 -    val = []
  42.421 -    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
  42.422 -        attr = sxpr[1]
  42.423 -        if elementp(attr, k_attr_open):
  42.424 -            val = attr[1:]
  42.425 -    return val
  42.426 -
  42.427 -def attribute(sxpr, key, val=None):
  42.428 -    """Get an attribute of an sxpr.
  42.429 -
  42.430 -    sxpr sxpr
  42.431 -    key  attribute key
  42.432 -    val  default value (default None)
  42.433 -
  42.434 -    returns attribute value
  42.435 -    """
  42.436 -    for x in attributes(sxpr):
  42.437 -        if x[0] == key:
  42.438 -            val = x[1]
  42.439 -            break
  42.440 -    return val
  42.441 +    if isinstance(sxpr, types.StringType):
  42.442 +        return sxpr
  42.443 +    if isinstance(sxpr, types.ListType) and len(sxpr):
  42.444 +        return sxpr[0]
  42.445 +    return None
  42.446  
  42.447  def children(sxpr, elt=None):
  42.448 -    """Get children of an sxpr.
  42.449 -
  42.450 -    sxpr sxpr
  42.451 -    elt  optional element type to filter by
  42.452 -
  42.453 -    returns children (filtered by elt if specified)
  42.454 +    """Get children of an s-expression @sxpr, optionally filtered by
  42.455 +    element type @elt.
  42.456      """
  42.457 -    val = []
  42.458 -    if isinstance(sxpr, types.ListType) and len(sxpr) > 1:
  42.459 -        i = 1
  42.460 -        x = sxpr[i]
  42.461 -        if elementp(x, k_attr_open):
  42.462 -            i += 1
  42.463 -        val = sxpr[i : ]
  42.464 +    if not isinstance(sxpr, types.ListType): return []
  42.465 +    val = filter(lambda x: isinstance(x, types.ListType) and len(x) > 0, sxpr)
  42.466      if elt:
  42.467 -        def iselt(x):
  42.468 -            return elementp(x, elt)
  42.469 -        val = filter(iselt, val)
  42.470 +        val = filter(lambda x,y=elt: x[0] == y, val)
  42.471      return val
  42.472  
  42.473 -def child(sxpr, elt, val=None):
  42.474 -    """Get the first child of the given element type.
  42.475 -
  42.476 -    sxpr sxpr
  42.477 -    elt  element type
  42.478 -    val  default value
  42.479 -    """
  42.480 -    for x in children(sxpr):
  42.481 -        if elementp(x, elt):
  42.482 -            val = x
  42.483 -            break
  42.484 -    return val
  42.485 -
  42.486 -def child_at(sxpr, index, val=None):
  42.487 -    """Get the child at the given index (zero-based).
  42.488 -
  42.489 -    sxpr  sxpr
  42.490 -    index index
  42.491 -    val   default value
  42.492 -    """
  42.493 -    kids = children(sxpr)
  42.494 -    if len(kids) > index:
  42.495 -        val = kids[index]
  42.496 -    return val
  42.497 -
  42.498 -def child0(sxpr, val=None):
  42.499 -    """Get the zeroth child.
  42.500 +def child(sxpr, elt=None, idx=0):
  42.501 +    """Get the @idx'th child of the optional filtering type @elt in @sxpr.
  42.502      """
  42.503 -    return child_at(sxpr, 0, val)
  42.504 -
  42.505 -def child1(sxpr, val=None):
  42.506 -    """Get the first child.
  42.507 -    """
  42.508 -    return child_at(sxpr, 1, val)
  42.509 -
  42.510 -def child2(sxpr, val=None):
  42.511 -    """Get the second child.
  42.512 -    """
  42.513 -    return child_at(sxpr, 2, val)
  42.514 -
  42.515 -def child3(sxpr, val=None):
  42.516 -    """Get the third child.
  42.517 -    """
  42.518 -    return child_at(sxpr, 3, val)
  42.519 -
  42.520 -def child4(sxpr, val=None):
  42.521 -    """Get the fourth child.
  42.522 -    """
  42.523 -    return child_at(sxpr, 4, val)
  42.524 -
  42.525 -def child_value(sxpr, elt, val=None):
  42.526 -    """Get the value of the first child of the given element type.
  42.527 -    Assumes the child has an atomic value.
  42.528 -
  42.529 -    sxpr sxpr
  42.530 -    elt  element type
  42.531 -    val  default value
  42.532 -    """
  42.533 -    kid = child(sxpr, elt)
  42.534 -    if kid:
  42.535 -        val = child_at(kid, 0, val)
  42.536 -    return val
  42.537 +    x = children(sxpr, elt)
  42.538 +    if len(x) > idx:
  42.539 +        return x[idx]
  42.540 +    return None
  42.541  
  42.542 -def has_id(sxpr, id):
  42.543 -    """Test if an s-expression has a given id.
  42.544 -    """
  42.545 -    return attribute(sxpr, 'id') == id
  42.546 -
  42.547 -def with_id(sxpr, id, val=None):
  42.548 -    """Find the first s-expression with a given id, at any depth.
  42.549 -
  42.550 -    sxpr   s-exp or list
  42.551 -    id     id
  42.552 -    val    value if not found (default None)
  42.553 -
  42.554 -    return s-exp or val
  42.555 +def child_value(sxpr, elt=None):
  42.556 +    """Get the value of the first child of @sxpr with the optional type @elt.
  42.557      """
  42.558 -    if isinstance(sxpr, types.ListType):
  42.559 -        for n in sxpr:
  42.560 -            if has_id(n, id):
  42.561 -                val = n
  42.562 -                break
  42.563 -            v = with_id(n, id)
  42.564 -            if v is None: continue
  42.565 -            val = v
  42.566 -            break
  42.567 -    return val
  42.568 -
  42.569 -def child_with_id(sxpr, id, val=None):
  42.570 -    """Find the first child with a given id.
  42.571 -
  42.572 -    sxpr   s-exp or list
  42.573 -    id     id
  42.574 -    val    value if not found (default None)
  42.575 -
  42.576 -    return s-exp or val
  42.577 -    """
  42.578 -    if isinstance(sxpr, types.ListType):
  42.579 -        for n in sxpr:
  42.580 -            if has_id(n, id):
  42.581 -                val = n
  42.582 -                break
  42.583 -    return val
  42.584 -
  42.585 -def elements(sxpr, ctxt=None):
  42.586 -    """Generate elements (at any depth).
  42.587 -    Visit elements in pre-order.
  42.588 -    Values generated are (node, context)
  42.589 -    The context is None if there is no parent, otherwise
  42.590 -    (index, parent, context) where index is the node's index w.r.t its parent,
  42.591 -    and context is the parent's context.
  42.592 -
  42.593 -    sxpr   s-exp
  42.594 -
  42.595 -    returns generator
  42.596 -    """
  42.597 -    yield (sxpr, ctxt)
  42.598 -    i = 0
  42.599 -    for n in children(sxpr):
  42.600 -        if isinstance(n, types.ListType):
  42.601 -            # Calling elements() recursively does not generate recursively,
  42.602 -            # it just returns a generator object. So we must iterate over it.
  42.603 -            for v in elements(n, (i, sxpr, ctxt)):
  42.604 -                yield v
  42.605 -        i += 1
  42.606 +    x = child(sxpr, elt)
  42.607 +    if not isinstance(x, types.ListType) or len(x) < 2:
  42.608 +        return None
  42.609 +    return x[1]
  42.610  
  42.611  def to_string(sxpr):
  42.612 -    """Convert an sxpr to a string.
  42.613 -
  42.614 -    sxpr sxpr
  42.615 -    returns string
  42.616 +    """Convert an s-expression @sxpr to a string.
  42.617      """
  42.618      io = StringIO()
  42.619      show(sxpr, io)
  42.620 @@ -608,35 +247,14 @@ def to_string(sxpr):
  42.621      return val
  42.622  
  42.623  def from_string(str):
  42.624 -    """Create an sxpr by parsing a string.
  42.625 -
  42.626 -    str string
  42.627 -    returns sxpr
  42.628 -    """
  42.629 -    io = StringIO(str)
  42.630 -    vals = parse(io)
  42.631 -    if vals is []:
  42.632 -        return None
  42.633 -    else:
  42.634 -        return vals[0]
  42.635 -    
  42.636 -
  42.637 -def all_from_string(str):
  42.638 -    """Create an sxpr list by parsing a string.
  42.639 -
  42.640 -    str string
  42.641 -    returns sxpr list
  42.642 +    """Create an sxpr list from a given input string @str.
  42.643      """
  42.644      io = StringIO(str)
  42.645      vals = parse(io)
  42.646      return vals
  42.647  
  42.648  def parse(io):
  42.649 -    """Completely parse all input from 'io'.
  42.650 -
  42.651 -    io	input file object
  42.652 -    returns list of values, None if incomplete
  42.653 -    raises ParseError on parse error
  42.654 +    """Completely parse all input from file @io.
  42.655      """
  42.656      pin = Parser()
  42.657      while 1:
  42.658 @@ -649,19 +267,11 @@ def parse(io):
  42.659      else:
  42.660          val = None
  42.661      return val
  42.662 +
  42.663     
  42.664 -
  42.665  if __name__ == '__main__':
  42.666 -    print ">main"
  42.667      pin = Parser()
  42.668 -    while 1:
  42.669 -        buf = sys.stdin.read(1024)
  42.670 -        #buf = sys.stdin.readline()
  42.671 -        pin.input(buf)
  42.672 -        while pin.ready():
  42.673 -            val = pin.get_val()
  42.674 -            print
  42.675 -            print '****** val=', val
  42.676 -        if len(buf) == 0:
  42.677 -            break
  42.678 -
  42.679 +    buf = sys.stdin.read(1024)
  42.680 +    pin.input(buf)
  42.681 +    while pin.ready():
  42.682 +        print '\n****** val=', pin.get_val()
    43.1 --- a/tools/python/xen/xm/create.py	Thu Jul 01 23:45:24 2004 +0000
    43.2 +++ b/tools/python/xen/xm/create.py	Tue Jul 06 20:42:26 2004 +0000
    43.3 @@ -1,4 +1,5 @@
    43.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    43.5 +
    43.6  """Domain creation.
    43.7  """
    43.8  import string
    43.9 @@ -12,15 +13,25 @@ from xen.util import console_client
   43.10  
   43.11  from xen.xm.opts import *
   43.12  
   43.13 -gopts = Opts(use="""[options]
   43.14 +gopts = Opts(use="""[options] [vars]
   43.15  
   43.16  Create a domain.
   43.17 +
   43.18 +Domain creation parameters can be set by command-line switches, from
   43.19 +a python configuration script or an SXP config file. See documentation
   43.20 +for --defaults, --config. Configuration variables can be set using
   43.21 +VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
   43.22 +
   43.23  """)
   43.24  
   43.25  gopts.opt('help', short='h',
   43.26           fn=set_true, default=0,
   43.27           use="Print this help.")
   43.28  
   43.29 +gopts.opt('help_config',
   43.30 +          fn=set_true, default=0,
   43.31 +          use="Print help for configuration file.")
   43.32 +
   43.33  gopts.opt('quiet', short='q',
   43.34           fn=set_true, default=0,
   43.35           use="Quiet.")
   43.36 @@ -31,58 +42,73 @@ gopts.opt('path', val='PATH',
   43.37  
   43.38  gopts.opt('defaults', short='f', val='FILE',
   43.39           fn=set_value, default='xmdefaults',
   43.40 -         use="Use the given default script.")
   43.41 +         use="""Use the given Python defaults script.
   43.42 +The defaults script is loaded after arguments have been processed.
   43.43 +Each command-line option sets a configuration variable named after
   43.44 +its long option name, and these variables are placed in the
   43.45 +environment of the script before it is loaded.
   43.46 +Variables for options that may be repeated have list values.
   43.47 +Other variables can be set using VAR=VAL on the command line.
   43.48 +
   43.49 +After the script is loaded, option values that were not set on the
   43.50 +command line are replaced by the values set in the script.
   43.51 +""")
   43.52  
   43.53  gopts.opt('config', short='F', val='FILE',
   43.54           fn=set_value, default=None,
   43.55 -         use='Domain configuration to use (SXP).')
   43.56 +         use="""Domain configuration to use (SXP).
   43.57 +SXP is the underlying configuration format used by Xen.
   43.58 +SXP configs can be hand-written or generated from Python defaults
   43.59 +scripts, using the -n (dryrun) option to print the config.
   43.60 +""")
   43.61  
   43.62  gopts.opt('load', short='L', val='FILE',
   43.63            fn=set_value, default=None,
   43.64            use='Domain saved state to load.')
   43.65  
   43.66 -gopts.opt('define', short='D', val='VAR=VAL',
   43.67 -         fn=set_var, default=None,
   43.68 -         use="""Set a variable before loading defaults, e.g. '-D vmid=3'
   43.69 -         to set vmid. May be repeated to set more thanone variable.""")
   43.70 -
   43.71  gopts.opt('dryrun', short='n',
   43.72           fn=set_true, default=0,
   43.73 -         use="Dry run - print the config but don't create the domain.")
   43.74 -
   43.75 -gopts.opt('name', short='N', val='NAME',
   43.76 -          fn=set_value, default=None,
   43.77 -          use="Domain name.")
   43.78 +         use="""Dry run - print the config but don't create the domain.
   43.79 +The defaults file is loaded and the SXP configuration is created and printed.         
   43.80 +""")
   43.81  
   43.82  gopts.opt('console_autoconnect', short='c',
   43.83           fn=set_true, default=0,
   43.84           use="Connect to console after domain is created.")
   43.85  
   43.86 -gopts.opt('kernel', short='k', val='FILE',
   43.87 +gopts.var('name', val='NAME',
   43.88 +          fn=set_value, default=None,
   43.89 +          use="Domain name.")
   43.90 +
   43.91 +gopts.var('kernel', val='FILE',
   43.92           fn=set_value, default=None,
   43.93           use="Path to kernel image.")
   43.94  
   43.95 -gopts.opt('ramdisk', short='r', val='FILE',
   43.96 +gopts.var('ramdisk', val='FILE',
   43.97           fn=set_value, default='',
   43.98           use="Path to ramdisk.")
   43.99  
  43.100 -gopts.opt('builder', short='b', val='FUNCTION',
  43.101 +gopts.var('builder', val='FUNCTION',
  43.102           fn=set_value, default='linux',
  43.103           use="Function to use to build the domain.")
  43.104  
  43.105 -gopts.opt('memory', short='m', val='MEMORY',
  43.106 +gopts.var('memory', val='MEMORY',
  43.107           fn=set_value, default=128,
  43.108           use="Domain memory in MB.")
  43.109  
  43.110 -gopts.opt('blkif',
  43.111 -          fn=set_true, default=0,
  43.112 +gopts.var('autorestart', val='no|yes',
  43.113 +         fn=set_bool, default=0,
  43.114 +         use="Whether to restart the domain on exit.")
  43.115 +
  43.116 +gopts.var('blkif', val='no|yes',
  43.117 +          fn=set_bool, default=0,
  43.118            use="Make the domain a block device backend.")
  43.119  
  43.120 -gopts.opt('netif',
  43.121 -          fn=set_true, default=0,
  43.122 +gopts.var('netif', val='no|yes',
  43.123 +          fn=set_bool, default=0,
  43.124            use="Make the domain a network interface backend.")
  43.125  
  43.126 -gopts.opt('disk', short='d', val='phy:DEV,VDEV,MODE',
  43.127 +gopts.var('disk', val='phy:DEV,VDEV,MODE',
  43.128           fn=append_value, default=[],
  43.129           use="""Add a disk device to a domain. The physical device is DEV,
  43.130           which is exported to the domain as VDEV. The disk is read-only if MODE
  43.131 @@ -90,18 +116,18 @@ gopts.opt('disk', short='d', val='phy:DE
  43.132           The option may be repeated to add more than one disk.
  43.133           """)
  43.134  
  43.135 -gopts.opt('pci', val='BUS,DEV,FUNC',
  43.136 +gopts.var('pci', val='BUS,DEV,FUNC',
  43.137           fn=append_value, default=[],
  43.138           use="""Add a PCI device to a domain, using given params (in hex).
  43.139           For example '-pci c0,02,1a'.
  43.140           The option may be repeated to add more than one pci device.
  43.141           """)
  43.142  
  43.143 -gopts.opt('ipaddr', short='i', val="IPADDR",
  43.144 +gopts.var('ipaddr', val="IPADDR",
  43.145           fn=append_value, default=[],
  43.146           use="Add an IP address to the domain.")
  43.147  
  43.148 -gopts.opt('vif', val="mac=MAC,bridge=BRIDGE",
  43.149 +gopts.var('vif', val="mac=MAC,bridge=BRIDGE",
  43.150           fn=append_value, default=[],
  43.151           use="""Add a network interface with the given MAC address and bridge.
  43.152           If mac is not specified a random MAC address is used.
  43.153 @@ -110,7 +136,7 @@ gopts.opt('vif', val="mac=MAC,bridge=BRI
  43.154           Specifying vifs will increase the number of interfaces as needed.
  43.155           """)
  43.156  
  43.157 -gopts.opt('nics', val="NUM",
  43.158 +gopts.var('nics', val="NUM",
  43.159           fn=set_int, default=1,
  43.160           use="""Set the number of network interfaces.
  43.161           Use the vif option to define interface parameters, otherwise
  43.162 @@ -118,44 +144,44 @@ gopts.opt('nics', val="NUM",
  43.163           number of interfaces as needed.
  43.164           """)
  43.165  
  43.166 -gopts.opt('root', short='R', val='DEVICE',
  43.167 +gopts.var('root', val='DEVICE',
  43.168           fn=set_value, default='',
  43.169           use="""Set the root= parameter on the kernel command line.
  43.170           Use a device, e.g. /dev/sda1, or /dev/nfs for NFS root.""")
  43.171  
  43.172 -gopts.opt('extra', short='E', val="ARGS",
  43.173 +gopts.var('extra', val="ARGS",
  43.174           fn=set_value, default='',
  43.175           use="Set extra arguments to append to the kernel command line.")
  43.176  
  43.177 -gopts.opt('ip', short='I', val='IPADDR',
  43.178 +gopts.var('ip', val='IPADDR',
  43.179           fn=set_value, default='',
  43.180           use="Set the kernel IP interface address.")
  43.181  
  43.182 -gopts.opt('gateway', val="IPADDR",
  43.183 +gopts.var('gateway', val="IPADDR",
  43.184           fn=set_value, default='',
  43.185           use="Set the kernel IP gateway.")
  43.186  
  43.187 -gopts.opt('netmask', val="MASK",
  43.188 +gopts.var('netmask', val="MASK",
  43.189           fn=set_value, default = '',
  43.190           use="Set the kernel IP netmask.")
  43.191  
  43.192 -gopts.opt('hostname', val="NAME",
  43.193 +gopts.var('hostname', val="NAME",
  43.194           fn=set_value, default='',
  43.195           use="Set the kernel IP hostname.")
  43.196  
  43.197 -gopts.opt('interface', val="INTF",
  43.198 +gopts.var('interface', val="INTF",
  43.199           fn=set_value, default="eth0",
  43.200           use="Set the kernel IP interface name.")
  43.201  
  43.202 -gopts.opt('dhcp', val="off|dhcp",
  43.203 +gopts.var('dhcp', val="off|dhcp",
  43.204           fn=set_value, default='off',
  43.205           use="Set the kernel dhcp option.")
  43.206  
  43.207 -gopts.opt('nfs_server', val="IPADDR",
  43.208 +gopts.var('nfs_server', val="IPADDR",
  43.209           fn=set_value, default=None,
  43.210           use="Set the address of the NFS server for NFS root.")
  43.211  
  43.212 -gopts.opt('nfs_root', val="PATH",
  43.213 +gopts.var('nfs_root', val="PATH",
  43.214           fn=set_value, default=None,
  43.215           use="Set the path of the root NFS directory.")
  43.216  
  43.217 @@ -244,6 +270,8 @@ def make_config(opts):
  43.218          config.append(['backend', ['blkif']])
  43.219      if opts.netif:
  43.220          config.append(['backend', ['netif']])
  43.221 +    if opts.autorestart:
  43.222 +        config.append(['autorestart'])
  43.223      
  43.224      configure_image(config, opts)
  43.225      config_devs = []
  43.226 @@ -282,7 +310,7 @@ def preprocess_vifs(opts):
  43.227          d = {}
  43.228          a = vif.split(',')
  43.229          for b in a:
  43.230 -            (k, v) = b.strip().split('=')
  43.231 +            (k, v) = b.strip().split('=', 1)
  43.232              k = k.strip()
  43.233              v = v.strip()
  43.234              if k not in ['mac', 'bridge']:
  43.235 @@ -352,7 +380,15 @@ def main(argv):
  43.236      args = opts.parse(argv)
  43.237      if opts.vals.help:
  43.238          opts.usage()
  43.239 +    if opts.vals.help or opts.vals.help_config:
  43.240 +        opts.load_defaults(help=1)
  43.241 +    if opts.vals.help or opts.vals.help_config:
  43.242          return
  43.243 +    # Process remaining args as config variables.
  43.244 +    for arg in args:
  43.245 +        if '=' in arg:
  43.246 +            (var, val) = arg.strip().split('=', 1)
  43.247 +            gopts.setvar(var.strip(), val.strip())
  43.248      if opts.vals.config:
  43.249          pass
  43.250      else:
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/tools/python/xen/xm/help.py	Tue Jul 06 20:42:26 2004 +0000
    44.3 @@ -0,0 +1,82 @@
    44.4 +# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    44.5 +
    44.6 +"""Variable definition and help support for Python defaults files.
    44.7 +"""
    44.8 +
    44.9 +import sys
   44.10 +
   44.11 +class Vars:
   44.12 +    """A set of configuration variables.
   44.13 +    """
   44.14 +
   44.15 +    def __init__(self, name, help, env):
   44.16 +        """Create a variable set.
   44.17 +
   44.18 +        name name of the defaults file
   44.19 +        help help flag
   44.20 +        env  local environment
   44.21 +        """
   44.22 +        self.name = name
   44.23 +        self.help = help
   44.24 +        self.env = env
   44.25 +        self.vars = []
   44.26 +
   44.27 +    def var(self, name, use=None, check=None):
   44.28 +        """Define a configuration variable.
   44.29 +        If provided, the check function will be called as check(var, val)
   44.30 +        where var is the variable name and val is its value (string).
   44.31 +        It should return a new value for the variable, or raise ValueError if
   44.32 +        the value is not acceptable.
   44.33 +
   44.34 +        name  variable name
   44.35 +        use   variable usage string
   44.36 +        check variable check function
   44.37 +        """
   44.38 +        self.vars.append(Var(name, use, check))
   44.39 +
   44.40 +    def check(self):
   44.41 +        """Execute the variable checks or print help, depending on the value
   44.42 +        of the help flag passed to the constructor.
   44.43 +        """
   44.44 +        if self.help:
   44.45 +            self.doHelp()
   44.46 +        else:
   44.47 +            for v in self.vars:
   44.48 +                v.doCheck(self.env)
   44.49 +
   44.50 +    def doHelp(self, out=sys.stderr):
   44.51 +        """Print help for the variables.
   44.52 +        """
   44.53 +        if self.vars:
   44.54 +            print >>out, "\nConfiguration variables for %s:\n" % self.name
   44.55 +            for v in self.vars:
   44.56 +                v.doHelp(out)
   44.57 +            print >>out
   44.58 +
   44.59 +class Var:
   44.60 +    """A single variable.
   44.61 +    """
   44.62 +
   44.63 +    def __init__(self, name, use, check):
   44.64 +        """Create a variable.
   44.65 +
   44.66 +        name  variable name
   44.67 +        use   variable use string
   44.68 +        check variable value check function
   44.69 +        """
   44.70 +        self.name = name
   44.71 +        self.use = use or ''
   44.72 +        self.check = check
   44.73 +
   44.74 +    def doCheck(self, env):
   44.75 +        """Execute the check and set the variable to the new value.
   44.76 +        """
   44.77 +        if not self.check: return
   44.78 +        env[self.name] = self.check(self.name, env.get(self.name))
   44.79 +
   44.80 +    def doHelp(self, out):
   44.81 +        """Print help for the variable.
   44.82 +        """
   44.83 +        print >>out, "%-12s" % self.name, self.use
   44.84 +
   44.85 +        
    45.1 --- a/tools/python/xen/xm/main.py	Thu Jul 01 23:45:24 2004 +0000
    45.2 +++ b/tools/python/xen/xm/main.py	Tue Jul 06 20:42:26 2004 +0000
    45.3 @@ -5,10 +5,12 @@ import os
    45.4  import os.path
    45.5  import sys
    45.6  from getopt import getopt
    45.7 +import socket
    45.8  
    45.9  from xen.xend import PrettyPrint
   45.10  from xen.xend import sxp
   45.11  from xen.xend.XendClient import server
   45.12 +from xen.xend.XendClient import main as xend_client_main
   45.13  from xen.xm import create, shutdown
   45.14  
   45.15  class Prog:
   45.16 @@ -65,6 +67,13 @@ class Xm:
   45.17          sys.exit(1)
   45.18  
   45.19      def main(self, args):
   45.20 +        try:
   45.21 +            self.main_call(args)
   45.22 +        except socket.error, ex:
   45.23 +            print >>sys.stderr, ex
   45.24 +            self.err("Error connecting to xend, is xend running?")
   45.25 +
   45.26 +    def main_call(self, args):
   45.27          """Main entry point. Dispatches to the progs.
   45.28          """
   45.29          self.name = args[0]
   45.30 @@ -237,11 +246,11 @@ class ProgList(Prog):
   45.31              info = server.xend_domain(dom)
   45.32              d = {}
   45.33              d['dom'] = int(dom)
   45.34 -            d['name'] = sxp.child_value(info, 'name', '??')
   45.35 -            d['mem'] = int(sxp.child_value(info, 'memory', '0'))
   45.36 -            d['cpu'] = int(sxp.child_value(info, 'cpu', '0'))
   45.37 -            d['state'] = sxp.child_value(info, 'state', '??')
   45.38 -            d['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
   45.39 +            d['name'] = sxp.child_value(info, 'name') or '??'
   45.40 +            d['mem'] = int(sxp.child_value(info, 'memory') or '-1')
   45.41 +            d['cpu'] = int(sxp.child_value(info, 'cpu') or '-1')
   45.42 +            d['state'] = sxp.child_value(info, 'state') or '??'
   45.43 +            d['cpu_time'] = float(sxp.child_value(info, 'cpu_time') or '-1')
   45.44              print ("%(dom)-4d %(name)-16s %(mem)7d  %(cpu)3d  %(state)5s  %(cpu_time)7.1f" % d)
   45.45  
   45.46      def long_list(self, doms):
   45.47 @@ -415,9 +424,9 @@ class ProgConsoles(Prog):
   45.48          for x in l:
   45.49              info = server.xend_console(x)
   45.50              d = {}
   45.51 -            d['dom'] = sxp.child(info, 'dst', ['dst', '?', '?'])[1]
   45.52 -            d['port'] = sxp.child_value(info, 'port', '?')
   45.53 -            d['id'] = sxp.child_value(info, 'id', '?')
   45.54 +            d['dom'] = (sxp.child(info, 'dst') or ['dst', '?', '?'])[1]
   45.55 +            d['port'] = sxp.child_value(info, 'port') or '?'
   45.56 +            d['id'] = sxp.child_value(info, 'id') or '?'
   45.57              print "%(dom)3s %(port)4s %(id)3s" % d
   45.58  
   45.59  xm.prog(ProgConsoles)
   45.60 @@ -444,5 +453,21 @@ class ProgConsole(Prog):
   45.61  
   45.62  xm.prog(ProgConsole)
   45.63  
   45.64 +class ProgCall(Prog):
   45.65 +    name = "call"
   45.66 +    info = "Call xend api functions."
   45.67 +
   45.68 +    def help (self, args):
   45.69 +        print "call fn argss..."
   45.70 +        print """
   45.71 +        Call a xend HTTP API function. The leading 'xend_' on the function
   45.72 +can be omitted. See xen.xend.XendClient for the API functions.
   45.73 +"""
   45.74 +
   45.75 +    def main(self, args):
   45.76 +        xend_client_main(args)
   45.77 +
   45.78 +xm.prog(ProgCall)
   45.79 +
   45.80  def main(args):
   45.81      xm.main(args)
    46.1 --- a/tools/python/xen/xm/opts.py	Thu Jul 01 23:45:24 2004 +0000
    46.2 +++ b/tools/python/xen/xm/opts.py	Tue Jul 06 20:42:26 2004 +0000
    46.3 @@ -126,6 +126,42 @@ class Opt:
    46.4          """
    46.5          return self.specified_opt
    46.6  
    46.7 +class OptVar(Opt):
    46.8 +    """An individual option variable.
    46.9 +    """
   46.10 +    def __init__(self, opts, name,
   46.11 +                 val=None, fn=None, use=None, default=None):
   46.12 +        """Create an option.
   46.13 +
   46.14 +        opts    parent options object
   46.15 +        name    name of the field it controls
   46.16 +        val     string used to print option args in help.
   46.17 +                If val is not specified the option has no arg.
   46.18 +        fn      function to call when the option is specified.
   46.19 +        use     usage (help) string
   46.20 +        default default value if not specified on command-line
   46.21 +        """
   46.22 +        if val is None:
   46.23 +            val = name.upper()
   46.24 +        Opt.__init__(self, opts, name, val=val, fn=fn, use=use, default=default)
   46.25 +        self.optkeys = []
   46.26 +        self.optkeys.append(self.long)
   46.27 +
   46.28 +    def short_opt(self):
   46.29 +        return None
   46.30 +
   46.31 +    def long_opt(self):
   46.32 +        return None
   46.33 +
   46.34 +    def show(self):
   46.35 +        print '%s=%s' %(self.optkeys[0], self.val) 
   46.36 +        print
   46.37 +        if self.use:
   46.38 +            print '\t',
   46.39 +            print self.use
   46.40 +        if self.val:
   46.41 +            print '\tDefault', self.default or 'None'
   46.42 +
   46.43  class OptVals:
   46.44      """Class to hold option values.
   46.45      """
   46.46 @@ -134,6 +170,13 @@ class OptVals:
   46.47  class Opts:
   46.48      """Container for options.
   46.49      """
   46.50 +
   46.51 +    imports = ["import sys",
   46.52 +               "import os",
   46.53 +               "import os.path",
   46.54 +               "from xen.util.ip import *",
   46.55 +               ]
   46.56 +
   46.57      def __init__(self, use=None):
   46.58          """Options constructor.
   46.59  
   46.60 @@ -168,6 +211,12 @@ class Opts:
   46.61          self.options_map[name] = x
   46.62          return x
   46.63  
   46.64 +    def var(self, name, **args):
   46.65 +        x = OptVar(self, name, **args)
   46.66 +        self.options.append(x)
   46.67 +        self.options_map[name] = x
   46.68 +        return x     
   46.69 +
   46.70      def setvar(self, var, val):
   46.71          """Set a default script variable.
   46.72          """
   46.73 @@ -232,7 +281,18 @@ class Opts:
   46.74              else:
   46.75                  print >>sys.stderr, "Error: Unknown option:", k
   46.76                  self.usage()
   46.77 -        return args
   46.78 +        xargs = []
   46.79 +        for arg in args:
   46.80 +            isvar = 0
   46.81 +            if '=' in arg:
   46.82 +                (k, v) = arg.split('=', 1)
   46.83 +                for opt in self.options:
   46.84 +                    if opt.specify(k, v):
   46.85 +                        isvar = 1
   46.86 +                        break
   46.87 +            if not isvar:
   46.88 +                xargs.append(arg)
   46.89 +        return xargs
   46.90  
   46.91      def short_opts(self):
   46.92          """Get short options specifier for getopt.
   46.93 @@ -257,9 +317,10 @@ class Opts:
   46.94      def usage(self):
   46.95          print 'Usage: ', self.argv[0], self.use or 'OPTIONS'
   46.96          for opt in self.options:
   46.97 +            print
   46.98              opt.show()
   46.99  
  46.100 -    def load_defaults(self):
  46.101 +    def load_defaults(self, help=0):
  46.102          """Load a defaults script. Assumes these options set:
  46.103          'path'    search path
  46.104          'default' script name
  46.105 @@ -270,12 +331,12 @@ class Opts:
  46.106              else:
  46.107                  p = self.vals.defaults
  46.108              if os.path.exists(p):
  46.109 -                self.load(p)
  46.110 +                self.load(p, help)
  46.111                  break
  46.112          else:
  46.113              self.err("Cannot open defaults file %s" % self.vals.defaults)
  46.114  
  46.115 -    def load(self, defaults, help=0):
  46.116 +    def load(self, defaults, help):
  46.117          """Load a defaults file. Local variables in the file
  46.118          are used to set options with the same names.
  46.119          Variables are not used to set options that are already specified.
  46.120 @@ -287,15 +348,22 @@ class Opts:
  46.121          globals = {}
  46.122          locals = {}
  46.123          locals.update(self.vars)
  46.124 -        cmd = '\n'.join(["import sys",
  46.125 -                         "import os",
  46.126 -                         "import os.path",
  46.127 -                         "import xen.util.ip",
  46.128 -                         "xm_file = '%s'" % defaults,
  46.129 -                         "xm_help = %d" % help ])
  46.130 +        cmd = '\n'.join(self.imports + 
  46.131 +                        [ "from xen.xm.help import Vars",
  46.132 +                          "xm_file = '%s'" % defaults,
  46.133 +                          "xm_help = %d" % help,
  46.134 +                          "xm_vars = Vars(xm_file, xm_help, locals())"
  46.135 +                          ])
  46.136          exec cmd in globals, locals
  46.137 -        execfile(defaults, globals, locals)
  46.138 -        if help: return
  46.139 +        try:
  46.140 +            execfile(defaults, globals, locals)
  46.141 +        except:
  46.142 +            if not help: raise
  46.143 +        if help:
  46.144 +            print 'The following imports are done automatically:'
  46.145 +            for x in self.imports:
  46.146 +                print x
  46.147 +            return
  46.148          # Extract the values set by the script and set the corresponding
  46.149          # options, if not set on the command line.
  46.150          vtypes = [ types.StringType,
  46.151 @@ -316,6 +384,17 @@ def set_false(opt, k, v):
  46.152      """Set an option false."""
  46.153      opt.set(0)
  46.154  
  46.155 +def set_bool(opt, k, v):
  46.156 +    """Set a boolean option.
  46.157 +    """
  46.158 +    if v in ['yes']:
  46.159 +        opt.set(1)
  46.160 +    elif v in ['no']:
  46.161 +        opt.set(0)
  46.162 +    else:
  46.163 +        opt.opts.err('Invalid value:' +v)
  46.164 +        
  46.165 +
  46.166  def set_value(opt, k, v):
  46.167      """Set an option to a valoue."""
  46.168      opt.set(v)
  46.169 @@ -335,6 +414,6 @@ def append_value(opt, k, v):
  46.170  def set_var(opt, k, v):
  46.171      """Set a default script variable.
  46.172      """
  46.173 -    (var, val) = v.strip().split('=')
  46.174 +    (var, val) = v.strip().split('=', 1)
  46.175      opt.opts.setvar(var.strip(), val.strip())
  46.176  
    47.1 --- a/tools/python/xen/xm/shutdown.py	Thu Jul 01 23:45:24 2004 +0000
    47.2 +++ b/tools/python/xen/xm/shutdown.py	Tue Jul 06 20:42:26 2004 +0000
    47.3 @@ -1,4 +1,5 @@
    47.4  # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    47.5 +
    47.6  """Domain shutdown.
    47.7  """
    47.8  import string
    47.9 @@ -10,7 +11,8 @@ from xen.xm.opts import *
   47.10  
   47.11  gopts = Opts(use="""[options] [DOM]
   47.12  
   47.13 -Shutdown one or more domains gracefully.""")
   47.14 +Shutdown one or more domains gracefully.
   47.15 +""")
   47.16  
   47.17  gopts.opt('help', short='h',
   47.18           fn=set_true, default=0,
   47.19 @@ -24,18 +26,22 @@ gopts.opt('wait', short='w',
   47.20           fn=set_true, default=0,
   47.21           use='Wait for shutdown to complete.')
   47.22  
   47.23 -gopts.opt('norestart', short='n',
   47.24 +gopts.opt('halt', short='H',
   47.25            fn=set_true, default=0,
   47.26 -          use='Prevent domain restart.')
   47.27 +          use='Shutdown without reboot.')
   47.28  
   47.29 -def shutdown(opts, doms, wait):
   47.30 +gopts.opt('reboot', short='R',
   47.31 +          fn=set_true, default=0,
   47.32 +          use='Shutdown and reboot.')
   47.33 +
   47.34 +def shutdown(opts, doms, mode, wait):
   47.35      def domains():
   47.36          return [ int(a) for a in server.xend_domains() ]
   47.37      if doms == None: doms = domains()
   47.38      if 0 in doms:
   47.39          doms.remove(0)
   47.40      for d in doms:
   47.41 -        server.xend_domain_shutdown(d)
   47.42 +        server.xend_domain_shutdown(d, mode)
   47.43      if wait:
   47.44          while doms:
   47.45              alive = domains()
   47.46 @@ -49,6 +55,21 @@ def shutdown(opts, doms, wait):
   47.47              time.sleep(1)
   47.48          opts.info("All domains terminated")
   47.49  
   47.50 +def shutdown_mode(opts):
   47.51 +    mode = 'poweroff'
   47.52 +    if opts.vals.wait:
   47.53 +        mode = 'halt'
   47.54 +        if opts.vals.reboot:
   47.55 +           opts.err("Can't specify wait and reboot") 
   47.56 +    else:
   47.57 +        if opts.vals.halt and opts.vals.reboot:
   47.58 +            opts.err("Can't specify halt and reboot")
   47.59 +        if opts.vals.halt:
   47.60 +            mode = 'halt'
   47.61 +        elif opts.vals.reboot:
   47.62 +            mode = 'reboot'
   47.63 +    return mode
   47.64 +
   47.65  def main_all(opts, args):
   47.66      shutdown(opts, None, opts.vals.wait)
   47.67  
   47.68 @@ -59,7 +80,9 @@ def main_dom(opts, args):
   47.69          domid = int(dom)
   47.70      except:
   47.71          opts.err('Invalid domain: ' + dom)
   47.72 -    shutdown(opts, [ domid ], opts.vals.wait)
   47.73 +        
   47.74 +    mode = shutdown_mode(opts)  
   47.75 +    shutdown(opts, [ domid ], mode, opts.vals.wait)
   47.76      
   47.77  def main(argv):
   47.78      opts = gopts
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/tools/xfrd/Make.xfrd	Tue Jul 06 20:42:26 2004 +0000
    48.3 @@ -0,0 +1,34 @@
    48.4 +# -*- mode: Makefile; -*-
    48.5 +#============================================================================
    48.6 +
    48.7 +UTIL_LIB = libutil.a
    48.8 +
    48.9 +UTIL_LIB_SRC =
   48.10 +UTIL_LIB_SRC += allocate.c
   48.11 +UTIL_LIB_SRC += enum.c
   48.12 +UTIL_LIB_SRC += file_stream.c
   48.13 +UTIL_LIB_SRC += gzip_stream.c
   48.14 +UTIL_LIB_SRC += hash_table.c
   48.15 +UTIL_LIB_SRC += iostream.c
   48.16 +UTIL_LIB_SRC += lexis.c
   48.17 +UTIL_LIB_SRC += lzi_stream.c
   48.18 +UTIL_LIB_SRC += marshal.c
   48.19 +UTIL_LIB_SRC += string_stream.c
   48.20 +UTIL_LIB_SRC += sxpr.c
   48.21 +#UTIL_LIB_SRC += sxpr_parser.c
   48.22 +UTIL_LIB_SRC += sys_net.c
   48.23 +UTIL_LIB_SRC += sys_string.c
   48.24 +#UTIL_LIB_SRC += util.c
   48.25 +UTIL_LIB_SRC += xdr.c
   48.26 +
   48.27 +#----------------------------------------------------------------------------
   48.28 +# Xfrd.
   48.29 +
   48.30 +XFRD_PROG_SRC =
   48.31 +XFRD_PROG_SRC += xfrd.c
   48.32 +#XFRD_PROG_SRC += xfr_msg.c
   48.33 +XFRD_PROG_SRC += xen_domain.c
   48.34 +XFRD_PROG_SRC += select.c
   48.35 +XFRD_PROG_SRC += connection.c
   48.36 +
   48.37 +#============================================================================
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/tools/xfrd/Makefile	Tue Jul 06 20:42:26 2004 +0000
    49.3 @@ -0,0 +1,68 @@
    49.4 +# -*- mode: Makefile; -*-
    49.5 +#============================================================================
    49.6 +#
    49.7 +# Mike Wray <mike.wray@hp.com>
    49.8 +#============================================================================
    49.9 +
   49.10 +XEN_ROOT  = ../..
   49.11 +include $(XEN_ROOT)/tools/Make.defs
   49.12 +
   49.13 +XFRD_INSTALL_DIR = /usr/sbin
   49.14 +
   49.15 +vpath %.h      $(XEN_HYPERVISOR_IFS)
   49.16 +INCLUDES += -I $(XEN_HYPERVISOR_IFS)
   49.17 +
   49.18 +vpath %h       $(XEN_LINUX_INCLUDE)
   49.19 +INCLUDES += -I $(XEN_LINUX_INCLUDE)
   49.20 +
   49.21 +vpath %.h      $(XEN_XU)
   49.22 +INCLUDES += -I $(XEN_XU)
   49.23 +
   49.24 +vpath %c       $(XEN_LIBXUTIL)
   49.25 +INCLUDES += -I $(XEN_LIBXUTIL)
   49.26 +
   49.27 +include Make.xfrd
   49.28 +
   49.29 +UTIL_LIB_OBJ = $(UTIL_LIB_SRC:.c=.o)
   49.30 +
   49.31 +XFRD_PROG_OBJ = $(XFRD_PROG_SRC:.c=.o)
   49.32 +XFRD_PROG_OBJ += $(UTIL_LIB)
   49.33 +
   49.34 +CPPFLAGS += -D _XEN_XFR_STUB_
   49.35 +
   49.36 +CFLAGS += -g
   49.37 +CFLAGS += -Wall
   49.38 +CFALGS += -Werror
   49.39 +CFLAGS += $(INCLUDES)
   49.40 +# Make gcc generate dependencies.
   49.41 +CFLAGS += -Wp,-MD,.$(@F).d
   49.42 +PROG_DEP = .*.d
   49.43 +
   49.44 +#LDFLAGS += -L $(COMPRESS_DIR) -lz
   49.45 +
   49.46 +$(warning XFRD_PROG_OBJ= $(XFRD_PROG_OBJ))
   49.47 +$(warning UTIL_LIB= $(UTIL_LIB))
   49.48 +$(warning UTIL_LIB_OBJ= $(UTIL_LIB_OBJ))
   49.49 +
   49.50 +all: xfrd
   49.51 +
   49.52 +xfrd: $(XFRD_PROG_OBJ) -lz
   49.53 +
   49.54 +.PHONY: install
   49.55 +install: xfrd
   49.56 +	mkdir -p $(prefix)/$(XFRD_INSTALL_DIR)
   49.57 +	install -m 0755 xfrd $(prefix)/$(XFRD_INSTALL_DIR)
   49.58 +
   49.59 +.PHONY: libutil
   49.60 +libutil: $(UTIL_LIB)
   49.61 +
   49.62 +$(UTIL_LIB): $(UTIL_LIB_OBJ)
   49.63 +	$(AR) rc $@ $^
   49.64 +
   49.65 +.PHONY: clean
   49.66 +clean:
   49.67 +	$(RM) *.o *.a *.so *~ xfrd
   49.68 +	$(RM) $(PROG_DEP)
   49.69 +
   49.70 +-include $(PROG_DEP)
   49.71 +
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/tools/xfrd/connection.c	Tue Jul 06 20:42:26 2004 +0000
    50.3 @@ -0,0 +1,163 @@
    50.4 +#include <stdlib.h>
    50.5 +#include <errno.h>
    50.6 +#include <unistd.h>
    50.7 +#include <sys/socket.h>
    50.8 +#include <netinet/in.h>
    50.9 +#include <arpa/inet.h>
   50.10 +
   50.11 +#include "connection.h"
   50.12 +#include "file_stream.h"
   50.13 +#include "lzi_stream.h"
   50.14 +
   50.15 +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
   50.16 +#define wprintf(fmt, args...) fprintf(stderr, "[WARN]  %s" fmt, __FUNCTION__, ##args)
   50.17 +#define iprintf(fmt, args...) fprintf(stdout, "[INFO]  %s" fmt, __FUNCTION__, ##args)
   50.18 +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
   50.19 +
   50.20 +/** Compress magic header. */
   50.21 +char compress_magic[2] = { 0x1f, 0x8b };
   50.22 +
   50.23 +/** Plain magic header. */
   50.24 +char plain_magic[2] = { 0x0, 0x0 };
   50.25 +
   50.26 +int Conn_read_header(int sock, int *flags){
   50.27 +    int err = 0;
   50.28 +    char magic[2] = {};
   50.29 +    int k, n = sizeof(magic);
   50.30 +    k = read(sock, magic, n);
   50.31 +    if(k != n){
   50.32 +        err = -EINVAL;
   50.33 +        goto exit;
   50.34 +    }
   50.35 +    dprintf("> magic={ 0x%x, 0x%x }\n", magic[0], magic[1]);
   50.36 +    if(magic[0] == compress_magic[0] && magic[1] == compress_magic[1]){
   50.37 +        *flags |= CONN_READ_COMPRESS;
   50.38 +        dprintf("> Using compress read.\n");
   50.39 +    } else {
   50.40 +        dprintf("> Using plain read.\n");
   50.41 +    }
   50.42 +  exit:
   50.43 +    return err;
   50.44 +}
   50.45 +
   50.46 +int Conn_write_header(int sock, int flags){
   50.47 +    int err = 0;
   50.48 +    if(flags & CONN_WRITE_COMPRESS){
   50.49 +        dprintf("> Using compress write.\n");
   50.50 +        err = write(sock, compress_magic, 2);
   50.51 +    } else { 
   50.52 +        dprintf("> Using plain write.\n");
   50.53 +       err = write(sock, plain_magic, 2);
   50.54 +    }
   50.55 +    if(err == 2) err = 0;
   50.56 +    return err;
   50.57 +}
   50.58 +
   50.59 +/** Initialize a file stream from a file desciptor.
   50.60 + *
   50.61 + * @param fd file descriptor
   50.62 + * @param mode file mode
   50.63 + * @param flags control compression and buffering
   50.64 + * @param io return parameter for the stream
   50.65 + * @return 0 on success, error code otherwise
   50.66 + */
   50.67 +int stream_init(int fd, const char *mode, int flags, int compress, IOStream **io){
   50.68 +    int err = 0;
   50.69 +    dprintf(">mode=%s flags=%x compress=%d\n", mode, flags, compress);
   50.70 +    if(compress){
   50.71 +        *io = lzi_stream_fdopen(fd, mode);
   50.72 +    } else {
   50.73 +        *io = file_stream_fdopen(fd, mode);
   50.74 +    }
   50.75 +    if(!*io){
   50.76 +        err = -errno;
   50.77 +        perror("fdopen");
   50.78 +        goto exit;
   50.79 +    }
   50.80 +    if(1 && (flags & CONN_NOBUFFER)){
   50.81 +        // Make unbuffered.
   50.82 +        dprintf("> unbuffer...\n");
   50.83 +        err = file_stream_setvbuf((compress ? lzi_stream_io(*io) : *io), NULL, _IONBF, 0);
   50.84 +        if(err){
   50.85 +            err = -errno;
   50.86 +            perror("setvbuf");
   50.87 +            goto exit;
   50.88 +        }
   50.89 +    }
   50.90 +  exit:
   50.91 +    if(err && *io){
   50.92 +        dprintf("> close err=%d\n", err);
   50.93 +        IOStream_close(*io);
   50.94 +        *io = NULL;
   50.95 +    }
   50.96 +    dprintf("< err=%d\n", err);
   50.97 +    return err;
   50.98 +}
   50.99 +    
  50.100 +/** Initialize a connection.
  50.101 + *
  50.102 + * @param conn connection
  50.103 + * @param flags
  50.104 + * @param sock socket
  50.105 + * @param ipaddr ip address
  50.106 + * @return 0 on success, error code otherwise
  50.107 + */
  50.108 +int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr){
  50.109 +    int err = 0;
  50.110 +    dprintf("> flags=%x\n", flags);
  50.111 +    conn->addr = addr;
  50.112 +    conn->sock = sock;
  50.113 +    dprintf("> write stream...\n");
  50.114 +    err = stream_init(sock, "w", flags, (flags & CONN_WRITE_COMPRESS), &conn->out);
  50.115 +    if(err) goto exit;
  50.116 +    IOStream_flush(conn->out);
  50.117 +    dprintf("> read stream...\n");
  50.118 +    err = stream_init(sock, "r", flags, (flags & CONN_READ_COMPRESS) , &conn->in);
  50.119 +    if(err) goto exit;
  50.120 +  exit:
  50.121 +    if(err) eprintf("< err=%d\n", err);
  50.122 +    return err;
  50.123 +}
  50.124 +
  50.125 +/** Open a connection.
  50.126 + *
  50.127 + * @param conn connection
  50.128 + * @param flags
  50.129 + * @param ipaddr ip address to connect to
  50.130 + * @param port port
  50.131 + * @return 0 on success, error code otherwise
  50.132 + */
  50.133 +int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port){
  50.134 +    int err = 0;
  50.135 +    int sock;
  50.136 +    struct sockaddr_in addr_in;
  50.137 +    struct sockaddr *addr = (struct sockaddr *)&addr_in;
  50.138 +    socklen_t addr_n = sizeof(addr_in);
  50.139 +    dprintf("> addr=%s:%d\n", inet_ntoa(ipaddr), ntohs(port));
  50.140 +    sock = socket(AF_INET, SOCK_STREAM, 0);
  50.141 +    if(sock < 0){
  50.142 +        err = -errno;
  50.143 +        goto exit;
  50.144 +    }
  50.145 +    addr_in.sin_family = AF_INET;
  50.146 +    addr_in.sin_addr = ipaddr;
  50.147 +    addr_in.sin_port = port;
  50.148 +    err = connect(sock, addr, addr_n);
  50.149 +    if(err) goto exit;
  50.150 +    //err = Conn_write_header(sock, flags);
  50.151 +    //if(err < 0) goto exit;
  50.152 +    err = Conn_init(conn, flags, sock, addr_in);
  50.153 +  exit:
  50.154 +    if(err) eprintf("< err=%d\n", err);
  50.155 +    return err;
  50.156 +}
  50.157 +
  50.158 +/** Close a connection.
  50.159 + *
  50.160 + * @param conn connection
  50.161 + */
  50.162 +void Conn_close(Conn *conn){
  50.163 +    if(conn->in) IOStream_close(conn->in);
  50.164 +    if(conn->out) IOStream_close(conn->out);
  50.165 +    shutdown(conn->sock, 2);
  50.166 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/tools/xfrd/connection.h	Tue Jul 06 20:42:26 2004 +0000
    51.3 @@ -0,0 +1,32 @@
    51.4 +/* $Id: connection.h,v 1.1 2003/10/17 15:48:43 mjw Exp $ */
    51.5 +#ifndef _VFC_CONNECTION_H_
    51.6 +#define _VFC_CONNECTION_H_
    51.7 +
    51.8 +#include <netinet/in.h>
    51.9 +
   51.10 +#include "iostream.h"
   51.11 +
   51.12 +/** A connection.
   51.13 + * The underlying transport is a socket. 
   51.14 + * Contains in and out streams using the socket.
   51.15 + */
   51.16 +typedef struct Conn {
   51.17 +    struct sockaddr_in addr;
   51.18 +    int sock;
   51.19 +    IOStream *in;
   51.20 +    IOStream *out;
   51.21 +} Conn;
   51.22 +
   51.23 +enum {
   51.24 +    CONN_NOBUFFER=1,
   51.25 +    CONN_READ_COMPRESS=2,
   51.26 +    CONN_WRITE_COMPRESS=4,
   51.27 +};
   51.28 +    
   51.29 +extern int Conn_read_header(int sock, int *flags);
   51.30 +extern int Conn_write_header(int sock, int flags);
   51.31 +extern int Conn_init(Conn *conn, int flags, int sock, struct sockaddr_in addr);
   51.32 +extern int Conn_connect(Conn *conn, int flags, struct in_addr ipaddr, uint16_t port);
   51.33 +extern void Conn_close(Conn *conn);
   51.34 +
   51.35 +#endif /* ! _VFC_CONNECTION_H_ */
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/tools/xfrd/debug.h	Tue Jul 06 20:42:26 2004 +0000
    52.3 @@ -0,0 +1,72 @@
    52.4 +/*
    52.5 + * Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
    52.6 + *
    52.7 + * This library is free software; you can redistribute it and/or modify
    52.8 + * it under the terms of the GNU Lesser General Public License as published by
    52.9 + * the Free Software Foundation; either version 2.1 of the License, or
   52.10 + * (at your option) any later version.
   52.11 + *
   52.12 + * This library is distributed in the hope that it will be useful,
   52.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   52.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   52.15 + * GNU Lesser General Public License for more details.
   52.16 + *
   52.17 + * You should have received a copy of the GNU Lesser General Public License
   52.18 + * along with this library; if not, write to the Free Software
   52.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   52.20 + */
   52.21 +#ifndef _XUTIL_DEBUG_H_
   52.22 +#define _XUTIL_DEBUG_H_
   52.23 +
   52.24 +#ifndef MODULE_NAME
   52.25 +#define MODULE_NAME ""
   52.26 +#endif
   52.27 +
   52.28 +#ifdef __KERNEL__
   52.29 +#include <linux/config.h>
   52.30 +#include <linux/kernel.h>
   52.31 +
   52.32 +#ifdef DEBUG
   52.33 +
   52.34 +#define dprintf(fmt, args...) printk(KERN_DEBUG   "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.35 +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.36 +#define iprintf(fmt, args...) printk(KERN_INFO    "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.37 +#define eprintf(fmt, args...) printk(KERN_ERR     "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.38 +
   52.39 +#else
   52.40 +
   52.41 +#define dprintf(fmt, args...) do {} while(0)
   52.42 +#define wprintf(fmt, args...) printk(KERN_WARNING "[WRN] " MODULE_NAME fmt, ##args)
   52.43 +#define iprintf(fmt, args...) printk(KERN_INFO    "[INF] " MODULE_NAME fmt, ##args)
   52.44 +#define eprintf(fmt, args...) printk(KERN_ERR     "[ERR] " MODULE_NAME fmt, ##args)
   52.45 +
   52.46 +#endif
   52.47 +
   52.48 +#else
   52.49 +
   52.50 +#include <stdio.h>
   52.51 +
   52.52 +#ifdef DEBUG
   52.53 +
   52.54 +#define dprintf(fmt, args...) fprintf(stdout, "[DBG] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.55 +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.56 +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.57 +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME ">%s" fmt, __FUNCTION__, ##args)
   52.58 +
   52.59 +#else
   52.60 +
   52.61 +#define dprintf(fmt, args...) do {} while(0)
   52.62 +#define wprintf(fmt, args...) fprintf(stderr, "[WRN] " MODULE_NAME fmt, ##args)
   52.63 +#define iprintf(fmt, args...) fprintf(stderr, "[INF] " MODULE_NAME fmt, ##args)
   52.64 +#define eprintf(fmt, args...) fprintf(stderr, "[ERR] " MODULE_NAME fmt, ##args)
   52.65 +
   52.66 +#endif
   52.67 +
   52.68 +#endif
   52.69 +
   52.70 +/** Print format for an IP address.
   52.71 + * See NIPQUAD(), HIPQUAD()
   52.72 + */
   52.73 +#define IPFMT "%u.%u.%u.%u"
   52.74 +
   52.75 +#endif /* ! _XUTIL_DEBUG_H_ */
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/tools/xfrd/enum.c	Tue Jul 06 20:42:26 2004 +0000
    53.3 @@ -0,0 +1,61 @@
    53.4 +/*
    53.5 + * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
    53.6 + *
    53.7 + * This library is free software; you can redistribute it and/or modify
    53.8 + * it under the terms of the GNU Lesser General Public License as
    53.9 + * published by the Free Software Foundation; either version 2.1 of the
   53.10 + * License, or  (at your option) any later version. This library is 
   53.11 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   53.12 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   53.13 + * FITNESS FOR A PARTICULAR PURPOSE.
   53.14 + * See the GNU Lesser General Public License for more details.
   53.15 + *
   53.16 + * You should have received a copy of the GNU Lesser General Public License
   53.17 + * along with this library; if not, write to the Free Software Foundation,
   53.18 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   53.19 + */
   53.20 +
   53.21 +#ifdef __KERNEL__
   53.22 +#include <linux/errno.h>
   53.23 +#else
   53.24 +#include <errno.h>
   53.25 +#endif
   53.26 +
   53.27 +#include "sys_string.h"
   53.28 +#include "enum.h"
   53.29 +
   53.30 +/** Map an enum name to its value using a table.
   53.31 + *
   53.32 + * @param name enum name
   53.33 + * @param defs enum definitions
   53.34 + * @return enum value or -1 if not known
   53.35 + */
   53.36 +int enum_name_to_val(char *name, EnumDef *defs){
   53.37 +    int val = -1;
   53.38 +    for(; defs->name; defs++){
   53.39 +	if(!strcmp(defs->name, name)){
   53.40 +	    val = defs->val;
   53.41 +	    break;
   53.42 +	}
   53.43 +    }
   53.44 +    return val;
   53.45 +}
   53.46 +
   53.47 +/** Map an enum value to its name using a table.
   53.48 + *
   53.49 + * @param val enum value
   53.50 + * @param defs enum definitions
   53.51 + * @param defs_n number of definitions
   53.52 + * @return enum name or NULL if not known
   53.53 + */
   53.54 +char *enum_val_to_name(int val, EnumDef *defs){
   53.55 +    char *name = NULL;
   53.56 +    for(; defs->name; defs++){
   53.57 +	if(val == defs->val){
   53.58 +	    name = defs->name;
   53.59 +	    break;
   53.60 +	}
   53.61 +    }
   53.62 +    return name;
   53.63 +}
   53.64 +
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/tools/xfrd/enum.h	Tue Jul 06 20:42:26 2004 +0000
    54.3 @@ -0,0 +1,30 @@
    54.4 +/*
    54.5 + * Copyright (C) 2002, 2004 Mike Wray <mike.wray@hp.com>
    54.6 + *
    54.7 + * This library is free software; you can redistribute it and/or modify
    54.8 + * it under the terms of the GNU Lesser General Public License as
    54.9 + * published by the Free Software Foundation; either version 2.1 of the
   54.10 + * License, or  (at your option) any later version. This library is 
   54.11 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   54.12 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   54.13 + * FITNESS FOR A PARTICULAR PURPOSE.
   54.14 + * See the GNU Lesser General Public License for more details.
   54.15 + *
   54.16 + * You should have received a copy of the GNU Lesser General Public License
   54.17 + * along with this library; if not, write to the Free Software Foundation,
   54.18 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   54.19 + */
   54.20 +
   54.21 +#ifndef _XUTIL_ENUM_H_
   54.22 +#define _XUTIL_ENUM_H_
   54.23 +
   54.24 +/** Mapping of an enum value to a name. */
   54.25 +typedef struct EnumDef {
   54.26 +    int val;
   54.27 +    char *name;
   54.28 +} EnumDef;
   54.29 +
   54.30 +extern int enum_name_to_val(char *name, EnumDef *defs);
   54.31 +extern char *enum_val_to_name(int val, EnumDef *defs);
   54.32 +
   54.33 +#endif /* _XUTIL_ENUM_H_ */
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/tools/xfrd/hash_table.c	Tue Jul 06 20:42:26 2004 +0000
    55.3 @@ -0,0 +1,640 @@
    55.4 +/*
    55.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    55.6 + *
    55.7 + * This library is free software; you can redistribute it and/or modify
    55.8 + * it under the terms of the GNU Lesser General Public License as published by
    55.9 + * the Free Software Foundation; either version 2.1 of the License, or
   55.10 + * (at your option) any later version.
   55.11 + *
   55.12 + * This library is distributed in the hope that it will be useful,
   55.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   55.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   55.15 + * GNU Lesser General Public License for more details.
   55.16 + *
   55.17 + * You should have received a copy of the GNU Lesser General Public License
   55.18 + * along with this library; if not, write to the Free Software
   55.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   55.20 + */
   55.21 +
   55.22 +#ifdef __KERNEL__
   55.23 +#  include <linux/config.h>
   55.24 +#  include <linux/module.h>
   55.25 +#  include <linux/kernel.h>
   55.26 +#  include <linux/errno.h>
   55.27 +#else
   55.28 +#  include <errno.h>
   55.29 +#  include <stddef.h>
   55.30 +#endif
   55.31 +
   55.32 +//#include <limits.h>
   55.33 +
   55.34 +#include "allocate.h"
   55.35 +#include "hash_table.h"
   55.36 +
   55.37 +/** @file
   55.38 + * Base support for hashtables.
   55.39 + *
   55.40 + * Hash codes are reduced modulo the number of buckets to index tables,
   55.41 + * so there is no need for hash functions to limit the range of hashcodes.
   55.42 + * In fact it is assumed that hashcodes do not change when the number of
   55.43 + * buckets in the table changes.
   55.44 + */
   55.45 +
   55.46 +/*==========================================================================*/
   55.47 +/** Number of bits in half a word. */
   55.48 +//#if __WORDSIZE == 64
   55.49 +//#define HALF_WORD_BITS 32
   55.50 +//#else
   55.51 +#define HALF_WORD_BITS 16
   55.52 +//#endif
   55.53 +
   55.54 +/** Mask for lo half of a word. On 32-bit this is 
   55.55 + * (1<<16) - 1 = 65535 = 0xffff
   55.56 + * It's 4294967295 = 0xffffffff on 64-bit.
   55.57 + */
   55.58 +#define LO_HALF_MASK ((1 << HALF_WORD_BITS) - 1)
   55.59 +
   55.60 +/** Get the lo half of a word. */
   55.61 +#define LO_HALF(x) ((x) & LO_HALF_MASK)
   55.62 +
   55.63 +/** Get the hi half of a word. */
   55.64 +#define HI_HALF(x) ((x) >> HALF_WORD_BITS)
   55.65 +
   55.66 +/** Do a full hash on both inputs, using DES-style non-linear scrambling.
   55.67 + * Both inputs are replaced with the results of the hash.
   55.68 + *
   55.69 + * @param pleft input/output word
   55.70 + * @param pright input/output word
   55.71 + */
   55.72 +void pseudo_des(unsigned long *pleft, unsigned long *pright){
   55.73 +    // Bit-rich mixing constant.
   55.74 +    static const unsigned long a_mixer[] = {
   55.75 +        0xbaa96887L, 0x1e17d32cL, 0x03bcdc3cL, 0x0f33d1b2L, };
   55.76 +
   55.77 +    // Bit-rich mixing constant.
   55.78 +    static const unsigned long b_mixer[] = {
   55.79 +        0x4b0f3b58L, 0xe874f0c3L, 0x6955c5a6L, 0x55a7ca46L, };
   55.80 +
   55.81 +    // Number of iterations - must be 2 or 4.
   55.82 +    static const int ncycle = 4;
   55.83 +    //static const int ncycle = 2;
   55.84 +
   55.85 +    unsigned long left = *pleft, right = *pright;
   55.86 +    unsigned long v, v_hi, v_lo;
   55.87 +    int i;
   55.88 +
   55.89 +    for(i=0; i<ncycle; i++){
   55.90 +        // Flip some bits in right to get v.
   55.91 +        v = right;
   55.92 +        v ^= a_mixer[i];
   55.93 +        // Get lo and hi halves of v.
   55.94 +        v_lo = LO_HALF(v);
   55.95 +        v_hi = HI_HALF(v);
   55.96 +        // Non-linear mix of the halves of v.
   55.97 +        v = ((v_lo * v_lo) + ~(v_hi * v_hi));
   55.98 +        // Swap the halves of v.
   55.99 +        v = (HI_HALF(v) | (LO_HALF(v) << HALF_WORD_BITS));
  55.100 +        // Flip some bits.
  55.101 +        v ^= b_mixer[i];
  55.102 +        // More non-linear mixing.
  55.103 +        v += (v_lo * v_hi);
  55.104 +        v ^= left;
  55.105 +        left = right;
  55.106 +        right = v;
  55.107 +    }
  55.108 +    *pleft = left;
  55.109 +    *pright = right;
  55.110 +}
  55.111 +
  55.112 +/** Hash a string.
  55.113 + *
  55.114 + * @param s input to hash
  55.115 + * @return hashcode
  55.116 + */
  55.117 +Hashcode hash_string(char *s){
  55.118 +    Hashcode h = 0;
  55.119 +    if(s){
  55.120 +        for( ; *s; s++){
  55.121 +            h = hash_2ul(h, *s);
  55.122 +        }
  55.123 +    }
  55.124 +    return h;
  55.125 +}
  55.126 +
  55.127 +/** Get the bucket for a hashcode in a hash table.
  55.128 + *
  55.129 + * @param table to get bucket from
  55.130 + * @param hashcode to get bucket for
  55.131 + * @return bucket
  55.132 + */
  55.133 +inline HTBucket * get_bucket(HashTable *table, Hashcode hashcode){
  55.134 +    return table->buckets + (hashcode % table->buckets_n);
  55.135 +}
  55.136 +
  55.137 +/** Initialize a hash table.
  55.138 + * Can be safely called more than once.
  55.139 + *
  55.140 + * @param table to initialize
  55.141 + */
  55.142 +void HashTable_init(HashTable *table){
  55.143 +    int i;
  55.144 +
  55.145 +    if(!table->init_done){
  55.146 +        table->init_done = 1;
  55.147 +        table->next_id = 0;
  55.148 +        for(i=0; i<table->buckets_n; i++){
  55.149 +            HTBucket *bucket = get_bucket(table, i);
  55.150 +            bucket->head = 0;
  55.151 +            bucket->count = 0;
  55.152 +        }
  55.153 +        table->entry_count = 0;
  55.154 +    }
  55.155 +}
  55.156 +
  55.157 +/** Allocate a new hashtable.
  55.158 + * If the number of buckets is not positive the default is used.
  55.159 + * The number of buckets should usually be prime.
  55.160 + *
  55.161 + * @param buckets_n number of buckets
  55.162 + * @return new hashtable or null
  55.163 + */
  55.164 +HashTable *HashTable_new(int buckets_n){
  55.165 +    HashTable *z = ALLOCATE(HashTable);
  55.166 +    if(!z) goto exit;
  55.167 +    if(buckets_n <= 0){
  55.168 +        buckets_n = HT_BUCKETS_N;
  55.169 +    }
  55.170 +    z->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
  55.171 +    if(!z->buckets){
  55.172 +        deallocate(z);
  55.173 +        z = 0;
  55.174 +        goto exit;
  55.175 +    }
  55.176 +    z->buckets_n = buckets_n;
  55.177 +    HashTable_init(z);
  55.178 +  exit:
  55.179 +    return z;
  55.180 +}
  55.181 +
  55.182 +/** Free a hashtable.
  55.183 + * Any entries are removed and freed.
  55.184 + *
  55.185 + * @param h hashtable (ignored if null)
  55.186 + */
  55.187 +void HashTable_free(HashTable *h){
  55.188 +    if(h){
  55.189 +        HashTable_clear(h);
  55.190 +        deallocate(h->buckets);
  55.191 +        deallocate(h);
  55.192 +    }
  55.193 +}
  55.194 +
  55.195 +/** Push an entry on the list in the bucket for a given hashcode.
  55.196 + *
  55.197 + * @param table to add entry to
  55.198 + * @param hashcode for the entry
  55.199 + * @param entry to add
  55.200 + */
  55.201 +static inline void push_on_bucket(HashTable *table, Hashcode hashcode,
  55.202 +				  HTEntry *entry){
  55.203 +    HTBucket *bucket;
  55.204 +    HTEntry *old_head;
  55.205 +
  55.206 +    bucket = get_bucket(table, hashcode);
  55.207 +    old_head = bucket->head;
  55.208 +    bucket->count++;
  55.209 +    bucket->head = entry;
  55.210 +    entry->next = old_head;
  55.211 +}
  55.212 +
  55.213 +/** Change the number of buckets in a hashtable.
  55.214 + * No-op if the number of buckets is not positive.
  55.215 + * Existing entries are reallocated to buckets based on their hashcodes.
  55.216 + * The table is unmodified if the number of buckets cannot be changed.
  55.217 + *
  55.218 + * @param table hashtable
  55.219 + * @param buckets_n new number of buckets
  55.220 + * @return 0 on success, error code otherwise
  55.221 + */
  55.222 +int HashTable_set_buckets_n(HashTable *table, int buckets_n){
  55.223 +    int err = 0;
  55.224 +    HTBucket *old_buckets = table->buckets;
  55.225 +    int old_buckets_n = table->buckets_n;
  55.226 +    int i;
  55.227 +
  55.228 +    if(buckets_n <= 0){
  55.229 +        err = -EINVAL;
  55.230 +        goto exit;
  55.231 +    }
  55.232 +    table->buckets = (HTBucket*)allocate(buckets_n * sizeof(HTBucket));
  55.233 +    if(!table->buckets){
  55.234 +        err = -ENOMEM;
  55.235 +        table->buckets = old_buckets;
  55.236 +        goto exit;
  55.237 +    }
  55.238 +    table->buckets_n = buckets_n;
  55.239 +    for(i=0; i<old_buckets_n; i++){
  55.240 +        HTBucket *bucket = old_buckets + i;
  55.241 +        HTEntry *entry, *next;
  55.242 +        for(entry = bucket->head; entry; entry = next){
  55.243 +            next = entry->next;
  55.244 +            push_on_bucket(table, entry->hashcode, entry);
  55.245 +        }
  55.246 +    }
  55.247 +    deallocate(old_buckets);
  55.248 +  exit:
  55.249 +    return err;
  55.250 +}
  55.251 +
  55.252 +/** Adjust the number of buckets so the table is neither too full nor too empty.
  55.253 + * The table is unmodified if adjusting fails.
  55.254 + *
  55.255 + * @param table hash table
  55.256 + * @param buckets_min minimum number of buckets (use default if 0 or negative)
  55.257 + * @return 0 on success, error code otherwise
  55.258 + */
  55.259 +int HashTable_adjust(HashTable *table, int buckets_min){
  55.260 +    int buckets_n = 0;
  55.261 +    int err = 0;
  55.262 +    if(buckets_min <= 0) buckets_min = HT_BUCKETS_N;
  55.263 +    if(table->entry_count >= table->buckets_n){
  55.264 +        // The table is dense - expand it.
  55.265 +        buckets_n = 2 * table->buckets_n;
  55.266 +    } else if((table->buckets_n > buckets_min) &&
  55.267 +              (4 * table->entry_count < table->buckets_n)){
  55.268 +        // The table is more than minimum size and sparse - shrink it.
  55.269 +        buckets_n = 2 * table->entry_count;
  55.270 +        if(buckets_n < buckets_min) buckets_n = buckets_min;
  55.271 +    }
  55.272 +    if(buckets_n){
  55.273 +        err = HashTable_set_buckets_n(table, buckets_n);
  55.274 +    }
  55.275 +    return err;
  55.276 +}
  55.277 +
  55.278 +/** Allocate a new entry for a given value.
  55.279 + *
  55.280 + * @param value to put in the entry
  55.281 + * @return entry, or 0 on failure
  55.282 + */
  55.283 +HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value){
  55.284 +    HTEntry *z = ALLOCATE(HTEntry);
  55.285 +    if(z){
  55.286 +        z->hashcode = hashcode;
  55.287 +        z->key = key;
  55.288 +        z->value = value;
  55.289 +    }
  55.290 +    return z;
  55.291 +}
  55.292 +
  55.293 +/** Free an entry.
  55.294 + *
  55.295 + * @param z entry to free
  55.296 + */
  55.297 +inline void HTEntry_free(HTEntry *z){
  55.298 +    if(z){
  55.299 +        deallocate(z);
  55.300 +    }
  55.301 +}
  55.302 +
  55.303 +/** Free an entry in a hashtable.
  55.304 + * The table's entry_free_fn is used is defined, otherwise 
  55.305 + * the HTEntry itself is freed.
  55.306 + *
  55.307 + * @param table hashtable
  55.308 + * @param entry to free
  55.309 + */
  55.310 +inline void HashTable_free_entry(HashTable *table, HTEntry *entry){
  55.311 +    if(!entry)return;
  55.312 +    if(table && table->entry_free_fn){
  55.313 +        table->entry_free_fn(table, entry);
  55.314 +    } else {
  55.315 +        HTEntry_free(entry);
  55.316 +    }
  55.317 +}
  55.318 +
  55.319 +/** Get the first entry satisfying a test from the bucket for the
  55.320 + * given hashcode.
  55.321 + *
  55.322 + * @param table to look in
  55.323 + * @param hashcode indicates the bucket
  55.324 + * @param test_fn test to apply to elements
  55.325 + * @param arg first argument to calls to test_fn
  55.326 + * @return entry found, or 0
  55.327 + */
  55.328 +inline HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
  55.329 +				      TableTestFn *test_fn, TableArg arg){
  55.330 +    HTBucket *bucket;
  55.331 +    HTEntry *entry = 0;
  55.332 +    HTEntry *next;
  55.333 +
  55.334 +    bucket = get_bucket(table, hashcode);
  55.335 +    for(entry = bucket->head; entry; entry = next){
  55.336 +        next = entry->next;
  55.337 +        if(test_fn(arg, table, entry)){
  55.338 +            break;
  55.339 +        }
  55.340 +    }
  55.341 +    return entry;
  55.342 +}
  55.343 +
  55.344 +/** Test hashtable keys for equality.
  55.345 + * Uses the table's key_equal_fn if defined, otherwise pointer equality.
  55.346 + *
  55.347 + * @param key1 key to compare
  55.348 + * @param key2 key to compare
  55.349 + * @return 1 if equal, 0 otherwise
  55.350 + */
  55.351 +inline int HashTable_key_equal(HashTable *table, void *key1, void *key2){
  55.352 +    return (table->key_equal_fn ? table->key_equal_fn(key1, key2) : key1==key2);
  55.353 +}
  55.354 +
  55.355 +/** Compute the hashcode of a hashtable key.
  55.356 + * The table's key_hash_fn is used if defined, otherwise the address of
  55.357 + * the key is hashed.
  55.358 + *
  55.359 + * @param table hashtable
  55.360 + * @param key to hash
  55.361 + * @return hashcode
  55.362 + */
  55.363 +inline Hashcode HashTable_key_hash(HashTable *table, void *key){
  55.364 +    return (table->key_hash_fn ? table->key_hash_fn(key) : hash_ul((unsigned long)key));
  55.365 +}
  55.366 +
  55.367 +/** Test if an entry has a given key.
  55.368 + *
  55.369 + * @param arg containing key to test for
  55.370 + * @param table the entry is in
  55.371 + * @param entry to test
  55.372 + * @return 1 if the entry has the key, 0 otherwise
  55.373 + */
  55.374 +static inline int has_key(TableArg arg, HashTable *table, HTEntry *entry){
  55.375 +    return HashTable_key_equal(table, arg.ptr, entry->key);
  55.376 +}
  55.377 +
  55.378 +/** Get an entry with a given key.
  55.379 + *
  55.380 + * @param table to search
  55.381 + * @param key to look for
  55.382 + * @return entry if found, null otherwise
  55.383 + */
  55.384 +#if 0
  55.385 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
  55.386 +    TableArg arg = { ptr: key };
  55.387 +    return HashTable_find_entry(table, HashTable_key_hash(table, key), has_key, arg);
  55.388 +}
  55.389 +#else
  55.390 +inline HTEntry * HashTable_get_entry(HashTable *table, void *key){
  55.391 +    Hashcode hashcode;
  55.392 +    HTBucket *bucket;
  55.393 +    HTEntry *entry = 0;
  55.394 +    HTEntry *next;
  55.395 +
  55.396 +    hashcode = HashTable_key_hash(table, key);
  55.397 +    bucket = get_bucket(table, hashcode);
  55.398 +    for(entry = bucket->head; entry; entry = next){
  55.399 +        next = entry->next;
  55.400 +        if(HashTable_key_equal(table, key, entry->key)){
  55.401 +            break;
  55.402 +        }
  55.403 +    }
  55.404 +    return entry;
  55.405 +}
  55.406 +#endif
  55.407 +
  55.408 +/** Get the value of an entry with a given key.
  55.409 + *
  55.410 + * @param table to search
  55.411 + * @param key to look for
  55.412 + * @return value if an entry was found, null otherwise
  55.413 + */
  55.414 +inline void * HashTable_get(HashTable *table, void *key){
  55.415 +    HTEntry *entry = HashTable_get_entry(table, key);
  55.416 +    return (entry ? entry->value : 0);
  55.417 +}
  55.418 +
  55.419 +/** Print the buckets in a table.
  55.420 + *
  55.421 + * @param table to print
  55.422 + */
  55.423 +void show_buckets(HashTable *table, IOStream *io){
  55.424 +    int i,j ;
  55.425 +    IOStream_print(io, "entry_count=%d buckets_n=%d\n", table->entry_count, table->buckets_n);
  55.426 +    for(i=0; i<table->buckets_n; i++){
  55.427 +        if(0 || table->buckets[i].count>0){
  55.428 +            IOStream_print(io, "bucket %3d %3d %10p ", i,
  55.429 +                        table->buckets[i].count,
  55.430 +                        table->buckets[i].head);
  55.431 +            for(j = table->buckets[i].count; j>0; j--){
  55.432 +                IOStream_print(io, "+");
  55.433 +            }
  55.434 +            IOStream_print(io, "\n");
  55.435 +        }
  55.436 +    }
  55.437 +    HashTable_print(table, io); 
  55.438 +}
  55.439 +    
  55.440 +/** Print an entry in a table.
  55.441 + *
  55.442 + * @param entry to print
  55.443 + * @param arg a pointer to an IOStream to print to
  55.444 + * @return 0
  55.445 + */
  55.446 +static int print_entry(TableArg arg, HashTable *table, HTEntry *entry){
  55.447 +    IOStream *io = (IOStream*)arg.ptr;
  55.448 +    IOStream_print(io, " b=%4lx h=%08lx i=%08lx |-> e=%8p k=%8p v=%8p\n",
  55.449 +                entry->hashcode % table->buckets_n,
  55.450 +                entry->hashcode,
  55.451 +                entry->index,
  55.452 +                entry, entry->key, entry->value);
  55.453 +    return 0;
  55.454 +}
  55.455 +
  55.456 +/** Print a hash table.
  55.457 + *
  55.458 + * @param table to print
  55.459 + */
  55.460 +void HashTable_print(HashTable *table, IOStream *io){
  55.461 +    IOStream_print(io, "{\n");
  55.462 +    HashTable_map(table, print_entry, (TableArg){ ptr: io });
  55.463 +    IOStream_print(io, "}\n");
  55.464 +}
  55.465 +/*==========================================================================*/
  55.466 +
  55.467 +/** Get the next entry id to use for a table.
  55.468 + *
  55.469 + * @param table hash table
  55.470 + * @return non-zero entry id
  55.471 + */
  55.472 +static inline unsigned long get_next_id(HashTable *table){
  55.473 +    unsigned long id;
  55.474 +
  55.475 +    if(table->next_id == 0){
  55.476 +        table->next_id = 1;
  55.477 +    }
  55.478 +    id = table->next_id++;
  55.479 +    return id;
  55.480 +}
  55.481 +
  55.482 +/** Add an entry to the bucket for the
  55.483 + * given hashcode.
  55.484 + *
  55.485 + * @param table to insert in
  55.486 + * @param hashcode indicates the bucket
  55.487 + * @param key to add an entry for
  55.488 + * @param value to add an entry for
  55.489 + * @return entry on success, 0 on failure
  55.490 + */
  55.491 +inline HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value){
  55.492 +    HTEntry *entry = HTEntry_new(hashcode, key, value);
  55.493 +    if(entry){
  55.494 +        entry->index = get_next_id(table);
  55.495 +        push_on_bucket(table, hashcode, entry);
  55.496 +        table->entry_count++;
  55.497 +    }
  55.498 +    return entry;
  55.499 +}
  55.500 +
  55.501 +/** Move the front entry for a bucket to the correct point in the bucket order as
  55.502 + * defined by the order function. If this is called every time a new entry is added
  55.503 + * the bucket will be maintained in sorted order.
  55.504 + *
  55.505 + * @param table to modify
  55.506 + * @param hashcode indicates the bucket
  55.507 + * @param order entry comparison function
  55.508 + * @return 0 if an entry was moved, 1 if not
  55.509 + */
  55.510 +int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order){
  55.511 +    HTEntry *new_entry = NULL, *prev = NULL, *entry = NULL;
  55.512 +    HTBucket *bucket;
  55.513 +    int err = 1;
  55.514 +
  55.515 +    bucket = get_bucket(table, hashcode);
  55.516 +    new_entry = bucket->head;
  55.517 +    if(!new_entry || !new_entry->next) goto exit;
  55.518 +    for(entry = new_entry->next; entry; prev = entry, entry = entry->next){
  55.519 +        if(order(new_entry, entry) <= 0) break;
  55.520 +    }
  55.521 +    if(prev){
  55.522 +        err = 0;
  55.523 +        bucket->head = new_entry->next; 
  55.524 +        new_entry->next = entry;
  55.525 +        prev->next = new_entry;
  55.526 +    }
  55.527 +  exit:
  55.528 +    return err;
  55.529 +}
  55.530 +
  55.531 +/** Add an entry to a hashtable.
  55.532 + * The entry is added to the bucket for its key's hashcode.
  55.533 + *
  55.534 + * @param table to insert in
  55.535 + * @param key to add an entry for
  55.536 + * @param value to add an entry for
  55.537 + * @return entry on success, 0 on failure
  55.538 + */
  55.539 +inline HTEntry * HashTable_add(HashTable *table, void *key, void *value){
  55.540 +    return HashTable_add_entry(table, HashTable_key_hash(table, key), key, value);
  55.541 +}
  55.542 +
  55.543 +
  55.544 +/** Remove entries satisfying a test from the bucket for the
  55.545 + * given hashcode. 
  55.546 + *
  55.547 + * @param table to remove from
  55.548 + * @param hashcode indicates the bucket
  55.549 + * @param test_fn test to apply to elements
  55.550 + * @param arg first argument to calls to test_fn
  55.551 + * @return number of entries removed
  55.552 + */
  55.553 +inline int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
  55.554 +				  TableTestFn *test_fn, TableArg arg){
  55.555 +    HTBucket *bucket;
  55.556 +    HTEntry *entry, *prev = 0, *next;
  55.557 +    int removed_count = 0;
  55.558 +
  55.559 +    bucket = get_bucket(table, hashcode);
  55.560 +    for(entry = bucket->head; entry; entry = next){
  55.561 +        next = entry->next;
  55.562 +        if(test_fn(arg, table, entry)){
  55.563 +            if(prev){
  55.564 +                prev->next = next;
  55.565 +            } else {
  55.566 +                bucket->head = next;
  55.567 +            }
  55.568 +            bucket->count--;
  55.569 +            table->entry_count--;
  55.570 +            removed_count++;
  55.571 +            HashTable_free_entry(table, entry);
  55.572 +            entry = 0;
  55.573 +        }
  55.574 +        prev = entry;
  55.575 +    }
  55.576 +    return removed_count;
  55.577 +}
  55.578 +
  55.579 +/** Remove entries with a given key. 
  55.580 + *
  55.581 + * @param table to remove from
  55.582 + * @param key of entries to remove
  55.583 + * @return number of entries removed
  55.584 + */
  55.585 +inline int HashTable_remove(HashTable *table, void *key){
  55.586 +#if 1
  55.587 +    Hashcode hashcode;
  55.588 +    HTBucket *bucket;
  55.589 +    HTEntry *entry, *prev = 0, *next;
  55.590 +    int removed_count = 0;
  55.591 +
  55.592 +    hashcode = HashTable_key_hash(table, key);
  55.593 +    bucket = get_bucket(table, hashcode);
  55.594 +    for(entry = bucket->head; entry; entry = next){
  55.595 +        next = entry->next;
  55.596 +        if(HashTable_key_equal(table, key, entry->key)){
  55.597 +            if(prev){
  55.598 +                prev->next = next;
  55.599 +            } else {
  55.600 +                bucket->head = next;
  55.601 +            }
  55.602 +            bucket->count--;
  55.603 +            table->entry_count--;
  55.604 +            removed_count++;
  55.605 +            HashTable_free_entry(table, entry);
  55.606 +            entry = 0;
  55.607 +        }
  55.608 +        prev = entry;
  55.609 +    }
  55.610 +    return removed_count;
  55.611 +#else
  55.612 +    return HashTable_remove_entry(table, HashTable_key_hash(table, key),
  55.613 +				  has_key, (TableArg){ ptr: key});
  55.614 +#endif
  55.615 +}
  55.616 +
  55.617 +/** Remove (and free) all the entries in a bucket.
  55.618 + *
  55.619 + * @param bucket to clear
  55.620 + */
  55.621 +static inline void bucket_clear(HashTable *table, HTBucket *bucket){
  55.622 +    HTEntry *entry, *next;
  55.623 +
  55.624 +    for(entry = bucket->head; entry; entry = next){
  55.625 +        next = entry->next;
  55.626 +        HashTable_free_entry(table, entry);
  55.627 +    }
  55.628 +    bucket->head = 0;
  55.629 +    table->entry_count -= bucket->count;
  55.630 +    bucket->count = 0;
  55.631 +}
  55.632 +
  55.633 +/** Remove (and free) all the entries in a table.
  55.634 + *
  55.635 + * @param table to clear
  55.636 + */
  55.637 +void HashTable_clear(HashTable *table){
  55.638 +    int i, n = table->buckets_n;
  55.639 +
  55.640 +    for(i=0; i<n; i++){
  55.641 +        bucket_clear(table, table->buckets + i);
  55.642 +    }
  55.643 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/tools/xfrd/hash_table.h	Tue Jul 06 20:42:26 2004 +0000
    56.3 @@ -0,0 +1,294 @@
    56.4 +/*
    56.5 + * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com>
    56.6 + *
    56.7 + * This library is free software; you can redistribute it and/or modify
    56.8 + * it under the terms of the GNU Lesser General Public License as published by
    56.9 + * the Free Software Foundation; either version 2.1 of the License, or
   56.10 + * (at your option) any later version.
   56.11 + *
   56.12 + * This library is distributed in the hope that it will be useful,
   56.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   56.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   56.15 + * GNU Lesser General Public License for more details.
   56.16 + *
   56.17 + * You should have received a copy of the GNU Lesser General Public License
   56.18 + * along with this library; if not, write to the Free Software
   56.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   56.20 + */
   56.21 +
   56.22 +#ifndef _XUTIL_HASH_TABLE_H_
   56.23 +#define _XUTIL_HASH_TABLE_H_
   56.24 +
   56.25 +#include "iostream.h"
   56.26 +
   56.27 +typedef unsigned long Hashcode;
   56.28 +
   56.29 +/** Type used to pass parameters to table functions. */
   56.30 +typedef union TableArg {
   56.31 +    unsigned long ul;
   56.32 +    void *ptr;
   56.33 +} TableArg;
   56.34 +
   56.35 +/** An entry in a bucket list. */
   56.36 +typedef struct HTEntry {
   56.37 +    /** Hashcode of the entry's key. */
   56.38 +    Hashcode hashcode;
   56.39 +    /** Identifier for this entry in the table. */
   56.40 +    int index;
   56.41 +    /** The key for this entry. */
   56.42 +    void *key;
   56.43 +    /** The value in this entry. */
   56.44 +    void *value;
   56.45 +    /** The next entry in the list. */
   56.46 +    struct HTEntry *next;
   56.47 +} HTEntry;
   56.48 +
   56.49 +/** A bucket in a rule table. */
   56.50 +typedef struct HTBucket {
   56.51 +    /** Number of entries in the bucket. */
   56.52 +    int count;
   56.53 +    /** First entry in the bucket (may be null). */
   56.54 +    HTEntry *head;
   56.55 +} HTBucket;
   56.56 +
   56.57 +/** Default number of buckets in a hash table.
   56.58 + * You want enough buckets so the lists in the buckets will typically be short.
   56.59 + * It's a good idea if this is prime, since that will help to spread hashcodes
   56.60 + * around the table.
   56.61 + */
   56.62 +//#define HT_BUCKETS_N 1
   56.63 +//#define HT_BUCKETS_N 3
   56.64 +//#define HT_BUCKETS_N 7
   56.65 +//#define HT_BUCKETS_N 17
   56.66 +//#define HT_BUCKETS_N 97
   56.67 +//#define HT_BUCKETS_N 211
   56.68 +//#define HT_BUCKETS_N 401
   56.69 +#define HT_BUCKETS_N 1021
   56.70 +
   56.71 +typedef struct HashTable HashTable;
   56.72 +
   56.73 +/** Type for a function used to select table entries. */
   56.74 +typedef int TableTestFn(TableArg arg, HashTable *table, HTEntry *entry);
   56.75 +
   56.76 +/** Type for a function to map over table entries. */
   56.77 +typedef int TableMapFn(TableArg arg, HashTable *table, HTEntry *entry);
   56.78 +
   56.79 +/** Type for a function to free table entries. */
   56.80 +typedef void TableFreeFn(HashTable *table, HTEntry *entry);
   56.81 +
   56.82 +/** Type for a function to hash table keys. */
   56.83 +typedef Hashcode TableHashFn(void *key);
   56.84 +
   56.85 +/** Type for a function to test table keys for equality. */
   56.86 +typedef int TableEqualFn(void *key1, void *key2);
   56.87 +
   56.88 +/** Type for a function to order table entries. */
   56.89 +typedef int TableOrderFn(HTEntry *e1, HTEntry *e2);
   56.90 +
   56.91 +/** General hash table.
   56.92 + * A hash table with a list in each bucket.
   56.93 + * Functions can be supplied for freeing entries, hashing keys, and comparing keys.
   56.94 + * These all default to 0, when default behaviour treating keys as integers is used.
   56.95 + */
   56.96 +struct HashTable {
   56.97 +    /** Flag indicating whether the table has been initialised. */
   56.98 +    int init_done;
   56.99 +    /** Next value for the id field in inserted rules. */
  56.100 +    unsigned long next_id;
  56.101 +    /** Number of buckets in the bucket array. */
  56.102 +    int buckets_n;
  56.103 +    /** Array of buckets, each with its own list. */
  56.104 +    HTBucket *buckets;
  56.105 +    /** Number of entries in the table. */
  56.106 +    int entry_count;
  56.107 +    /** Function to free keys and values in entries. */
  56.108 +    TableFreeFn *entry_free_fn;
  56.109 +    /** Function to hash keys. */
  56.110 +    TableHashFn *key_hash_fn;
  56.111 +    /** Function to compare keys for equality. */
  56.112 +    TableEqualFn *key_equal_fn;
  56.113 +    /** Place for the user of the table to hang extra data. */
  56.114 +    void *user_data;
  56.115 +};
  56.116 +
  56.117 +extern HashTable *HashTable_new(int bucket_n);
  56.118 +extern void HashTable_free(HashTable *table);
  56.119 +extern HTEntry * HTEntry_new(Hashcode hashcode, void *key, void *value);
  56.120 +extern void HTEntry_free(HTEntry *entry);
  56.121 +extern int HashTable_set_bucket_n(HashTable *table, int bucket_n);
  56.122 +extern void HashTable_clear(HashTable *table);
  56.123 +extern HTEntry * HashTable_add_entry(HashTable *table, Hashcode hashcode, void *key, void *value);
  56.124 +extern HTEntry * HashTable_get_entry(HashTable *table, void *key);
  56.125 +extern HTEntry * HashTable_add(HashTable *table, void *key, void *value);
  56.126 +extern void * HashTable_get(HashTable *table, void *key);
  56.127 +extern int HashTable_remove(HashTable *table, void *key);
  56.128 +extern HTEntry * HashTable_find_entry(HashTable *table, Hashcode hashcode,
  56.129 +                                      TableTestFn *test_fn, TableArg arg);
  56.130 +extern int HashTable_remove_entry(HashTable *table, Hashcode hashcode,
  56.131 +                                   TableTestFn *test_fn, TableArg arg);
  56.132 +//extern int HashTable_map(HashTable *table, TableMapFn *map_fn, TableArg arg);
  56.133 +extern void HashTable_print(HashTable *table, IOStream *out);
  56.134 +extern int HashTable_set_buckets_n(HashTable *table, int buckets_n);
  56.135 +extern int HashTable_adjust(HashTable *table, int buckets_min);
  56.136 +extern void pseudo_des(unsigned long *pleft, unsigned long *pright);
  56.137 +extern Hashcode hash_string(char *s);
  56.138 +
  56.139 +extern int HashTable_order_bucket(HashTable *table, Hashcode hashcode, TableOrderFn *order);
  56.140 +
  56.141 +/** Control whether to use hashing based on DES or simple
  56.142 + * hashing. DES hashing is `more random' but much more expensive.
  56.143 + */
  56.144 +#define HASH_PSEUDO_DES 0
  56.145 +
  56.146 +/** Hash a long using a quick and dirty linear congruential random number generator.
  56.147 + *  See `Numerical Recipes in C', Chapter 7, "An Even Quicker Generator".
  56.148 + *
  56.149 + * @param a value to hash
  56.150 + * @return hashed input
  56.151 + */
  56.152 +static inline unsigned long lcrng_hash(unsigned long a){
  56.153 +    return (1664525L * a + 1013904223L);
  56.154 +}
  56.155 +
  56.156 +/** Hash an unsigned long.
  56.157 + *
  56.158 + * @param a input to hash
  56.159 + * @return hashcode
  56.160 + */
  56.161 +static inline Hashcode hash_ul(unsigned long a){
  56.162 +#if HASH_PSEUDO_DES
  56.163 +    unsigned long left = a;
  56.164 +    unsigned long right = 0L;
  56.165 +    pseudo_des(&left, &right);
  56.166 +    return right;
  56.167 +#else
  56.168 +    a = lcrng_hash(a);
  56.169 +    a = lcrng_hash(a);
  56.170 +    return a;
  56.171 +#endif
  56.172 +}
  56.173 +
  56.174 +/** Hash two unsigned longs together.
  56.175 + *
  56.176 + * @param a input to hash
  56.177 + * @param b input to hash
  56.178 + * @return hashcode
  56.179 + */
  56.180 +static inline Hashcode hash_2ul(unsigned long a, unsigned long b){
  56.181 +#if HASH_PSEUDO_DES
  56.182 +    unsigned long left = a;
  56.183 +    unsigned long right = b;
  56.184 +    pseudo_des(&left, &right);
  56.185 +    return right;
  56.186 +#else
  56.187 +    a = lcrng_hash(a);
  56.188 +    a ^= b;
  56.189 +    a = lcrng_hash(a);
  56.190 +    return a;
  56.191 +#endif
  56.192 +}
  56.193 +
  56.194 +/** Hash a hashcode and an unsigned long together.
  56.195 + *
  56.196 + * @param a input hashcode
  56.197 + * @param b input to hash
  56.198 + * @return hashcode
  56.199 + */
  56.200 +static inline Hashcode hash_hul(Hashcode a, unsigned long b){
  56.201 +#if HASH_PSEUDO_DES
  56.202 +    unsigned long left = a;
  56.203 +    unsigned long right = b;
  56.204 +    pseudo_des(&left, &right);
  56.205 +    return right;
  56.206 +#else
  56.207 +    a ^= b;
  56.208 +    a = lcrng_hash(a);
  56.209 +    return a;
  56.210 +#endif
  56.211 +}
  56.212 +
  56.213 +/** Macro to declare variables for HashTable_for_each() to use.
  56.214 + *
  56.215 + * @param entry variable that is set to entries in the table
  56.216 + */
  56.217 +#define HashTable_for_decl(entry) \
  56.218 +  HashTable *_var_table; \
  56.219 +  HTBucket *_var_bucket; \
  56.220 +  HTBucket *_var_end; \
  56.221 +  HTEntry *_var_next; \
  56.222 +  HTEntry *entry
  56.223 +
  56.224 +/** Macro to iterate over the entries in a hashtable.
  56.225 + * Must be in a scope where HashTable_for_decl() has been used to declare
  56.226 + * variables for it to use.
  56.227 + * The variable 'entry' is iterated over entries in the table.
  56.228 + * The code produced is syntactically a loop, so it must be followed by
  56.229 + * a loop body, typically some statements in braces:
  56.230 + * HashTable_for_each(entry, table){ ...loop body... }
  56.231 + *
  56.232 + * HashTable_for_each() and HashTable_for_decl() cannot be used for nested
  56.233 + * loops as variables will clash.
  56.234 + *
  56.235 + * @note The simplest way to code a direct loop over the entries in a hashtable
  56.236 + * is to use a loop over the buckets, with a nested loop over the entries
  56.237 + * in a bucket. Using this approach in a macro means the macro contains
  56.238 + * an opening brace, and calls to it must be followed by 2 braces!
  56.239 + * To avoid this the code has been restructured so that it is a for loop.
  56.240 + * So that statements could be used in the test expression of the for loop,
  56.241 + * we have used the gcc statement expression extension ({ ... }).
  56.242 + *
  56.243 + * @param entry variable to iterate over the entries
  56.244 + * @param table to iterate over (non-null)
  56.245 + */
  56.246 +#define HashTable_for_each(entry, table) \
  56.247 +  _var_table = table; \
  56.248 +  _var_bucket = _var_table->buckets; \
  56.249 +  _var_end = _var_bucket + _var_table->buckets_n; \
  56.250 +  for(entry=0, _var_next=0; \
  56.251 +      ({ if(_var_next){ \
  56.252 +             entry = _var_next; \
  56.253 +             _var_next = entry->next; \
  56.254 +          } else { \
  56.255 +             while(_var_bucket < _var_end){ \
  56.256 +                 entry = _var_bucket->head; \
  56.257 +                 _var_bucket++; \
  56.258 +                 if(entry){ \
  56.259 +                      _var_next = entry->next; \
  56.260 +                      break; \
  56.261 +                 } \
  56.262 +             } \
  56.263 +          }; \
  56.264 +         entry; }); \
  56.265 +      entry = _var_next )
  56.266 +
  56.267 +/** Map a function over the entries in a table.
  56.268 + * Mapping stops when the function returns a non-zero value.
  56.269 + * Uses the gcc statement expression extension ({ ... }).
  56.270 + *
  56.271 + * @param table to map over
  56.272 + * @param fn function to apply to entries
  56.273 + * @param arg first argument to call the function with
  56.274 + * @return 0 if fn always returned 0, first non-zero value otherwise
  56.275 + */
  56.276 +#define HashTable_map(table, fn, arg) \
  56.277 +  ({ HashTable_for_decl(_var_entry); \
  56.278 +    TableArg _var_arg = arg; \
  56.279 +    int _var_value = 0; \
  56.280 +    HashTable_for_each(_var_entry, table){ \
  56.281 +        if((_var_value = fn(_var_arg, _var_table, _var_entry))) break; \
  56.282 +    } \
  56.283 +    _var_value; })
  56.284 +
  56.285 +/** Cast x to the type for a key or value in a hash table.
  56.286 + * This avoids compiler warnings when using short integers
  56.287 + * as keys or values (especially on 64-bit platforms).
  56.288 + */
  56.289 +#define HKEY(x) ((void*)(unsigned long)(x))
  56.290 +
  56.291 +/** Cast x from the type for a key or value in a hash table.
  56.292 + * to an unsigned long. This avoids compiler warnings when using
  56.293 + * short integers as keys or values (especially on 64-bit platforms).
  56.294 + */
  56.295 +#define HVAL(x) ((unsigned long)(x))
  56.296 +
  56.297 +#endif /* !_XUTIL_HASH_TABLE_H_ */
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/tools/xfrd/lexis.c	Tue Jul 06 20:42:26 2004 +0000
    57.3 @@ -0,0 +1,93 @@
    57.4 +/*
    57.5 + *
    57.6 + * This library is free software; you can redistribute it and/or modify
    57.7 + * it under the terms of the GNU Lesser General Public License as
    57.8 + * published by the Free Software Foundation; either version 2.1 of the
    57.9 + * License, or  (at your option) any later version. This library is 
   57.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   57.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   57.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   57.13 + * See the GNU Lesser General Public License for more details.
   57.14 + *
   57.15 + * You should have received a copy of the GNU Lesser General Public License
   57.16 + * along with this library; if not, write to the Free Software Foundation,
   57.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   57.18 + */
   57.19 +
   57.20 +/** @file
   57.21 + * Lexical analysis.
   57.22 + */
   57.23 +
   57.24 +#include "sys_string.h"
   57.25 +#include "lexis.h"
   57.26 +#include <errno.h>
   57.27 +
   57.28 +/** Check if a value lies in a (closed) range.
   57.29 + *
   57.30 + * @param x value to test
   57.31 + * @param lo low end of the range
   57.32 + * @param hi high end of the range
   57.33 + * @return 1 if x is in the interval [lo, hi], 0 otherwise
   57.34 + */
   57.35 +inline static int in_range(int x, int lo, int hi){
   57.36 +    return (lo <= x) && (x <= hi);
   57.37 +}
   57.38 +
   57.39 +/** Determine if a string is an (unsigned) decimal number.
   57.40 + * 
   57.41 + * @param s pointer to characters to test
   57.42 + * @param n length of string
   57.43 + * @return 1 if s is a decimal number, 0 otherwise.
   57.44 + */
   57.45 +int is_decimal_number(const char *s, int n){
   57.46 +    int i;
   57.47 +    if(n <= 0)return 0;
   57.48 +    for(i = 0; i < n; i++){
   57.49 +        if(!in_decimal_digit_class(s[i])) return 0;
   57.50 +    }
   57.51 +    return 1;
   57.52 +}
   57.53 +
   57.54 +/** Determine if a string is a hex number.
   57.55 + * Hex numbers are 0, or start with 0x or 0X followed
   57.56 + * by a non-zero number of hex digits (0-9,a-f,A-F).
   57.57 + * 
   57.58 + * @param s pointer to characters to test
   57.59 + * @param n length of string
   57.60 + * @return 1 if s is a hex number, 0 otherwise.
   57.61 + */
   57.62 +int is_hex_number(const char *s, int n){
   57.63 +    int i;
   57.64 +    if(n <= 0) return 0;
   57.65 +    if(n == 1){
   57.66 +        return s[0]=='0';
   57.67 +    }
   57.68 +    if(n <= 3) return 0;
   57.69 +    if(s[0] != '0' || (s[1] != 'x' && s[1] != 'X')) return 0;
   57.70 +    for(i = 2; i < n; i++){
   57.71 +        if(!in_hex_digit_class(s[i])) return 0;
   57.72 +    }
   57.73 +    return 1;
   57.74 +}
   57.75 +
   57.76 +/** Test if a string matches a keyword.
   57.77 + * The comparison is case-insensitive.
   57.78 + * The comparison fails if either argument is null.
   57.79 + *
   57.80 + * @param s string
   57.81 + * @param k keyword
   57.82 + * @return 1 if they match, 0 otherwise
   57.83 + */
   57.84 +int is_keyword(const char *s, const char *k){
   57.85 +  return s && k && !strcasecmp(s, k);
   57.86 +}
   57.87 +
   57.88 +/** Test if a string matches a character.
   57.89 + *
   57.90 + * @param s string
   57.91 + * @param c character (non-null)
   57.92 + * @return 1 if s contains exactly c, 0 otherwise
   57.93 + */
   57.94 +int is_keychar(const char *s, char c){
   57.95 +  return c && (s[0] == c) && !s[1];
   57.96 +}
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/tools/xfrd/lexis.h	Tue Jul 06 20:42:26 2004 +0000
    58.3 @@ -0,0 +1,127 @@
    58.4 +/*
    58.5 + *
    58.6 + * This library is free software; you can redistribute it and/or modify
    58.7 + * it under the terms of the GNU Lesser General Public License as
    58.8 + * published by the Free Software Foundation; either version 2.1 of the
    58.9 + * License, or  (at your option) any later version. This library is 
   58.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   58.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   58.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   58.13 + * See the GNU Lesser General Public License for more details.
   58.14 + *
   58.15 + * You should have received a copy of the GNU Lesser General Public License
   58.16 + * along with this library; if not, write to the Free Software Foundation,
   58.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   58.18 + */
   58.19 +
   58.20 +#ifndef _XUTIL_LEXIS_H_
   58.21 +#define _XUTIL_LEXIS_H_
   58.22 +
   58.23 +#include "sys_string.h"
   58.24 +
   58.25 +#ifdef __KERNEL__
   58.26 +#  include <linux/ctype.h>
   58.27 +#else
   58.28 +#  include <ctype.h>
   58.29 +#endif
   58.30 +
   58.31 +/** @file
   58.32 + * Lexical analysis.
   58.33 + */
   58.34 +
   58.35 +/** Class of characters treated as space. */
   58.36 +#define space_class ((char []){ '\n', '\r', '\t', ' ', '\f' , 0 })
   58.37 +
   58.38 +/** Class of separator characters. */
   58.39 +#define sep_class "{}()<>[]@!;"
   58.40 +
   58.41 +#define comment_class "#"
   58.42 +
   58.43 +/** Determine if a character is in a given class.
   58.44 + * 
   58.45 + * @param c character to test
   58.46 + * @param s null-terminated string of characters in the class
   58.47 + * @return 1 if c is in the class, 0 otherwise.
   58.48 + */
   58.49 +static inline int in_class(int c, const char *s){
   58.50 +  return s && (strchr(s, c) != 0);
   58.51 +}
   58.52 +
   58.53 +/** Determine if a character is in the space class.
   58.54 + * 
   58.55 + * @param c character to test
   58.56 + * @return 1 if c is in the class, 0 otherwise.
   58.57 + */
   58.58 +static inline int in_space_class(int c){
   58.59 +    return in_class(c, space_class);
   58.60 +}
   58.61 +
   58.62 +static inline int in_comment_class(int c){
   58.63 +    return in_class(c, comment_class);
   58.64 +}
   58.65 +
   58.66 +/** Determine if a character is in the separator class.
   58.67 + * Separator characters terminate tokens, and do not need space
   58.68 + * to separate them.
   58.69 + * 
   58.70 + * @param c character to test
   58.71 + * @return 1 if c is in the class, 0 otherwise.
   58.72 + */
   58.73 +static inline int in_sep_class(int c){
   58.74 +    return in_class(c, sep_class);
   58.75 +}
   58.76 +
   58.77 +/** Determine if a character is in the alpha class.
   58.78 + * 
   58.79 + * @param c character to test
   58.80 + * @return 1 if c is in the class, 0 otherwise.
   58.81 + */
   58.82 +static inline int in_alpha_class(int c){
   58.83 +    return isalpha(c);
   58.84 +}
   58.85 +
   58.86 +/** Determine if a character is in the octal digit class.
   58.87 + * 
   58.88 + * @param c character to test
   58.89 + * @return 1 if c is in the class, 0 otherwise.
   58.90 + */
   58.91 +static inline int in_octal_digit_class(int c){
   58.92 +    return '0' <= c && c <= '7';
   58.93 +}
   58.94 +
   58.95 +/** Determine if a character is in the decimal digit class.
   58.96 + * 
   58.97 + * @param c character to test
   58.98 + * @return 1 if c is in the class, 0 otherwise.
   58.99 + */
  58.100 +static inline int in_decimal_digit_class(int c){
  58.101 +    return isdigit(c);
  58.102 +}
  58.103 +
  58.104 +/** Determine if a character is in the hex digit class.
  58.105 + * 
  58.106 + * @param c character to test
  58.107 + * @return 1 if c is in the class, 0 otherwise.
  58.108 + */
  58.109 +static inline int in_hex_digit_class(int c){
  58.110 +    return isdigit(c) || in_class(c, "abcdefABCDEF");
  58.111 +}
  58.112 +
  58.113 +
  58.114 +static inline int in_string_quote_class(int c){
  58.115 +    return in_class(c, "'\"");
  58.116 +}
  58.117 +
  58.118 +static inline int in_printable_class(int c){
  58.119 +    return ('A' <= c && c <= 'Z')
  58.120 +        || ('a' <= c && c <= 'z')
  58.121 +        || ('0' <= c && c <= '9')
  58.122 +        || in_class(c, "!$%&*+,-./:;<=>?@^_`{|}~");
  58.123 +}
  58.124 +
  58.125 +extern int is_decimal_number(const char *s, int n);
  58.126 +extern int is_hex_number(const char *s, int n);
  58.127 +extern int is_keyword(const char *s, const char *k);
  58.128 +extern int is_keychar(const char *s, char c);
  58.129 +
  58.130 +#endif /* !_XUTIL_LEXIS_H_ */
    59.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    59.2 +++ b/tools/xfrd/lzi_stream.c	Tue Jul 06 20:42:26 2004 +0000
    59.3 @@ -0,0 +1,533 @@
    59.4 +/*
    59.5 + * Copyright (C) 2003 Hewlett-Packard Company.
    59.6 + *
    59.7 + * This library is free software; you can redistribute it and/or modify
    59.8 + * it under the terms of the GNU Lesser General Public License as published by
    59.9 + * the Free Software Foundation; either version 2.1 of the License, or
   59.10 + * (at your option) any later version.
   59.11 + *
   59.12 + * This library is distributed in the hope that it will be useful,
   59.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   59.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   59.15 + * GNU Lesser General Public License for more details.
   59.16 + *
   59.17 + * You should have received a copy of the GNU Lesser General Public License
   59.18 + * along with this library; if not, write to the Free Software
   59.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   59.20 + */
   59.21 +
   59.22 +/** @file
   59.23 + * An IOStream implementation using LZI to provide compression and decompression.
   59.24 + * This is designed to provide compression without output latency.
   59.25 + * Flushing an LZI stream flushes all pending data to the underlying stream.
   59.26 + * This is essential for stream-based (e.g. networked) applications.
   59.27 + *
   59.28 + * A compressed data stream is a sequence of blocks.
   59.29 + * Each block is the block size followed by the compressed data.
   59.30 + * The last block has size zero.
   59.31 + * Sizes are 4-byte unsigned in network order.
   59.32 + *
   59.33 + * This format allows compressed data to be read from a stream without reading
   59.34 + * past the logical end of compressed data.
   59.35 + *
   59.36 + * @author Mike Wray <mike.wray@hpl.hp.com>
   59.37 + */
   59.38 +#ifndef __KERNEL__
   59.39 +
   59.40 +#include <stdio.h>
   59.41 +#include <stdlib.h>
   59.42 +#include <errno.h>
   59.43 +#include <string.h>
   59.44 +
   59.45 +#include "zlib.h"
   59.46 +
   59.47 +#include "allocate.h"
   59.48 +#include "lzi_stream.h"
   59.49 +#include "file_stream.h"
   59.50 +#include "marshal.h"
   59.51 +
   59.52 +#define dprintf(fmt, args...) fprintf(stdout, "[DEBUG] LZI>%s" fmt, __FUNCTION__, ##args)
   59.53 +#define wprintf(fmt, args...) fprintf(stderr, "[WARN]  LZI>%s" fmt, __FUNCTION__, ##args)
   59.54 +#define iprintf(fmt, args...) fprintf(stdout, "[INFO]  LZI>%s" fmt, __FUNCTION__, ##args)
   59.55 +#define eprintf(fmt, args...) fprintf(stderr, "[ERROR] LZI>%s" fmt, __FUNCTION__, ##args)
   59.56 +
   59.57 +static int lzi_read(IOStream *s, void *buf, size_t n);
   59.58 +static int lzi_write(IOStream *s, const void *buf, size_t n);
   59.59 +static int lzi_error(IOStream *s);
   59.60 +static int lzi_close(IOStream *s);
   59.61 +static void lzi_free(IOStream *s);
   59.62 +static int lzi_flush(IOStream *s);
   59.63 +
   59.64 +enum {
   59.65 +    LZI_WRITE = 1,
   59.66 +    LZI_READ = 2,
   59.67 +};
   59.68 +
   59.69 +/** Methods used by a gzFile* IOStream. */
   59.70 +static const IOMethods lzi_methods = {
   59.71 +    read:  lzi_read,
   59.72 +    write: lzi_write,
   59.73 +    error: lzi_error,
   59.74 +    close: lzi_close,
   59.75 +    free:  lzi_free,
   59.76 +    flush: lzi_flush,
   59.77 +};
   59.78 +
   59.79 +#define BUFFER_SIZE (512 * 1024)
   59.80 +
   59.81 +typedef struct LZIState {
   59.82 +    z_stream zstream;
   59.83 +    void *inbuf;
   59.84 +    uint32_t inbuf_size;
   59.85 +    void *outbuf;
   59.86 +    uint32_t outbuf_size;
   59.87 +    /** Underlying stream for I/O. */
   59.88 +    IOStream *io;
   59.89 +    /** Flags. */
   59.90 +    int flags;
   59.91 +    /** Error indicator. */
   59.92 +    int error;
   59.93 +    int eof;
   59.94 +    int plain_bytes;
   59.95 +    int comp_bytes;
   59.96 +    int zstream_initialized;
   59.97 +    int flushed;
   59.98 +} LZIState;
   59.99 +
  59.100 +static inline int LZIState_writeable(LZIState *s){
  59.101 +    return (s->flags & LZI_WRITE) != 0;
  59.102 +}
  59.103 +
  59.104 +static inline int LZIState_readable(LZIState *s){
  59.105 +    return (s->flags & LZI_READ) != 0;
  59.106 +}
  59.107 +
  59.108 +void LZIState_free(LZIState *z){
  59.109 +    if(!z) return;
  59.110 +    if(z->zstream_initialized){
  59.111 +        if(LZIState_writeable(z)){
  59.112 +            deflateEnd(&z->zstream);
  59.113 +        } else if(LZIState_readable(z)){
  59.114 +            inflateEnd(&z->zstream);
  59.115 +        }
  59.116 +    }
  59.117 +    deallocate(z->inbuf);
  59.118 +    deallocate(z->outbuf);
  59.119 +    deallocate(z);
  59.120 +}
  59.121 +
  59.122 +static int mode_flags(const char *mode, int *flags){
  59.123 +    int err = 0;
  59.124 +    int r=0, w=0;
  59.125 +    if(!mode){
  59.126 +        err = -EINVAL;
  59.127 +        goto exit;
  59.128 +    }
  59.129 +    for(; *mode; mode++){
  59.130 +        if(*mode == 'w') w = 1;
  59.131 +        if(*mode == 'r') r = 1;
  59.132 +    }
  59.133 +    if(r + w != 1){
  59.134 +        err = -EINVAL;
  59.135 +        goto exit;
  59.136 +    }
  59.137 +    if(r) *flags |= LZI_READ;
  59.138 +    if(w) *flags |= LZI_WRITE;
  59.139 +  exit:
  59.140 +    return err;
  59.141 +}
  59.142 +
  59.143 +/** Get the stream state.
  59.144 + * 
  59.145 + * @param s lzi stream
  59.146 + * @return stream state.
  59.147 + */
  59.148 +static inline LZIState * lzi_state(IOStream *io){
  59.149 +    return (LZIState*)io->data;
  59.150 +}
  59.151 +
  59.152 +IOStream *lzi_stream_io(IOStream *io){
  59.153 +    LZIState *s = lzi_state(io);
  59.154 +    return s->io;
  59.155 +}
  59.156 +
  59.157 +static inline void set_error(LZIState *s, int err){
  59.158 +    if(err < 0 && !s->error){
  59.159 +        s->error = err;
  59.160 +    }
  59.161 +}
  59.162 +
  59.163 +static int zerror(LZIState *s, int err){
  59.164 +    if(err){
  59.165 +        //dprintf("> err=%d\n", err);
  59.166 +        if(err < 0) set_error(s, -EIO);
  59.167 +    }
  59.168 +    return s->error;
  59.169 +}
  59.170 +
  59.171 +int lzi_stream_plain_bytes(IOStream *io){
  59.172 +    LZIState *s = lzi_state(io);
  59.173 +    return s->plain_bytes;
  59.174 +}
  59.175 +
  59.176 +int lzi_stream_comp_bytes(IOStream *io){
  59.177 +    LZIState *s = lzi_state(io);
  59.178 +    return s->comp_bytes;
  59.179 +}
  59.180 +
  59.181 +float lzi_stream_ratio(IOStream *io){
  59.182 +    LZIState *s = lzi_state(io);
  59.183 +    float ratio = 0.0;
  59.184 +    if(s->comp_bytes){
  59.185 +        ratio = ((float) s->comp_bytes)/((float) s->plain_bytes);
  59.186 +    }
  59.187 +    return ratio;
  59.188 +}
  59.189 +
  59.190 +static int alloc(void **p, int n){
  59.191 +    *p = allocate(n);
  59.192 +    return (p ? 0 : -ENOMEM);
  59.193 +}
  59.194 +
  59.195 +LZIState * LZIState_new(IOStream *io, int flags){
  59.196 +    int err = -ENOMEM;
  59.197 +    int zlevel = Z_BEST_SPEED; // Level 1 compression - fastest.
  59.198 +    int zstrategy = Z_DEFAULT_STRATEGY;
  59.199 +    int zwindow = MAX_WBITS;
  59.200 +    int zmemory = 8;
  59.201 +    LZIState *z = ALLOCATE(LZIState);
  59.202 +
  59.203 +    //dprintf(">\n");
  59.204 +    if(!z) goto exit;
  59.205 +    z->io = io;
  59.206 +    z->flags = flags;
  59.207 +
  59.208 +    if(LZIState_writeable(z)){
  59.209 +        z->outbuf_size = BUFFER_SIZE;
  59.210 +        /* windowBits is passed < 0 to suppress zlib header */
  59.211 +        err = deflateInit2(&z->zstream, zlevel, Z_DEFLATED, -zwindow, zmemory, zstrategy);
  59.212 +        if (err != Z_OK) goto exit;
  59.213 +        z->zstream_initialized = 1;
  59.214 +        err = alloc(&z->outbuf, z->outbuf_size);
  59.215 +        if(err) goto exit;
  59.216 +        z->zstream.next_out = z->outbuf;
  59.217 +        z->zstream.avail_out = z->outbuf_size;
  59.218 +    } else {
  59.219 +        z->inbuf_size = BUFFER_SIZE;
  59.220 +        err = alloc(&z->inbuf, z->inbuf_size);
  59.221 +        if(err) goto exit;
  59.222 +        ///z->zstream.next_in  = z->inbuf;
  59.223 +
  59.224 +        /* windowBits is passed < 0 to tell that there is no zlib header.
  59.225 +         * Note that in this case inflate *requires* an extra "dummy" byte
  59.226 +         * after the compressed stream in order to complete decompression and
  59.227 +         * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
  59.228 +         * present after the compressed stream.
  59.229 +         */
  59.230 +        err = inflateInit2(&z->zstream, -zwindow);
  59.231 +        if(err != Z_OK) goto exit;
  59.232 +        z->zstream_initialized = 1;
  59.233 +    }
  59.234 +        
  59.235 +  exit:
  59.236 +    if(err){
  59.237 +        LZIState_free(z);
  59.238 +        z = NULL;
  59.239 +    }
  59.240 +    //dprintf("< z=%p\n", z);
  59.241 +    return z;
  59.242 +}
  59.243 +
  59.244 +int read_block(LZIState *s){
  59.245 +    int err = 0, k = 0;
  59.246 +    //dprintf(">\n");
  59.247 +    if(s->eof) goto exit;
  59.248 +    err = unmarshal_uint32(s->io, &k);
  59.249 +    if(err) goto exit;
  59.250 +    if(k > s->inbuf_size){
  59.251 +        err = -EINVAL;
  59.252 +        goto exit;
  59.253 +    }
  59.254 +    if(k){
  59.255 +        err = unmarshal_bytes(s->io, s->inbuf, k);
  59.256 +        if(err) goto exit;
  59.257 +    } else {
  59.258 +        s->eof = 1;
  59.259 +    }        
  59.260 +    s->zstream.avail_in = k;
  59.261 +    s->zstream.next_in = s->inbuf;
  59.262 +    s->comp_bytes += 4;
  59.263 +    s->comp_bytes += k;
  59.264 +  exit:
  59.265 +    //dprintf("< err=%d\n", err);
  59.266 +    return err;
  59.267 +}
  59.268 +
  59.269 +int write_block(LZIState *s){
  59.270 +    int err = 0;
  59.271 +    int k = ((char*)s->zstream.next_out) - ((char*)s->outbuf);
  59.272 +    //int k2 = s->outbuf_size - s->zstream.avail_out;
  59.273 +    //dprintf("> k=%d k2=%d\n", k, k2);
  59.274 +    if(!k) goto exit;
  59.275 +    err = marshal_uint32(s->io, k);
  59.276 +    if(err) goto exit;
  59.277 +    err = marshal_bytes(s->io, s->outbuf, k);
  59.278 +    if(err) goto exit;
  59.279 +    s->zstream.next_out = s->outbuf;
  59.280 +    s->zstream.avail_out = s->outbuf_size;
  59.281 +    s->comp_bytes += 4;
  59.282 +    s->comp_bytes += k;
  59.283 +  exit:
  59.284 +    //dprintf("< err=%d\n", err);
  59.285 +    return err;
  59.286 +}
  59.287 +
  59.288 +int write_terminator(LZIState *s){
  59.289 +    int err = 0;
  59.290 +    char c = 0;
  59.291 +    err = marshal_uint32(s->io, 1);
  59.292 +    if(err) goto exit;
  59.293 +    err = marshal_bytes(s->io, &c, 1);
  59.294 +    if(err) goto exit;
  59.295 +    err = marshal_uint32(s->io, 0);
  59.296 +    if(err) goto exit;
  59.297 +    s->comp_bytes += 9;
  59.298 +  exit:
  59.299 +    return err;
  59.300 +}
  59.301 +
  59.302 +/** Write to the underlying stream using fwrite();
  59.303 + *
  59.304 + * @param io destination
  59.305 + * @param buf data
  59.306 + * @param n number of bytes to write
  59.307 + * @return number of bytes written
  59.308 + */
  59.309 +static int lzi_write(IOStream *io, const void *buf, size_t n){
  59.310 +    int err = 0;
  59.311 +    LZIState *s = lzi_state(io);
  59.312 +
  59.313 +    //dprintf("> buf=%p n=%d\n", buf, n);
  59.314 +    if(!LZIState_writeable(s)){
  59.315 +        err = -EINVAL;
  59.316 +        goto exit;
  59.317 +    }
  59.318 +    s->flushed = 0;
  59.319 +    s->zstream.next_in = (void*)buf;
  59.320 +    s->zstream.avail_in = n;
  59.321 +    while(s->zstream.avail_in){
  59.322 +        if(s->zstream.avail_out == 0){
  59.323 +            err = write_block(s);
  59.324 +            if(err) goto exit;
  59.325 +        }
  59.326 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.327 +        //dprintf("> 1 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
  59.328 +        err = zerror(s, deflate(&s->zstream, Z_NO_FLUSH));
  59.329 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.330 +        //dprintf("> 2 deflate next_in=%p next_out=%p\n", s->zstream.next_in, s->zstream.next_out);
  59.331 +        if(err) goto exit;
  59.332 +    }
  59.333 +    err = n;
  59.334 +    s->plain_bytes += n;
  59.335 +  exit:
  59.336 +    //dprintf("< err=%d\n", err);
  59.337 +    return err;
  59.338 +}
  59.339 +
  59.340 +
  59.341 +/** Read from the underlying stream.
  59.342 + *
  59.343 + * @param io input
  59.344 + * @param buf where to put input
  59.345 + * @param n number of bytes to read
  59.346 + * @return number of bytes read
  59.347 + */
  59.348 +static int lzi_read(IOStream *io, void *buf, size_t n){
  59.349 +    int err, zerr;
  59.350 +    LZIState *s = lzi_state(io);
  59.351 +
  59.352 +    //dprintf("> n=%d\n", n);
  59.353 +    if(!LZIState_readable(s)){
  59.354 +        err = -EINVAL;
  59.355 +        goto exit;
  59.356 +    }
  59.357 +    s->zstream.next_out = buf;
  59.358 +    s->zstream.avail_out = n;
  59.359 +    while(s->zstream.avail_out){
  59.360 +        if(s->zstream.avail_in == 0){
  59.361 +            err = read_block(s);
  59.362 +        }
  59.363 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.364 +        zerr = inflate(&s->zstream, Z_NO_FLUSH);
  59.365 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.366 +        if(zerr == Z_STREAM_END) break;
  59.367 +        //dprintf("> zerr=%d\n", zerr);
  59.368 +        err = zerror(s, zerr);
  59.369 +        if(err) goto exit;
  59.370 +    }
  59.371 +    err = n - s->zstream.avail_out;
  59.372 +    s->plain_bytes += err;
  59.373 +  exit:
  59.374 +    set_error(s, err);
  59.375 +    //dprintf("< err=%d\n", err);
  59.376 +    return err;
  59.377 +}
  59.378 +
  59.379 +static int flush_output(LZIState *s, int mode){
  59.380 +    int err = 0, zerr;
  59.381 +    int done = 0;
  59.382 +    int avail_out_old;
  59.383 +
  59.384 +    //dprintf("> avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.385 +    if(s->flushed == 1 + mode) goto exit;
  59.386 +    //s->zstream.avail_in = 0; /* should be zero already anyway */
  59.387 +    for(;;){
  59.388 +        // Write any available output.
  59.389 +        if(done || s->zstream.avail_out == 0){
  59.390 +            err = write_block(s);
  59.391 +            if(err) goto exit;
  59.392 +            if(done) break;
  59.393 +        }
  59.394 +        //dprintf("> 1 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.395 +        avail_out_old = s->zstream.avail_out;
  59.396 +        zerr = deflate(&s->zstream, mode);
  59.397 +        err = zerror(s, zerr);
  59.398 +        //dprintf("> 2 deflate avail_in=%d avail_out=%d\n", s->zstream.avail_in, s->zstream.avail_out);
  59.399 +        //dprintf("> deflate=%d\n", err);
  59.400 +        //done = (s->zstream.avail_out != 0);
  59.401 +        //done = (s->zstream.avail_in == 0) && (s->zstream.avail_out == avail_out_old);
  59.402 +        if(0 && mode == Z_FINISH){
  59.403 +            done = (zerr ==  Z_STREAM_END);
  59.404 +        } else {
  59.405 +            done = (s->zstream.avail_in == 0)
  59.406 +                //&& (s->zstream.avail_out == avail_out_old)
  59.407 +                && (s->zstream.avail_out != 0);
  59.408 +        }
  59.409 +    }
  59.410 +    s->flushed = 1 + mode;
  59.411 +  exit:
  59.412 +    //dprintf("< err=%d\n", err);
  59.413 +    return err;
  59.414 +}
  59.415 +
  59.416 +/** Flush any pending input to the underlying stream.
  59.417 + *
  59.418 + * @param s lzi stream
  59.419 + * @return 0 on success, error code otherwise
  59.420 + */
  59.421 +static int lzi_flush(IOStream *io){
  59.422 +    int err = 0;
  59.423 +    LZIState *s = lzi_state(io);
  59.424 +    //dprintf(">\n");
  59.425 +    if(!LZIState_writeable(s)){
  59.426 +        err = -EINVAL;
  59.427 +        goto exit;
  59.428 +    }
  59.429 +    err = flush_output(s, Z_SYNC_FLUSH);
  59.430 +    if(err) goto exit;
  59.431 +    err = IOStream_flush(s->io);
  59.432 +  exit:
  59.433 +    set_error(s, err);
  59.434 +    //dprintf("< err=%d\n", err);
  59.435 +    return (err < 0 ? err : 0);
  59.436 +}
  59.437 +
  59.438 +/** Check if a stream has an error.
  59.439 + *
  59.440 + * @param s lzi stream
  59.441 + * @return code if has an error, 0 otherwise
  59.442 + */
  59.443 +static int lzi_error(IOStream *s){
  59.444 +    int err = 0;
  59.445 +    LZIState *state = lzi_state(s);
  59.446 +    err = state->error;
  59.447 +    if(err) goto exit;
  59.448 +    err = IOStream_error(state->io);
  59.449 +  exit:
  59.450 +    return err;
  59.451 +}
  59.452 +
  59.453 +/** Close an lzi stream.
  59.454 + *
  59.455 + * @param s lzi stream to close
  59.456 + * @return result of the close
  59.457 + */
  59.458 +static int lzi_close(IOStream *io){
  59.459 +    int err = 0;
  59.460 +    LZIState *s = lzi_state(io);
  59.461 +    if(LZIState_writeable(s)){
  59.462 +        err = flush_output(s, Z_FINISH);
  59.463 +        if(err) goto exit;
  59.464 +        err = write_terminator(s);
  59.465 +        if(err) goto exit;
  59.466 +        err = IOStream_flush(s->io);
  59.467 +    }   
  59.468 +  exit:
  59.469 +    err = IOStream_close(s->io);
  59.470 +    set_error(s, err);
  59.471 +    return err;
  59.472 +}
  59.473 +
  59.474 +/** Free an lzi stream.
  59.475 + *
  59.476 + * @param s lzi stream
  59.477 + */
  59.478 +static void lzi_free(IOStream *s){
  59.479 +    LZIState *state = lzi_state(s);
  59.480 +    IOStream_free(state->io);
  59.481 +    LZIState_free(state);
  59.482 +    s->data = NULL;
  59.483 +}
  59.484 +
  59.485 +/** Create an lzi stream for an IOStream.
  59.486 + *
  59.487 + * @param io stream to wrap
  59.488 + * @return new IOStream using f for i/o
  59.489 + */
  59.490 +IOStream *lzi_stream_new(IOStream *io, const char *mode){
  59.491 +    int err = -ENOMEM;
  59.492 +    int flags = 0;
  59.493 +    IOStream *zio = NULL;
  59.494 +    LZIState *state = NULL;
  59.495 +
  59.496 +    zio = ALLOCATE(IOStream);
  59.497 +    if(!zio) goto exit;
  59.498 +    err = mode_flags(mode, &flags);
  59.499 +    if(err) goto exit;
  59.500 +    state = LZIState_new(io, flags);
  59.501 +    if(!state) goto exit;
  59.502 +    err = 0;
  59.503 +    zio->data = state;
  59.504 +    zio->methods = &lzi_methods;
  59.505 +  exit:
  59.506 +    if(err){
  59.507 +        if(state) LZIState_free(state);
  59.508 +        if(zio) deallocate(zio);
  59.509 +        zio = NULL;
  59.510 +    }
  59.511 +    return zio;
  59.512 +}
  59.513 +
  59.514 +/** IOStream version of fdopen().
  59.515 + *
  59.516 + * @param fd file descriptor
  59.517 + * @param flags giving the mode to open in (as for fdopen())
  59.518 + * @return new stream for the open file, or NULL if failed
  59.519 + */
  59.520 +IOStream *lzi_stream_fdopen(int fd, const char *mode){
  59.521 +    int err = -ENOMEM;
  59.522 +    IOStream *io = NULL, *zio = NULL;
  59.523 +    io = file_stream_fdopen(fd, mode);
  59.524 +    if(!io) goto exit;
  59.525 +    zio = lzi_stream_new(io, mode);
  59.526 +    if(!io) goto exit;
  59.527 +    err = 0;
  59.528 +  exit:
  59.529 +    if(err){
  59.530 +        IOStream_free(io);
  59.531 +        IOStream_free(zio);
  59.532 +        zio = NULL;
  59.533 +    }
  59.534 +    return zio;
  59.535 +}
  59.536 +#endif
    60.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    60.2 +++ b/tools/xfrd/lzi_stream.h	Tue Jul 06 20:42:26 2004 +0000
    60.3 @@ -0,0 +1,35 @@
    60.4 +/*
    60.5 + * Copyright (C) 2003 Hewlett-Packard Company.
    60.6 + *
    60.7 + * This library is free software; you can redistribute it and/or modify
    60.8 + * it under the terms of the GNU Lesser General Public License as published by
    60.9 + * the Free Software Foundation; either version 2.1 of the License, or
   60.10 + * (at your option) any later version.
   60.11 + *
   60.12 + * This library is distributed in the hope that it will be useful,
   60.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   60.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   60.15 + * GNU Lesser General Public License for more details.
   60.16 + *
   60.17 + * You should have received a copy of the GNU Lesser General Public License
   60.18 + * along with this library; if not, write to the Free Software
   60.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   60.20 + */
   60.21 +
   60.22 +#ifndef _XUTIL_LZI_STREAM_H_
   60.23 +#define _XUTIL_LZI_STREAM_H_
   60.24 +
   60.25 +#ifndef __KERNEL__
   60.26 +#include "iostream.h"
   60.27 +
   60.28 +extern IOStream *lzi_stream_new(IOStream *io, const char *mode);
   60.29 +extern IOStream *lzi_stream_fopen(const char *file, const char *mode);
   60.30 +extern IOStream *lzi_stream_fdopen(int fd, const char *mode);
   60.31 +extern IOStream *lzi_stream_io(IOStream *zio);
   60.32 +
   60.33 +extern int lzi_stream_plain_bytes(IOStream *io);
   60.34 +extern int lzi_stream_comp_bytes(IOStream *io);
   60.35 +extern float lzi_stream_ratio(IOStream *io);
   60.36 +
   60.37 +#endif
   60.38 +#endif /* !_XUTIL_LZI_STREAM_H_ */
    61.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    61.2 +++ b/tools/xfrd/marshal.c	Tue Jul 06 20:42:26 2004 +0000
    61.3 @@ -0,0 +1,207 @@
    61.4 +#include <errno.h>
    61.5 +#include "sys_net.h"
    61.6 +#include "allocate.h"
    61.7 +#include "marshal.h"
    61.8 +
    61.9 +#define dprintf(fmt, args...) IOStream_print(iostdout, "[DEBUG] %s" fmt, __FUNCTION__, ##args)
   61.10 +#define wprintf(fmt, args...) IOStream_print(iostderr, "[WARN]  %s" fmt, __FUNCTION__, ##args)
   61.11 +#define iprintf(fmt, args...) IOStream_print(iostdout, "[INFO]  %s" fmt, __FUNCTION__, ##args)
   61.12 +#define eprintf(fmt, args...) IOStream_print(iostderr, "[ERROR] %s" fmt, __FUNCTION__, ##args)
   61.13 +
   61.14 +
   61.15 +#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof((ary)[0]))
   61.16 +
   61.17 +/* Messages are coded as msgid followed by message fields.
   61.18 + * Initial message on any channel is hello - so can check version
   61.19 + * compatibility.
   61.20 + *
   61.21 + * char* -> uint16_t:n <n bytes>
   61.22 + * ints/uints go as suitable number of bytes (e.g. uint16_t is 2 bytes).
   61.23 + * optional fields go as '1' <val> or '0' (the 0/1 is 1 byte).
   61.24 + * lists go as ('1' <elt>)* '0'
   61.25 + */
   61.26 +
   61.27 +int marshal_flush(IOStream *io){
   61.28 +    int err  = 0;
   61.29 +    err = IOStream_flush(io);
   61.30 +    return err;
   61.31 +}
   61.32 +
   61.33 +int marshal_bytes(IOStream *io, void *s, uint32_t s_n){
   61.34 +    int err = 0;
   61.35 +    int n;
   61.36 +    n = IOStream_write(io, s, s_n);
   61.37 +    if(n < 0){
   61.38 +        err = n;
   61.39 +    } else if (n < s_n){
   61.40 +        wprintf("> Wanted %d, got %d\n", s_n, n);
   61.41 +        err = -EIO;
   61.42 +    }
   61.43 +    return err;
   61.44 +}
   61.45 +
   61.46 +int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n){
   61.47 +    int err = 0;
   61.48 +    int n;
   61.49 +    //dprintf("> s_n=%d\n", s_n);
   61.50 +    n = IOStream_read(io, s, s_n);
   61.51 +    //dprintf("> n=%d\n", n);
   61.52 +    if(n < 0){
   61.53 +        err = n;
   61.54 +    } else if(n < s_n){
   61.55 +        wprintf("> Wanted %d, got %d\n", s_n, n);
   61.56 +        err = -EIO;
   61.57 +    }
   61.58 +    //dprintf("< err=%d\n", err);
   61.59 +    return err;
   61.60 +}
   61.61 +
   61.62 +int marshal_uint8(IOStream *io, uint8_t x){
   61.63 +    return marshal_bytes(io, &x, sizeof(x));
   61.64 +}
   61.65 +
   61.66 +int unmarshal_uint8(IOStream *io, uint8_t *x){
   61.67 +    return unmarshal_bytes(io, x, sizeof(*x));
   61.68 +}
   61.69 +
   61.70 +int marshal_uint16(IOStream *io, uint16_t x){
   61.71 +    x = htons(x);
   61.72 +    return marshal_bytes(io, &x, sizeof(x));
   61.73 +}
   61.74 +
   61.75 +int unmarshal_uint16(IOStream *io, uint16_t *x){
   61.76 +    int err = 0;
   61.77 +    err = unmarshal_bytes(io, x, sizeof(*x));
   61.78 +    *x = ntohs(*x);
   61.79 +    return err;
   61.80 +}
   61.81 +
   61.82 +int marshal_int32(IOStream *io, int32_t x){
   61.83 +    int err = 0;
   61.84 +    //dprintf("> x=%d\n", x);
   61.85 +    x = htonl(x);
   61.86 +    err = marshal_bytes(io, &x, sizeof(x));
   61.87 +    //dprintf("< err=%d\n", err);
   61.88 +    return err;
   61.89 +}
   61.90 +
   61.91 +int unmarshal_int32(IOStream *io, int32_t *x){
   61.92 +    int err = 0;
   61.93 +    //dprintf(">\n");
   61.94 +    err = unmarshal_bytes(io, x, sizeof(*x));
   61.95 +    *x = ntohl(*x);
   61.96 +    //dprintf("< err=%d x=%d\n", err, *x);
   61.97 +    return err;
   61.98 +}
   61.99 +
  61.100 +int marshal_uint32(IOStream *io, uint32_t x){
  61.101 +    int err = 0;
  61.102 +    //dprintf("> x=%u\n", x);
  61.103 +    x = htonl(x);
  61.104 +    err = marshal_bytes(io, &x, sizeof(x));
  61.105 +    //dprintf("< err=%d\n", err);
  61.106 +    return err;
  61.107 +}
  61.108 +
  61.109 +int unmarshal_uint32(IOStream *io, uint32_t *x){
  61.110 +    int err = 0;
  61.111 +    //dprintf(">\n");
  61.112 +    err = unmarshal_bytes(io, x, sizeof(*x));
  61.113 +    *x = ntohl(*x);
  61.114 +    //dprintf("< err=%d x=%u\n", err, *x);
  61.115 +    return err;
  61.116 +}
  61.117 +
  61.118 +int marshal_uint64(IOStream *io, uint64_t x){
  61.119 +    int err;
  61.120 +    err = marshal_uint32(io, (uint32_t) ((x >> 32) & 0xffffffff));
  61.121 +    if(err) goto exit;
  61.122 +    err = marshal_uint32(io, (uint32_t) ( x        & 0xffffffff));
  61.123 +  exit:
  61.124 +    return err;
  61.125 +}
  61.126 +
  61.127 +int unmarshal_uint64(IOStream *io, uint64_t *x){
  61.128 +    int err = 0;
  61.129 +    uint32_t hi, lo;
  61.130 +    err = unmarshal_uint32(io, &hi);
  61.131 +    if(err) goto exit;
  61.132 +    err = unmarshal_uint32(io, &lo);
  61.133 +    *x = (((uint64_t) hi) << 32) | lo;
  61.134 +  exit:
  61.135 +    return err;
  61.136 +}
  61.137 +
  61.138 +int marshal_net16(IOStream *io, net16_t x){
  61.139 +    return marshal_bytes(io, &x, sizeof(x));
  61.140 +}
  61.141 +
  61.142 +int unmarshal_net16(IOStream *io, net16_t *x){
  61.143 +    int err = 0;
  61.144 +    err = unmarshal_bytes(io, x, sizeof(*x));
  61.145 +    return err;
  61.146 +}
  61.147 +
  61.148 +int marshal_net32(IOStream *io, net32_t x){
  61.149 +    return marshal_bytes(io, &x, sizeof(x));
  61.150 +}
  61.151 +
  61.152 +int unmarshal_net32(IOStream *io, net32_t *x){
  61.153 +    int err = 0;
  61.154 +    err = unmarshal_bytes(io, x, sizeof(*x));
  61.155 +    return err;
  61.156 +}
  61.157 +
  61.158 +int marshal_string(IOStream *io, char *s, uint32_t s_n){
  61.159 +    int err;
  61.160 +    //dprintf("> s=%s\n", s);
  61.161 +    err = marshal_uint32(io, s_n);
  61.162 +    if(err) goto exit;
  61.163 +    err = marshal_bytes(io, s, s_n);
  61.164 +  exit:
  61.165 +    //dprintf("< err=%d\n", err);
  61.166 +    return err;
  61.167 +}
  61.168 +
  61.169 +int unmarshal_string(IOStream *io, char *s, uint32_t s_n){
  61.170 +    int err = 0, val_n = 0;
  61.171 +    //dprintf(">\n");
  61.172 +    err = unmarshal_uint32(io, &val_n);
  61.173 +    if(err) goto exit;
  61.174 +    if(val_n >= s_n){
  61.175 +        err = -EINVAL;
  61.176 +        goto exit;
  61.177 +    }
  61.178 +    err = unmarshal_bytes(io, s, val_n);
  61.179 +    if(err) goto exit;
  61.180 +    s[val_n] = '\0';
  61.181 +  exit:
  61.182 +    //dprintf("< err=%d s=%s\n", err, s);
  61.183 +    return err;
  61.184 +}
  61.185 +
  61.186 +int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n){
  61.187 +    int err = 0, val_n = 0;
  61.188 +    char *val = NULL;
  61.189 +    //dprintf(">\n");
  61.190 +    err = unmarshal_uint32(io, &val_n);
  61.191 +    if(err) goto exit;
  61.192 +    val = allocate(val_n + 1);
  61.193 +    if(!val){
  61.194 +        err = -ENOMEM;
  61.195 +        goto exit;
  61.196 +    }
  61.197 +    err = unmarshal_bytes(io, val, val_n);
  61.198 +    if(err) goto exit;
  61.199 +    val[val_n] = '\0';
  61.200 +  exit:
  61.201 +    if(err){
  61.202 +        if(val) deallocate(val);
  61.203 +        val = NULL;
  61.204 +        val_n = 0;
  61.205 +    }
  61.206 +    *s = val;
  61.207 +    if(s_n) *s_n = val_n;
  61.208 +    //dprintf("< err=%d s=%s\n", err, *s);
  61.209 +    return err;
  61.210 +}
    62.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    62.2 +++ b/tools/xfrd/marshal.h	Tue Jul 06 20:42:26 2004 +0000
    62.3 @@ -0,0 +1,42 @@
    62.4 +#ifndef _XUTIL_MARSHAL_H_
    62.5 +#define _XUTIL_MARSHAL_H_
    62.6 +
    62.7 +#include "iostream.h"
    62.8 +
    62.9 +/** A 16-bit uint in network order, e.g. a port number. */
   62.10 +typedef uint16_t net16_t;
   62.11 +
   62.12 +/** A 32-bit uint in network order, e.g. an IP address. */
   62.13 +typedef uint32_t net32_t;
   62.14 +
   62.15 +extern int marshal_flush(IOStream *io);
   62.16 +
   62.17 +extern int marshal_bytes(IOStream *io, void *s, uint32_t s_n);
   62.18 +extern int unmarshal_bytes(IOStream *io, void *s, uint32_t s_n);
   62.19 +
   62.20 +extern int marshal_uint8(IOStream *io, uint8_t x);
   62.21 +extern int unmarshal_uint8(IOStream *io, uint8_t *x);
   62.22 +
   62.23 +extern int marshal_uint16(IOStream *io, uint16_t x);
   62.24 +extern int unmarshal_uint16(IOStream *io, uint16_t *x);
   62.25 +
   62.26 +extern int marshal_uint32(IOStream *io, uint32_t x);
   62.27 +extern int unmarshal_uint32(IOStream *io, uint32_t *x);
   62.28 +
   62.29 +extern int marshal_int32(IOStream *io, int32_t x);
   62.30 +extern int unmarshal_int32(IOStream *io, int32_t *x);
   62.31 +
   62.32 +extern int marshal_uint64(IOStream *io, uint64_t x);
   62.33 +extern int unmarshal_uint64(IOStream *io, uint64_t *x);
   62.34 +
   62.35 +extern int marshal_net16(IOStream *io, net16_t x);
   62.36 +extern int unmarshal_net16(IOStream *io, net16_t *x);
   62.37 +
   62.38 +extern int marshal_net32(IOStream *io, net32_t x);
   62.39 +extern int unmarshal_net32(IOStream *io, net32_t *x);
   62.40 +
   62.41 +extern int marshal_string(IOStream *io, char *s, uint32_t s_n);
   62.42 +extern int unmarshal_string(IOStream *io, char *s, uint32_t s_n);
   62.43 +extern int unmarshal_new_string(IOStream *io, char **s, uint32_t *s_n);
   62.44 +
   62.45 +#endif /* ! _XUTIL_MARSHAL_H_ */
    63.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    63.2 +++ b/tools/xfrd/select.c	Tue Jul 06 20:42:26 2004 +0000
    63.3 @@ -0,0 +1,50 @@
    63.4 +#include <stdlib.h>
    63.5 +#include <errno.h>
    63.6 +#include <unistd.h>
    63.7 +
    63.8 +#include "select.h"
    63.9 +
   63.10 +/** Zero all the file descriptor sets.
   63.11 + *
   63.12 + * @param set select set
   63.13 + * @param fd file descriptor
   63.14 + * @return 0 on success, -1 otherwise
   63.15 + */
   63.16 +void SelectSet_zero(SelectSet *set){
   63.17 +    set->n = 0;
   63.18 +    FD_ZERO(&set->rd);
   63.19 +    FD_ZERO(&set->wr);
   63.20 +    FD_ZERO(&set->er);
   63.21 +}
   63.22 +
   63.23 +/** Add a file descriptor to the write set.
   63.24 + *
   63.25 + * @param set select set
   63.26 + * @param fd file descriptor
   63.27 + * @return 0 on success, -1 otherwise
   63.28 + */
   63.29 +void SelectSet_add_read(SelectSet *set, int fd){
   63.30 +    FD_SET(fd, &set->rd);
   63.31 +    if(fd > set->n) set->n = fd;
   63.32 +}
   63.33 +
   63.34 +/** Add a file descriptor to the write set.
   63.35 + *
   63.36 + * @param set select set
   63.37 + * @param fd file descriptor
   63.38 + * @return 0 on success, -1 otherwise
   63.39 + */
   63.40 +void SelectSet_add_write(SelectSet *set, int fd){
   63.41 +    FD_SET(fd, &set->wr);
   63.42 +    if(fd > set->n) set->n = fd;
   63.43 +}
   63.44 +
   63.45 +/** Select on file descriptors.
   63.46 + *
   63.47 + * @param set select set
   63.48 + * @param timeout timeout (may be NULL for no timeout)
   63.49 + * @return 0 on success, -1 otherwise
   63.50 + */
   63.51 +int SelectSet_select(SelectSet *set, struct timeval *timeout){
   63.52 +    return select(set->n+1, &set->rd, &set->wr, &set->er, timeout);
   63.53 +}
    64.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    64.2 +++ b/tools/xfrd/select.h	Tue Jul 06 20:42:26 2004 +0000
    64.3 @@ -0,0 +1,16 @@
    64.4 +#ifndef _XFRD_SELECT_H_
    64.5 +#define _XFRD_SELECT_H_
    64.6 +
    64.7 +/** Set of file descriptors for select.
    64.8 + */
    64.9 +typedef struct SelectSet {
   64.10 +    int n;
   64.11 +    fd_set rd, wr, er;
   64.12 +} SelectSet;
   64.13 +
   64.14 +extern void SelectSet_zero(SelectSet *set);
   64.15 +extern void SelectSet_add_read(SelectSet *set, int fd);
   64.16 +extern void SelectSet_add_write(SelectSet *set, int fd);
   64.17 +extern int SelectSet_select(SelectSet *set, struct timeval *timeout);
   64.18 +
   64.19 +#endif /* ! _XFRD_SELECT_H_ */
    65.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    65.2 +++ b/tools/xfrd/sxpr.c	Tue Jul 06 20:42:26 2004 +0000
    65.3 @@ -0,0 +1,950 @@
    65.4 +/*
    65.5 + *
    65.6 + * This library is free software; you can redistribute it and/or modify
    65.7 + * it under the terms of the GNU Lesser General Public License as
    65.8 + * published by the Free Software Foundation; either version 2.1 of the
    65.9 + * License, or  (at your option) any later version. This library is 
   65.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   65.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   65.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   65.13 + * See the GNU Lesser General Public License for more details.
   65.14 + *
   65.15 + * You should have received a copy of the GNU Lesser General Public License
   65.16 + * along with this library; if not, write to the Free Software Foundation,
   65.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   65.18 + */
   65.19 +
   65.20 +#include <stdarg.h>
   65.21 +#include "sys_string.h"
   65.22 +#include "lexis.h"
   65.23 +#include "sys_net.h"
   65.24 +#include "hash_table.h"
   65.25 +#include "sxpr.h"
   65.26 +
   65.27 +#include <errno.h>
   65.28 +#undef free
   65.29 +
   65.30 +/** @file
   65.31 + * General representation of sxprs.
   65.32 + * Includes print, equal, and free functions for the sxpr types.
   65.33 + *
   65.34 + * Zero memory containing an Sxpr will have the value ONONE - this is intentional.
   65.35 + * When a function returning an sxpr cannot allocate memory we return ONOMEM.
   65.36 + *
   65.37 + */
   65.38 +
   65.39 +static int atom_print(IOStream *io, Sxpr obj, unsigned flags);
   65.40 +static int atom_equal(Sxpr x, Sxpr y);
   65.41 +static void atom_free(Sxpr obj);
   65.42 +
   65.43 +static int string_print(IOStream *io, Sxpr obj, unsigned flags);
   65.44 +static int string_equal(Sxpr x, Sxpr y);
   65.45 +static void string_free(Sxpr obj);
   65.46 +
   65.47 +static int cons_print(IOStream *io, Sxpr obj, unsigned flags);
   65.48 +static int cons_equal(Sxpr x, Sxpr y);
   65.49 +static void cons_free(Sxpr obj);
   65.50 +
   65.51 +static int null_print(IOStream *io, Sxpr obj, unsigned flags);
   65.52 +static int none_print(IOStream *io, Sxpr obj, unsigned flags);
   65.53 +static int int_print(IOStream *io, Sxpr obj, unsigned flags);
   65.54 +static int bool_print(IOStream *io, Sxpr obj, unsigned flags);
   65.55 +
   65.56 +/** Type definitions. */
   65.57 +static SxprType types[1024] = {
   65.58 +    [T_NONE]     { type:    T_NONE,     name: "none",       print: none_print      },
   65.59 +    [T_NULL]     { type:    T_NULL,     name: "null",       print: null_print      },
   65.60 +    [T_UINT]     { type:    T_UINT,     name: "int",        print: int_print,      },
   65.61 +    [T_BOOL]     { type:    T_BOOL,     name: "bool",       print: bool_print,     },
   65.62 +    [T_ATOM]     { type:    T_ATOM,     name: "atom",       print: atom_print,
   65.63 +		   pointer: TRUE,
   65.64 +		   free:    atom_free,
   65.65 +		   equal:   atom_equal,
   65.66 +		 },
   65.67 +    [T_STRING]   { type:    T_STRING,   name: "string",     print: string_print,
   65.68 +		   pointer: TRUE,
   65.69 +		   free:    string_free,
   65.70 +		   equal:   string_equal,
   65.71 +		 },
   65.72 +    [T_CONS]     { type:    T_CONS,     name: "cons",       print: cons_print,
   65.73 +		   pointer: TRUE,
   65.74 +		   free:    cons_free,
   65.75 +		   equal:   cons_equal,
   65.76 +		 },
   65.77 +};
   65.78 +
   65.79 +/** Number of entries in the types array. */
   65.80 +static int type_sup = sizeof(types)/sizeof(types[0]);
   65.81 +
   65.82 +/** Get the type definition for a given type code.
   65.83 + *
   65.84 + * @param ty type code
   65.85 + * @return type definition or null
   65.86 + */
   65.87 +SxprType *get_sxpr_type(int ty){
   65.88 +    if(0 <= ty && ty < type_sup){
   65.89 +        return types+ty;
   65.90 +    }
   65.91 +    return NULL;
   65.92 +}
   65.93 +
   65.94 +/** The default print function.
   65.95 + *
   65.96 + * @param io stream to print to
   65.97 + * @param x sxpr to print
   65.98 + * @param flags print flags
   65.99 + * @return number of bytes written on success
  65.100 + */
  65.101 +int default_print(IOStream *io, Sxpr x, unsigned flags){
  65.102 +    return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));
  65.103 +}
  65.104 +
  65.105 +/** The default equal function.
  65.106 + * Uses eq().
  65.107 + *
  65.108 + * @param x sxpr to compare
  65.109 + * @param y sxpr to compare
  65.110 + * @return 1 if equal, 0 otherwise
  65.111 + */
  65.112 +int default_equal(Sxpr x, Sxpr y){
  65.113 +    return eq(x, y);
  65.114 +}
  65.115 +
  65.116 +/** General sxpr print function.
  65.117 + * Prints an sxpr on a stream using the print function for the sxpr type.
  65.118 + * Printing is controlled by flags from the PrintFlags enum.
  65.119 + * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr
  65.120 + * (for debugging).
  65.121 + *
  65.122 + * @param io stream to print to
  65.123 + * @param x sxpr to print
  65.124 + * @param flags print flags
  65.125 + * @return number of bytes written
  65.126 + */
  65.127 +int objprint(IOStream *io, Sxpr x, unsigned flags){
  65.128 +    SxprType *def = get_sxpr_type(get_type(x));
  65.129 +    ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);
  65.130 +    int k = 0;
  65.131 +    if(!io) return k;
  65.132 +    if(flags & PRINT_TYPE){
  65.133 +	k += IOStream_print(io, "%s:", def->name);
  65.134 +    }
  65.135 +    k += print_fn(io, x, flags);
  65.136 +    return k;
  65.137 +}
  65.138 +
  65.139 +/** General sxpr free function.
  65.140 + * Frees an sxpr using the free function for its type.
  65.141 + * Free functions must recursively free any subsxprs.
  65.142 + * If no function is defined then the default is to
  65.143 + * free sxprs whose type has pointer true.
  65.144 + * Sxprs must not be used after freeing.
  65.145 + *
  65.146 + * @param x sxpr to free
  65.147 + */
  65.148 +void objfree(Sxpr x){
  65.149 +    SxprType *def = get_sxpr_type(get_type(x));
  65.150 +
  65.151 +    if(def){
  65.152 +	if(def->free){
  65.153 +	    def->free(x);
  65.154 +	} else if (def->pointer){
  65.155 +	    hfree(x);
  65.156 +	}
  65.157 +    }
  65.158 +}
  65.159 +
  65.160 +/** General sxpr equality function.
  65.161 + * Compares x and y using the equal function for x.
  65.162 + * Uses default_equal() if x has no equal function.
  65.163 + *
  65.164 + * @param x sxpr to compare
  65.165 + * @param y sxpr to compare
  65.166 + * @return 1 if equal, 0 otherwise
  65.167 + */
  65.168 +int objequal(Sxpr x, Sxpr y){
  65.169 +    SxprType *def = get_sxpr_type(get_type(x));
  65.170 +    ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);
  65.171 +    return equal_fn(x, y);
  65.172 +}
  65.173 +
  65.174 +/** Search for a key in an alist.
  65.175 + * An alist is a list of conses, where the cars
  65.176 + * of the conses are the keys. Compares keys using equality.
  65.177 + *
  65.178 + * @param k key
  65.179 + * @param l alist to search
  65.180 + * @return first element of l with car k, or ONULL
  65.181 + */
  65.182 +Sxpr assoc(Sxpr k, Sxpr l){
  65.183 +    for( ; CONSP(l) ; l = CDR(l)){
  65.184 +        Sxpr x = CAR(l);
  65.185 +        if(CONSP(x) && objequal(k, CAR(x))){
  65.186 +            return x;   
  65.187 +        }
  65.188 +    }
  65.189 +    return ONULL;
  65.190 +}
  65.191 +
  65.192 +/** Search for a key in an alist.
  65.193 + * An alist is a list of conses, where the cars
  65.194 + * of the conses are the keys. Compares keys using eq.
  65.195 + *
  65.196 + * @param k key
  65.197 + * @param l alist to search
  65.198 + * @return first element of l with car k, or ONULL
  65.199 + */
  65.200 +Sxpr assocq(Sxpr k, Sxpr l){
  65.201 +    for( ; CONSP(l); l = CDR(l)){
  65.202 +        Sxpr x = CAR(l);
  65.203 +        if(CONSP(x) && eq(k, CAR(x))){
  65.204 +            return x;
  65.205 +        }
  65.206 +    }
  65.207 +    return ONULL;
  65.208 +}
  65.209 +
  65.210 +/** Add a new key and value to an alist.
  65.211 + *
  65.212 + * @param k key
  65.213 + * @param l value
  65.214 + * @param l alist
  65.215 + * @return l with the new cell added to the front
  65.216 + */
  65.217 +Sxpr acons(Sxpr k, Sxpr v, Sxpr l){
  65.218 +    Sxpr x, y;
  65.219 +    x = cons_new(k, v);
  65.220 +    if(NOMEMP(x)) return x;
  65.221 +    y = cons_new(x, l);
  65.222 +    if(NOMEMP(y)) cons_free_cells(x);
  65.223 +    return y;
  65.224 +}
  65.225 +
  65.226 +/** Test if a list contains an element.
  65.227 + * Uses sxpr equality.
  65.228 + *
  65.229 + * @param l list
  65.230 + * @param x element to look for
  65.231 + * @return a tail of l with x as car, or ONULL
  65.232 + */
  65.233 +Sxpr cons_member(Sxpr l, Sxpr x){
  65.234 +    for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}
  65.235 +    return l;
  65.236 +}
  65.237 +
  65.238 +/** Test if a list contains an element satisfying a test.
  65.239 + * The test function is called with v and an element of the list.
  65.240 + *
  65.241 + * @param l list
  65.242 + * @param test_fn test function to use
  65.243 + * @param v value for first argument to the test
  65.244 + * @return a tail of l with car satisfying the test, or 0
  65.245 + */
  65.246 +Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
  65.247 +    for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }
  65.248 +    return l;
  65.249 +}
  65.250 +
  65.251 +/** Test if the elements of list 't' are a subset of the elements
  65.252 + * of list 's'. Element order is not significant.
  65.253 + *
  65.254 + * @param s element list to check subset of
  65.255 + * @param t element list to check if is a subset
  65.256 + * @return 1 if is a subset, 0 otherwise
  65.257 + */
  65.258 +int cons_subset(Sxpr s, Sxpr t){
  65.259 +    for( ; CONSP(t); t = CDR(t)){
  65.260 +	if(!CONSP(cons_member(s, CAR(t)))){
  65.261 +	    return 0;
  65.262 +	}
  65.263 +    }
  65.264 +    return 1;
  65.265 +}
  65.266 +
  65.267 +/** Test if two lists have equal sets of elements.
  65.268 + * Element order is not significant.
  65.269 + *
  65.270 + * @param s list to check
  65.271 + * @param t list to check
  65.272 + * @return 1 if equal, 0 otherwise
  65.273 + */
  65.274 +int cons_set_equal(Sxpr s, Sxpr t){
  65.275 +    return cons_subset(s, t) && cons_subset(t, s);
  65.276 +}
  65.277 +
  65.278 +#ifdef USE_GC
  65.279 +/*============================================================================*/
  65.280 +/* The functions inside this ifdef are only safe if GC is used.
  65.281 + * Otherwise they may leak memory.
  65.282 + */
  65.283 +
  65.284 +/** Remove an element from a list (GC only).
  65.285 + * Uses sxpr equality and removes all instances, even
  65.286 + * if there are more than one.
  65.287 + *
  65.288 + * @param l list to remove elements from
  65.289 + * @param x element to remove
  65.290 + * @return modified input list
  65.291 + */
  65.292 +Sxpr cons_remove(Sxpr l, Sxpr x){
  65.293 +    return cons_remove_if(l, eq, x);
  65.294 +}
  65.295 +
  65.296 +/** Remove elements satisfying a test (GC only).
  65.297 + * The test function is called with v and an element of the set.
  65.298 + *
  65.299 + * @param l list to remove elements from
  65.300 + * @param test_fn function to use to decide if an element should be removed
  65.301 + * @return modified input list
  65.302 + */
  65.303 +Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){
  65.304 +    Sxpr prev = ONULL, elt, next;
  65.305 +
  65.306 +    for(elt = l; CONSP(elt); elt = next){
  65.307 +        next = CDR(elt);
  65.308 +        if(test_fn(v, CAR(elt))){
  65.309 +            if(NULLP(prev)){
  65.310 +                l = next;
  65.311 +            } else {
  65.312 +                CDR(prev) = next;
  65.313 +            }
  65.314 +        }
  65.315 +    }
  65.316 +    return l;
  65.317 +}
  65.318 +
  65.319 +/** Set the value for a key in an alist (GC only).
  65.320 + * If the key is present, changes the value, otherwise
  65.321 + * adds a new cell.
  65.322 + *
  65.323 + * @param k key
  65.324 + * @param v value
  65.325 + * @param l alist
  65.326 + * @return modified or extended list
  65.327 + */
  65.328 +Sxpr setf(Sxpr k, Sxpr v, Sxpr l){
  65.329 +    Sxpr e = assoc(k, l);
  65.330 +    if(NULLP(e)){
  65.331 +        l = acons(k, v, l);
  65.332 +    } else {
  65.333 +        CAR(CDR(e)) = v;
  65.334 +    }
  65.335 +    return l;
  65.336 +}
  65.337 +/*============================================================================*/
  65.338 +#endif /* USE_GC */
  65.339 +
  65.340 +/** Create a new atom with the given name.
  65.341 + *
  65.342 + * @param name the name
  65.343 + * @return new atom
  65.344 + */
  65.345 +Sxpr atom_new(char *name){
  65.346 +    Sxpr n, obj = ONOMEM;
  65.347 +
  65.348 +    n = string_new(name);
  65.349 +    if(NOMEMP(n)) goto exit;
  65.350 +    obj = HALLOC(ObjAtom, T_ATOM);
  65.351 +    if(NOMEMP(obj)) goto exit;
  65.352 +    OBJ_ATOM(obj)->name = n;
  65.353 +  exit:
  65.354 +    return obj;
  65.355 +}
  65.356 +
  65.357 +/** Free an atom.
  65.358 + *
  65.359 + * @param obj to free
  65.360 + */
  65.361 +void atom_free(Sxpr obj){
  65.362 +    // Interned atoms are shared, so do not free.
  65.363 +    if(OBJ_ATOM(obj)->interned) return;
  65.364 +    objfree(OBJ_ATOM(obj)->name);
  65.365 +    hfree(obj);
  65.366 +}
  65.367 +
  65.368 +/** Print an atom. Prints the atom name.
  65.369 + *
  65.370 + * @param io stream to print to
  65.371 + * @param obj to print
  65.372 + * @param flags print flags
  65.373 + * @return number of bytes printed
  65.374 + */
  65.375 +int atom_print(IOStream *io, Sxpr obj, unsigned flags){
  65.376 +    //return string_print(io, OBJ_ATOM(obj)->name, (flags | PRINT_RAW));
  65.377 +    return string_print(io, OBJ_ATOM(obj)->name, flags);
  65.378 +}
  65.379 +
  65.380 +/** Atom equality.
  65.381 + *
  65.382 + * @param x to compare
  65.383 + * @param y to compare
  65.384 + * @return 1 if equal, 0 otherwise
  65.385 + */
  65.386 +int atom_equal(Sxpr x, Sxpr y){
  65.387 +    int ok;
  65.388 +    ok = eq(x, y);
  65.389 +    if(ok) goto exit;
  65.390 +    ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);
  65.391 +    if(ok) goto exit;
  65.392 +    ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);
  65.393 +  exit:
  65.394 +    return ok;
  65.395 +}
  65.396 +
  65.397 +/** Get the name of an atom.
  65.398 + *
  65.399 + * @param obj atom
  65.400 + * @return name
  65.401 + */
  65.402 +char * atom_name(Sxpr obj){
  65.403 +    return string_string(OBJ_ATOM(obj)->name);
  65.404 +}
  65.405 +
  65.406 +/** Get the C string from a string sxpr.
  65.407 + *
  65.408 + * @param obj string sxpr
  65.409 + * @return string
  65.410 + */
  65.411 +char * string_string(Sxpr obj){
  65.412 +    return OBJ_STRING(obj);
  65.413 +}
  65.414 +
  65.415 +/** Get the length of a string.
  65.416 + *
  65.417 + * @param obj string
  65.418 + * @return length
  65.419 + */
  65.420 +int string_length(Sxpr obj){
  65.421 +    return strlen(OBJ_STRING(obj));
  65.422 +}
  65.423 +
  65.424 +/** Create a new string. The input string is copied,
  65.425 + * and must be null-terminated.
  65.426 + *
  65.427 + * @param s characters to put in the string
  65.428 + * @return new sxpr
  65.429 + */
  65.430 +Sxpr string_new(char *s){
  65.431 +    int n = (s ? strlen(s) : 0);
  65.432 +    Sxpr obj;
  65.433 +    obj = halloc(n+1, T_STRING);
  65.434 +    if(!NOMEMP(obj)){
  65.435 +        char *str = OBJ_STRING(obj);
  65.436 +        strncpy(str, s, n);
  65.437 +        str[n] = '\0';
  65.438 +    }
  65.439 +    return obj;
  65.440 +}
  65.441 +
  65.442 +/** Free a string.
  65.443 + *
  65.444 + * @param obj to free
  65.445 + */
  65.446 +void string_free(Sxpr obj){
  65.447 +    hfree(obj);
  65.448 +}
  65.449 +
  65.450 +/** Determine if a string needs escapes when printed
  65.451 + * using the given flags.
  65.452 + *
  65.453 + * @param str string to check
  65.454 + * @param flags print flags
  65.455 + * @return 1 if needs escapes, 0 otherwise
  65.456 + */
  65.457 +int needs_escapes(char *str, unsigned flags){
  65.458 +    char *c;
  65.459 +    int val = 0;
  65.460 +
  65.461 +    if(str){
  65.462 +	for(c=str; *c; c++){
  65.463 +	    if(in_alpha_class(*c)) continue;
  65.464 +	    if(in_decimal_digit_class(*c)) continue;
  65.465 +	    if(in_class(*c, "/._+:@~-")) continue;
  65.466 +	    val = 1;
  65.467 +	    break;
  65.468 +	}
  65.469 +    }
  65.470 +    //printf("\n> val=%d str=|%s|\n", val, str);
  65.471 +    return val;
  65.472 +}
  65.473 +
  65.474 +/** Print a string to a stream, with escapes if necessary.
  65.475 + *
  65.476 + * @param io stream to print to
  65.477 + * @param str string
  65.478 + * @param flags print flags
  65.479 + * @return number of bytes written
  65.480 + */
  65.481 +int _string_print(IOStream *io, char *str, unsigned flags){
  65.482 +    int k = 0;
  65.483 +    if((flags & PRINT_RAW) || !needs_escapes(str, flags)){
  65.484 +        k += IOStream_print(io, str);
  65.485 +    } else {
  65.486 +	k += IOStream_print(io, "\"");
  65.487 +	if(str){
  65.488 +            char *s;
  65.489 +            for(s = str; *s; s++){
  65.490 +                if(*s < ' ' || *s >= 127 ){
  65.491 +                    switch(*s){
  65.492 +                    case '\a': k += IOStream_print(io, "\\a");  break;
  65.493 +                    case '\b': k += IOStream_print(io, "\\b");  break;
  65.494 +                    case '\f': k += IOStream_print(io, "\\f");  break;
  65.495 +                    case '\n': k += IOStream_print(io, "\\n");  break;
  65.496 +                    case '\r': k += IOStream_print(io, "\\r");  break;
  65.497 +                    case '\t': k += IOStream_print(io, "\\t");  break;
  65.498 +                    case '\v': k += IOStream_print(io, "\\v");  break;
  65.499 +                    default:
  65.500 +                        // Octal escape;
  65.501 +                        k += IOStream_print(io, "\\%o", *s);
  65.502 +                        break;
  65.503 +                    }
  65.504 +                } else if(*s == c_double_quote ||
  65.505 +                          *s == c_single_quote ||
  65.506 +                          *s == c_escape){
  65.507 +                    k += IOStream_print(io, "\\%c", *s);
  65.508 +                } else {
  65.509 +                    k+= IOStream_print(io, "%c", *s);
  65.510 +                }
  65.511 +            }
  65.512 +	}
  65.513 +	k += IOStream_print(io, "\"");
  65.514 +    }
  65.515 +    return k;
  65.516 +}
  65.517 +
  65.518 +/** Print a string to a stream, with escapes if necessary.
  65.519 + *
  65.520 + * @param io stream to print to
  65.521 + * @param obj string
  65.522 + * @param flags print flags
  65.523 + * @return number of bytes written
  65.524 + */
  65.525 +int string_print(IOStream *io, Sxpr obj, unsigned flags){
  65.526 +    return _string_print(io, OBJ_STRING(obj), flags);
  65.527 +}
  65.528 +
  65.529 +/** Compare an sxpr with a string for equality.
  65.530 + *
  65.531 + * @param x string to compare with
  65.532 + * @param y sxpr to compare
  65.533 + * @return 1 if equal, 0 otherwise
  65.534 + */
  65.535 +int string_equal(Sxpr x, Sxpr y){
  65.536 +    int ok = 0;
  65.537 +    ok = eq(x,y);
  65.538 +    if(ok) goto exit;
  65.539 +    ok = has_type(y, T_STRING) && !strcmp(OBJ_STRING(x), OBJ_STRING(y));
  65.540 +    if(ok) goto exit;
  65.541 +    ok = has_type(y, T_ATOM) && !strcmp(OBJ_STRING(x), atom_name(y));
  65.542 +  exit:
  65.543 +    return ok;
  65.544 +}
  65.545 +
  65.546 +/** Create a new cons cell.
  65.547 + * The cell is ONOMEM if either argument is.
  65.548 + *
  65.549 + * @param car sxpr for the car
  65.550 + * @param cdr sxpr for the cdr
  65.551 + * @return new cons
  65.552 + */
  65.553 +Sxpr cons_new(Sxpr car, Sxpr cdr){
  65.554 +    Sxpr obj;
  65.555 +    if(NOMEMP(car) || NOMEMP(cdr)){
  65.556 +        obj = ONOMEM;
  65.557 +    } else {
  65.558 +        obj = HALLOC(ObjCons, T_CONS);
  65.559 +        if(!NOMEMP(obj)){
  65.560 +            ObjCons *z = OBJ_CONS(obj);
  65.561 +            z->car = car;
  65.562 +            z->cdr = cdr;
  65.563 +        }
  65.564 +    }
  65.565 +    return obj;
  65.566 +}
  65.567 +
  65.568 +/** Push a new element onto a list.
  65.569 + *
  65.570 + * @param list list to add to
  65.571 + * @param elt element to add
  65.572 + * @return 0 if successful, error code otherwise
  65.573 + */
  65.574 +int cons_push(Sxpr *list, Sxpr elt){
  65.575 +    Sxpr l;
  65.576 +    l = cons_new(elt, *list);
  65.577 +    if(NOMEMP(l)) return -ENOMEM;
  65.578 +    *list = l;
  65.579 +    return 0;
  65.580 +}
  65.581 +
  65.582 +/** Free a cons. Recursively frees the car and cdr.
  65.583 + *
  65.584 + * @param obj to free
  65.585 + */
  65.586 +void cons_free(Sxpr obj){
  65.587 +    Sxpr next;
  65.588 +    for(; CONSP(obj); obj = next){
  65.589 +	next = CDR(obj);
  65.590 +	objfree(CAR(obj));
  65.591 +	hfree(obj);
  65.592 +    }
  65.593 +    if(!NULLP(obj)){
  65.594 +	objfree(obj);
  65.595 +    }
  65.596 +}
  65.597 +
  65.598 +/** Free a cons and its cdr cells, but not the car sxprs.
  65.599 + * Does nothing if called on something that is not a cons.
  65.600 + *
  65.601 + * @param obj to free
  65.602 + */
  65.603 +void cons_free_cells(Sxpr obj){
  65.604 +    Sxpr next;
  65.605 +    for(; CONSP(obj); obj = next){
  65.606 +	next = CDR(obj);
  65.607 +	hfree(obj);
  65.608 +    }
  65.609 +}
  65.610 +
  65.611 +/** Print a cons.
  65.612 + * Prints the cons in list format if the cdrs are conses.
  65.613 + * uses pair (dot) format if the last cdr is not a cons (or null).
  65.614 + *
  65.615 + * @param io stream to print to
  65.616 + * @param obj to print
  65.617 + * @param flags print flags
  65.618 + * @return number of bytes written
  65.619 + */
  65.620 +int cons_print(IOStream *io, Sxpr obj, unsigned flags){
  65.621 +    int first = 1;
  65.622 +    int k = 0;
  65.623 +    k += IOStream_print(io, "(");
  65.624 +    for( ; CONSP(obj) ; obj = CDR(obj)){
  65.625 +        if(first){ 
  65.626 +            first = 0;
  65.627 +        } else {
  65.628 +            k += IOStream_print(io, " ");
  65.629 +        }
  65.630 +        k += objprint(io, CAR(obj), flags);
  65.631 +    }
  65.632 +    if(!NULLP(obj)){
  65.633 +        k += IOStream_print(io, " . ");
  65.634 +        k += objprint(io, obj, flags);
  65.635 +    }
  65.636 +    k += IOStream_print(io, ")");
  65.637 +    return (IOStream_error(io) ? -1 : k);
  65.638 +}
  65.639 +
  65.640 +/** Compare a cons with another sxpr for equality.
  65.641 + * If y is a cons, compares the cars and cdrs recursively.
  65.642 + *
  65.643 + * @param x cons to compare
  65.644 + * @param y sxpr to compare
  65.645 + * @return 1 if equal, 0 otherwise
  65.646 + */
  65.647 +int cons_equal(Sxpr x, Sxpr y){
  65.648 +    return CONSP(y) &&
  65.649 +        objequal(CAR(x), CAR(y)) &&
  65.650 +        objequal(CDR(x), CDR(y));
  65.651 +}
  65.652 +
  65.653 +/** Return the length of a cons list.
  65.654 + *
  65.655 + * @param obj list
  65.656 + * @return length
  65.657 + */
  65.658 +int cons_length(Sxpr obj){
  65.659 +    int count = 0;
  65.660 +    for( ; CONSP(obj); obj = CDR(obj)){
  65.661 +        count++;
  65.662 +    }
  65.663 +    return count;
  65.664 +}
  65.665 +
  65.666 +/** Destructively reverse a cons list in-place.
  65.667 + * If the argument is not a cons it is returned unchanged.
  65.668 + * 
  65.669 + * @param l to reverse
  65.670 + * @return reversed list
  65.671 + */
  65.672 +Sxpr nrev(Sxpr l){
  65.673 +    if(CONSP(l)){
  65.674 +	// Iterate down the cells in the list making the cdr of
  65.675 +	// each cell point to the previous cell. The last cell 
  65.676 +	// is the head of the reversed list.
  65.677 +	Sxpr prev = ONULL;
  65.678 +	Sxpr cell = l;
  65.679 +	Sxpr next;
  65.680 +
  65.681 +	while(1){
  65.682 +	    next = CDR(cell);
  65.683 +	    CDR(cell) = prev;
  65.684 +	    if(!CONSP(next)) break;
  65.685 +	    prev = cell;
  65.686 +	    cell = next;
  65.687 +	}
  65.688 +	l = cell;
  65.689 +    }
  65.690 +    return l;
  65.691 +}
  65.692 +
  65.693 +/** Print the null sxpr.	
  65.694 + *
  65.695 + * @param io stream to print to
  65.696 + * @param obj to print
  65.697 + * @param flags print flags
  65.698 + * @return number of bytes written
  65.699 + */
  65.700 +static int null_print(IOStream *io, Sxpr obj, unsigned flags){
  65.701 +    return IOStream_print(io, "()");
  65.702 +}
  65.703 +
  65.704 +/** Print the `unspecified' sxpr none.
  65.705 + *
  65.706 + * @param io stream to print to
  65.707 + * @param obj to print
  65.708 + * @param flags print flags
  65.709 + * @return number of bytes written
  65.710 + */
  65.711 +static int none_print(IOStream *io, Sxpr obj, unsigned flags){
  65.712 +    return IOStream_print(io, "<none>");
  65.713 +}
  65.714 +
  65.715 +/** Print an integer.
  65.716 + *
  65.717 + * @param io stream to print to
  65.718 + * @param obj to print
  65.719 + * @param flags print flags
  65.720 + * @return number of bytes written
  65.721 + */
  65.722 +static int int_print(IOStream *io, Sxpr obj, unsigned flags){
  65.723 +    return IOStream_print(io, "%d", OBJ_INT(obj));
  65.724 +}
  65.725 +
  65.726 +/** Print a boolean.
  65.727 + *
  65.728 + * @param io stream to print to
  65.729 + * @param obj to print
  65.730 + * @param flags print flags
  65.731 + * @return number of bytes written
  65.732 + */
  65.733 +static int bool_print(IOStream *io, Sxpr obj, unsigned flags){
  65.734 +    return IOStream_print(io, (OBJ_UINT(obj) ? k_true : k_false));
  65.735 +}
  65.736 +
  65.737 +int sxprp(Sxpr obj, Sxpr name){
  65.738 +    return CONSP(obj) && objequal(CAR(obj), name);
  65.739 +}
  65.740 +
  65.741 +/** Get the name of an element.
  65.742 + * 
  65.743 + * @param obj element
  65.744 + * @return name
  65.745 + */
  65.746 +Sxpr sxpr_name(Sxpr obj){
  65.747 +    Sxpr val = ONONE;
  65.748 +    if(CONSP(obj)){
  65.749 +        val = CAR(obj);
  65.750 +    } else if(STRINGP(obj) || ATOMP(obj)){
  65.751 +        val = obj;
  65.752 +    }
  65.753 +    return val;
  65.754 +}
  65.755 +
  65.756 +int sxpr_is(Sxpr obj, char *s){
  65.757 +    if(ATOMP(obj)) return !strcmp(atom_name(obj), s);
  65.758 +    if(STRINGP(obj)) return !strcmp(string_string(obj), s);
  65.759 +    return 0;
  65.760 +}
  65.761 +
  65.762 +int sxpr_elementp(Sxpr obj, Sxpr name){
  65.763 +    int ok = 0;
  65.764 +    ok = CONSP(obj) && objequal(CAR(obj), name);
  65.765 +    return ok;
  65.766 +}
  65.767 +
  65.768 +/** Get the attributes of an sxpr.
  65.769 + * 
  65.770 + * @param obj sxpr
  65.771 + * @return attributes
  65.772 + */
  65.773 +Sxpr sxpr_attributes(Sxpr obj){
  65.774 +    Sxpr val = ONULL;
  65.775 +    if(CONSP(obj)){
  65.776 +        obj = CDR(obj);
  65.777 +        if(CONSP(obj)){
  65.778 +            obj = CAR(obj);
  65.779 +            if(sxprp(obj, intern("@"))){
  65.780 +                val = CDR(obj);
  65.781 +            }
  65.782 +        }
  65.783 +    }
  65.784 +    return val;
  65.785 +}
  65.786 +
  65.787 +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def){
  65.788 +    Sxpr val = ONONE;
  65.789 +    val = assoc(sxpr_attributes(obj), key);
  65.790 +    if(CONSP(val) && CONSP(CDR(val))){
  65.791 +        val = CADR(def);
  65.792 +    } else {
  65.793 +        val = def;
  65.794 +    }
  65.795 +    return val;
  65.796 +}
  65.797 +
  65.798 +/** Get the children of an sxpr.
  65.799 + * 
  65.800 + * @param obj sxpr
  65.801 + * @return children
  65.802 + */
  65.803 +Sxpr sxpr_children(Sxpr obj){
  65.804 +    Sxpr val = ONULL;
  65.805 +    if(CONSP(obj)){
  65.806 +        val = CDR(obj);
  65.807 +        if(CONSP(val) && sxprp(CAR(val), intern("@"))){
  65.808 +            val = CDR(val);
  65.809 +        }
  65.810 +    }
  65.811 +    return val;
  65.812 +}
  65.813 +
  65.814 +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def){
  65.815 +    Sxpr val = ONONE;
  65.816 +    Sxpr l;
  65.817 +    for(l = sxpr_children(obj); CONSP(l); l = CDR(l)){
  65.818 +        if(sxprp(CAR(l), name)){
  65.819 +            val = CAR(l);
  65.820 +            break;
  65.821 +        }
  65.822 +    }
  65.823 +    if(NONEP(val)) val = def;
  65.824 +    return val;
  65.825 +}
  65.826 +
  65.827 +Sxpr sxpr_child0(Sxpr obj, Sxpr def){
  65.828 +    Sxpr val = ONONE;
  65.829 +    Sxpr l = sxpr_children(obj);
  65.830 +    if(CONSP(l)){
  65.831 +        val = CAR(l);
  65.832 +    } else {
  65.833 +        val = def;
  65.834 +    }
  65.835 +    return val;
  65.836 +}
  65.837 +
  65.838 +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def){
  65.839 +    Sxpr val = def;
  65.840 +    Sxpr l;
  65.841 +    int i;
  65.842 +    for (i = 0, l = sxpr_children(obj); CONSP(l); i++, l = CDR(l)){
  65.843 +        if(i == n){
  65.844 +            val = CAR(l);
  65.845 +            break;
  65.846 +        }
  65.847 +    }
  65.848 +    return val;
  65.849 +}
  65.850 +    
  65.851 +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def){
  65.852 +    Sxpr val = ONONE;
  65.853 +    val = sxpr_child(obj, name, ONONE);
  65.854 +    if(NONEP(val)){
  65.855 +        val = def;
  65.856 +    } else {
  65.857 +        val = sxpr_child0(val, def);
  65.858 +    }
  65.859 +    return val;
  65.860 +}
  65.861 +
  65.862 +/** Table of interned symbols. Indexed by symbol name. */
  65.863 +static HashTable *symbols = NULL;
  65.864 +
  65.865 +/** Hash function for entries in the symbol table.
  65.866 + *
  65.867 + * @param key to hash
  65.868 + * @return hashcode
  65.869 + */
  65.870 +static Hashcode sym_hash_fn(void *key){
  65.871 +    return hash_string((char*)key);
  65.872 +}
  65.873 +
  65.874 +/** Key equality function for the symbol table.
  65.875 + *
  65.876 + * @param x to compare
  65.877 + * @param y to compare
  65.878 + * @return 1 if equal, 0 otherwise
  65.879 + */
  65.880 +static int sym_equal_fn(void *x, void *y){
  65.881 +    return !strcmp((char*)x, (char*)y);
  65.882 +}
  65.883 +
  65.884 +/** Entry free function for the symbol table.
  65.885 + *
  65.886 + * @param table the entry is in
  65.887 + * @param entry being freed
  65.888 + */
  65.889 +static void sym_free_fn(HashTable *table, HTEntry *entry){
  65.890 +    if(entry){
  65.891 +	objfree(((ObjAtom*)entry->value)->name);
  65.892 +	HTEntry_free(entry);
  65.893 +    }
  65.894 +}
  65.895 +	
  65.896 +/** Initialize the symbol table.
  65.897 + *
  65.898 + * @return 0 on sucess, error code otherwise
  65.899 + */
  65.900 +static int init_symbols(void){
  65.901 +    symbols = HashTable_new(100);
  65.902 +    if(symbols){
  65.903 +        symbols->key_hash_fn = sym_hash_fn;
  65.904 +        symbols->key_equal_fn = sym_equal_fn;
  65.905 +	symbols->entry_free_fn = sym_free_fn;
  65.906 +        return 0;
  65.907 +    }
  65.908 +    return -1;
  65.909 +}
  65.910 +
  65.911 +/** Cleanup the symbol table. Frees the table and all its symbols.
  65.912 + */
  65.913 +void cleanup_symbols(void){
  65.914 +    HashTable_free(symbols);
  65.915 +    symbols = NULL;
  65.916 +}
  65.917 +
  65.918 +/** Get the interned symbol with the given name.
  65.919 + * No new symbol is created.
  65.920 + *
  65.921 + * @return symbol or null
  65.922 + */
  65.923 +Sxpr get_symbol(char *sym){
  65.924 +    HTEntry *entry;
  65.925 +    if(!symbols){
  65.926 +	if(init_symbols()) return ONOMEM;
  65.927 +	return ONULL;
  65.928 +    }
  65.929 +    entry = HashTable_get_entry(symbols, sym);
  65.930 +    if(entry){
  65.931 +        return OBJP(T_ATOM, entry->value);
  65.932 +    } else {
  65.933 +        return ONULL;
  65.934 +    }
  65.935 +}
  65.936 +
  65.937 +/** Get the interned symbol with the given name.
  65.938 + * Creates a new symbol if necessary.
  65.939 + *
  65.940 + * @return symbol
  65.941 + */
  65.942 +Sxpr intern(char *sym){
  65.943 +    Sxpr symbol = get_symbol(sym);
  65.944 +    if(NULLP(symbol)){
  65.945 +	if(!symbols) return ONOMEM;
  65.946 +        symbol = atom_new(sym);
  65.947 +        if(!NOMEMP(symbol)){
  65.948 +	    OBJ_ATOM(symbol)->interned = TRUE;
  65.949 +            HashTable_add(symbols, atom_name(symbol), get_ptr(symbol));
  65.950 +        }
  65.951 +    }
  65.952 +    return symbol;
  65.953 +}
    66.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    66.2 +++ b/tools/xfrd/sxpr.h	Tue Jul 06 20:42:26 2004 +0000
    66.3 @@ -0,0 +1,414 @@
    66.4 +/*
    66.5 + *
    66.6 + * This library is free software; you can redistribute it and/or modify
    66.7 + * it under the terms of the GNU Lesser General Public License as
    66.8 + * published by the Free Software Foundation; either version 2.1 of the
    66.9 + * License, or  (at your option) any later version. This library is 
   66.10 + * distributed in the  hope that it will be useful, but WITHOUT ANY
   66.11 + * WARRANTY; without even the implied warranty of MERCHANTABILITY or
   66.12 + * FITNESS FOR A PARTICULAR PURPOSE.
   66.13 + * See the GNU Lesser General Public License for more details.
   66.14 + *
   66.15 + * You should have received a copy of the GNU Lesser General Public License
   66.16 + * along with this library; if not, write to the Free Software Foundation,
   66.17 + * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   66.18 + */
   66.19 +#ifndef _XUTIL_SXPR_H_
   66.20 +#define _XUTIL_SXPR_H_
   66.21 +
   66.22 +#include <stdint.h>
   66.23 +
   66.24 +#include "hash_table.h"
   66.25 +#include "iostream.h"
   66.26 +#include "allocate.h"
   66.27 +
   66.28 +/** @file
   66.29 + * Definitions for rules and sxprs.
   66.30 + */
   66.31 +
   66.32 +#ifndef NULL
   66.33 +#define NULL 0
   66.34 +#endif
   66.35 +
   66.36 +#ifndef TRUE
   66.37 +#define TRUE 1
   66.38 +#endif
   66.39 +
   66.40 +#ifndef FALSE
   66.41 +#define FALSE 0
   66.42 +#endif
   66.43 +
   66.44 +/** Sxpr type. */
   66.45 +typedef int16_t TypeCode;
   66.46 +
   66.47 +/** A typed sxpr handle.*/
   66.48 +typedef struct Sxpr {
   66.49 +    /** Sxpr type. */
   66.50 +    TypeCode type;
   66.51 +    union {
   66.52 +	/** Sxpr value. */
   66.53 +        unsigned long ul;
   66.54 +	/** Pointer. */
   66.55 +        void *ptr;
   66.56 +    } v;
   66.57 +} Sxpr;
   66.58 +
   66.59 +/** Sxpr type to indicate out of memory. */
   66.60 +#define T_NOMEM      ((TypeCode)-1)
   66.61 +/** The 'unspecified' sxpr. */
   66.62 +#define T_NONE       ((TypeCode)0)
   66.63 +/** The empty list. */
   66.64 +#define T_NULL       ((TypeCode)1)
   66.65 +/** Unsigned integer. */
   66.66 +#define T_UINT       ((TypeCode)2)
   66.67 +/** A string. */
   66.68 +#define T_STRING     ((TypeCode)3)
   66.69 +/** An atom. */
   66.70 +#define T_ATOM       ((TypeCode)4)
   66.71 +/** A boolean. */
   66.72 +#define T_BOOL       ((TypeCode)5)
   66.73 +
   66.74 +/** A cons (pair or list). */
   66.75 +#define T_CONS       ((TypeCode)10)
   66.76 +
   66.77 +/** An error. */
   66.78 +#define T_ERR        ((TypeCode)40)
   66.79 +
   66.80 +/** An atom. */
   66.81 +typedef struct ObjAtom {
   66.82 +    Sxpr name;
   66.83 +    Hashcode hashcode;
   66.84 +    int interned;
   66.85 +} ObjAtom;
   66.86 +
   66.87 +/** A cons (pair). */
   66.88 +typedef struct ObjCons {
   66.89 +    Sxpr car;
   66.90 +    Sxpr cdr;
   66.91 +} ObjCons;
   66.92 +
   66.93 +/** A vector. */
   66.94 +typedef struct ObjVector {
   66.95 +    int n;
   66.96 +    Sxpr data[0];
   66.97 +} ObjVector;
   66.98 +
   66.99 +/** Flags for sxpr printing. */
  66.100 +enum PrintFlags {
  66.101 +    PRINT_RAW           = 0x001,
  66.102 +    PRINT_TYPE          = 0x002,
  66.103 +    PRINT_PRETTY        = 0x004,
  66.104 +    PRINT_NUM           = 0x008,
  66.105 +};
  66.106 +
  66.107 +/** An integer sxpr.
  66.108 + *
  66.109 + * @param ty type
  66.110 + * @param val integer value
  66.111 + */
  66.112 +#define OBJI(ty, val) (Sxpr){ type: (ty), v: { ul: (val) }}
  66.113 +
  66.114 +/** A pointer sxpr.
  66.115 + * If the pointer is non-null, returns an sxpr containing it.
  66.116 + * If the pointer is null, returns ONOMEM.
  66.117 + *
  66.118 + * @param ty type
  66.119 + * @param val pointer
  66.120 + */
  66.121 +#define OBJP(ty, val) ((val) ? (Sxpr){ type: (ty), v: { ptr: (val) }} : ONOMEM)
  66.122 +
  66.123 +/** Make an integer sxpr containing a pointer.
  66.124 + *
  66.125 + * @param val pointer
  66.126 + */
  66.127 +#define PTR(val) OBJP(T_UINT, (void*)(val))
  66.128 +
  66.129 +/** Make an integer sxpr.
  66.130 + * @param x value
  66.131 + */
  66.132 +#define OINT(x)       OBJI(T_UINT,  x)
  66.133 +
  66.134 +/** Make an error sxpr.
  66.135 + *
  66.136 + * @param x value
  66.137 + */
  66.138 +#define OERR(x)       OBJI(T_ERR,   x)
  66.139 +
  66.140 +/** Out of memory constant. */
  66.141 +#define ONOMEM        OBJI(T_NOMEM, 0)
  66.142 +
  66.143 +/** The `unspecified' constant. */
  66.144 +#define ONONE         OBJI(T_NONE,  0)
  66.145 +
  66.146 +/** Empty list constant. */
  66.147 +#define ONULL         OBJI(T_NULL,  0)
  66.148 +
  66.149 +/** False constant. */
  66.150 +#define OFALSE        OBJI(T_BOOL,  0)
  66.151 +
  66.152 +/** True constant. */
  66.153 +#define OTRUE         OBJI(T_BOOL,  1)
  66.154 +
  66.155 +/* Recognizers for the various sxpr types.  */
  66.156 +#define ATOMP(obj)        has_type(obj, T_ATOM)
  66.157 +#define BOOLP(obj)        has_type(obj, T_BOOL)
  66.158 +#define CONSP(obj)        has_type(obj, T_CONS)
  66.159 +#define ERRP(obj)         has_type(obj, T_ERR)
  66.160 +#define INTP(obj)         has_type(obj, T_UINT)
  66.161 +#define NOMEMP(obj)       has_type(obj, T_NOMEM)
  66.162 +#define NONEP(obj)        has_type(obj, T_NONE)
  66.163 +#define NULLP(obj)        has_type(obj, T_NULL)
  66.164 +#define STRINGP(obj)      has_type(obj, T_STRING)
  66.165 +
  66.166 +#define TRUEP(obj)    get_ul(obj)
  66.167 +
  66.168 +/** Convert an sxpr to an unsigned integer. */
  66.169 +#define OBJ_UINT(x)   get_ul(x)
  66.170 +/** Convert an sxpr to an integer. */
  66.171 +#define OBJ_INT(x)    (int)get_ul(x)
  66.172 +
  66.173 +/* Conversions of sxprs to their values.
  66.174 + * No checking is done.
  66.175 + */
  66.176 +#define OBJ_STRING(x)  ((char*)get_ptr(x))
  66.177 +#define OBJ_CONS(x)    ((ObjCons*)get_ptr(x))
  66.178 +#define OBJ_ATOM(x)    ((ObjAtom*)get_ptr(x))
  66.179 +#define OBJ_SET(x)     ((ObjSet*)get_ptr(x))
  66.180 +#define CAR(x)         (OBJ_CONS(x)->car)
  66.181 +#define CDR(x)         (OBJ_CONS(x)->cdr)
  66.182 +
  66.183 +#define CAAR(x)        (CAR(CAR(x)))
  66.184 +#define CADR(x)        (CAR(CDR(x)))
  66.185 +#define CDAR(x)        (CDR(CAR(x)))
  66.186 +#define CDDR(x)        (CDR(CDR(x)))
  66.187 +
  66.188 +/** Get the integer value from an sxpr.
  66.189 + *
  66.190 + * @param obj sxpr
  66.191 + * @return value
  66.192 + */
  66.193 +static inline unsigned long get_ul(Sxpr obj){
  66.194 +    return obj.v.ul;
  66.195 +}
  66.196 +
  66.197 +/** Get the pointer value from an sxpr.
  66.198 + *
  66.199 + * @param obj sxpr
  66.200 + * @return value
  66.201 + */
  66.202 +static inline void * get_ptr(Sxpr obj){
  66.203 +    return obj.v.ptr;
  66.204 +}
  66.205 +
  66.206 +/** Create an sxpr containing a pointer.
  66.207 + *
  66.208 + * @param type typecode
  66.209 + * @param val pointer
  66.210 + * @return sxpr
  66.211 + */
  66.212 +static inline Sxpr obj_ptr(TypeCode type, void *val){
  66.213 +    return (Sxpr){ type: type, v: { ptr: val } };
  66.214 +}
  66.215 +
  66.216 +/** Create an sxpr containing an integer.
  66.217 + *
  66.218 + * @param type typecode
  66.219 + * @param val integer
  66.220 + * @return sxpr
  66.221 + */
  66.222 +static inline Sxpr obj_ul(TypeCode type, unsigned long val){
  66.223 +    return (Sxpr){ type: type, v: { ul: val } };
  66.224 +}
  66.225 +
  66.226 +/** Get the type of an sxpr.
  66.227 + *
  66.228 + * @param obj sxpr
  66.229 + * @return type
  66.230 + */
  66.231 +static inline TypeCode get_type(Sxpr obj){
  66.232 +    return obj.type;
  66.233 +}
  66.234 +
  66.235 +/** Check the type of an sxpr.
  66.236 + *
  66.237 + * @param obj sxpr
  66.238 + * @param type to check
  66.239 + * @return 1 if has the type, 0 otherwise
  66.240 + */
  66.241 +static inline int has_type(Sxpr obj, TypeCode type){
  66.242 +    return get_type(obj) == type;
  66.243 +}
  66.244 +
  66.245 +/** Compare sxprs for literal equality of type and value.
  66.246 + *
  66.247 + * @param x sxpr to compare
  66.248 + * @param y sxpr to compare
  66.249 + * @return 1 if equal, 0 otherwise
  66.250 + */
  66.251 +static inline int eq(Sxpr x, Sxpr y){
  66.252 +    return ((get_type(x) == get_type(y)) && (get_ul(x) == get_ul(y)));
  66.253 +}
  66.254 +
  66.255 +/** Checked version of CAR
  66.256 + *
  66.257 + * @param x sxpr
  66.258 + * @return CAR if a cons, x otherwise
  66.259 + */
  66.260 +static inline Sxpr car(Sxpr x){
  66.261 +    return (CONSP(x) ? CAR(x) : x);
  66.262 +}
  66.263 +
  66.264 +/** Checked version of CDR.
  66.265 + *
  66.266 + * @param x sxpr
  66.267 + * @return CDR if a cons, null otherwise
  66.268 + */
  66.269 +static inline Sxpr cdr(Sxpr x){
  66.270 +    return (CONSP(x) ? CDR(x) : ONULL);
  66.271 +}
  66.272 +
  66.273 +/** Allocate some memory and return an sxpr containing it.
  66.274 + * Returns ONOMEM if allocation failed.
  66.275 + *
  66.276 + * @param n number of bytes to allocate
  66.277 + * @param ty typecode
  66.278 + * @return sxpr
  66.279 + */
  66.280 +static inline Sxpr halloc(size_t n,  TypeCode ty){
  66.281 +    return OBJP(ty, allocate(n));
  66.282 +}
  66.283 +
  66.284 +/** Allocate an sxpr containing a pointer to the given type.
  66.285 + *
  66.286 + * @param ty type (uses sizeof to determine how many bytes to allocate)
  66.287 + * @param code typecode
  66.288 + * @return sxpr, ONOMEM if allocation failed
  66.289 + */
  66.290 +#define HALLOC(ty, code) halloc(sizeof(ty), code)
  66.291 +
  66.292 +typedef int ObjPrintFn(IOStream *io, Sxpr obj, unsigned flags);
  66.293 +typedef int ObjEqualFn(Sxpr obj, Sxpr other);
  66.294 +typedef void ObjFreeFn(Sxpr obj);
  66.295 +
  66.296 +/** An sxpr type definition. */
  66.297 +typedef struct SxprType {
  66.298 +    TypeCode type;
  66.299 +    char *name;
  66.300 +    int pointer;
  66.301 +    ObjPrintFn *print;
  66.302 +    ObjEqualFn *equal;
  66.303 +    ObjFreeFn *free;
  66.304 +} SxprType;
  66.305 +
  66.306 +
  66.307 +extern SxprType *get_sxpr_type(int ty);
  66.308 +
  66.309 +/** Free the pointer in an sxpr.
  66.310 + *
  66.311 + * @param x sxpr containing a pointer
  66.312 + */
  66.313 +static inline void hfree(Sxpr x){
  66.314 +    deallocate(get_ptr(x));
  66.315 +}
  66.316 +
  66.317 +extern int objprint(IOStream *io, Sxpr x, unsigned flags);
  66.318 +extern int objequal(Sxpr x, Sxpr y);
  66.319 +extern void objfree(Sxpr x);
  66.320 +
  66.321 +extern void cons_free_cells(Sxpr obj);
  66.322 +extern Sxpr intern(char *s);
  66.323 +
  66.324 +extern Sxpr assoc(Sxpr k, Sxpr l);
  66.325 +extern Sxpr assocq(Sxpr k, Sxpr l);
  66.326 +extern Sxpr acons(Sxpr k, Sxpr v, Sxpr l);
  66.327 +extern Sxpr nrev(Sxpr l);
  66.328 +extern Sxpr cons_member(Sxpr l, Sxpr x);
  66.329 +extern Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
  66.330 +extern int cons_subset(Sxpr s, Sxpr t);
  66.331 +extern int cons_set_equal(Sxpr s, Sxpr t);
  66.332 +
  66.333 +#ifdef USE_GC
  66.334 +extern Sxpr cons_remove(Sxpr l, Sxpr x);
  66.335 +extern Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v);
  66.336 +#endif
  66.337 +
  66.338 +extern Sxpr atom_new(char *name);
  66.339 +extern char * atom_name(Sxpr obj);
  66.340 +
  66.341 +extern Sxpr string_new(char *s);
  66.342 +extern char * string_string(Sxpr obj);
  66.343 +extern int string_length(Sxpr obj);
  66.344 +
  66.345 +extern Sxpr cons_new(Sxpr car, Sxpr cdr);
  66.346 +extern int cons_push(Sxpr *list, Sxpr elt);
  66.347 +extern int cons_length(Sxpr obj);
  66.348 +
  66.349 +Sxpr sxpr_name(Sxpr obj);
  66.350 +int sxpr_is(Sxpr obj, char *s);
  66.351 +int sxpr_elementp(Sxpr obj, Sxpr name);
  66.352 +Sxpr sxpr_attributes(Sxpr obj);
  66.353 +Sxpr sxpr_attribute(Sxpr obj, Sxpr key, Sxpr def);
  66.354 +Sxpr sxpr_children(Sxpr obj);
  66.355 +Sxpr sxpr_child(Sxpr obj, Sxpr name, Sxpr def);
  66.356 +Sxpr sxpr_childN(Sxpr obj, int n, Sxpr def);
  66.357 +Sxpr sxpr_child0(Sxpr obj, Sxpr def);
  66.358 +Sxpr sxpr_child_value(Sxpr obj, Sxpr name, Sxpr def);
  66.359 +
  66.360 +/** Create a new atom.
  66.361 + *
  66.362 + * @param s atom name
  66.363 + * @return new atom
  66.364 + */
  66.365 +static inline Sxpr mkatom(char *s){
  66.366 +    return atom_new(s);
  66.367 +}
  66.368 +
  66.369 +/** Create a new string sxpr.
  66.370 + *
  66.371 + * @param s string bytes (copied)
  66.372 + * @return new string
  66.373 + */
  66.374 +static inline Sxpr mkstring(char *s){
  66.375 +    return string_new(s);
  66.376 +}
  66.377 +
  66.378 +/** Create an integer sxpr.
  66.379 + *
  66.380 + * @param i value
  66.381 + * @return sxpr
  66.382 + */
  66.383 +static inline Sxpr mkint(int i){
  66.384 +    return OBJI(T_UINT, i);
  66.385 +}
  66.386 +
  66.387 +/** Create a boolean sxpr.
  66.388 + *
  66.389 + * @param b value
  66.390 + * @return sxpr
  66.391 + */
  66.392 +static inline Sxpr mkbool(int b){
  66.393 +    return OBJI(T_BOOL, (b ? 1 : 0));
  66.394 +}
  66.395 +
  66.396 +/* Constants used in parsing and printing. */
  66.397 +#define k_list_open    "("
  66.398 +#define c_list_open    '('
  66.399 +#define k_list_close   ")"
  66.400 +#define c_list_close   ')'
  66.401 +#define k_true         "true"
  66.402 +#define k_false        "false"
  66.403 +
  66.404 +#define c_var          '$'
  66.405 +#define c_escape       '\\'
  66.406 +#define c_single_quote '\''
  66.407 +#define c_double_quote '"'
  66.408 +#define c_string_open  c_double_quote
  66.409 +#define c_string_close c_double_quote
  66.410 +#define c_data_open    '['
  66.411 +#define c_data_close   ']'
  66.412 +#define c_binary       '*'
  66.413 +#define c_eval         '!'
  66.414 +#define c_concat_open  '{'
  66.415 +#define c_concat_close '}'
  66.416 +
  66.417 +#endif /* ! _XUTIL_SXPR_H_ */
    67.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    67.2 +++ b/tools/xfrd/xdr.c	Tue Jul 06 20:42:26 2004 +0000
    67.3 @@ -0,0 +1,316 @@
    67.4 +#include <errno.h>
    67.5 +#include "xdr.h"
    67.6 +
    67.7 +#define MODULE_NAME "XDR"
    67.8 +//#define DEBUG 1
    67.9 +#undef DEBUG
   67.10 +#include "debug.h"
   67.11 +
   67.12 +/** @file
   67.13 + * XDR packer/unpacker for elements.
   67.14 + *
   67.15 + * string -> [T_STRING] [len:u16] <len bytes>
   67.16 + * atom   -> [T_ATOM]   [len:u16] <len bytes>
   67.17 + * uint   -> [T_UINT]   [value]
   67.18 + * cons   -> [T_LIST]   {1 elt}* 0
   67.19 + * null   -> [T_NULL]
   67.20 + * none   -> [T_NONE]
   67.21 + * bool   -> [T_BOOL]   { 0:u8 | 1:u8 }
   67.22 + *
   67.23 + * types packed as u16.
   67.24 + *
   67.25 + * So (a b c) -> [T_CONS] a [T_CONS] b [T_CONS] c [T_NULL]
   67.26 + *    ()      -> [T_NULL]
   67.27 + */
   67.28 +
   67.29 +int pack_bool(IOStream *io, int x){
   67.30 +    int err=0;
   67.31 +    //dprintf("> x=%d\n", x);
   67.32 +    err = IOStream_print(io, "%c", 0xff & x);
   67.33 +    if(err > 0) err = 0;
   67.34 +    //dprintf("< err=%d\n", err);
   67.35 +    return err;
   67.36 +}
   67.37 +
   67.38 +int unpack_bool(IOStream *io, int *x){
   67.39 +    int err = 0;
   67.40 +    int c;
   67.41 +    //dprintf(">\n");
   67.42 +    c = IOStream_getc(io);
   67.43 +    *x = (c < 0 ? 0 : c);
   67.44 +    err = IOStream_error(io);
   67.45 +    if(c < 0 && !err) err = -EIO;
   67.46 +    //dprintf("< err=%d x=%d\n", err, *x);
   67.47 +    return err;
   67.48 +}
   67.49 +
   67.50 +int pack_ushort(IOStream *io, unsigned short x){
   67.51 +    int err=0;
   67.52 +    //dprintf("> x=%u\n", x);
   67.53 +    err = IOStream_print(io, "%c%c",
   67.54 +                         0xff & (x >>  8),
   67.55 +                         0xff & (x      ));
   67.56 +    if(err > 0) err = 0;
   67.57 +    //dprintf("< err=%d\n", err);
   67.58 +    return err;
   67.59 +}
   67.60 +
   67.61 +int unpack_ushort(IOStream *io, unsigned short *x){
   67.62 +    int err = 0;
   67.63 +    int i, c = 0;
   67.64 +    //dprintf(">\n");
   67.65 +    *x = 0;
   67.66 +    for(i = 0; i< 2; i++){
   67.67 +        c = IOStream_getc(io);
   67.68 +        if(c < 0) break;
   67.69 +        *x <<= 8;
   67.70 +        *x |= (0xff & c);
   67.71 +    }
   67.72 +    err = IOStream_error(io);
   67.73 +
   67.74 +    if(c < 0 && !err) err = -EIO;
   67.75 +    //dprintf("< err=%d x=%u\n", err, *x);
   67.76 +    return err;
   67.77 +}
   67.78 +
   67.79 +int pack_type(IOStream *io, unsigned short x){
   67.80 +    return pack_ushort(io, x);
   67.81 +}
   67.82 +
   67.83 +int unpack_type(IOStream *io, unsigned short *x){
   67.84 +    return unpack_ushort(io, x);
   67.85 +}
   67.86 +
   67.87 +int pack_uint(IOStream *io, unsigned int x){
   67.88 +    int err=0;
   67.89 +    //dprintf("> x=%u\n", x);
   67.90 +    err = IOStream_print(io, "%c%c%c%c",
   67.91 +                         0xff & (x >> 24),
   67.92 +                         0xff & (x >> 16),
   67.93 +                         0xff & (x >>  8),
   67.94 +                         0xff & (x      ));
   67.95 +    if(err > 0) err = 0;
   67.96 +    //dprintf("< err=%d\n", err);
   67.97 +    return err;
   67.98 +}
   67.99 +
  67.100 +int unpack_uint(IOStream *io, unsigned int *x){
  67.101 +    int err = 0;
  67.102 +    int i, c = 0;
  67.103 +    //dprintf(">\n");
  67.104 +    *x = 0;
  67.105 +    for(i = 0; i< 4; i++){
  67.106 +        c = IOStream_getc(io);
  67.107 +        if(c < 0) break;
  67.108 +        *x <<= 8;
  67.109 +        *x |= (0xff & c);
  67.110 +    }
  67.111 +    err = IOStream_error(io);
  67.112 +    if(c < 0 && !err) err = -EIO;
  67.113 +    //dprintf("< err=%d x=%u\n", err, *x);
  67.114 +    return err;
  67.115 +}
  67.116 +
  67.117 +int pack_string(IOStream *io, Sxpr x){
  67.118 +    int err = 0;
  67.119 +    unsigned short n = 0xffff & string_length(x);
  67.120 +    char *s = string_string(x);
  67.121 +    int i;
  67.122 +    //dprintf("> n=%d s=%s\n", n, s);
  67.123 +    err = pack_ushort(io, n);
  67.124 +    if(err) goto exit;
  67.125 +    for(i = 0; i < n; i++){
  67.126 +        err = IOStream_print(io, "%c", s[i]);
  67.127 +        if(err < 0) break;
  67.128 +    }
  67.129 +    if(err > 0) err = 0;
  67.130 +  exit:
  67.131 +    //dprintf("< err=%d\n", err);
  67.132 +    return err;
  67.133 +}
  67.134 +
  67.135 +int unpack_string(IOStream *io, Sxpr *x){
  67.136 +    int err;
  67.137 +    unsigned short n;
  67.138 +    int i, c = 0;
  67.139 +    char *s;
  67.140 +    Sxpr val = ONONE;
  67.141 +    
  67.142 +    //dprintf(">\n");
  67.143 +    err = unpack_ushort(io, &n);
  67.144 +    if(err) goto exit;
  67.145 +    val = halloc(n+1, T_STRING);
  67.146 +    if(NOMEMP(val)){
  67.147 +        err = -ENOMEM;
  67.148 +        goto exit;
  67.149 +    }
  67.150 +    s = string_string(val);
  67.151 +    for(i=0; i<n; i++){
  67.152 +        c = IOStream_getc(io);
  67.153 +        if(c < 0) break;
  67.154 +        s[i] = (char)c;
  67.155 +    }
  67.156 +    s[n] = '\0';
  67.157 +  exit:
  67.158 +    err = IOStream_error(io);
  67.159 +    if(c < 0 && !err) err = -EIO;
  67.160 +    if(err){
  67.161 +        objfree(val);
  67.162 +        val = ONONE;
  67.163 +    }
  67.164 +    *x = val;
  67.165 +    //IOStream_print(iostdout, "n=%d str=", n); 
  67.166 +    //objprint(iostdout, *x, 0);
  67.167 +    //IOStream_print(iostdout, "\n");
  67.168 +    //dprintf("< err=%d\n", err);
  67.169 +    return err;
  67.170 +}
  67.171 +
  67.172 +int pack_cons(IOStream *io, Sxpr x){
  67.173 +    int err = 0;
  67.174 +    Sxpr l;
  67.175 +    //dprintf(">\n");
  67.176 +    for(l = x; CONSP(l); l = CDR(l)){
  67.177 +        err = pack_bool(io, 1);
  67.178 +        if(err) goto exit;
  67.179 +        err = pack_sxpr(io, CAR(l));
  67.180 +        if(err) goto exit;
  67.181 +    }
  67.182 +    err = pack_bool(io, 0);
  67.183 +  exit:
  67.184 +    //dprintf("< err=%d\n", err);
  67.185 +    return err;
  67.186 +}
  67.187 +
  67.188 +int unpack_cons(IOStream *io, Sxpr *x){
  67.189 +    int err = 0;
  67.190 +    int more = 0;
  67.191 +    Sxpr u = ONONE, v = ONONE, val = ONULL;
  67.192 +
  67.193 +    dprintf(">\n");
  67.194 +    while(1){
  67.195 +        err = unpack_bool(io, &more);
  67.196 +        if(err) goto exit;
  67.197 +        if(!more){
  67.198 +            //IOStream_print(iostdout, "unpack_cons 1 val=");
  67.199 +            ////objprint(iostdout, val, 0);
  67.200 +            IOStream_print(iostdout, "\n");
  67.201 +
  67.202 +            val = nrev(val);
  67.203 +
  67.204 +            //IOStream_print(iostdout, "unpack_cons 2 val=");
  67.205 +            //objprint(iostdout, val, 0);
  67.206 +            //IOStream_print(iostdout, "\n");
  67.207 +
  67.208 +            break;
  67.209 +        }
  67.210 +        err = unpack_sxpr(io, &u);
  67.211 +        if(err) goto exit;
  67.212 +        v = cons_new(u, val);
  67.213 +        if(NOMEMP(v)){
  67.214 +            err = -ENOMEM;
  67.215 +            objfree(u);
  67.216 +            goto exit;
  67.217 +        }
  67.218 +        val = v;
  67.219 +    }
  67.220 +  exit:
  67.221 +    if(err){
  67.222 +        objfree(val);
  67.223 +        val = ONONE;
  67.224 +    }
  67.225 +    *x = val;
  67.226 +    dprintf("< err=%d\n", err);
  67.227 +    return err;
  67.228 +}
  67.229 +    
  67.230 +int pack_sxpr(IOStream *io, Sxpr x){
  67.231 +    int err = 0;
  67.232 +    unsigned short type = get_type(x);
  67.233 +    //dprintf(">\n");
  67.234 +    //objprint(iostdout, x, 0);
  67.235 +    //IOStream_print(iostdout, "\n");
  67.236 +
  67.237 +    err = pack_type(io, type);
  67.238 +    if(err) goto exit;
  67.239 +    switch(type){
  67.240 +    case T_NULL:
  67.241 +        break;
  67.242 +    case T_NONE:
  67.243 +        break;
  67.244 +    case T_BOOL:
  67.245 +        err = pack_bool(io, get_ul(x));
  67.246 +        break;
  67.247 +    case T_CONS:
  67.248 +        err = pack_cons(io, x);
  67.249 +        break;
  67.250 +    case T_ATOM:
  67.251 +        err = pack_string(io, OBJ_ATOM(x)->name);
  67.252 +        break;
  67.253 +    case T_STRING:
  67.254 +        err = pack_string(io, x);
  67.255 +        break;
  67.256 +    case T_UINT:
  67.257 +        err = pack_uint(io, get_ul(x));
  67.258 +        break;
  67.259 +    default:
  67.260 +        err = -EINVAL;
  67.261 +        IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
  67.262 +        break;
  67.263 +    }
  67.264 +  exit:
  67.265 +    //dprintf("< err=%d\n", err);
  67.266 +    return err;
  67.267 +}
  67.268 +
  67.269 +int unpack_sxpr(IOStream *io, Sxpr *x){
  67.270 +    int err = 0;
  67.271 +    unsigned short type;
  67.272 +    unsigned int u;
  67.273 +    Sxpr val = ONONE, y;
  67.274 +
  67.275 +    //dprintf(">\n");
  67.276 +    err = unpack_type(io, &type);
  67.277 +    if(err) goto exit;
  67.278 +    switch(type){
  67.279 +    case T_NULL:
  67.280 +        val = ONULL;
  67.281 +        break;
  67.282 +    case T_NONE:
  67.283 +        val = ONONE;
  67.284 +        break;
  67.285 +    case T_CONS:
  67.286 +        err = unpack_cons(io, &val);
  67.287 +        break;
  67.288 +    case T_BOOL:
  67.289 +        err = unpack_bool(io, &u);
  67.290 +        if(err) goto exit;
  67.291 +        val = (u ? OTRUE : OFALSE);
  67.292 +        break;
  67.293 +    case T_ATOM:
  67.294 +        err = unpack_string(io, &y);
  67.295 +        if(err) goto exit;
  67.296 +        val = intern(string_string(y));
  67.297 +        objfree(y);
  67.298 +        break;
  67.299 +    case T_STRING:
  67.300 +        err = unpack_string(io, &val);
  67.301 +        break;
  67.302 +    case T_UINT:
  67.303 +        err = unpack_uint(io, &u);
  67.304 +        if(err) goto exit;
  67.305 +        val = OBJI(type, u);
  67.306 +        break;
  67.307 +    default:
  67.308 +        err = -EINVAL;
  67.309 +        IOStream_print(iostderr, "%s> invalid type %d\n", __FUNCTION__, type);
  67.310 +        break;
  67.311 +    }
  67.312 +  exit:
  67.313 +    *x = (err ? ONONE : val);
  67.314 +    //IOStream_print(iostdout, "sxpr="); 
  67.315 +    //objprint(iostdout, *x, 0);
  67.316 +    //IOStream_print(iostdout, "\n");
  67.317 +    //dprintf("< err=%d\n", err);
  67.318 +    return err;
  67.319 +}
    68.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    68.2 +++ b/tools/xfrd/xdr.h	Tue Jul 06 20:42:26 2004 +0000
    68.3 @@ -0,0 +1,30 @@
    68.4 +#ifndef _XUTIL_XDR_H_
    68.5 +#define _XUTIL_XDR_H_
    68.6 +#include "iostream.h"
    68.7 +#include "sxpr.h"
    68.8 +
    68.9 +int pack_type(IOStream *io, unsigned short x);
   68.10 +
   68.11 +int unpack_type(IOStream *io, unsigned short *x);
   68.12 +
   68.13 +int pack_bool(IOStream *io, int x);
   68.14 +
   68.15 +int unpack_bool(IOStream *io, int *x);
   68.16 +
   68.17 +int pack_uint(IOStream *out, unsigned int x);
   68.18 +
   68.19 +int unpack_uint(IOStream *in, unsigned int *x);
   68.20 +
   68.21 +int pack_string(IOStream *out, Sxpr x);
   68.22 +
   68.23 +int unpack_string(IOStream *in, Sxpr *x);
   68.24 +
   68.25 +int pack_cons(IOStream *out, Sxpr x);
   68.26 +
   68.27 +int unpack_cons(IOStream *in, Sxpr *x);
   68.28 +
   68.29 +int pack_sxpr(IOStream *out, Sxpr x);
   68.30 +
   68.31 +int unpack_sxpr(IOStream *in, Sxpr *x);
   68.32 +
   68.33 +#endif /* _XUTIL_XDR_H_ */
    69.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    69.2 +++ b/tools/xfrd/xen_domain.c	Tue Jul 06 20:42:26 2004 +0000
    69.3 @@ -0,0 +1,90 @@
    69.4 +#include <unistd.h>
    69.5 +#include <stdlib.h>
    69.6 +#include <stdio.h>
    69.7 +
    69.8 +#ifndef _XEN_XFR_STUB_
    69.9 +#include "dom0_defs.h"
   69.10 +#include "mem_defs.h"
   69.11 +#endif
   69.12 +
   69.13 +#include "xen_domain.h"
   69.14 +#include "marshal.h"
   69.15 +#include "xdr.h"
   69.16 +
   69.17 +#define MODULE_NAME "XFRD"
   69.18 +#define DEBUG 1
   69.19 +#include "debug.h"
   69.20 +
   69.21 +/** Write domain state.
   69.22 + *
   69.23 + * At some point during this the domain is suspended, and then there's no way back.
   69.24 + * Even if something later goes wrong we can't restart the domain.
   69.25 + */
   69.26 +int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n){
   69.27 +    int err = 0;
   69.28 +    char buf[1024];
   69.29 +    int n, k, d, buf_n;
   69.30 +    dprintf("> dom=%d\n", dom);
   69.31 +#ifdef _XEN_XFR_STUB_
   69.32 +    err = marshal_uint32(io, dom);
   69.33 +    if(err) goto exit;
   69.34 +    err = marshal_string(io, vmconfig, vmconfig_n);
   69.35 +    if(err) goto exit;
   69.36 +    n = 32 * 1024 * 1024;
   69.37 +    buf_n = sizeof(buf);
   69.38 +    err = marshal_uint32(io, n);
   69.39 +    for(k = 0; k < n; k += d){
   69.40 +        d = n - k;
   69.41 +        if(d > buf_n) d = buf_n;
   69.42 +        err = marshal_bytes(io, buf, d);
   69.43 +        if(err) goto exit;
   69.44 +        //dprintf("> k=%d n=%d\n", k, n);
   69.45 +    }
   69.46 +    
   69.47 +  exit:
   69.48 +#else 
   69.49 +#endif   
   69.50 +    dprintf("< err=%d\n", err);
   69.51 +    return err;
   69.52 +}
   69.53 +
   69.54 +/** Receive domain state.
   69.55 + * Create a new domain and store the received state into it.
   69.56 + */
   69.57 +int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n){
   69.58 +    int err = 0;
   69.59 +    char buf[1024];
   69.60 +    int n, k, d, buf_n;
   69.61 +    dprintf(">\n");
   69.62 +#ifdef _XEN_XFR_STUB_
   69.63 +    err = unmarshal_uint32(io, dom);
   69.64 +    if(err) goto exit;
   69.65 +    err = unmarshal_new_string(io, vmconfig, vmconfig_n);
   69.66 +    if(err) goto exit;
   69.67 +    err = unmarshal_uint32(io, &n);
   69.68 +    buf_n = sizeof(buf);
   69.69 +    for(k = 0; k < n; k += d){
   69.70 +        d = n - k;
   69.71 +        if(d > buf_n) d = buf_n;
   69.72 +        err = unmarshal_bytes(io, buf, d);
   69.73 +        if(err) goto exit;
   69.74 +        //dprintf("> k=%d n=%d\n", k, n);
   69.75 +    }
   69.76 +  exit:
   69.77 +#else    
   69.78 +#endif   
   69.79 +    dprintf("< err=%d\n", err);
   69.80 +    return err;
   69.81 +}
   69.82 +
   69.83 +/** Configure a new domain. Talk to xend. Use libcurl?
   69.84 + */
   69.85 +int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n){
   69.86 +    int err = 0;
   69.87 +    dprintf(">\n");
   69.88 +#ifdef _XEN_XFR_STUB_
   69.89 +#else    
   69.90 +#endif   
   69.91 +    dprintf("< err=%d\n", err);
   69.92 +    return err;
   69.93 +}
    70.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    70.2 +++ b/tools/xfrd/xen_domain.h	Tue Jul 06 20:42:26 2004 +0000
    70.3 @@ -0,0 +1,15 @@
    70.4 +#ifndef _XFRD_XEN_DOMAIN_H_
    70.5 +#define _XFRD_XEN_DOMAIN_H_
    70.6 +#include <sys/types.h>
    70.7 +#include <iostream.h>
    70.8 +#include "connection.h"
    70.9 +
   70.10 +/** Define to use stubs. Undefine to use Xen ops. */
   70.11 +//#define _XEN_XFR_STUB_
   70.12 +
   70.13 +extern int xen_domain_snd(Conn *xend, IOStream *io, uint32_t dom, char *vmconfig, int vmconfig_n);
   70.14 +extern int xen_domain_rcv(IOStream *io, uint32_t *dom, char **vmconfig, int *vmconfig_n);
   70.15 +
   70.16 +
   70.17 +extern int xen_domain_configure(uint32_t dom, char *vmconfig, int vmconfig_n);
   70.18 +#endif
    71.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    71.2 +++ b/tools/xfrd/xfrd.c	Tue Jul 06 20:42:26 2004 +0000
    71.3 @@ -0,0 +1,1127 @@
    71.4 +/** @file
    71.5 + * XFRD - Domain Transfer Daemon for Xen.
    71.6 + *
    71.7 + * The xfrd is forked by xend to transfer a vm to a remote system.
    71.8 + *
    71.9 + * The vm is suspended, then its state and memory are transferred to the remote system.
   71.10 + * The remote system attempts to create a vm and copy the transferred state and memory into it,
   71.11 + * finally resuming the vm. If all is OK the vm ends up running on the remote
   71.12 + * system and is removed from the originating system. If the transfer does not complete
   71.13 + * successfully the originating system attempts to resume the vm.
   71.14 + * The children exit when the transfer completes.
   71.15 + *
   71.16 + * @author Mike Wray <mike.wray@hpl.hp.com>
   71.17 + */
   71.18 +
   71.19 +#include <stdlib.h>
   71.20 +#include <unistd.h>
   71.21 +#include <stdio.h>
   71.22 +#include <getopt.h>
   71.23 +#include <errno.h>
   71.24 +#include <sys/types.h>
   71.25 +#include <time.h>
   71.26 +#include <sys/socket.h>
   71.27 +#include <netinet/in.h>
   71.28 +#include <arpa/inet.h>
   71.29 +#include <string.h>
   71.30 +
   71.31 +#include <signal.h>
   71.32 +#include <sys/wait.h>
   71.33 +#include <sys/select.h>
   71.34 +
   71.35 +#include "allocate.h"
   71.36 +#include "file_stream.h"
   71.37 +#include "string_stream.h"
   71.38 +#include "lzi_stream.h"
   71.39 +#include "sys_net.h"
   71.40 +#include "sys_string.h"
   71.41 +
   71.42 +#include "xdr.h"
   71.43 +#include "enum.h"
   71.44 +#include "xfrd.h"
   71.45 +
   71.46 +#include "xen_domain.h"
   71.47 +
   71.48 +#include "connection.h"
   71.49 +#include "select.h"
   71.50 +
   71.51 +#define MODULE_NAME "XFRD"
   71.52 +#define DEBUG 1
   71.53 +#include "debug.h"
   71.54 +
   71.55 +/*
   71.56 +sender:
   71.57 +        xend connects to xfrd and writes migrate message
   71.58 +        xend writes domain config to xfrd
   71.59 +
   71.60 +        xfrd forks
   71.61 +
   71.62 +        xfrd connects to peer
   71.63 +        xfrd sends hello, reads response
   71.64 +        xfrd sends domain
   71.65 +        xfrd reads response
   71.66 +        reports progress/status to xend
   71.67 +
   71.68 +        xend reads xfrd for progress/status, disconnects
   71.69 +        If ok, destroys domain.
   71.70 +        If not ok, unpauses domain.
   71.71 +
   71.72 +receiver:
   71.73 +        xfrd accepts connection on inbound port
   71.74 +        xfrd forks and accepts connection
   71.75 +        xfrd receives hello, writes response
   71.76 +        xfrd receives domain
   71.77 +        xfrd connects to xend, configures new domain
   71.78 +        xfrd writes status back to peer, child exits
   71.79 +
   71.80 +
   71.81 +        (xfr.hello <major> <minor>)
   71.82 +        (xfr.err <code> <reason>)
   71.83 +
   71.84 +        xend->xfrd (xfr.migrate  <domain> <vmconfig> <host> <port>)
   71.85 +                   (xfr.save <domain> <vmconfig> <file>)
   71.86 +        xfrd->xend (xfr.suspend <domain>)
   71.87 +        xfrd->xend (xfr.progress <percent> <rate: kb/s>)
   71.88 +        xfrd->xend (xfr.err <code> <reason>) | (xfr.ok <domain>)
   71.89 +        xfrd->xfrd (xfr.xfr <domain>)
   71.90 +        xfrd->xfrd (xfr.err <code>) | (xfr.ok <domain>)
   71.91 +
   71.92 +        xfrd->xend (xfr.configure <domain> <vmconfig>)
   71.93 + */
   71.94 +
   71.95 +Sxpr oxfr_configure; // (xfr.configure <vmid> <vmconfig>)
   71.96 +Sxpr oxfr_err;       // (xfr.err <code>)
   71.97 +Sxpr oxfr_hello;     // (xfr.hello <major> <minor>)
   71.98 +Sxpr oxfr_migrate;   // (xfr.migrate <vmid> <vmconfig> <host> <port>)
   71.99 +Sxpr oxfr_ok;        // (xfr.ok <value>)
  71.100 +Sxpr oxfr_progress;  // (xfr.progress <percent> <rate: kb/s>)
  71.101 +Sxpr oxfr_save;      // (xfr.save <vmid> <vmconfig> <file>)
  71.102 +Sxpr oxfr_suspend;   // (xfr.suspend <vmid>)
  71.103 +Sxpr oxfr_xfr;       // (xfr.xfr <vmid>)
  71.104 +
  71.105 +void xfr_init(void){
  71.106 +    oxfr_configure = intern("xfr.configure");
  71.107 +    oxfr_err       = intern("xfr.err");
  71.108 +    oxfr_hello     = intern("xfr.hello");
  71.109 +    oxfr_migrate   = intern("xfr.migrate");
  71.110 +    oxfr_ok        = intern("xfr.ok");
  71.111 +    oxfr_progress  = intern("xfr.progress");
  71.112 +    oxfr_save      = intern("xfr.save");
  71.113 +    oxfr_suspend   = intern("xfr.suspend");
  71.114 +    oxfr_xfr       = intern("xfr.xfr");
  71.115 +}
  71.116 +
  71.117 +#ifndef TRUE
  71.118 +#define TRUE 1
  71.119 +#endif
  71.120 +
  71.121 +#ifndef FALSE
  71.122 +#define FALSE 0
  71.123 +#endif
  71.124 +
  71.125 +#define PROGRAM      "xfrd"
  71.126 +
  71.127 +#define OPT_PORT     'P'
  71.128 +#define KEY_PORT     "port"
  71.129 +#define DOC_PORT     "<port>\n\txfr port (as a number or service name)"
  71.130 +
  71.131 +#define OPT_COMPRESS 'Z'
  71.132 +#define KEY_COMPRESS "compress"
  71.133 +#define DOC_COMPRESS "\n\tuse compression for migration"
  71.134 +
  71.135 +#define OPT_HELP     'h'
  71.136 +#define KEY_HELP     "help"
  71.137 +#define DOC_HELP     "\n\tprint help"
  71.138 +
  71.139 +#define OPT_VERSION  'v'
  71.140 +#define KEY_VERSION  "version"
  71.141 +#define DOC_VERSION  "\n\tprint version"
  71.142 +
  71.143 +#define OPT_VERBOSE  'V'
  71.144 +#define KEY_VERBOSE  "verbose"
  71.145 +#define DOC_VERBOSE  "\n\tverbose flag"
  71.146 +
  71.147 +/** Print a usage message.
  71.148 + * Prints to stdout if err is zero, and exits with 0.
  71.149 + * Prints to stderr if err is non-zero, and exits with 1.
  71.150 + */
  71.151 +void usage(int err){
  71.152 +    FILE *out = (err ? stderr : stdout);
  71.153 +
  71.154 +    fprintf(out, "Usage: %s [options]\n", PROGRAM);
  71.155 +    fprintf(out, "-%c, --%s %s\n", OPT_PORT,     KEY_PORT,     DOC_PORT);
  71.156 +    fprintf(out, "-%c, --%s %s\n", OPT_COMPRESS, KEY_COMPRESS, DOC_COMPRESS);
  71.157 +    fprintf(out, "-%c, --%s %s\n", OPT_VERBOSE,  KEY_VERBOSE,  DOC_VERBOSE);
  71.158 +    fprintf(out, "-%c, --%s %s\n", OPT_VERSION,  KEY_VERSION,  DOC_VERSION);
  71.159 +    fprintf(out, "-%c, --%s %s\n", OPT_HELP,     KEY_HELP,     DOC_HELP);
  71.160 +    exit(err ? 1 : 0);
  71.161 +}
  71.162 +
  71.163 +/** Short options. Options followed by ':' take an argument. */
  71.164 +static char *short_opts = (char[]){
  71.165 +    OPT_PORT,     ':',
  71.166 +    OPT_COMPRESS,
  71.167 +    OPT_HELP,
  71.168 +    OPT_VERSION,
  71.169 +    OPT_VERBOSE,
  71.170 +    0 };
  71.171 +
  71.172 +/** Long options. */
  71.173 +static struct option const long_opts[] = {
  71.174 +    { KEY_PORT,     required_argument, NULL, OPT_PORT     },
  71.175 +    { KEY_COMPRESS, no_argument,       NULL, OPT_COMPRESS },
  71.176 +    { KEY_HELP,     no_argument,       NULL, OPT_HELP     },
  71.177 +    { KEY_VERSION,  no_argument,       NULL, OPT_VERSION  },
  71.178 +    { KEY_VERBOSE,  no_argument,       NULL, OPT_VERBOSE  },
  71.179 +    { NULL,         0,                 NULL, 0            }
  71.180 +};
  71.181 +
  71.182 +typedef struct Args {
  71.183 +    int bufsize;
  71.184 +    unsigned long port;
  71.185 +    int verbose;
  71.186 +    int compress;
  71.187 +} Args;
  71.188 +
  71.189 +/** Transfer states. */
  71.190 +enum {
  71.191 +    XFR_INIT,
  71.192 +    XFR_HELLO,
  71.193 +    XFR_STATE,
  71.194 +    XFR_RUN,
  71.195 +    XFR_FAIL,
  71.196 +    XFR_DONE,
  71.197 +    XFR_MAX
  71.198 +};
  71.199 +
  71.200 +/** Initialize an array element for a constant to its string name. */
  71.201 +#define VALDEF(val) { val, #val }
  71.202 +
  71.203 +/** Names for the transfer states. */
  71.204 +static EnumDef xfr_states[] = {
  71.205 +    VALDEF(XFR_INIT),
  71.206 +    VALDEF(XFR_HELLO),
  71.207 +    VALDEF(XFR_STATE),
  71.208 +    VALDEF(XFR_RUN),
  71.209 +    VALDEF(XFR_FAIL),
  71.210 +    VALDEF(XFR_DONE),
  71.211 +    { 0, NULL }
  71.212 +};
  71.213 +    
  71.214 +
  71.215 +/** State machine for transfer. */
  71.216 +typedef struct XfrState {
  71.217 +    /** Current state. */
  71.218 +    int state;
  71.219 +    /** Error codes for the states. */
  71.220 +    int state_err[XFR_MAX];
  71.221 +    /** First error. */
  71.222 +    int err;
  71.223 +    /** State when first error happened. */
  71.224 +    int err_state;
  71.225 +
  71.226 +    uint32_t vmid;
  71.227 +    char* vmconfig;