Large reorg of shibsp lib, new SPRequest API, ported modules, shifted code out of...
[shibboleth/sp.git] / shar / shar.cpp
index d1f1474..c224b3c 100644 (file)
@@ -1,61 +1,28 @@
 /*
- * The Shibboleth License, Version 1.
- * Copyright (c) 2002
- * University Corporation for Advanced Internet Development, Inc.
- * All rights reserved
+ *  Copyright 2001-2005 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 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, if any, must include
- * the following acknowledgment: "This product includes software developed by
- * the University Corporation for Advanced Internet Development
- * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
- * may appear in the software itself, if and wherever such third-party
- * acknowledgments normally appear.
- *
- * Neither the name of Shibboleth nor the names of its contributors, nor
- * Internet2, nor the University Corporation for Advanced Internet Development,
- * Inc., nor UCAID may be used to endorse or promote products derived from this
- * software without specific prior written permission. For written permission,
- * please contact shibboleth@shibboleth.org
- *
- * Products derived from this software may not be called Shibboleth, Internet2,
- * UCAID, or the University Corporation for Advanced Internet Development, nor
- * may Shibboleth appear in their name, without prior written permission of the
- * University Corporation for Advanced Internet Development.
- *
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
- * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
- * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 /*
- * shar.cpp -- the SHAR "main" code.  All the functionality is elsewhere
- *           (in case you want to turn this into a library later).
+ * shar.cpp -- the shibd "main" code.  All the functionality is elsewhere
  *
  * Created By: Derek Atkins <derek@ihtfp.com>
  *
  * $Id$
  */
 
+
 // eventually we might be able to support autoconf via cygwin...
 #if defined (_MSC_VER) || defined(__BORLANDC__)
 # include "config_win32.h"
 # include "config.h"
 #endif
 
+#ifdef WIN32
+# define _CRT_NONSTDC_NO_DEPRECATE 1
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <shib-target/shib-target.h>
+#include <shibsp/SPConfig.h>
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #include <sys/select.h>
 #endif
 
 #include <stdio.h>
-#include <errno.h>
 #include <signal.h>
-
-#include "shar-utils.h"
 #include <log4cpp/Category.hh>
 
-using namespace std;
-using namespace saml;
-using namespace shibboleth;
+using namespace shibsp;
 using namespace shibtarget;
+using namespace shibboleth;
+using namespace saml;
 using namespace log4cpp;
+using namespace std;
 
-#ifndef FD_SETSIZE
-# define FD_SETSIZE 1024
-#endif
-
-extern "C" void shibrpc_prog_1(struct svc_req* rqstp, register SVCXPRT* transp);
-
-int shar_run = 1;
-const char* config = NULL;
-const char* schemadir = NULL;
+bool shibd_shutdown = false;
+const char* shar_config = NULL;
+const char* shar_schemadir = NULL;
+bool shar_checkonly = false;
 static int unlink_socket = 0;
+const char* pidfile = NULL;
 
-static bool new_connection(IListener::ShibSocket& listener, const Iterator<ShibRPCProtocols>& protos)
-{
-    IListener::ShibSocket sock;
+#ifdef WIN32
 
-    // Accept the connection.
-    if (!ShibTargetConfig::getConfig().getINI()->getListener()->accept(listener, sock))
-        return false;
+//#include <CRTDBG.H>
 
-    // We throw away the result because the children manage themselves...
-    new SharChild(sock,protos);
-    return true;
-}
+#define nNoMansLandSize 4
+typedef struct _CrtMemBlockHeader
+{
+        struct _CrtMemBlockHeader * pBlockHeaderNext;
+        struct _CrtMemBlockHeader * pBlockHeaderPrev;
+        char *                      szFileName;
+        int                         nLine;
+        size_t                      nDataSize;
+        int                         nBlockUse;
+        long                        lRequest;
+        unsigned char               gap[nNoMansLandSize];
+        /* followed by:
+         *  unsigned char           data[nDataSize];
+         *  unsigned char           anotherGap[nNoMansLandSize];
+         */
+} _CrtMemBlockHeader;
 
