SiteCast in mod_gridsite
authorAndrew McNab <andrew.mcnab@manchester.ac.uk>
Thu, 29 Sep 2005 19:34:30 +0000 (19:34 +0000)
committerAndrew McNab <andrew.mcnab@manchester.ac.uk>
Thu, 29 Sep 2005 19:34:30 +0000 (19:34 +0000)
org.gridsite.core/CHANGES
org.gridsite.core/VERSION
org.gridsite.core/doc/httpd-fileserver.conf
org.gridsite.core/doc/httpd-webserver.conf
org.gridsite.core/interface/gridsite.h
org.gridsite.core/project/version.properties
org.gridsite.core/src/Makefile
org.gridsite.core/src/grst_htcp.c [new file with mode: 0644]
org.gridsite.core/src/htcp
org.gridsite.core/src/mod_gridsite.c

index e68d642..beef484 100644 (file)
@@ -1,3 +1,11 @@
+* Thu Sep 29 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
+- Add SiteCast support to mod_gridsite (file location
+  discovery via UDP multicast of HTCP messages.)
+* Wed Sep 21 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
+- Add ports 777 and 488 to example httpd.conf files in
+  docs. See http://www.gridsite.org/wiki/IP_Ports
+* Tue Sep 13 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
+- ==== GridSite version 1.1.12 ====
 * Tue Sep 13 2005 Andrew McNab <Andrew.McNab@man.ac.uk>
 - Fix bug #10031 submitted by Fabrizio Pacini 
   <fabrizio.pacini@cern.ch> (invalid free in 
index 2e3c1a3..9429197 100644 (file)
@@ -1,4 +1,4 @@
 MAJOR_VERSION=1
 MINOR_VERSION=1.1
-PATCH_VERSION=1.1.11
+PATCH_VERSION=1.1.12
 VERSION=$(PATCH_VERSION)
index eddad08..a14a559 100644 (file)
@@ -1,10 +1,14 @@
 ##############################################################################
 ## GridSite httpd-fileserver.conf - Andrew McNab <Andrew.McNab@man.ac.uk>
 ##
-## Example configuration file for GridSite as an HTTP(S) fileserver.
-##
 ## For GridSite documentation, see http://www.gridsite.org/
 ##
+## Example configuration file for GridSite as an HTTP(S) fileserver,
+## listening on ports 80/777 (HTTP) and 443/488 (HTTPS) 
+##
+## (777/488 is to allow firewalls to distinguish between Grid and 
+## Web HTTP(S) traffic. See http://www.gridsite.org/wiki/IP_Ports )
+##
 ## This file should be renamed /etc/httpd/conf/httpd.conf and Apache
 ## restarted to use Apache2/GridSite as a simple HTTP(S) fileserver. 
 ##
@@ -67,6 +71,7 @@
 ##
 ## (or with  --cert /tmp/x509up_u`id -u` --key /tmp/x509up_u`id -u`  to use
 ##  a Globus GSI Proxy created with grid-proxy-init.)
+##
 ##############################################################################
 
 ServerRoot "/etc/httpd"
@@ -105,11 +110,12 @@ ErrorLog  logs/httpd-gridsite-errors
 HostnameLookups On
 
 ######################################################################
-# Plain unauthenticated HTTP on port 80
+# Plain unauthenticated HTTP on ports 80 and 777
 ######################################################################
 
 Listen 80
-<VirtualHost *:80>
+Listen 777
+<VirtualHost *:80 *:777>
 
 <Directory "/var/www/htdocs">
  GridSiteIndexes       on
@@ -120,13 +126,14 @@ Listen 80
 </VirtualHost>
 
 ######################################################################
-# Secured and possibly authenticated HTTPS on port 443
+# Secured and possibly authenticated HTTPS on ports 443 and 488
 ######################################################################
 Listen 443
+Listen 488
 SSLSessionCacheTimeout  300
 SSLSessionCache         dbm:/var/cache/mod_ssl/scache
 # This version of GridSite is NOT compatible with the SHM SSL cache!!!
-<VirtualHost *:443>
+<VirtualHost *:443 *:488>
  
 SSLEngine               on
 SSLCertificateFile      /etc/grid-security/hostcert.pem
index 57adb5d..59b7487 100644 (file)
@@ -1,10 +1,14 @@
 ##############################################################################
 ## GridSite httpd-webserver.conf - Andrew McNab <Andrew.McNab@man.ac.uk>
 ##
+## For GridSite documentation, see http://www.gridsite.org/
+##
 ## Example configuration file for GridSite as a Web Server 
 ## (that is, primarily for interactive use with a browser.)
+## Listening is on ports 80/777 (HTTP) and 443/488 (HTTPS).
 ##
-## For GridSite documentation, see http://www.gridsite.org/
+## (777/488 is to allow firewalls to distinguish between Grid and
+## Web HTTP(S) traffic. See http://www.gridsite.org/wiki/IP_Ports )
 ##
 ## This file should be renamed /etc/httpd/conf/httpd.conf and Apache
 ## restarted to use Apache2/GridSite as a webserver. 
@@ -113,11 +117,12 @@ ErrorLog  logs/httpd-gridsite-errors
 HostnameLookups On
 
 ######################################################################
-# Plain unauthenticated HTTP on port 80
+# Plain unauthenticated HTTP on ports 80 and 777
 ######################################################################
 
 Listen 80
-<VirtualHost *:80>
+Listen 777
+<VirtualHost *:80 *:777>
 
 ## This is used to serve the Manage Directory links in footers,
 ## and to allow you to edit files and ACLs via your browser.
@@ -150,13 +155,14 @@ ScriptAlias /real-gridsite-admin.cgi /usr/sbin/real-gridsite-admin.cgi
 </VirtualHost>
 
 ######################################################################
-# Secured and possibly authenticated HTTPS on port 443
+# Secured and possibly authenticated HTTPS on ports 443 and 488
 ######################################################################
 Listen 443
+Listen 488
 SSLSessionCacheTimeout  300
 SSLSessionCache         dbm:/var/cache/mod_ssl/scache
 # This version of GridSite is NOT compatible with the SHM SSL cache!!!
-<VirtualHost *:443>
+<VirtualHost *:443 *:488>
  
 SSLEngine               on
 SSLCertificateFile      /etc/grid-security/hostcert.pem
index e252019..9e6b302 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2002-3, Andrew McNab, University of Manchester
+   Copyright (c) 2002-5, Andrew McNab, University of Manchester
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or
@@ -124,6 +124,39 @@ struct GRSTasn1TagList { char treecoords[GRST_ASN1_MAXCOORDLEN+1];
                          int  length;
                          int  tag; } ;
 
+#define GRST_HTTP_PORT         777
+#define GRST_HTTPS_PORT                488
+#define GRST_HTCP_PORT         777
+                         
+#define GRSThtcpNOPop 0
+#define GRSThtcpTSTop 1
+
+typedef struct { unsigned char length_msb;
+                 unsigned char length_lsb;
+                 char text[1]; } GRSThtcpCountstr;
+
+#define GRSThtcpCountstrLen(string) (256*((string)->length_msb) + (string)->length_lsb)
+
+typedef struct { unsigned char total_length_msb;
+                 unsigned char total_length_lsb;
+                 unsigned char version_msb;
+                 unsigned char version_lsb;
+                 unsigned char data_length_msb;
+                 unsigned char data_length_lsb;
+                 unsigned int  response : 4;
+                 unsigned int  opcode   : 4;
+                 unsigned int  rr       : 1;                 
+                 unsigned int  f1       : 1;
+                 unsigned int  reserved : 6;
+                 unsigned int  trans_id;       /* must be 4 bytes */
+                 GRSThtcpCountstr *method;
+                 GRSThtcpCountstr *uri;
+                 GRSThtcpCountstr *version;
+                 GRSThtcpCountstr *req_hdrs;
+                 GRSThtcpCountstr *resp_hdrs;
+                 GRSThtcpCountstr *entity_hdrs;
+                 GRSThtcpCountstr *cache_hdrs;   } GRSThtcpMessage;
+
 int GRSTgaclInit(void);
 
 /* #define GACLnewCred(x)              GRSTgaclCredNew((x)) */
@@ -285,3 +318,9 @@ int    GRSTasn1ParseDump(BIO *, unsigned char *, long,
                          struct GRSTasn1TagList taglist[], int, int *);
 int    GRSTasn1GetX509Name(char *, int, char *, char *,
                            struct GRSTasn1TagList taglist[], int);
+
+int    GRSThtcpNOPrequestMake(char **, int *, unsigned int);
+int    GRSThtcpNOPresponseMake(char **, int *, unsigned int);
+int    GRSThtcpTSTrequestMake(char **, int *, unsigned int, char *, char *, char *);
+int    GRSThtcpTSTresponseMake(char **, int *, unsigned int, char *, char *, char *);
+int    GRSThtcpMessageParse(GRSThtcpMessage *, char *, int);
index 381def9..5eeac2e 100644 (file)
@@ -64,40 +64,44 @@ build: libgridsite_globus.so.$(VERSION) libgridsite_globus.a
 
 # First, normal versions using system OpenSSL rather than Globus OpenSSL
 
-libgridsite.so.$(VERSION): grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o
+libgridsite.so.$(VERSION): grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o grst_htcp.o
        gcc -shared -Wl,-soname,libgridsite.so.$(MINOR_VERSION) \
-         -o libgridsite.so.$(PATCH_VERSION) grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o
+         -o libgridsite.so.$(PATCH_VERSION) grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o grst_htcp.o
 
-libgridsite.a: grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o
-       ar src libgridsite.a grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o
+libgridsite.a: grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o grst_htcp.o
+       ar src libgridsite.a grst_x509.o grst_gacl.o grst_xacml.o grst_http.o grst_asn1.o grst_htcp.o
 
 grst_x509.o: grst_x509.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) \
