48ac4c4ae02d9154d2ae0bbd58f1acd0c3c30c0f
[shibboleth/sp.git] / shar / shar.cpp
1 /*
2  *  Copyright 2001-2007 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * shar.cpp -- the shibd "main" code.  All the functionality is elsewhere
19  *
20  * Created By:  Derek Atkins <derek@ihtfp.com>
21  *
22  * $Id$
23  */
24
25
26 // eventually we might be able to support autoconf via cygwin...
27 #if defined (_MSC_VER) || defined(__BORLANDC__)
28 # include "config_win32.h"
29 #else
30 # include "config.h"
31 #endif
32
33 #ifdef WIN32
34 # define _CRT_NONSTDC_NO_DEPRECATE 1
35 # define _CRT_SECURE_NO_DEPRECATE 1
36 #endif
37
38 #include <shibsp/SPConfig.h>
39
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #include <sys/select.h>
43 #endif
44
45 #include <stdio.h>
46 #include <signal.h>
47 #include <log4cpp/Category.hh>
48 #include <shibsp/ServiceProvider.h>
49 #include <shibsp/remoting/ListenerService.h>
50 #include <xercesc/util/XMLUniDefs.hpp>
51 #include <xmltooling/XMLToolingConfig.h>
52 #include <xmltooling/util/XMLHelper.h>
53
54 using namespace shibsp;
55 using namespace log4cpp;
56 using namespace xmltooling;
57 using namespace std;
58
59 bool shibd_shutdown = false;
60 const char* shar_config = NULL;
61 const char* shar_schemadir = NULL;
62 bool shar_checkonly = false;
63 static int unlink_socket = 0;
64 const char* pidfile = NULL;
65
66 #ifdef WIN32
67
68 //#include <CRTDBG.H>
69
70 #define nNoMansLandSize 4
71 typedef struct _CrtMemBlockHeader
72 {
73         struct _CrtMemBlockHeader * pBlockHeaderNext;
74         struct _CrtMemBlockHeader * pBlockHeaderPrev;
75         char *                      szFileName;
76         int                         nLine;
77         size_t                      nDataSize;
78         int                         nBlockUse;
79         long                        lRequest;
80         unsigned char               gap[nNoMansLandSize];
81         /* followed by:
82          *  unsigned char           data[nDataSize];
83          *  unsigned char           anotherGap[nNoMansLandSize];
84          */
85 } _CrtMemBlockHeader;
86
87 /*
88 int MyAllocHook(int nAllocType, void *pvData,
89       size_t nSize, int nBlockUse, long lRequest,
90       const unsigned char * szFileName, int nLine)
91 {
92     if ( nBlockUse == _CRT_BLOCK )
93       return( TRUE );
94     if (nAllocType == _HOOK_FREE) {
95         _CrtMemBlockHeader* ptr = (_CrtMemBlockHeader*)(((_CrtMemBlockHeader *)pvData)-1);
96         if (ptr->nDataSize == 8192)
97             fprintf(stderr,"free  request %u size %u\n", ptr->lRequest, ptr->nDataSize);
98     }
99     else if (nAllocType == _HOOK_ALLOC && nSize == 8192)
100         fprintf(stderr,"%s request %u size %u\n", ((nAllocType == _HOOK_ALLOC) ? "alloc" : "realloc"), lRequest, nSize);
101     return (TRUE);
102 }
103 */
104
105 int real_main(int preinit)
106 {
107     SPConfig& conf=SPConfig::getConfig();
108     if (preinit) {
109
110         // Initialize the SP library.
111         conf.setFeatures(
112             SPConfig::Listener |
113             SPConfig::Caching |
114             SPConfig::Metadata |
115             SPConfig::Trust |
116             SPConfig::Credentials |
117             SPConfig::AttributeResolver |
118             SPConfig::OutOfProcess |
119             (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
120             );
121         if (!shar_config)
122             shar_config=getenv("SHIBCONFIG");
123         if (!shar_schemadir)
124             shar_schemadir=getenv("SHIBSCHEMAS");
125         if (!shar_schemadir)
126             shar_schemadir=SHIBSP_SCHEMAS;
127         if (!shar_config)
128             shar_config=SHIBSP_CONFIG;
129         if (!conf.init(shar_schemadir)) {
130             fprintf(stderr, "configuration is invalid, see console for specific problems\n");
131             return -1;
132         }
133         
134         try {
135             fprintf(stderr, "loading configuration file: %s\n", shar_config);
136             static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
137             DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
138             XercesJanitor<DOMDocument> docjanitor(dummydoc);
139             DOMElement* dummy = dummydoc->createElementNS(NULL,path);
140             auto_ptr_XMLCh src(shar_config);
141             dummy->setAttributeNS(NULL,path,src.get());
142     
143             conf.setServiceProvider(conf.ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));
144             conf.getServiceProvider()->init();
145         }
146         catch (exception& ex) {
147             fprintf(stderr, "caught exception while loading configuration: %s\n", ex.what());
148             conf.term();
149             return -2;
150         }
151
152         // If just a test run, bail.
153         if (shar_checkonly) {
154             fprintf(stdout, "overall configuration is loadable, check console for non-fatal problems\n");
155             return 0;
156         }
157     }
158     else {
159
160         //_CrtSetAllocHook(MyAllocHook);
161
162         // Run the listener
163         if (!shar_checkonly) {
164
165             // Run the listener.
166             if (!conf.getServiceProvider()->getListenerService()->run(&shibd_shutdown)) {
167                 fprintf(stderr, "listener failed to enter listen loop\n");
168                 return -3;
169             }
170         }
171
172         conf.term();
173     }
174     return 0;
175 }
176
177 #else
178
179 static void term_handler(int arg)
180 {
181     shibd_shutdown = true;
182 }
183
184 static int setup_signals(void)
185 {
186     struct sigaction sa;
187     memset(&sa, 0, sizeof (sa));
188     sa.sa_handler = SIG_IGN;
189     sa.sa_flags = SA_RESTART;
190
191     if (sigaction(SIGPIPE, &sa, NULL) < 0) {
192         return -1;
193     }
194
195     memset(&sa, 0, sizeof (sa));
196     sa.sa_handler = term_handler;
197     sa.sa_flags = SA_RESTART;
198
199     if (sigaction(SIGHUP, &sa, NULL) < 0) {
200         return -1;
201     }
202     if (sigaction(SIGINT, &sa, NULL) < 0) {
203         return -1;
204     }
205     if (sigaction(SIGQUIT, &sa, NULL) < 0) {
206         return -1;
207     }
208     if (sigaction(SIGTERM, &sa, NULL) < 0) {
209         return -1;
210     }
211     return 0;
212 }
213
214 static void usage(char* whoami)
215 {
216     fprintf(stderr, "usage: %s [-fcdt]\n", whoami);
217     fprintf(stderr, "  -c\tconfig file to use.\n");
218     fprintf(stderr, "  -d\tschema directory to use.\n");
219     fprintf(stderr, "  -t\tcheck configuration file for problems.\n");
220     fprintf(stderr, "  -f\tforce removal of listener socket.\n");
221     fprintf(stderr, "  -p\tpid file to use.\n");
222     fprintf(stderr, "  -h\tprint this help message.\n");
223     exit(1);
224 }
225
226 static int parse_args(int argc, char* argv[])
227 {
228     int opt;
229
230     while ((opt = getopt(argc, argv, "c:d:p:fth")) > 0) {
231         switch (opt) {
232             case 'c':
233                 shar_config=optarg;
234                 break;
235             case 'd':
236                 shar_schemadir=optarg;
237                 break;
238             case 'f':
239                 unlink_socket = 1;
240                 break;
241             case 't':
242                 shar_checkonly=true;
243                 break;
244             case 'p':
245                 pidfile=optarg;
246                 break;
247             default:
248                 return -1;
249         }
250     }
251     return 0;
252 }
253
254 int main(int argc, char *argv[])
255 {
256     if (setup_signals() != 0)
257         return -1;
258
259     if (parse_args(argc, argv) != 0)
260         usage(argv[0]);
261
262     if (!shar_config)
263         shar_config=getenv("SHIBCONFIG");
264     if (!shar_schemadir)
265         shar_schemadir=getenv("SHIBSCHEMAS");
266     if (!shar_schemadir)
267         shar_schemadir=SHIBSP_SCHEMAS;
268     if (!shar_config)
269         shar_config=SHIBSP_CONFIG;
270
271     // initialize the shib-target library
272     SPConfig& conf=SPConfig::getConfig();
273     conf.setFeatures(
274         SPConfig::Listener |
275         SPConfig::Caching |
276         SPConfig::Metadata |
277         SPConfig::Trust |
278         SPConfig::Credentials |
279         SPConfig::AttributeResolver |
280         SPConfig::OutOfProcess |
281         (shar_checkonly ? (SPConfig::InProcess | SPConfig::RequestMapping) : SPConfig::Logging)
282         );
283     if (!conf.init(shar_schemadir)) {
284         fprintf(stderr, "configuration is invalid, check console for specific problems\n");
285         return -1;
286     }
287
288     try {
289         fprintf(stderr, "loading configuration file: %s\n", shar_config);
290         static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
291         DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();
292         XercesJanitor<DOMDocument> docjanitor(dummydoc);
293         DOMElement* dummy = dummydoc->createElementNS(NULL,path);
294         auto_ptr_XMLCh src(shar_config);
295         dummy->setAttributeNS(NULL,path,src.get());
296
297         conf.setServiceProvider(conf.ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));
298         conf.getServiceProvider()->init();
299     }
300     catch (exception& ex) {
301         fprintf(stderr, "caught exception while loading configuration: %s\n", ex.what());
302         conf.term();
303         return -2;
304     }
305
306     if (shar_checkonly)
307         fprintf(stderr, "overall configuration is loadable, check console for non-fatal problems\n");
308     else {
309
310         // Write the pid file
311         if (pidfile) {
312             FILE* pidf = fopen(pidfile, "w");
313             if (pidf) {
314                 fprintf(pidf, "%d\n", getpid());
315                 fclose(pidf);
316             } else {
317                 perror(pidfile);  // keep running though
318             }
319         }
320     
321         // Run the listener
322         if (!conf.getServiceProvider()->getListenerService()->run(&shibd_shutdown)) {
323             fprintf(stderr, "listener failed to enter listen loop\n");
324             return -3;
325         }
326     }
327
328     conf.term();
329     if (pidfile)
330         unlink(pidfile);
331     return 0;
332 }
333
334 #endif