Some disabled memory diagnostics, prepping for patch release.
[shibboleth/cpp-sp.git] / shar / shar.cpp
1 /*
2  *  Copyright 2001-2005 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 SHAR "main" code.  All the functionality is elsewhere
19  *           (in case you want to turn this into a library later).
20  *
21  * Created By:  Derek Atkins <derek@ihtfp.com>
22  *
23  * $Id$
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 HAVE_UNISTD_H
34 #include <unistd.h>
35 #include <sys/select.h>
36 #endif
37
38 #include <stdio.h>
39 #include <errno.h>
40 #include <signal.h>
41
42 #include "shar-utils.h"
43 #include <log4cpp/Category.hh>
44
45
46 using namespace std;
47 using namespace saml;
48 using namespace shibboleth;
49 using namespace shibtarget;
50 using namespace log4cpp;
51
52 #ifndef FD_SETSIZE
53 # define FD_SETSIZE 1024
54 #endif
55
56 extern "C" void shibrpc_prog_2(struct svc_req* rqstp, register SVCXPRT* transp);
57
58 // Declare a "MemoryListener" that our server methods will forward their work to.
59 IListener* g_MemoryListener = NULL;
60
61 int shar_run = 1;
62 const char* shar_config = NULL;
63 const char* shar_schemadir = NULL;
64 bool shar_checkonly = false;
65 static int unlink_socket = 0;
66
67 static bool new_connection(IListener::ShibSocket& listener, const Iterator<ShibRPCProtocols>& protos)
68 {
69     IListener::ShibSocket sock;
70
71     // Accept the connection.
72     if (!ShibTargetConfig::getConfig().getINI()->getListener()->accept(listener, sock))
73         return false;
74
75     // We throw away the result because the children manage themselves...
76     try {
77         new SharChild(sock,protos);
78     }
79     catch (...) {
80         saml::NDC ndc("new_connection");
81         Category& log=Category::getInstance("shibd");
82         log.crit("error starting new child thread to service request");
83         return false;
84     }
85     return true;
86 }
87
88 static void shar_svc_run(IListener::ShibSocket& listener, const Iterator<ShibRPCProtocols>& protos)
89 {
90 #ifdef _DEBUG
91     saml::NDC ndc("shar_svc_run");
92 #endif
93     Category& log=Category::getInstance("shibd");
94
95     while (shar_run) {
96         fd_set readfds;
97         FD_ZERO(&readfds);
98         FD_SET(listener, &readfds);
99         struct timeval tv = { 0, 0 };
100         tv.tv_sec = 5;
101     
102         switch (select(listener + 1, &readfds, 0, 0, &tv)) {
103 #ifdef WIN32
104             case SOCKET_ERROR:
105 #else
106             case -1:
107 #endif
108                 if (errno == EINTR) continue;
109                 SHARUtils::log_error();
110                 log.error("select() on main listener socket failed");
111                 return;
112         
113             case 0:
114                 continue;
115         
116             default:
117                 if (!new_connection(listener, protos))
118                     log.crit("new_connection failed");
119         }
120     }
121     log.info("shar_svc_run ended");
122 }
123
124 #ifdef WIN32
125
126 //#include <CRTDBG.H>
127
128 #define nNoMansLandSize 4
129 typedef struct _CrtMemBlockHeader
130 {
131         struct _CrtMemBlockHeader * pBlockHeaderNext;
132         struct _CrtMemBlockHeader * pBlockHeaderPrev;
133         char *                      szFileName;
134         int                         nLine;
135         size_t                      nDataSize;
136         int                         nBlockUse;
137         long                        lRequest;
138         unsigned char               gap[nNoMansLandSize];
139         /* followed by:
140          *  unsigned char           data[nDataSize];
141          *  unsigned char           anotherGap[nNoMansLandSize];
142          */
143 } _CrtMemBlockHeader;
144
145 /*
146 int MyAllocHook(int nAllocType, void *pvData,
147       size_t nSize, int nBlockUse, long lRequest,
148       const unsigned char * szFileName, int nLine)
149 {
150     if ( nBlockUse == _CRT_BLOCK )
151       return( TRUE );
152     if (nAllocType == _HOOK_FREE) {
153         _CrtMemBlockHeader* ptr = (_CrtMemBlockHeader*)(((_CrtMemBlockHeader *)pvData)-1);
154         if (ptr->nDataSize == 8192)
155             fprintf(stderr,"free  request %u size %u\n", ptr->lRequest, ptr->nDataSize);
156     }
157     else if (nAllocType == _HOOK_ALLOC && nSize == 8192)
158         fprintf(stderr,"%s request %u size %u\n", ((nAllocType == _HOOK_ALLOC) ? "alloc" : "realloc"), lRequest, nSize);
159     return (TRUE);
160 }
161 */
162
163 int real_main(int preinit)
164 {
165     static IListener::ShibSocket sock;
166     ShibRPCProtocols protos[1] = {
167         { SHIBRPC_PROG, SHIBRPC_VERS_2, shibrpc_prog_2 }
168     };
169
170     ShibTargetConfig& conf=ShibTargetConfig::getConfig();
171     if (preinit) {
172
173         // initialize the shib-target library
174         conf.setFeatures(
175             ShibTargetConfig::Listener |
176             ShibTargetConfig::Caching |
177             ShibTargetConfig::Metadata |
178             ShibTargetConfig::Trust |
179             ShibTargetConfig::Credentials |
180             ShibTargetConfig::AAP |
181             ShibTargetConfig::GlobalExtensions |
182             (shar_checkonly ? (ShibTargetConfig::LocalExtensions | ShibTargetConfig::RequestMapper) : ShibTargetConfig::Logging)
183             );
184         if (!shar_config)
185             shar_config=getenv("SHIBCONFIG");
186         if (!shar_schemadir)
187             shar_schemadir=getenv("SHIBSCHEMAS");
188         if (!shar_schemadir)
189             shar_schemadir=SHIB_SCHEMAS;
190         if (!shar_config)
191             shar_config=SHIB_CONFIG;
192         if (!conf.init(shar_schemadir) || !conf.load(shar_config)) {
193             fprintf(stderr, "configuration is invalid, see console for specific problems\n");
194             return -2;
195         }
196
197         // If just a test run, bail.
198         if (shar_checkonly) {
199             fprintf(stdout, "overall configuration is loadable, check console for non-fatal problems\n");
200             return 0;
201         }
202         
203         // Build an internal "listener" to handle the work.
204         IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(shibtarget::XML::MemoryListenerType,NULL);
205         g_MemoryListener=dynamic_cast<IListener*>(plugin);
206         if (!g_MemoryListener) {
207             delete plugin;
208             fprintf(stderr, "MemoryListener plugin failed to load");
209             conf.shutdown();
210             return -3;
211         }
212
213         const IListener* listener=conf.getINI()->getListener();
214         
215         // Create the SHAR listener socket
216         if (!listener->create(sock)) {
217             delete g_MemoryListener;
218             conf.shutdown();
219             return -4;
220         }
221
222         // Bind to the proper port
223         if (!listener->bind(sock)) {
224             delete g_MemoryListener;
225             conf.shutdown();
226             return -5;
227         }
228
229         // Initialize the SHAR Utilitites
230         SHARUtils::init();
231     }
232     else {
233
234         //_CrtSetAllocHook(MyAllocHook);
235
236         // Run the listener
237         if (!shar_checkonly) {
238             shar_svc_run(sock, ArrayIterator<ShibRPCProtocols>(protos,1));
239             fprintf(stdout,"shar_svc_run returned\n");
240
241             // Finalize the SHAR, close all clients
242             SHARUtils::fini();
243             conf.getINI()->getListener()->close(sock);
244         }
245
246         delete g_MemoryListener;
247         conf.shutdown();
248         fprintf(stdout, "shibd shutdown complete\n");
249     }
250     return 0;
251 }
252
253 #else
254
255 static void term_handler(int arg)
256 {
257     shar_run = 0;
258 }
259
260 static int setup_signals(void)
261 {
262     NDC ndc("setup_signals");
263     
264     struct sigaction sa;
265     memset(&sa, 0, sizeof (sa));
266     sa.sa_handler = SIG_IGN;
267     sa.sa_flags = SA_RESTART;
268
269     if (sigaction(SIGPIPE, &sa, NULL) < 0) {
270         SHARUtils::log_error();
271         return -1;
272     }
273
274     memset(&sa, 0, sizeof (sa));
275     sa.sa_handler = term_handler;
276     sa.sa_flags = SA_RESTART;
277
278     if (sigaction(SIGHUP, &sa, NULL) < 0) {
279         SHARUtils::log_error();
280         return -1;
281     }
282     if (sigaction(SIGINT, &sa, NULL) < 0) {
283         SHARUtils::log_error();
284         return -1;
285     }
286     if (sigaction(SIGQUIT, &sa, NULL) < 0) {
287         SHARUtils::log_error();
288         return -1;
289     }
290     if (sigaction(SIGTERM, &sa, NULL) < 0) {
291         SHARUtils::log_error();
292         return -1;
293     }
294     return 0;
295 }
296
297 static void usage(char* whoami)
298 {
299     fprintf(stderr, "usage: %s [-fcdt]\n", whoami);
300     fprintf(stderr, "  -c\tconfig file to use.\n");
301     fprintf(stderr, "  -d\tschema directory to use.\n");
302     fprintf(stderr, "  -t\tcheck configuration file for problems.\n");
303     fprintf(stderr, "  -f\tforce removal of listener socket.\n");
304     fprintf(stderr, "  -h\tprint this help message.\n");
305     exit(1);
306 }
307
308 static int parse_args(int argc, char* argv[])
309 {
310     int opt;
311
312     while ((opt = getopt(argc, argv, "c:d:fth")) > 0) {
313         switch (opt) {
314             case 'c':
315                 shar_config=optarg;
316                 break;
317             case 'd':
318                 shar_schemadir=optarg;
319                 break;
320             case 'f':
321                 unlink_socket = 1;
322                 break;
323             case 't':
324                 shar_checkonly=true;
325                 break;
326             default:
327                 return -1;
328         }
329     }
330     return 0;
331 }
332
333 int main(int argc, char *argv[])
334 {
335     IListener::ShibSocket sock;
336     ShibRPCProtocols protos[] = {
337         { SHIBRPC_PROG, SHIBRPC_VERS_2, shibrpc_prog_2 }
338     };
339
340     if (setup_signals() != 0)
341         return -1;
342
343     if (parse_args(argc, argv) != 0)
344         usage(argv[0]);
345
346     if (!shar_config)
347         shar_config=getenv("SHIBCONFIG");
348     if (!shar_schemadir)
349         shar_schemadir=getenv("SHIBSCHEMAS");
350     if (!shar_schemadir)
351         shar_schemadir=SHIB_SCHEMAS;
352     if (!shar_config)
353         shar_config=SHIB_CONFIG;
354
355     // initialize the shib-target library
356     ShibTargetConfig& conf=ShibTargetConfig::getConfig();
357     conf.setFeatures(
358         ShibTargetConfig::Listener |
359         ShibTargetConfig::Caching |
360         ShibTargetConfig::Metadata |
361         ShibTargetConfig::Trust |
362         ShibTargetConfig::Credentials |
363         ShibTargetConfig::AAP |
364         ShibTargetConfig::GlobalExtensions |
365         (shar_checkonly ? (ShibTargetConfig::LocalExtensions | ShibTargetConfig::RequestMapper) : ShibTargetConfig::Logging)
366         );
367     if (!conf.init(shar_schemadir) || !conf.load(shar_config)) {
368         fprintf(stderr, "configuration is invalid, check console for specific problems\n");
369         return -2;
370     }
371
372     if (shar_checkonly)
373         fprintf(stderr, "overall configuration is loadable, check console for non-fatal problems\n");
374     else {
375
376         // Build an internal "listener" to handle the work.
377         IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(shibtarget::XML::MemoryListenerType,NULL);
378         g_MemoryListener=dynamic_cast<IListener*>(plugin);
379         if (!g_MemoryListener) {
380             delete plugin;
381             fprintf(stderr, "MemoryListener plugin failed to load");
382             conf.shutdown();
383             return -3;
384         }
385
386         const IListener* listener=conf.getINI()->getListener();
387         
388         // Create the SHAR listener socket
389         if (!listener->create(sock)) {
390             delete g_MemoryListener;
391             conf.shutdown();
392             return -4;
393         }
394     
395         // Bind to the proper port
396         if (!listener->bind(sock, unlink_socket==1)) {
397             delete g_MemoryListener;
398             conf.shutdown();
399             return -5;
400         }
401     
402         // Initialize the SHAR Utilitites
403         SHARUtils::init();
404     
405         // Run the listener
406         shar_svc_run(sock, ArrayIterator<ShibRPCProtocols>(protos,1));
407     
408         /* Finalize the SHAR, close all clients */
409         SHARUtils::fini();
410         fprintf(stderr, "shar utils finalized\n");
411     
412         listener->close(sock);
413         fprintf(stderr, "shib socket closed\n");
414     }
415
416     conf.shutdown();
417     fprintf(stderr, "shibd shutdown complete\n");
418     return 0;
419 }
420
421 #endif