+       gcc -g $(MYCFLAGS) \
             -I/usr/kerberos/include -c grst_x509.c
 
 grst_gacl.o: grst_gacl.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) \
+       gcc -g $(MYCFLAGS) \
             -I/usr/kerberos/include `xml2-config --cflags` -c grst_gacl.c
 
 grst_xacml.o: grst_xacml.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) \
+       gcc -g $(MYCFLAGS) \
             -I/usr/kerberos/include `xml2-config --cflags` -c grst_xacml.c
 
 grst_http.o: grst_http.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) \
+       gcc -g $(MYCFLAGS) \
                         -I/usr/kerberos/include -c grst_http.c
 
 grst_asn1.o: grst_asn1.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) \
+       gcc -g $(MYCFLAGS) \
             -I/usr/kerberos/include -c grst_asn1.c
 
+grst_htcp.o: grst_htcp.c ../interface/gridsite.h
+       gcc -g $(MYCFLAGS) \
+            -I/usr/kerberos/include -c grst_htcp.c
+
 # Then build versions using Globus OpenSSL if configured
 
 ifdef OPENSSL_GLOBUS_LIBS
 
 libgridsite_globus.so.$(VERSION): \
                grst_x509_globus.o grst_gacl_globus.o grst_http_globus.o \
-               grst_asn1_globus.o grst_xacml_globus.o
+               grst_asn1_globus.o grst_xacml_globus.o grst_htcp_globus.o
        gcc -shared -Wl,-soname,libgridsite_globus.so.$(MINOR_VERSION) \
          -o libgridsite_globus.so.$(PATCH_VERSION) \
          grst_x509_globus.o grst_gacl_globus.o grst_xacml_globus.o grst_http_globus.o grst_asn1_globus.o
@@ -107,30 +111,35 @@ libgridsite_globus.a: grst_x509_globus.o grst_gacl_globus.o grst_http_globus.o g
                grst_x509_globus.o grst_gacl_globus.o grst_http_globus.o grst_asn1_globus.o
 
 grst_x509_globus.o: grst_x509.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
             -I/usr/kerberos/include -c grst_x509.c \
             -o grst_x509_globus.o
 
 grst_gacl_globus.o: grst_gacl.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
             -I/usr/kerberos/include `xml2-config --cflags` -c grst_gacl.c \
             -o grst_gacl_globus.o
 
 grst_xacml_globus.o: grst_xacml.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
             -I/usr/kerberos/include `xml2-config --cflags` -c grst_xacml.c \
             -o grst_xacml_globus.o
 
 grst_http_globus.o: grst_http.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
             -I/usr/kerberos/include -c grst_http.c \
             -o grst_http_globus.o
 
 grst_asn1_globus.o: grst_asn1.c ../interface/gridsite.h
-       gcc $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
             -I/usr/kerberos/include -c grst_asn1.c \
             -o grst_asn1_globus.o
 
+grst_htcp_globus.o: grst_htcp.c ../interface/gridsite.h
+       gcc -g $(MYCFLAGS) $(OPENSSL_GLOBUS_FLAGS) \
+            -I/usr/kerberos/include -c grst_htcp.c \
+            -o grst_htcp_globus.o
+
 else
 
 libgridsite_globus.so.$(VERSION): libgridsite.so.$(VERSION)
@@ -142,21 +151,21 @@ libgridsite_globus.a: libgridsite.a
 endif
 
 gsexec:        gsexec.c gsexec.h
-       gcc -DVERSION=\"$(PATCH_VERSION)\" -I/usr/include/httpd \
+       gcc -g -DVERSION=\"$(PATCH_VERSION)\" -I/usr/include/httpd \
            -I/usr/include/apr-0 \
            -o gsexec gsexec.c
 
 urlencode: urlencode.c libgridsite.a
-       gcc -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
+       gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \
             -o urlencode urlencode.c -L. \
              -I/usr/kerberos/include -lgridsite
 
 htcp: htcp.c
-       gcc -DVERSION=\"$(PATCH_VERSION)\" -I. -o htcp htcp.c \
+       gcc -g -DVERSION=\"$(PATCH_VERSION)\" -I. -o htcp htcp.c \
           `curl-config --cflags` `curl-config --libs` 
 
 mod_gridsite.so: mod_gridsite.c mod_ssl-private.h libgridsite.a
-       gcc $(MYCFLAGS) -shared -Wl,-soname=gridsite_module \
+       gcc -g $(MYCFLAGS) -shared -Wl,-soname=gridsite_module \
            -I/usr/kerberos/include \
            -I/usr/include/libxml2 \
            -DVERSION=\"$(VERSION)\" -o mod_gridsite.so \
@@ -164,7 +173,7 @@ mod_gridsite.so: mod_gridsite.c mod_ssl-private.h libgridsite.a
 
 real-gridsite-admin.cgi: grst_admin_main.c grst_admin_gacl.c \
                          grst_admin_file.c grst_admin.h