-static void shar_svc_run(IListener::ShibSocket& listener, const Iterator<ShibRPCProtocols>& protos)
+/*
+int MyAllocHook(int nAllocType, void *pvData,
+      size_t nSize, int nBlockUse, long lRequest,
+      const unsigned char * szFileName, int nLine)
 {
-    NDC ndc("shar_svc_run");
-    Category& log=Category::getInstance("SHAR");
-
-    while (shar_run) {
-        fd_set readfds;
-        FD_ZERO(&readfds);
-        FD_SET(listener, &readfds);
-        struct timeval tv = { 0, 0 };
-        tv.tv_sec = 5;
-    
-        switch (select(FD_SETSIZE, &readfds, 0, 0, &tv)) {
-            case -1:
-                if (errno == EINTR) continue;
-                SHARUtils::log_error();
-                return;
-        
-            case 0:
-                continue;
-        
-            default:
-                if (!new_connection(listener, protos))
-                    log.error("new_connection failed");
-        }
+    if ( nBlockUse == _CRT_BLOCK )
+      return( TRUE );
+    if (nAllocType == _HOOK_FREE) {
+        _CrtMemBlockHeader* ptr = (_CrtMemBlockHeader*)(((_CrtMemBlockHeader *)pvData)-1);
+        if (ptr->nDataSize == 8192)
+            fprintf(stderr,"free  request %u size %u\n", ptr->lRequest, ptr->nDataSize);
     }
-    log.info("shar_svc_run ended");
+    else if (nAllocType == _HOOK_ALLOC && nSize == 8192)
+        fprintf(stderr,"%s request %u size %u\n", ((nAllocType == _HOOK_ALLOC) ? "alloc" : "realloc"), lRequest, nSize);
+    return (TRUE);
 }
-
-#ifdef WIN32
+*/
 
 int real_main(int preinit)
 {
-    static IListener::ShibSocket sock;
-    ShibRPCProtocols protos[1] = {
-        { SHIBRPC_PROG, SHIBRPC_VERS_1, shibrpc_prog_1 }
-    };
-
     ShibTargetConfig& conf=ShibTargetConfig::getConfig();
     if (preinit) {
 
         // initialize the shib-target library
-        conf.setFeatures(
-            ShibTargetConfig::Listener |
-            ShibTargetConfig::SessionCache |
-            ShibTargetConfig::Metadata |
-            ShibTargetConfig::Trust |
-            ShibTargetConfig::Credentials |
-            ShibTargetConfig::AAP |
-            ShibTargetConfig::SHARExtensions
+        SPConfig::getConfig().setFeatures(
+            SPConfig::Listener |
+            SPConfig::Caching |
+            SPConfig::Metadata |
+            SPConfig::Trust |
+            SPConfig::Credentials |
+            SPConfig::AAP |
+            SPConfig::OutOfProcess |
+            (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
             );
-        if (!config)
-            config=getenv("SHIBCONFIG");
-        if (!schemadir)
-            schemadir=getenv("SHIBSCHEMAS");
-       if (!schemadir)
-           schemadir=SHIB_SCHEMAS;
-       if (!config)
-           config=SHIB_CONFIG;
-        if (!conf.init(schemadir,config))
+        if (!shar_config)
+            shar_config=getenv("SHIBCONFIG");
+        if (!shar_schemadir)
+            shar_schemadir=getenv("SHIBSCHEMAS");
+        if (!shar_schemadir)
+            shar_schemadir=SHIB_SCHEMAS;
+        if (!shar_config)
+            shar_config=SHIB_CONFIG;
+        if (!conf.init(shar_schemadir) || !conf.load(shar_config)) {
+            fprintf(stderr, "configuration is invalid, see console for specific problems\n");
             return -2;
+        }
 
-        const IListener* listener=conf.getINI()->getListener();
-        
-        // Create the SHAR listener socket
-        if (!listener->create(sock))
-            return -3;
-
-        // Bind to the proper port
-        if (!listener->bind(sock))
-            return -4;
-
-        // Initialize the SHAR Utilitites
-        SHARUtils::init();
+        // If just a test run, bail.
+        if (shar_checkonly) {
+            fprintf(stdout, "overall configuration is loadable, check console for non-fatal problems\n");
+            return 0;
+        }
     }
     else {
+
+        //_CrtSetAllocHook(MyAllocHook);
+
         // Run the listener
-        shar_svc_run(sock, ArrayIterator<ShibRPCProtocols>(protos,1));
-        fprintf(stderr,"shar_svc_run returned\n");
+        if (!shar_checkonly) {
+
+            // Run the listener.
+            if (!conf.getINI()->getListenerService()->run(&shibd_shutdown)) {
+                fprintf(stderr, "listener failed to enter listen loop\n");
+                return -3;
+            }
+        }
 
-        // Finalize the SHAR, close all clients
-        SHARUtils::fini();
-        conf.getINI()->getListener()->close(sock);
         conf.shutdown();
     }
     return 0;
@@ -197,20 +158,17 @@ int real_main(int preinit)
 
 static void term_handler(int arg)
 {
-    shar_run = 0;
+    shibd_shutdown = true;
 }
 
 static int setup_signals(void)
 {
-    NDC ndc("setup_signals");
-    
     struct sigaction sa;
     memset(&sa, 0, sizeof (sa));
     sa.sa_handler = SIG_IGN;
     sa.sa_flags = SA_RESTART;
 
     if (sigaction(SIGPIPE, &sa, NULL) < 0) {
-        SHARUtils::log_error();
         return -1;
     }
 
@@ -219,19 +177,15 @@ static int setup_signals(void)
     sa.sa_flags = SA_RESTART;
 
     if (sigaction(SIGHUP, &sa, NULL) < 0) {
-        SHARUtils::log_error();
         return -1;
     }
     if (sigaction(SIGINT, &sa, NULL) < 0) {
-        SHARUtils::log_error();
         return -1;
     }
     if (sigaction(SIGQUIT, &sa, NULL) < 0) {
-        SHARUtils::log_error();
         return -1;
     }
     if (sigaction(SIGTERM, &sa, NULL) < 0) {
-        SHARUtils::log_error();
         return -1;
     }
     return 0;
@@ -239,10 +193,12 @@ static int setup_signals(void)
 
 static void usage(char* whoami)
 {
-    fprintf(stderr, "usage: %s [-f]\n", whoami);
+    fprintf(stderr, "usage: %s [-fcdt]\n", whoami);
     fprintf(stderr, "  -c\tconfig file to use.\n");
     fprintf(stderr, "  -d\tschema directory to use.\n");
+    fprintf(stderr, "  -t\tcheck configuration file for problems.\n");
     fprintf(stderr, "  -f\tforce removal of listener socket.\n");
+    fprintf(stderr, "  -p\tpid file to use.\n");
     fprintf(stderr, "  -h\tprint this help message.\n");
     exit(1);
 }
@@ -251,17 +207,23 @@ static int parse_args(int argc, char* argv[])
 {
     int opt;
 
-    while ((opt = getopt(argc, argv, "cdfFh")) > 0) {
+    while ((opt = getopt(argc, argv, "c:d:p:fth")) > 0) {
         switch (opt) {
             case 'c':
-                config=optarg;
+                shar_config=optarg;
                 break;
             case 'd':
-                schemadir=optarg;
+                shar_schemadir=optarg;
                 break;
             case 'f':
                 unlink_socket = 1;
                 break;
+            case 't':
+                shar_checkonly=true;
+                break;
+            case 'p':
+                pidfile=optarg;
+                break;
             default:
                 return -1;
         }
@@ -271,65 +233,63 @@ static int parse_args(int argc, char* argv[])
 
 int main(int argc, char *argv[])
 {
-    IListener::ShibSocket sock;
-    ShibRPCProtocols protos[] = {
-        { SHIBRPC_PROG, SHIBRPC_VERS_1, shibrpc_prog_1 }
-    };
-
     if (setup_signals() != 0)
         return -1;
 
     if (parse_args(argc, argv) != 0)
         usage(argv[0]);
 
-    if (!schemadir)
-        schemadir=getenv("SHIBSCHEMAS");
-    if (!config)
-        config=getenv("SHIBCONFIG");
-    if (!schemadir)
-        schemadir=SHIB_SCHEMAS;
-    if (!config)
-        config=SHIB_CONFIG;
+    if (!shar_config)
+        shar_config=getenv("SHIBCONFIG");
+    if (!shar_schemadir)
+        shar_schemadir=getenv("SHIBSCHEMAS");
+    if (!shar_schemadir)
+        shar_schemadir=SHIB_SCHEMAS;
+    if (!shar_config)
+        shar_config=SHIB_CONFIG;
 
     // initialize the shib-target library
     ShibTargetConfig& conf=ShibTargetConfig::getConfig();
-    conf.setFeatures(
-        ShibTargetConfig::Listener |
-        ShibTargetConfig::SessionCache |
-        ShibTargetConfig::Metadata |
-        ShibTargetConfig::Trust |
-        ShibTargetConfig::Credentials |
-        ShibTargetConfig::AAP |
-        ShibTargetConfig::SHARExtensions
+    SPConfig::getConfig().setFeatures(
+        SPConfig::Listener |
+        SPConfig::Caching |
+        SPConfig::Metadata |
+        SPConfig::Trust |
+        SPConfig::Credentials |
+        SPConfig::AAP |
+        SPConfig::OutOfProcess |
+        (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
         );
-    if (!conf.init(schemadir,config))
+    if (!conf.init(shar_schemadir) || !conf.load(shar_config)) {
+        fprintf(stderr, "configuration is invalid, check console for specific problems\n");
         return -2;
+    }
 
-    const IListener* listener=conf.getINI()->getListener();
-    
-    // Create the SHAR listener socket
-    if (!listener->create(sock))
-        return -3;
-
-    // Bind to the proper port
-    if (!listener->bind(sock, unlink_socket==1))
-        return -4;
-
-    // Initialize the SHAR Utilitites
-    SHARUtils::init();
-
-    // Run the listener
-    shar_svc_run(sock, ArrayIterator<ShibRPCProtocols>(protos,1));
-
-    /* Finalize the SHAR, close all clients */
-    SHARUtils::fini();
-    fprintf(stderr, "shar utils finalized\n");
+    if (shar_checkonly)
+        fprintf(stderr, "overall configuration is loadable, check console for non-fatal problems\n");
+    else {
 
-    listener->close(sock);
-    fprintf(stderr, "shib socket closed\n");
+        // Write the pid file
+        if (pidfile) {
+            FILE* pidf = fopen(pidfile, "w");
+            if (pidf) {
+                fprintf(pidf, "%d\n", getpid());
+                fclose(pidf);
+            } else {
+                perror(pidfile);  // keep running though
+            }
+        }
+    
+        // Run the listener
+        if (!conf.getINI()->getListenerService()->run(&shibd_shutdown)) {
+            fprintf(stderr, "listener failed to enter listen loop\n");
+            return -3;
+        }
+    }
 
     conf.shutdown();
-    fprintf(stderr, "shar finished.  bye bye.\n");
+    if (pidfile)
+        unlink(pidfile);
     return 0;
 }