-       gcc $(MYCFLAGS) $(MYLDFLAGS) -o real-gridsite-admin.cgi \
+       gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o real-gridsite-admin.cgi \
             grst_admin_main.c \
             grst_admin_gacl.c \
             grst_admin_file.c \
@@ -172,13 +181,13 @@ real-gridsite-admin.cgi: grst_admin_main.c grst_admin_gacl.c \
             -DVERSION=\"$(VERSION)\" -lgridsite -lssl -lcrypto -lxml2 -lz -lm
 
 findproxyfile: findproxyfile.c libgridsite.a
-       gcc -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
+       gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
             -o findproxyfile findproxyfile.c -L. \
             -I/usr/kerberos/include -lgridsite \
             -lssl -lcrypto -lxml2 -lz -lm
 
 showx509exts: showx509exts.c libgridsite.a
-       gcc -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
+       gcc -g -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \
             -o showx509exts showx509exts.c -L. \
             -I/usr/kerberos/include \
             -lgridsite \
@@ -188,12 +197,12 @@ apidoc:
        doxygen Doxyfile
 
 gaclexample: gaclexample.c libgridsite.a
-       gcc -o gaclexample gaclexample.c -I. -L. \
+       gcc -g -o gaclexample gaclexample.c -I. -L. \
             -I/usr/kerberos/include -lgridsite \
             -lssl -lcrypto -lxml2 -lz -lm
            
 xacmlexample: xacmlexample.c libgridsite.a
-       gcc -o xacmlexample xacmlexample.c -I. -L. \
+       gcc -g -o xacmlexample xacmlexample.c -I. -L. \
             -I/usr/kerberos/include -lgridsite \
             -lssl -lcrypto -lxml2 -lz -lm
 
@@ -212,12 +221,12 @@ delegation.wsdl: delegation.h
        $(GSOAPDIR)/bin/soapcpp2 -c delegation.h
 
 libstdsoap2.a: $(GSOAPDIR)/stdsoap2.c
-       gcc -c -DWITH_OPENSSL $(GSOAPDIR)/stdsoap2.c
+       gcc -g -c -DWITH_OPENSSL $(GSOAPDIR)/stdsoap2.c
        ar src libstdsoap2.a stdsoap2.o
 
 gridsite-delegation.cgi: grst-delegation.c delegation.h delegation.wsdl \
                          soapC.c soapServer.c
-       gcc $(MYCFLAGS) $(MYLDFLAGS) -o gridsite-delegation.cgi \
+       gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o gridsite-delegation.cgi \
             grst-delegation.c \
             -I/usr/kerberos/include -I$(GSOAPDIR)/include \
             -DVERSION=\"$(VERSION)\" -L$(GSOAPDIR)/lib \
@@ -226,7 +235,7 @@ gridsite-delegation.cgi: grst-delegation.c delegation.h delegation.wsdl \
 
 htproxyput: htproxyput.c delegation.h delegation.wsdl \
             soapC.c soapServer.c
-       gcc $(MYCFLAGS) $(MYLDFLAGS) -o htproxyput \
+       gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o htproxyput \
             htproxyput.c \
             -I/usr/kerberos/include \
             -g -DVERSION=\"$(VERSION)\" \
@@ -236,7 +245,7 @@ htproxyput: htproxyput.c delegation.h delegation.wsdl \
 
 proxyput-example: proxyput-example.c delegation.h delegation.wsdl \
             soapC.c soapServer.c
-       gcc $(MYCFLAGS) $(MYLDFLAGS) -o proxyput-example \
+       gcc -g $(MYCFLAGS) $(MYLDFLAGS) -o proxyput-example \
             proxyput-example.c \
             -I/usr/kerberos/include \
             -g -DVERSION=\"$(VERSION)\" \
diff --git a/org.gridsite.core/src/grst_htcp.c b/org.gridsite.core/src/grst_htcp.c
new file mode 100644 (file)
index 0000000..55a32e6
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+   Copyright (c) 2002-5, Andrew McNab, University of Manchester
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or
+   without modification, are permitted provided that the following
+   conditions are met:
+
+     o Redistributions of source code must retain the above
+       copyright notice, this list of conditions and the following
+       disclaimer. 
+     o Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials
+       provided with the distribution. 
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+   BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VERSION
+#define VERSION "x.x.x"
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include <string.h> 
+#include <sys/types.h> 
+#include <sys/socket.h> 
+#include <netinet/in.h> 
+#include <arpa/inet.h> 
+
+#include "gridsite.h"
+
+int GRSThtcpNOPrequestMake(char **request, int *request_length,
+                           unsigned int trans_id)
+/* 
+    Make a complete HTCP NOP request and return a pointer to malloc'd
+    memory pointing to it.
+*/
+{
+   *request_length = 
+     asprintf(request,"%c%c"           /* place holder for total length */
+                      "%c%c"           /* HTCP version 0.0 */
+                      "%c%c"           /* DATA length place holder */
+                      "%c%c"           /* OPCODE,RESPONSE,RESERVED,F1,RR */
+                      "%c%c%c%c"       /* TRANS-ID placeholder */
+                      "%c%c",          /* AUTH (LENGTH=2 means no AUTH) */
+                     0, 0,
+                     0, 0,
+                     0, 0,
+                     GRSThtcpNOPop * 16, 2,
+                     0, 0, 0, 0,
+                     0, 2);
+
+   if (*request_length < 0) return GRST_RET_FAILED;
+   
+   (*request)[0] = *request_length / 256;
+   (*request)[1] = *request_length % 256;
+
+   (*request)[4] = (*request_length - 6) / 256;
+   (*request)[5] = (*request_length - 6) % 256;
+   
+   memcpy(&((*request)[8]), &trans_id, 4);
+
+   return GRST_RET_OK;
+}
+
+int GRSThtcpNOPresponseMake(char **message, int *message_length,
+                            unsigned int trans_id)
+/* 
+    Make a complete HTCP NOP response for a found file and return a pointer
+    to malloc'd memory pointing to it.
+*/
+{
+   *message_length = 
+        asprintf(message, 
+                       "%c%c"          /* place holder for total length */
+                       "%c%c"          /* HTCP version 0.0 */
+                       "%c%c"          /* DATA length place holder */
+                       "%c%c"          /* OPCODE,RESPONSE,RESERVED,F1,RR */
+                       "%c%c%c%c"      /* TRANS-ID place holder */
+                       "%c%c",         /* AUTH (LENGTH=2 means no AUTH) */
+            0, 0,
+            0, 0,
+            0, 0,
+            GRSThtcpNOPop * 16, 1, /* RR=1, MO=0, RESPONSE=0 (ie found) */
+            0, 0, 0, 0,
+            0, 2);
+
+   if (*message_length < 0) return GRST_RET_FAILED;
+   
+   (*message)[0] = *message_length / 256;
+   (*message)[1] = *message_length % 256;
+
+   (*message)[4] = (*message_length - 6) / 256;
+   (*message)[5] = (*message_length - 6) % 256;
+
+   memcpy(&((*message)[8]), &trans_id, 4);
+
+   return GRST_RET_OK;
+}
+
+int GRSThtcpTSTrequestMake(char **request, int *request_length,
+                           unsigned int trans_id,
+                           char *method, char *uri, char *req_hdrs)
+/* 
+    Make a complete HTCP TST request and return a pointer to malloc'd
+    memory pointing to it.
+*/
+{
+   if ((method == NULL) || (uri == NULL) || (req_hdrs == NULL)) 
+                                               return GRST_RET_FAILED;
+
+   *request_length = 
+     asprintf(request,"%c%c"           /* place holder for total length */
+                      "%c%c"           /* HTCP version 0.0 */
+                      "%c%c"           /* DATA length place holder */
+                      "%c%c"           /* OPCODE,RESPONSE,RESERVED,F1,RR */
+                      "%c%c%c%c"       /* TRANS-ID placeholder */                    
+                      "%c%c%s"         /* OP-DATA: METHOD */
+                      "%c%c%s"         /* OP-DATA: URI */
+                      "%c%c%s"         /* OP-DATA: VERSION */
+                      "%c%c%s"         /* OP-DATA: REQ-HDRS */
+                      "%c%c",          /* AUTH (LENGTH=2 means no AUTH) */
+                     0, 0, 
+                     0, 0, 
+                     0, 0,       
+                     GRSThtcpTSTop * 16, 2,
+                     0, 0, 0, 0,
+                     strlen(method) / 256, strlen(method) % 256, method,
+                     strlen(uri)    / 256, strlen(uri) % 256,    uri,
+                     0,                    8,                    "HTTP/1.1",
+                     strlen(req_hdrs)/256, strlen(req_hdrs) % 256, req_hdrs,
+                     0, 2);
+
+   if (*request_length < 0) return GRST_RET_FAILED;
+   
+   (*request)[0] = *request_length / 256;
+   (*request)[1] = *request_length % 256;
+
+   (*request)[4] = (*request_length - 6) / 256;
+   (*request)[5] = (*request_length - 6) % 256;
+   
+   memcpy(&((*request)[8]), &trans_id, 4);
+
+   return GRST_RET_OK;
+}
+
+int GRSThtcpTSTresponseMake(char **message, int *message_length,
+                            unsigned int trans_id,
+                            char *resp_hdrs, char *entity_hdrs, 
+                            char *cache_hdrs)
+/* 
+    Make a complete HTCP TST response for a found file and return a pointer
+    to malloc'd memory pointing to it.
+*/
+{
+   if ((resp_hdrs != NULL) && (entity_hdrs != NULL) && (cache_hdrs != NULL)) 
+      /* found file response */
+      *message_length = 
+        asprintf(message, 
+                       "%c%c"          /* place holder for total length */
+                       "%c%c"          /* HTCP version 0.0 */
+                       "%c%c"          /* DATA length place holder */
+                       "%c%c"          /* OPCODE,RESPONSE,RESERVED,F1,RR */
+                       "%c%c%c%c"      /* TRANS-ID place holder */
+                       "%c%c%s"                /* OP-DATA: RESP-HDRS */
+                       "%c%c%s"                /* OP-DATA: ENTITY-HDRS */
+                       "%c%c%s"                /* OP-DATA: CACHE-HDRS */
+                       "%c%c",         /* AUTH (LENGTH=2 means no AUTH) */
+            0, 0, 
+            0, 0, 
+            0, 0,       
+            GRSThtcpTSTop * 16, 1, /* RR=1, MO=0, RESPONSE=0 (ie found) */
+            0, 0, 0, 0,
+            strlen(resp_hdrs) / 256,   strlen(resp_hdrs) % 256,   resp_hdrs,
+            strlen(entity_hdrs) / 256, strlen(entity_hdrs) % 256, entity_hdrs,
+            strlen(cache_hdrs) / 256,  strlen(cache_hdrs) % 256,  cache_hdrs,
+            0, 2);
+   else if (cache_hdrs != NULL) 
+      /* not found file response, just cache_hdrs given */
+      *message_length = 
+        asprintf(message, 
+                       "%c%c"          /* place holder for total length */
+                       "%c%c"          /* HTCP version 0.0 */
+                       "%c%c"          /* DATA length place holder */
+                       "%c%c"          /* OPCODE,RESPONSE,RESERVED,F1,RR */
+                       "%c%c%c%c"      /* TRANS-ID */                
+                       "%c%c%s"                /* OP-DATA: CACHE-HDRS */
+                       "%c%c",         /* AUTH (LENGTH=2 means no AUTH) */
+            0, 0, 
+            0, 0, 
+            0, 0,       
+            GRSThtcpTSTop * 16 + 1, 1, /* RR=1, MO=0, RESPONSE=1 (missing) */
+            0, 0, 0, 0,
+            strlen(cache_hdrs) / 256,  strlen(cache_hdrs) % 256,  cache_hdrs,
+            0, 2);
+   else return GRST_RET_FAILED;
+
+   if (*message_length < 0) return GRST_RET_FAILED;
+   
+   (*message)[0] = *message_length / 256;
+   (*message)[1] = *message_length % 256;
+
+   (*message)[4] = (*message_length - 6) / 256;
+   (*message)[5] = (*message_length - 6) % 256;
+
+   memcpy(&((*message)[8]), &trans_id, 4);
+
+   return GRST_RET_OK;
+}
+
+int GRSThtcpMessageParse(GRSThtcpMessage *parsed, char *raw, int length)
+{
+   GRSThtcpCountstr *s;
+   
+   bzero(parsed, sizeof(GRSThtcpMessage));
+   
+   if (length < (void *) &(parsed->method) 
+                - (void *) &(parsed->total_length_msb) + 2) 
+           return GRST_RET_FAILED;
+
+   memcpy(parsed, raw, (void *) &(parsed->method) 
+                       - (void *) &(parsed->total_length_msb));
+   
+   if (parsed->opcode == GRSThtcpNOPop) return GRST_RET_OK;
+
+   if ((parsed->opcode == GRSThtcpTSTop) && (parsed->rr == 0))
+     {
+       /* point to start of data/auth in raw */
+       s = (GRSThtcpCountstr *) &(((GRSThtcpMessage *) raw)->method); 
+
+       /* METHOD string */
+
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->method = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+       
+       /* URI string */
+
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->uri = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+
+       /* VERSION string */
+           
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->version = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+
+       /* REQ-HDRS string */
+           
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->req_hdrs = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+                  
+       return GRST_RET_OK;
+     }   
+
+   if ((parsed->opcode == GRSThtcpTSTop) && (parsed->rr == 1))
+     {
+       /* point to start of data/auth in raw */
+       s = (GRSThtcpCountstr *) &(((GRSThtcpMessage *) raw)->method); 
+
+       /* RESP-HDRS string */
+
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->resp_hdrs = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+       
+       /* ENTITY-HDRS string */
+
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->entity_hdrs = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+
+       /* CACHE-HDRS string */
+           
+       if ((void *) s + 2 + GRSThtcpCountstrLen(s) > (void *) raw + length)
+                                                   return GRST_RET_FAILED;
+       parsed->cache_hdrs = s;
+       s = (GRSThtcpCountstr *) ((void *) s + 2 + GRSThtcpCountstrLen(s));
+                  
+       return GRST_RET_OK;
+     }   
+
+   return GRST_RET_FAILED; 
+}
index a71a2c5..96935f7 100644 (file)
Binary files a/org.gridsite.core/src/htcp and b/org.gridsite.core/src/htcp differ
index b81d7b2..a64d155 100644 (file)
@@ -42,6 +42,7 @@
 #endif
 
 #include <apr_strings.h>
+#include <apr_tables.h>
 
 #include <ap_config.h>
 #include <httpd.h>
@@ -56,6 +57,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>              
+#include <netdb.h>
 #include <malloc.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include <time.h>
 
+#include <sys/select.h> 
+#include <sys/socket.h> 
+#include <netinet/in.h> 
+#include <arpa/inet.h> 
+
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 
 
 module AP_MODULE_DECLARE_DATA gridsite_module;
 
-typedef struct
-{
-   char                        *onetimesdir;
-}  mod_gridsite_srv_cfg; /* per-server config choices */
+#define GRST_SITECAST_GROUPS 32
+
+struct sitecast_group
+   { int socket; int quad1; int quad2; int quad3; int quad4; int port; };
+
+#define GRST_SITECAST_ALIASES 32
+   
+struct sitecast_alias
+   { const char *sitecast_url; const char *local_path; server_rec *server; };
+
+/* Globals, defined by main server directives in httpd.conf  
+   These are assigned default values in create_gridsite_srv_config() */
+
+int                    gridhttpport = 0;
+char                    *onetimesdir = NULL;
+char                   *sitecastdnlists = NULL;
+struct sitecast_group  sitecastgroups[GRST_SITECAST_GROUPS+1];
+struct sitecast_alias  sitecastaliases[GRST_SITECAST_ALIASES];
 
 typedef struct
 {
@@ -890,9 +911,7 @@ int http_gridhttp(request_rec *r, mod_gridsite_dir_cfg *conf)
 
     filetemplate = apr_psprintf(r->pool, "%s/%016llxXXXXXX", 
      ap_server_root_relative(r->pool,
-      ((mod_gridsite_srv_cfg *) 
-       ap_get_module_config(r->server->module_config, 
-                                    &gridsite_module))->onetimesdir),
+     onetimesdir),
      gridauthcookie);
 
     if (apr_file_mktemp(&fp, 
@@ -946,9 +965,13 @@ int http_gridhttp(request_rec *r, mod_gridsite_dir_cfg *conf)
                   "domain=%s; "
                   "path=%s",
                   cookievalue, expires_str, r->hostname, r->uri));
-    
-    httpurl = apr_pstrcat(r->pool, "http://", r->hostname,
-                        ap_escape_uri(r->pool, r->uri), NULL);
+
+    if (gridhttpport != DEFAULT_HTTP_PORT)
+         httpurl = apr_psprintf(r->pool, "http://%s:%d%s", r->hostname,
+                                gridhttpport, ap_escape_uri(r->pool, r->uri));
+    else httpurl = apr_pstrcat(r->pool, "http://", r->hostname,
+                                ap_escape_uri(r->pool, r->uri), NULL);
+
     apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "Location"), httpurl);
 
     r->status = HTTP_MOVED_TEMPORARILY;  
@@ -1495,24 +1518,37 @@ static int mod_gridsite_dnlistsuri_handler(request_rec *r,
 
 static void *create_gridsite_srv_config(apr_pool_t *p, server_rec *s)
 {
-    mod_gridsite_srv_cfg *srv_conf = apr_palloc(p, sizeof(*srv_conf));
+    int i;
 
-    srv_conf->onetimesdir = apr_pstrdup(p, "/var/www/onetimes");
-                                     /* GridSiteOnetimesDir dir-path */
-    return srv_conf;
-}
+    if (!(s->is_virtual))
+      {
+        gridhttpport = GRST_HTTP_PORT;
+      
+        onetimesdir = apr_pstrdup(p, "/var/www/onetimes");
+                                      /* GridSiteOnetimesDir dir-path   */
 
-static void *merge_gridsite_srv_config(apr_pool_t *p, void *srvroot,
-                                                      void *vhost)
-/* merge virtual host with server-wide configs */
-{
-    mod_gridsite_srv_cfg *conf;;
+        sitecastdnlists = NULL;
 
-    conf = apr_palloc(p, sizeof(*conf));
+        sitecastgroups[0].quad1 = 0;
+        sitecastgroups[0].quad2 = 0;
+        sitecastgroups[0].quad3 = 0;
+        sitecastgroups[0].quad4 = 0;
+        sitecastgroups[0].port  = GRST_HTCP_PORT;
+                                      /* GridSiteCastUniPort udp-port */
 
-    conf->onetimesdir = ((mod_gridsite_srv_cfg *) srvroot)->onetimesdir;
-                
-    return conf;
+        for (i=1; i <= GRST_SITECAST_GROUPS; ++i)
+                   sitecastgroups[i].port = 0;
+                                      /* GridSiteCastGroup mcast-list */
+
+        for (i=1; i <= GRST_SITECAST_ALIASES; ++i)
+           {
+             sitecastaliases[i].sitecast_url = NULL;
+             sitecastaliases[i].local_path   = NULL;
+             sitecastaliases[i].server       = NULL;                   
+           }                              /* GridSiteCastAlias url path */
+      }
+
+    return NULL;
 }
 
 static void *create_gridsite_dir_config(apr_pool_t *p, char *path)
@@ -1547,7 +1583,7 @@ static void *create_gridsite_dir_config(apr_pool_t *p, char *path)
         conf->footfile = apr_pstrdup(p, GRST_FOOTFILE);
                /* GridSiteHeadFile and GridSiteFootFile  file name */
 
-        conf->gridhttp       = 0;     /* GridSiteGridHTTP     on/off       */
+        conf->gridhttp      = 0;     /* GridSiteGridHTTP      on/off       */
         conf->soap2cgi      = 0;     /* GridSiteSoap2cgi      on/off       */
        conf->aclformat     = apr_pstrdup(p, "GACL");
                                      /* GridSiteACLFormat     gacl/xacml */
@@ -1690,18 +1726,60 @@ static void *merge_gridsite_dir_config(apr_pool_t *p, void *vserver,
 static const char *mod_gridsite_take1_cmds(cmd_parms *a, void *cfg,
                                            const char *parm)
 {
-    int   n;
+    int   n, i;
     char *p;
-    mod_gridsite_srv_cfg *srv_cfg = 
-     (mod_gridsite_srv_cfg *) ap_get_module_config(a->server->module_config, 
-     &gridsite_module);
   
     if (strcasecmp(a->cmd->name, "GridSiteOnetimesDir") == 0)
     {
       if (a->server->is_virtual)
        return "GridSiteOnetimesDir cannot be used inside a virtual server";
     
-      srv_cfg->onetimesdir = apr_pstrdup(a->pool, parm);
+      onetimesdir = apr_pstrdup(a->pool, parm);
+    }
+    else if (strcasecmp(a->cmd->name, "GridSiteGridHTTPport") == 0)
+    {
+      gridhttpport = atoi(parm);
+    }
+    else if (strcasecmp(a->cmd->name, "GridSiteCastDNlists") == 0)
+    {
+      if (a->server->is_virtual)
+       return "GridSiteDNlists cannot be used inside a virtual server";
+    
+      sitecastdnlists = apr_pstrdup(a->pool, parm);
+    }
+    else if (strcasecmp(a->cmd->name, "GridSiteCastUniPort") == 0)
+    {
+      if (a->server->is_virtual)
+       return "GridSiteCastUniPort cannot be used inside a virtual server";
+
+      if (sscanf(parm, "%d", &(sitecastgroups[0].port)) != 1)
+        return "Failed parsing GridSiteCastUniPort numeric value";
+    }
+    else if (strcasecmp(a->cmd->name, "GridSiteCastGroup") == 0)
+    {
+      if (a->server->is_virtual)
+       return "GridSiteCastGroup cannot be used inside a virtual server";
+
+      for (i=1; i <= GRST_SITECAST_GROUPS; ++i)
+         {
+           if (sitecastgroups[i].port == 0) /* a free slot */
+             {
+               sitecastgroups[i].port = GRST_HTCP_PORT;
+             
+               if (sscanf(parm, "%d.%d.%d.%d:%d",
+                          &(sitecastgroups[i].quad1), 
+                          &(sitecastgroups[i].quad2), 
+                          &(sitecastgroups[i].quad3), 
+                          &(sitecastgroups[i].quad4), 
+                          &(sitecastgroups[i].port)) < 4)
+                 return "Failed parsing GridSiteCastGroup nnn.nnn.nnn.nnn[:port]";
+                 
+               break;
+             }
+         }
+         
+      if (i > GRST_SITECAST_GROUPS)
+                     return "Maximum GridSiteCastGroup groups reached";
     }
     else if (strcasecmp(a->cmd->name, "GridSiteAdminFile") == 0)
     {
@@ -1827,6 +1905,8 @@ static const char *mod_gridsite_take1_cmds(cmd_parms *a, void *cfg,
 static const char *mod_gridsite_take2_cmds(cmd_parms *a, void *cfg,
                                        const char *parm1, const char *parm2)
 {
+    int i;
+    
     if (strcasecmp(a->cmd->name, "GridSiteUserGroup") == 0)
     {
       if (!(unixd_config.suexec_enabled))
@@ -1859,6 +1939,27 @@ static const char *mod_gridsite_take2_cmds(cmd_parms *a, void *cfg,
        | ((APR_GREAD | APR_GWRITE) * (strcasecmp(parm1, "GroupWrite") == 0))
        | ((APR_GREAD | APR_WREAD)  * (strcasecmp(parm2, "WorldRead") == 0));
     }
+    else if (strcasecmp(a->cmd->name, "GridSiteCastAlias") == 0)
+    {
+      for (i=0; i < GRST_SITECAST_ALIASES; ++i) /* look for free slot */
+         {
+           if (
+//               srv_cfg->
+                        sitecastaliases[i].sitecast_url == NULL)
+             {
+/*
+               srv_cfg->sitecastaliases[i].sitecast_url  = parm1;
+               srv_cfg->sitecastaliases[i].local_path    = parm2;
+               srv_cfg->sitecastaliases[i].server        = a->server;
+*/                       
+               sitecastaliases[i].sitecast_url  = parm1;
+               sitecastaliases[i].local_path    = parm2;
+               sitecastaliases[i].server        = a->server;
+               
+               break;
+             }
+         }
+    }
     
     return NULL;
 }
@@ -1945,9 +2046,20 @@ static const command_rec mod_gridsite_cmds[] =
     
     AP_INIT_FLAG("GridSiteGridHTTP", mod_gridsite_flag_cmds,
                  NULL, OR_FILEINFO, "on or off"),
+    AP_INIT_TAKE1("GridSiteGridHTTPport", mod_gridsite_take1_cmds,
+                   NULL, RSRC_CONF, "GridHTTP port"),
     AP_INIT_TAKE1("GridSiteOnetimesDir", mod_gridsite_take1_cmds,
                  NULL, RSRC_CONF, "directory with GridHTTP onetime passcodes"),
-    
+
+    AP_INIT_TAKE1("GridSiteCastDNlists", mod_gridsite_take1_cmds,
+                 NULL, RSRC_CONF, "DN Lists directories search path for SiteCast"),
+    AP_INIT_TAKE1("GridSiteCastUniPort", mod_gridsite_take1_cmds,
+                 NULL, RSRC_CONF, "UDP port for unicast/replies"),
+    AP_INIT_TAKE1("GridSiteCastGroup", mod_gridsite_take1_cmds,
+                 NULL, RSRC_CONF, "multicast group[:port] to listen for HTCP on"),
+    AP_INIT_TAKE2("GridSiteCastAlias", mod_gridsite_take2_cmds,
+                 NULL, RSRC_CONF, "URL and local path mapping"),
+
     AP_INIT_FLAG("GridSiteSoap2cgi", mod_gridsite_flag_cmds,
                  NULL, OR_FILEINFO, "on or off"),
 
@@ -2196,9 +2308,7 @@ static int mod_gridsite_perm_handler(request_rec *r)
       {
         cookiefile = apr_psprintf(r->pool, "%s/%s",
                  ap_server_root_relative(r->pool,
-                   ((mod_gridsite_srv_cfg *) 
-                    ap_get_module_config(r->server->module_config, 
-                                    &gridsite_module))->onetimesdir),
+                 onetimesdir),
                  &gridauthonetime[18]);
                                       
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
@@ -2551,12 +2661,390 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx)
    return returned_ok;
 }
 
+void sitecast_handle_NOP_request(server_rec *main_server, 
+                                 GRSThtcpMessage *htcp_mesg, int igroup,
+                                 struct sockaddr_in *client_addr_ptr)
+{
+  int  outbuf_len;
+  char *outbuf;
+  
+  if (GRSThtcpNOPresponseMake(&outbuf, &outbuf_len,
+                              htcp_mesg->trans_id) == GRST_RET_OK)
+    {
+      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+            "SiteCast sends NOP response from port %d to %s:%d",
+            sitecastgroups[0].port, inet_ntoa(client_addr_ptr->sin_addr),
+            ntohs(client_addr_ptr->sin_port));
+
+      sendto(sitecastgroups[0].socket, outbuf, outbuf_len, 0,
+                 client_addr_ptr, sizeof(struct sockaddr_in));
+                 
+      free(outbuf);
+    }
+}
+
+void sitecast_handle_TST_GET(server_rec *main_server, 
+                             GRSThtcpMessage *htcp_mesg, int igroup,
+                             struct sockaddr_in *client_addr_ptr)
+{
+  int             i, outbuf_len, ialias, port;
+  char            *filename, *outbuf, *location, *local_uri = NULL;
+  struct stat     statbuf;
+  SSLSrvConfigRec *ssl_srv;
+  
+  /* check sanity of requested uri */
+
+  if (strncmp(htcp_mesg->uri->text, "http://", 7) == 0)
+    {
+      for (i=7; i < GRSThtcpCountstrLen(htcp_mesg->uri); ++i)
+         if (htcp_mesg->uri->text[i] == '/') 
+           {
+             local_uri = &(htcp_mesg->uri->text[i]);
+             break;
+           }
+    }
+  else if (strncmp(htcp_mesg->uri->text, "https://", 8) == 0)
+    {
+      for (i=8; i < GRSThtcpCountstrLen(htcp_mesg->uri); ++i)
+         if (htcp_mesg->uri->text[i] == '/') 
+           {
+             local_uri = &(htcp_mesg->uri->text[i]);
+             break;
+           }
+    }
+
+  if (local_uri == NULL)
+    {
+      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+              "SiteCast responder only handles http(s):// (%*s requested by %s:%d)",
+                        GRSThtcpCountstrLen(htcp_mesg->uri),
+                        htcp_mesg->uri->text,
+                        inet_ntoa(client_addr_ptr->sin_addr),
+                        ntohs(client_addr_ptr->sin_port));      
+      return;
+    }
+
+  /* find if any GridSiteCastAlias lines match */
+
+  for (ialias=0; ialias < GRST_SITECAST_ALIASES ; ++ialias)
+     {
+       if (sitecastaliases[ialias].sitecast_url == NULL) return; /* no match */
+                             
+       if ((strlen(sitecastaliases[ialias].sitecast_url)
+                                <= GRSThtcpCountstrLen(htcp_mesg->uri)) &&
+           (strncmp(sitecastaliases[ialias].sitecast_url,
+                    htcp_mesg->uri->text,
+                    strlen(sitecastaliases[ialias].sitecast_url))==0)) break;
+     }
+
+  if (ialias == GRST_SITECAST_ALIASES) 
+    {
+      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+              "SiteCast responder does not handle %*s requested by %s:%d",
+                        GRSThtcpCountstrLen(htcp_mesg->uri),
+                        htcp_mesg->uri->text,
+                        inet_ntoa(client_addr_ptr->sin_addr),
+                        ntohs(client_addr_ptr->sin_port));
+      
+      return; /* no match */
+    }
+
+  /* convert URL to filename, using alias mapping */
+  
+  asprintf(&filename, "%s%*s", 
+           sitecastaliases[ialias].local_path,
+           GRSThtcpCountstrLen(htcp_mesg->uri) 
+                        - strlen(sitecastaliases[ialias].sitecast_url),
+           &(htcp_mesg->uri->text[strlen(sitecastaliases[ialias].sitecast_url)]) );
+
+  if (stat(filename, &statbuf) == 0) /* found file */
+    { 
+      ssl_srv = (SSLSrvConfigRec *)
+       ap_get_module_config(sitecastaliases[ialias].server->module_config,
+                                                             &ssl_module);
+
+      port = sitecastaliases[ialias].server->addrs->host_port;
+      if (port == 0) port = ((ssl_srv != NULL) && (ssl_srv->enabled))
+                                 ? GRST_HTTPS_PORT : GRST_HTTP_PORT;
+                
+      asprintf(&location, "Location: http%s://%s:%d%s\r\n",
+                  ((ssl_srv != NULL) && (ssl_srv->enabled)) ? "s" : "",
+                  sitecastaliases[ialias].server->server_hostname, port,
+                  local_uri);
+
+      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+            "SiteCast finds %*s at %s, redirects with %s",
+            GRSThtcpCountstrLen(htcp_mesg->uri),
+            htcp_mesg->uri->text, filename, location);
+
+      if (GRSThtcpTSTresponseMake(&outbuf, &outbuf_len,
+                                  htcp_mesg->trans_id,
+                                  location, "", "") == GRST_RET_OK)
+        {
+          ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+            "SiteCast sends TST response from port %d to %s:%d",
+            sitecastgroups[0].port, inet_ntoa(client_addr_ptr->sin_addr),
+            ntohs(client_addr_ptr->sin_port));
+
+          sendto(sitecastgroups[0].socket, outbuf, outbuf_len, 0,
+                 client_addr_ptr, sizeof(struct sockaddr_in));
+                 
+          free(outbuf);
+        }
+
+      free(location);
+    }
+
+  free(filename);                      
+}
+
+void sitecast_handle_request(server_rec *main_server, 
+                             char *reqbuf, int reqbuf_len, int igroup,
+                             struct sockaddr_in *client_addr_ptr)
+{
+  GRSThtcpMessage htcp_mesg;
+
+  if (GRSThtcpMessageParse(&htcp_mesg,reqbuf,reqbuf_len) != GRST_RET_OK)
+    {
+      ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+              "SiteCast responder rejects format of UDP message from %s:%d",
+                        inet_ntoa(client_addr_ptr->sin_addr),
+                        ntohs(client_addr_ptr->sin_port));
+      return;
+    }
+
+  if (htcp_mesg.rr != 0) /* ignore HTCP responses: we just do requests */
+    {
+      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+              "SiteCast responder ignores HTCP response from %s:%d",
+                        inet_ntoa(client_addr_ptr->sin_addr),
+                        ntohs(client_addr_ptr->sin_port));
+      return;
+    }
+
+  if (htcp_mesg.opcode == GRSThtcpNOPop)
+    {
+      sitecast_handle_NOP_request(main_server, &htcp_mesg, 
+                                  igroup, client_addr_ptr);
+      return;
+    }
+
+  if (htcp_mesg.opcode == GRSThtcpTSTop)
+    {
+      if (((GRSThtcpCountstrLen(htcp_mesg.method) == 3) &&
+           (strncmp(htcp_mesg.method->text, "GET", 3) == 0)) ||
+          ((GRSThtcpCountstrLen(htcp_mesg.method) == 4) &&
+           (strncmp(htcp_mesg.method->text, "HEAD", 4) == 0)))
+        {
+          sitecast_handle_TST_GET(main_server, &htcp_mesg, 
+                                  igroup, client_addr_ptr);
+          return;
+        }
+        
+      ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+          "SiteCast responder rejects method %*s in TST message from %s:%d",
+          GRSThtcpCountstrLen(htcp_mesg.method), htcp_mesg.method->text,
+          inet_ntoa(client_addr_ptr->sin_addr),
+          ntohs(client_addr_ptr->sin_port));
+      return;
+    }
+
+  ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+          "SiteCast does not implement HTCP op-code %d in message from %s:%d",
+          htcp_mesg.opcode,
+          inet_ntoa(client_addr_ptr->sin_addr),
+          ntohs(client_addr_ptr->sin_port));
+}
+
+void sitecast_responder(server_rec *main_server)
+{
+#define GRST_SITECAST_MAXBUF 8192
+  char   reqbuf[GRST_SITECAST_MAXBUF], *p;
+  int    n, reqbuf_len, i, j, igroup,
+         quad1, quad2, quad3, quad4, port, retval, client_addr_len;
+  struct sockaddr_in srv, client_addr;
+  struct ip_mreq mreq;
+  fd_set readsckts;
+  struct hostent *server_hostent;
+
+  strcpy((char *) main_server->process->argv[0], "GridSiteCast UDP responder");
+
+  /* initialise unicast/replies socket first */
+
+  bzero(&srv, sizeof(srv));
+  srv.sin_family = AF_INET;
+  srv.sin_port = htons(sitecastgroups[0].port);
+
+  if ((server_hostent = gethostbyname(main_server->server_hostname)) == NULL)
+    {
+      ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+              "SiteCast UDP Responder fails to look up servername %s",
+              main_server->server_hostname);
+      return;
+    }
+
+  srv.sin_addr.s_addr = (u_int32_t) (server_hostent->h_addr_list[0][0]);
+  
+  if (((sitecastgroups[0].socket 
+                                = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
+       (bind(sitecastgroups[0].socket, 
+                                (struct sockaddr *) &srv, sizeof(srv)) < 0))
+    {
+      ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+              "mod_gridsite: sitecast responder fails on unicast bind (%s)",
+              strerror(errno));
+      return;
+    }
+
+  ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+                "SiteCast UDP unicast/replies on %d.%d.%d.%d:%d",
+                   server_hostent->h_addr_list[0][0],
+                   server_hostent->h_addr_list[0][1],
+                   server_hostent->h_addr_list[0][2],
+                   server_hostent->h_addr_list[0][3],
+                   sitecastgroups[0].port);
+
+  /* initialise multicast listener sockets next */
+
+  for (i=1; (i <= GRST_SITECAST_GROUPS) && 
+            (sitecastgroups[i].port != 0); ++i)
+     {
+       bzero(&srv, sizeof(srv));
+       srv.sin_family = AF_INET;
+       srv.sin_port = htons(sitecastgroups[i].port);
+       srv.sin_addr.s_addr = htonl(sitecastgroups[i].quad1*0x1000000
+                                 + sitecastgroups[i].quad2*0x10000
+                                 + sitecastgroups[i].quad3*0x100 
+                                 + sitecastgroups[i].quad4);
+
+       if (((sitecastgroups[i].socket 
+                                     = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ||
+               (bind(sitecastgroups[i].socket, 
+                                  (struct sockaddr *) &srv, sizeof(srv)) < 0))
+         {
+           ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+                "SiteCast UDP Responder fails on multicast bind (%s)",
+                strerror(errno));
+           return;
+         }
+     
+       bzero(&mreq, sizeof(mreq));
+       mreq.imr_multiaddr.s_addr = srv.sin_addr.s_addr;
+       mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+
+       if (setsockopt(sitecastgroups[i].socket, IPPROTO_IP,
+                      IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) 
+         { 
+           ap_log_error(APLOG_MARK, APLOG_ERR, 0, main_server,
+                "SiteCast UDP Responder fails on setting multicast");
+           return; 
+         }
+         
+       ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+        "SiteCast UDP Responder listening on %d.%d.%d.%d:%d",
+        sitecastgroups[i].quad1, sitecastgroups[i].quad2,
+        sitecastgroups[i].quad3, sitecastgroups[i].quad4, sitecastgroups[i].port);
+     }
+
+  while (1) /* **** main listening loop **** */
+       {
+         /* set up bitmasks for select */
+       
+         FD_ZERO(&readsckts);
+         
+         n = 0;
+         for (i=0; (i <= GRST_SITECAST_GROUPS) && 
+                   (sitecastgroups[i].port != 0); ++i) /* reset bitmask */
+            {
+              FD_SET(sitecastgroups[i].socket, &readsckts);
+              if (sitecastgroups[i].socket > n) n = sitecastgroups[i].socket;
+            }
+
+         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+                      "SiteCast UDP Responder waiting for requests");
+
+         if ((retval = select(n + 1, &readsckts, NULL, NULL, NULL)) < 1)
+                                   continue; /* < 1 on timeout or error */
+
+         for (igroup=0; (igroup <= GRST_SITECAST_GROUPS) && 
+                   (sitecastgroups[igroup].port != 0); ++igroup)
+            {
+              if (FD_ISSET(sitecastgroups[igroup].socket, &readsckts))
+                {
+                  client_addr_len = sizeof(client_addr);
+
+                  if ((reqbuf_len = recvfrom(sitecastgroups[igroup].socket, 
+                                             reqbuf, GRST_SITECAST_MAXBUF, 0,
+                      (struct sockaddr *) &client_addr, &client_addr_len)) >= 0)
+                    {
+                      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server,
+                        "SiteCast receives UDP message from %s:%d "
+                        "to %d.%d.%d.%d:%d",
+                        inet_ntoa(client_addr.sin_addr),
+                        ntohs(client_addr.sin_port),
+                        sitecastgroups[igroup].quad1,
+                        sitecastgroups[igroup].quad2,
+                        sitecastgroups[igroup].quad3,
+                        sitecastgroups[igroup].quad4,
+                        sitecastgroups[igroup].port);
+
+                      sitecast_handle_request(main_server, reqbuf, 
+                                              reqbuf_len, igroup,
+                                              &client_addr);
+                    }
+                }
+            }
+            
+       } /* **** end of main listening loop **** */
+}
+
 static int mod_gridsite_server_post_config(apr_pool_t *pPool,
                   apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *main_server)
 {
    SSL_CTX         *ctx;
    SSLSrvConfigRec *sc;
    server_rec      *this_server;
+   apr_proc_t      *procnew = NULL;
+   apr_status_t     status;
+   const char *userdata_key = "sitecast_init";
+
+   apr_pool_userdata_get((void **) &procnew, userdata_key, 
+                         main_server->process->pool);
+
+   /* we only fork responder if one not already forked and we have at
+      least one GridSiteCastAlias defined. This means it is possible
+      to run a responder with no groups - listening on unicast only! */
+
+   if ((procnew == NULL) &&
+       (sitecastaliases[0].sitecast_url != NULL))
+     {
+       /* UDP multicast responder required but not yet started */
+
+       procnew = apr_pcalloc(main_server->process->pool, sizeof(*procnew));
+       apr_pool_userdata_set((const void *) procnew, userdata_key,
+                     apr_pool_cleanup_null, main_server->process->pool);
+
+       status = apr_proc_fork(procnew, pPool);
+
+       if (status < 0)
+         {
+           ap_log_error(APLOG_MARK, APLOG_CRIT, status, main_server,
+              "mod_gridsite: Failed to spawn SiteCast responder process");
+           return HTTP_INTERNAL_SERVER_ERROR;
+         }
+       else if (status == APR_INCHILD)
+         {
+           ap_log_error(APLOG_MARK, APLOG_NOTICE, status, main_server,
+              "mod_gridsite: Spawning SiteCast responder process");
+           sitecast_responder(main_server);
+           exit(-1);
+         }
+
+       apr_pool_note_subprocess(main_server->process->pool,
+                                procnew, APR_KILL_AFTER_TIMEOUT);
+     }
+
+   /* continue with normal HTTP/HTTPS servers */
 
    ap_add_version_component(pPool,
                             apr_psprintf(pPool, "mod_gridsite/%s", VERSION));
@@ -2565,6 +3053,8 @@ static int mod_gridsite_server_post_config(apr_pool_t *pPool,
         this_server != NULL; 
         this_server = this_server->next)
       {
+        /* we do some GridSite OpenSSL magic for HTTPS servers */
+      
         sc = ap_get_module_config(this_server->module_config, &ssl_module);
 
         if ((sc                  != NULL)  &&
@@ -2676,7 +3166,7 @@ module AP_MODULE_DECLARE_DATA gridsite_module =
     create_gridsite_dir_config, /* dir config creater */
     merge_gridsite_dir_config,  /* dir merger */
     create_gridsite_srv_config, /* create server config */
-    merge_gridsite_srv_config,  /* merge server config */
+    NULL,                      /* merge server config */
     mod_gridsite_cmds,          /* command apr_table_t */
     register_hooks              /* register hooks */
 };