source: branches/prototype-v0/zoo-project/zoo-kernel/zoo_service_loader.c @ 873

Last change on this file since 873 was 873, checked in by djay, 6 years ago

Add support for R language and its documentation.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 73.1 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 *  Copyright 2008-2013 GeoLabs SARL. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 
25extern "C" int yylex ();
26extern "C" int crlex ();
27
28#ifdef META_DB
29#include "ogrsf_frmts.h"
30#if GDAL_VERSION_MAJOR >= 2
31#include <gdal_priv.h>
32#endif
33#endif
34
35#ifdef USE_OTB
36#include "service_internal_otb.h"
37#endif
38
39#ifdef USE_R
40#include "service_internal_r.h"
41#endif
42
43#ifdef USE_HPC
44#include "service_internal_hpc.h"
45#endif
46
47#include "cgic.h"
48
49#include <libxml/tree.h>
50#include <libxml/xmlmemory.h>
51#include <libxml/parser.h>
52#include <libxml/xpath.h>
53#include <libxml/xpathInternals.h>
54
55#include "ulinet.h"
56
57#include <libintl.h>
58#include <locale.h>
59#include <string.h>
60
61#include "service.h"
62
63#include "service_internal.h"
64#include "server_internal.h"
65#include "response_print.h"
66#include "request_parser.h"
67#include "sqlapi.h"
68#ifdef WIN32
69#include "caching.h"
70#endif
71
72#ifdef META_DB
73#include "meta_sql.h"
74#endif
75
76#ifdef USE_PYTHON
77#include "service_internal_python.h"
78#endif
79
80#ifdef USE_SAGA
81#include "service_internal_saga.h"
82#endif
83
84#ifdef USE_JAVA
85#include "service_internal_java.h"
86#endif
87
88#ifdef USE_PHP
89#include "service_internal_php.h"
90#endif
91
92#ifdef USE_JS
93#include "service_internal_js.h"
94#endif
95
96#ifdef USE_RUBY
97#include "service_internal_ruby.h"
98#endif
99
100#ifdef USE_PERL
101#include "service_internal_perl.h"
102#endif
103
104#ifdef USE_MONO
105#include "service_internal_mono.h"
106#endif
107
108#include "service_json.h"
109#include "service_callback.h"
110
111#include <dirent.h>
112#include <signal.h>
113#include <execinfo.h>
114#include <unistd.h>
115#ifndef WIN32
116#include <dlfcn.h>
117#include <libgen.h>
118#else
119#include <windows.h>
120#include <direct.h>
121#include <sys/types.h>
122#include <sys/stat.h>
123#include <unistd.h>
124#define pid_t int;
125#endif
126#include <fcntl.h>
127#include <time.h>
128#include <stdarg.h>
129
130#include <libxml/tree.h>
131#include <libxml/parser.h>
132#include <libxml/xpath.h>
133#include <libxml/xpathInternals.h>
134
135#include <libxslt/xslt.h>
136#include <libxslt/xsltInternals.h>
137#include <libxslt/transform.h>
138#include <libxslt/xsltutils.h>
139
140#ifndef WIN32
141extern char **environ;
142#endif
143
144
145#ifdef WIN32
146extern "C"
147{
148  __declspec (dllexport) char *strcasestr (char const *a, char const *b)
149#ifndef USE_MS
150  {
151    char *x = zStrdup (a);
152    char *y = zStrdup (b);
153
154      x = _strlwr (x);
155      y = _strlwr (y);
156    char *pos = strstr (x, y);
157    char *ret = pos == NULL ? NULL : (char *) (a + (pos - x));
158      free (x);
159      free (y);
160      return ret;
161  };
162#else
163   ;
164#endif
165}
166#endif
167
168/**
169 * Translation function for zoo-kernel
170 */
171#define _(String) dgettext ("zoo-kernel",String)
172/**
173 * Translation function for zoo-service
174 */
175#define __(String) dgettext ("zoo-service",String)
176
177#ifdef WIN32
178#ifndef PROGRAMNAME
179#define PROGRAMNAME "zoo_loader.cgi"
180#endif
181#endif
182
183
184/**
185 * Replace a char by another one in a string
186 *
187 * @param str the string to update
188 * @param toReplace the char to replace
189 * @param toReplaceBy the char that will be used
190 */
191void
192translateChar (char *str, char toReplace, char toReplaceBy)
193{
194  int i = 0, len = strlen (str);
195  for (i = 0; i < len; i++)
196    {
197      if (str[i] == toReplace)
198        str[i] = toReplaceBy;
199    }
200}
201
202/**
203 * Dump back the final file fbkp1 to fbkp
204 *
205 * @param m the conf maps containing the main.cfg settings
206 * @param fbkp the string corresponding to the name of the file
207 * @param fbkp1 the string corresponding to the name of the file
208 */
209int dumpBackFinalFile(maps* m,char* fbkp,char* fbkp1)
210{
211  FILE *f2 = fopen (fbkp1, "rb");
212#ifndef RELY_ON_DB
213  semid lid = getShmLockId (m, 1);
214  if (lid < 0)
215    return -1;
216  lockShm (lid);
217#endif
218  FILE *f3 = fopen (fbkp, "wb+");
219  free (fbkp);
220  fseek (f2, 0, SEEK_END);
221  long flen = ftell (f2);
222  fseek (f2, 0, SEEK_SET);
223  char *tmps1 = (char *) malloc ((flen + 1) * sizeof (char));
224  fread (tmps1, flen, 1, f2);
225#ifdef WIN32
226  char *pchr=strrchr(tmps1,'>');
227  flen=strlen(tmps1)-strlen(pchr)+1;
228  tmps1[flen]=0;
229#endif
230  fwrite (tmps1, 1, flen, f3);
231  fclose (f2);
232  fclose (f3);
233  free(tmps1);
234  return 1;
235}
236
237/**
238 * Recursivelly parse zcfg starting from the ZOO-Kernel cwd.
239 * Call the func function given in arguments after parsing the ZCFG file.
240 *
241 * @param m the conf maps containing the main.cfg settings
242 * @param r the registry containing profiles hierarchy
243 * @param n the root XML Node to add the sub-elements
244 * @param conf_dir the location of the main.cfg file (basically cwd)
245 * @param prefix the current prefix if any, or NULL
246 * @param saved_stdout the saved stdout identifier
247 * @param level the current level (number of sub-directories to reach the
248 * current path)
249 * @param func a pointer to a function having 4 parameters
250 *  (registry*, maps*, xmlNodePtr and service*).
251 * @see inheritance, readServiceFile
252 */
253int
254recursReaddirF ( maps * m, registry *r, xmlDocPtr doc, xmlNodePtr n, char *conf_dir, 
255                 char *prefix, int saved_stdout, int level, 
256                 void (func) (registry *, maps *, xmlDocPtr, xmlNodePtr, service *) )
257{
258  struct dirent *dp;
259  int scount = 0;
260
261  if (conf_dir == NULL)
262    return 1;
263  DIR *dirp = opendir (conf_dir);
264  if (dirp == NULL)
265    {
266      if (level > 0)
267        return 1;
268      else
269        return -1;
270    }
271  char tmp1[25];
272  sprintf (tmp1, "sprefix_%d", level);
273  char levels[17];
274  sprintf (levels, "%d", level);
275  setMapInMaps (m, "lenv", "level", levels);
276  while ((dp = readdir (dirp)) != NULL)
277    if ((dp->d_type == DT_DIR || dp->d_type == DT_LNK) && dp->d_name[0] != '.'
278        && strstr (dp->d_name, ".") == NULL)
279      {
280
281        char *tmp =
282          (char *) malloc ((strlen (conf_dir) + strlen (dp->d_name) + 2) *
283                           sizeof (char));
284        sprintf (tmp, "%s/%s", conf_dir, dp->d_name);
285
286        if (prefix != NULL)
287          {
288            prefix = NULL;
289          }
290        prefix = (char *) malloc ((strlen (dp->d_name) + 2) * sizeof (char));
291        sprintf (prefix, "%s.", dp->d_name);
292
293        //map* tmpMap=getMapFromMaps(m,"lenv",tmp1);
294
295        int res;
296        if (prefix != NULL)
297          {
298            setMapInMaps (m, "lenv", tmp1, prefix);
299            char levels1[17];
300            sprintf (levels1, "%d", level + 1);
301            setMapInMaps (m, "lenv", "level", levels1);
302            res =
303              recursReaddirF (m, r, doc, n, tmp, prefix, saved_stdout, level + 1,
304                              func);
305            sprintf (levels1, "%d", level);
306            setMapInMaps (m, "lenv", "level", levels1);
307            free (prefix);
308            prefix = NULL;
309          }
310        else
311          res = -1;
312        free (tmp);
313        if (res < 0)
314          {
315            return res;
316          }
317      }
318    else
319      {
320        char* extn = strstr(dp->d_name, ".zcfg");
321        if(dp->d_name[0] != '.' && extn != NULL && strlen(extn) == 5 && strlen(dp->d_name)>6)
322          {
323            int t;
324            char tmps1[1024];
325            memset (tmps1, 0, 1024);
326            snprintf (tmps1, 1024, "%s/%s", conf_dir, dp->d_name);
327
328            char *tmpsn = (char*)malloc((strlen(dp->d_name)-4)*sizeof(char));//zStrdup (dp->d_name);
329            memset (tmpsn, 0, strlen(dp->d_name)-4);
330            snprintf(tmpsn,strlen(dp->d_name)-4,"%s",dp->d_name);
331           
332            map* import = getMapFromMaps (m, IMPORTSERVICE, tmpsn);
333            if (import == NULL || import->value == NULL || zoo_path_compare(tmps1, import->value) != 0 ) { // service is not in [include] block
334              service *s1 = (service *) malloc (SERVICE_SIZE);
335              if (s1 == NULL)
336                {
337                  dup2 (saved_stdout, fileno (stdout));
338                  errorException (m, _("Unable to allocate memory"),
339                                  "InternalError", NULL);
340                  return -1;
341                }
342  #ifdef DEBUG
343              fprintf (stderr, "#################\n%s\n#################\n",
344                       tmps1);
345  #endif
346              t = readServiceFile (m, tmps1, &s1, tmpsn);
347              free (tmpsn);
348              if (t < 0)
349                {
350                  map *tmp00 = getMapFromMaps (m, "lenv", "message");
351                  char tmp01[1024];
352                  if (tmp00 != NULL)
353                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"),
354                             dp->d_name, tmp00->value);
355                  else
356                    sprintf (tmp01, _("Unable to parse the ZCFG file: %s."),
357                             dp->d_name);
358                  dup2 (saved_stdout, fileno (stdout));
359                  errorException (m, tmp01, "InternalError", NULL);
360                  return -1;
361                }
362  #ifdef DEBUG
363              dumpService (s1);
364              fflush (stdout);
365              fflush (stderr);
366  #endif
367              inheritance(r,&s1);
368              func (r, m, doc, n, s1);
369              freeService (&s1);
370              free (s1);
371              scount++;
372            }
373          }
374      }
375  (void) closedir (dirp);
376  return 1;
377}
378
379/**
380 * Signal handling function which simply call exit(0).
381 *
382 * @param sig the signal number
383 */
384void
385donothing (int sig)
386{
387#ifdef DEBUG
388  fprintf (stderr, "Signal %d after the ZOO-Kernel returned result!\n", sig);
389#endif
390  exit (0);
391}
392
393/**
394 * Signal handling function which create an ExceptionReport node containing the
395 * information message corresponding to the signal number.
396 *
397 * @param sig the signal number
398 */
399void
400sig_handler (int sig)
401{
402 
403  char tmp[100];
404  const char *ssig;
405  switch (sig)
406    {
407    case SIGSEGV:
408      ssig = "SIGSEGV";
409      break;
410    case SIGTERM:
411      ssig = "SIGTERM";
412      break;
413    case SIGINT:
414      ssig = "SIGINT";
415      break;
416    case SIGILL:
417      ssig = "SIGILL";
418      break;
419    case SIGFPE:
420      ssig = "SIGFPE";
421      break;
422    case SIGABRT:
423      ssig = "SIGABRT";
424      break;
425    default:
426      ssig = "UNKNOWN";
427      break;
428    }
429  sprintf (tmp,
430           _
431           ("ZOO Kernel failed to process your request, receiving signal %d = %s "),
432           sig, ssig);
433  errorException (NULL, tmp, "InternalError", NULL);
434#ifdef DEBUG
435  fprintf (stderr, "Not this time!\n");
436#endif
437  exit (0);
438}
439
440/**
441 * Load a service provider and run the service function.
442 *
443 * @param myMap the conf maps containing the main.cfg settings
444 * @param s1 the service structure
445 * @param request_inputs map storing all the request parameters
446 * @param inputs the inputs maps
447 * @param ioutputs the outputs maps
448 * @param eres the result returned by the service execution
449 */
450void
451loadServiceAndRun (maps ** myMap, service * s1, map * request_inputs,
452                   maps ** inputs, maps ** ioutputs, int *eres)
453{
454  char tmps1[1024];
455  char ntmp[1024];
456  maps *m = *myMap;
457  maps *request_output_real_format = *ioutputs;
458  maps *request_input_real_format = *inputs;
459  /**
460   * Extract serviceType to know what kind of service should be loaded
461   */
462  map *r_inputs = NULL;
463  map* cwdMap=getMapFromMaps(m,"main","servicePath");
464  if(cwdMap!=NULL){
465    sprintf(ntmp,"%s",cwdMap->value);
466  }else{
467#ifndef WIN32
468    getcwd (ntmp, 1024);
469#else
470    _getcwd (ntmp, 1024);
471#endif
472  }
473  r_inputs = getMap (s1->content, "serviceType");
474#ifdef DEBUG
475  fprintf (stderr, "LOAD A %s SERVICE PROVIDER \n", r_inputs->value);
476  fflush (stderr);
477#endif
478
479  map* libp = getMapFromMaps(m, "main", "libPath");
480
481  if (strlen (r_inputs->value) == 1
482      && strncasecmp (r_inputs->value, "C", 1) == 0)
483  {
484     if (libp != NULL && libp->value != NULL) {
485            r_inputs = getMap (s1->content, "ServiceProvider");
486                sprintf (tmps1, "%s/%s", libp->value, r_inputs->value);
487         }
488     else {     
489        r_inputs = getMap (request_inputs, "metapath");
490        if (r_inputs != NULL)
491          sprintf (tmps1, "%s/%s", ntmp, r_inputs->value);
492        else
493          sprintf (tmps1, "%s/", ntmp);
494         
495        char *altPath = zStrdup (tmps1);
496        r_inputs = getMap (s1->content, "ServiceProvider");
497        sprintf (tmps1, "%s/%s", altPath, r_inputs->value);
498        free (altPath);
499         }
500#ifdef DEBUG
501      fprintf (stderr, "Trying to load %s\n", tmps1);
502#endif
503#ifdef WIN32
504      HINSTANCE so =
505        LoadLibraryEx (tmps1, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
506#else
507      void *so = dlopen (tmps1, RTLD_LAZY);
508#endif
509#ifdef WIN32
510      char* errstr = getLastErrorMessage();
511#else
512      char *errstr;
513      errstr = dlerror ();
514#endif
515#ifdef DEBUG
516          fprintf (stderr, "%s loaded (%s) \n", tmps1, errstr);
517#endif
518      if (so != NULL)
519        {
520#ifdef DEBUG
521          fprintf (stderr, "Library loaded %s \n", errstr);
522          fprintf (stderr, "Service Shared Object = %s\n", r_inputs->value);
523#endif
524          r_inputs = getMap (s1->content, "serviceType");
525#ifdef DEBUG
526          dumpMap (r_inputs);
527          fprintf (stderr, "%s\n", r_inputs->value);
528          fflush (stderr);
529#endif
530          if (strncasecmp (r_inputs->value, "C-FORTRAN", 9) == 0)
531            {
532              r_inputs = getMap (request_inputs, "Identifier");
533              char fname[1024];
534              sprintf (fname, "%s_", r_inputs->value);
535#ifdef DEBUG
536              fprintf (stderr, "Try to load function %s\n", fname);
537#endif
538#ifdef WIN32
539              typedef int (CALLBACK * execute_t) (char ***, char ***,
540                                                  char ***);
541              execute_t execute = (execute_t) GetProcAddress (so, fname);
542#else
543              typedef int (*execute_t) (char ***, char ***, char ***);
544              execute_t execute = (execute_t) dlsym (so, fname);
545#endif
546#ifdef DEBUG
547#ifdef WIN32
548                          errstr = getLastErrorMessage();
549#else
550              errstr = dlerror ();
551#endif
552              fprintf (stderr, "Function loaded %s\n", errstr);
553#endif
554
555              char main_conf[10][30][1024];
556              char inputs[10][30][1024];
557              char outputs[10][30][1024];
558              for (int i = 0; i < 10; i++)
559                {
560                  for (int j = 0; j < 30; j++)
561                    {
562                      memset (main_conf[i][j], 0, 1024);
563                      memset (inputs[i][j], 0, 1024);
564                      memset (outputs[i][j], 0, 1024);
565                    }
566                }
567              mapsToCharXXX (m, (char ***) main_conf);
568              mapsToCharXXX (request_input_real_format, (char ***) inputs);
569              mapsToCharXXX (request_output_real_format, (char ***) outputs);
570              *eres =
571                execute ((char ***) &main_conf[0], (char ***) &inputs[0],
572                         (char ***) &outputs[0]);
573#ifdef DEBUG
574              fprintf (stderr, "Function run successfully \n");
575#endif
576              charxxxToMaps ((char ***) &outputs[0],
577                             &request_output_real_format);
578            }
579          else
580            {
581#ifdef DEBUG
582#ifdef WIN32
583                          errstr = getLastErrorMessage();
584              fprintf (stderr, "Function %s failed to load because of %s\n",
585                       r_inputs->value, errstr);
586#endif
587#endif
588              r_inputs = getMapFromMaps (m, "lenv", "Identifier");
589#ifdef DEBUG
590              fprintf (stderr, "Try to load function %s\n", r_inputs->value);
591#endif
592              typedef int (*execute_t) (maps **, maps **, maps **);
593#ifdef WIN32
594              execute_t execute =
595                (execute_t) GetProcAddress (so, r_inputs->value);
596#else
597              execute_t execute = (execute_t) dlsym (so, r_inputs->value);
598#endif
599
600              if (execute == NULL)
601                {
602#ifdef WIN32
603                                  errstr = getLastErrorMessage();
604#else
605                  errstr = dlerror ();
606#endif
607                  char *tmpMsg =
608                    (char *) malloc (2048 + strlen (r_inputs->value));
609                  sprintf (tmpMsg,
610                           _
611                           ("Error occurred while running the %s function: %s"),
612                           r_inputs->value, errstr);
613                  errorException (m, tmpMsg, "InternalError", NULL);
614                  free (tmpMsg);
615#ifdef DEBUG
616                  fprintf (stderr, "Function %s error %s\n", r_inputs->value,
617                           errstr);
618#endif
619                  *eres = -1;
620                  return;
621                }
622
623#ifdef DEBUG
624#ifdef WIN32
625                          errstr = getLastErrorMessage();
626#else
627              errstr = dlerror ();
628#endif
629              fprintf (stderr, "Function loaded %s\n", errstr);
630#endif
631
632#ifdef DEBUG
633              fprintf (stderr, "Now run the function \n");
634              fflush (stderr);
635#endif
636              *eres =
637                execute (&m, &request_input_real_format,
638                         &request_output_real_format);
639#ifdef DEBUG
640              fprintf (stderr, "Function loaded and returned %d\n", eres);
641              fflush (stderr);
642#endif
643            }
644#ifdef WIN32
645          *ioutputs = dupMaps (&request_output_real_format);
646          FreeLibrary (so);
647#else
648          dlclose (so);
649#endif
650        }
651      else
652        {
653      /**
654       * Unable to load the specified shared library
655       */
656          char tmps[1024];
657#ifdef WIN32
658                  errstr = getLastErrorMessage();
659#else
660              errstr = dlerror ();
661#endif
662          sprintf (tmps, _("Unable to load C Library %s"), errstr);
663          errorException(m,tmps,"InternalError",NULL);
664          *eres = -1;
665        }
666    }
667  else
668
669#ifdef USE_HPC
670  if (strncasecmp (r_inputs->value, "HPC", 3) == 0)
671    {
672      *eres =
673        zoo_hpc_support (&m, request_inputs, s1,
674                            &request_input_real_format,
675                            &request_output_real_format);
676    }
677  else
678#endif
679
680#ifdef USE_SAGA
681  if (strncasecmp (r_inputs->value, "SAGA", 4) == 0)
682    {
683      *eres =
684        zoo_saga_support (&m, request_inputs, s1,
685                            &request_input_real_format,
686                            &request_output_real_format);
687    }
688  else
689#endif
690
691#ifdef USE_OTB
692  if (strncasecmp (r_inputs->value, "OTB", 3) == 0)
693    {
694      *eres =
695        zoo_otb_support (&m, request_inputs, s1,
696                            &request_input_real_format,
697                            &request_output_real_format);
698    }
699  else
700#endif
701#ifdef USE_PYTHON
702  if (strncasecmp (r_inputs->value, "PYTHON", 6) == 0)
703    {     
704      *eres =
705        zoo_python_support (&m, request_inputs, s1,
706                            &request_input_real_format,
707                            &request_output_real_format);
708    }
709  else
710#endif
711
712#ifdef USE_R
713  if (strncasecmp (r_inputs->value, "R", 6) == 0)
714    {     
715      *eres =
716        zoo_r_support (&m, request_inputs, s1,
717                            &request_input_real_format,
718                            &request_output_real_format);
719    }
720  else
721#endif
722
723#ifdef USE_JAVA
724  if (strncasecmp (r_inputs->value, "JAVA", 4) == 0)
725    {
726      *eres =
727        zoo_java_support (&m, request_inputs, s1, &request_input_real_format,
728                          &request_output_real_format);
729    }
730  else
731#endif
732
733#ifdef USE_PHP
734  if (strncasecmp (r_inputs->value, "PHP", 3) == 0)
735    {
736      *eres =
737        zoo_php_support (&m, request_inputs, s1, &request_input_real_format,
738                         &request_output_real_format);         
739    }
740  else
741#endif
742
743
744#ifdef USE_PERL
745  if (strncasecmp (r_inputs->value, "PERL", 4) == 0)
746    {
747      *eres =
748        zoo_perl_support (&m, request_inputs, s1, &request_input_real_format,
749                          &request_output_real_format);
750    }
751  else
752#endif
753
754#ifdef USE_JS
755  if (strncasecmp (r_inputs->value, "JS", 2) == 0)
756    {
757      *eres =
758        zoo_js_support (&m, request_inputs, s1, &request_input_real_format,
759                        &request_output_real_format);
760    }
761  else
762#endif
763
764#ifdef USE_RUBY
765  if (strncasecmp (r_inputs->value, "Ruby", 4) == 0)
766    {
767      *eres =
768        zoo_ruby_support (&m, request_inputs, s1, &request_input_real_format,
769                          &request_output_real_format);
770    }
771  else
772#endif
773
774#ifdef USE_MONO
775  if (strncasecmp (r_inputs->value, "Mono", 4) == 0)
776    {
777      *eres =
778        zoo_mono_support (&m, request_inputs, s1, &request_input_real_format,
779                          &request_output_real_format);
780    }
781  else
782#endif
783
784    {
785      char tmpv[1024];
786      sprintf (tmpv,
787               _
788               ("Programming Language (%s) set in ZCFG file is not currently supported by ZOO Kernel.\n"),
789               r_inputs->value);
790      errorException (m, tmpv, "InternalError", NULL);
791      *eres = -1;
792    }
793  *myMap = m;
794  *ioutputs = request_output_real_format;
795}
796
797
798#ifdef WIN32
799/**
800 * createProcess function: create a new process after setting some env variables
801 */
802void
803createProcess (maps * m, map * request_inputs, service * s1, char *opts,
804               int cpid, maps * inputs, maps * outputs)
805{
806  STARTUPINFO si;
807  PROCESS_INFORMATION pi;
808  ZeroMemory (&si, sizeof (si));
809  si.cb = sizeof (si);
810  ZeroMemory (&pi, sizeof (pi));
811  char *tmp = (char *) malloc ((1024 + cgiContentLength) * sizeof (char));
812  char *tmpq = (char *) malloc ((1024 + cgiContentLength) * sizeof (char));
813  map *req = getMap (request_inputs, "request");
814  map *id = getMap (request_inputs, "identifier");
815  map *di = getMap (request_inputs, "DataInputs");
816
817  // The required size for the dataInputsKVP and dataOutputsKVP buffers
818  // may exceed cgiContentLength, hence a 2 kb extension. However, a
819  // better solution would be to have getMapsAsKVP() determine the required
820  // buffer size before allocating memory.     
821  char *dataInputsKVP = getMapsAsKVP (inputs, cgiContentLength + 2048, 0);
822  char *dataOutputsKVP = getMapsAsKVP (outputs, cgiContentLength + 2048, 1);
823#ifdef DEBUG
824  fprintf (stderr, "DATAINPUTSKVP %s\n", dataInputsKVP);
825  fprintf (stderr, "DATAOUTPUTSKVP %s\n", dataOutputsKVP);
826#endif
827  map *sid = getMapFromMaps (m, "lenv", "osid");
828  map *usid = getMapFromMaps (m, "lenv", "usid");
829  map *r_inputs = getMapFromMaps (m, "main", "tmpPath");
830  map *r_inputs1 = getMap (request_inputs, "metapath");
831 
832  int hasIn = -1;
833  if (r_inputs1 == NULL)
834    {
835      r_inputs1 = createMap ("metapath", "");
836      hasIn = 1;
837    }
838  map *r_inputs2 = getMap (request_inputs, "ResponseDocument");
839  if (r_inputs2 == NULL)
840    r_inputs2 = getMap (request_inputs, "RawDataOutput");
841  map *tmpPath = getMapFromMaps (m, "lenv", "cwd");
842
843  map *tmpReq = getMap (request_inputs, "xrequest");
844
845  if(r_inputs2 != NULL && tmpReq != NULL) {
846    const char key[] = "rfile=";
847    char* kvp = (char*) malloc((FILENAME_MAX + strlen(key))*sizeof(char));
848    char* filepath = kvp + strlen(key);
849    strncpy(kvp, key, strlen(key));
850    addToCache(m, tmpReq->value, tmpReq->value, "text/xml", strlen(tmpReq->value), 
851               filepath, FILENAME_MAX);
852    if (filepath == NULL) {
853      errorException( m, _("Unable to cache HTTP POST Execute request."), "InternalError", NULL); 
854      return;
855    }   
856    sprintf(tmp,"\"metapath=%s&%s&cgiSid=%s&usid=%s\"",
857            r_inputs1->value,kvp,sid->value,usid->value);
858    sprintf(tmpq,"metapath=%s&%s",
859            r_inputs1->value,kvp);
860    free(kvp); 
861  }
862  else if (r_inputs2 != NULL)
863    {
864      sprintf (tmp,
865               "\"metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&%s=%s&cgiSid=%s&usid=%s\"",
866               r_inputs1->value, req->value, id->value, dataInputsKVP,
867               r_inputs2->name, dataOutputsKVP, sid->value, usid->value);
868      sprintf (tmpq,
869               "metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&%s=%s",
870               r_inputs1->value, req->value, id->value, dataInputsKVP,
871               r_inputs2->name, dataOutputsKVP);                   
872    }
873  else
874    {
875      sprintf (tmp,
876               "\"metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s&cgiSid=%s&usid=%s\"",
877               r_inputs1->value, req->value, id->value, dataInputsKVP,
878               sid->value, usid->value);
879      sprintf (tmpq,
880               "metapath=%s&request=%s&service=WPS&version=1.0.0&Identifier=%s&DataInputs=%s",
881               r_inputs1->value, req->value, id->value, dataInputsKVP,
882               sid->value);   
883    }
884
885  if (hasIn > 0)
886    {
887      freeMap (&r_inputs1);
888      free (r_inputs1);
889    }
890  char *tmp1 = zStrdup (tmp);
891  sprintf (tmp, "\"%s\" %s \"%s\"", PROGRAMNAME, tmp1, sid->value); 
892  free (dataInputsKVP);
893  free (dataOutputsKVP);
894#ifdef DEBUG
895  fprintf (stderr, "REQUEST IS : %s \n", tmp);
896#endif
897
898  usid = getMapFromMaps (m, "lenv", "usid");
899  if (usid != NULL && usid->value != NULL) {
900    SetEnvironmentVariable("USID", TEXT (usid->value));
901  }
902  SetEnvironmentVariable ("CGISID", TEXT (sid->value));
903  SetEnvironmentVariable ("QUERY_STRING", TEXT (tmpq));
904  // knut: Prevent REQUEST_METHOD=POST in background process call to cgic:main
905  // (process hangs when reading cgiIn):
906  SetEnvironmentVariable("REQUEST_METHOD", "GET");
907  SetEnvironmentVariable("CONTENT_TYPE", "text/plain");
908 
909  char clen[1000];
910  sprintf (clen, "%d", strlen (tmpq));
911  SetEnvironmentVariable ("CONTENT_LENGTH", TEXT (clen));
912
913  // ref. https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863%28v=vs.85%29.aspx
914  if (!CreateProcess (NULL,     // No module name (use command line)
915                      TEXT (tmp),       // Command line
916                      NULL,     // Process handle not inheritable
917                      NULL,     // Thread handle not inheritable
918                      FALSE,    // Set handle inheritance to FALSE
919                      CREATE_NO_WINDOW, // Apache won't wait until the end
920                      NULL,     // Use parent's environment block
921                      NULL,     // Use parent's starting directory
922                      &si,      // Pointer to STARTUPINFO struct
923                      &pi)      // Pointer to PROCESS_INFORMATION struct
924    )
925    {
926#ifdef DEBUG
927      fprintf (stderr, "CreateProcess failed (%d).\n", GetLastError ());
928#endif
929      if (tmp != NULL) {
930        free(tmp);
931      }
932      if (tmpq != NULL) {
933        free(tmpq);
934      }         
935      return;
936    }
937  else
938    {
939#ifdef DEBUG
940      fprintf (stderr, "CreateProcess successful (%d).\n\n\n\n",
941               GetLastError ());
942#endif
943    }
944  CloseHandle (pi.hProcess);
945  CloseHandle (pi.hThread);
946 
947  if (tmp != NULL) {
948    free(tmp);
949  }
950  if (tmpq != NULL) {
951    free(tmpq);
952  }
953 
954#ifdef DEBUG
955  fprintf (stderr, "CreateProcess finished !\n");
956#endif
957}
958#endif
959
960/**
961 * Process the request.
962 *
963 * @param inputs the request parameters map
964 * @return 0 on sucess, other value on failure
965 * @see conf_read,recursReaddirF
966 */
967int
968runRequest (map ** inputs)
969{
970 
971#ifndef USE_GDB
972#ifndef WIN32
973  signal (SIGCHLD, SIG_IGN);
974#endif 
975  signal (SIGSEGV, sig_handler);
976  signal (SIGTERM, sig_handler);
977  signal (SIGINT, sig_handler);
978  signal (SIGILL, sig_handler);
979  signal (SIGFPE, sig_handler);
980  signal (SIGABRT, sig_handler);
981#endif
982
983 
984  map *r_inputs = NULL;
985  map *request_inputs = *inputs;
986  //fprintf(stderr,"%s \n",json_object_to_json_string_ext(mapToJson(request_inputs),JSON_C_TO_STRING_PLAIN));
987 
988#ifdef IGNORE_METAPATH
989  addToMap(request_inputs, "metapath", "");
990#endif 
991  maps *m = NULL;
992  char *REQUEST = NULL;
993  /**
994   * Parsing service specfic configuration file
995   */
996  m = (maps *) malloc (MAPS_SIZE);
997  if (m == NULL)
998    {
999      return errorException (NULL, _("Unable to allocate memory"),
1000                             "InternalError", NULL);
1001    }
1002  m->child=NULL;
1003  char ntmp[1024];
1004#ifndef ETC_DIR
1005#ifndef WIN32
1006  getcwd (ntmp, 1024);
1007#else
1008  _getcwd (ntmp, 1024);
1009#endif
1010#else
1011  sprintf(ntmp,"%s",ETC_DIR);
1012#endif
1013  r_inputs = getMapOrFill (&request_inputs, "metapath", "");
1014
1015  char conf_file[10240];
1016  snprintf (conf_file, 10240, "%s/%s/main.cfg", ntmp, r_inputs->value);
1017#ifdef ETC_DIR
1018#ifndef WIN32
1019  getcwd (ntmp, 1024);
1020#else
1021  _getcwd (ntmp, 1024);
1022#endif
1023#endif
1024
1025  if (conf_read (conf_file, m) == 2)
1026    {
1027      errorException (NULL, _("Unable to load the main.cfg file."),
1028                      "InternalError", NULL);
1029      free (m);
1030      return 1;
1031    }
1032#ifdef DEBUG
1033  fprintf (stderr, "***** BEGIN MAPS\n");
1034  dumpMaps (m);
1035  fprintf (stderr, "***** END MAPS\n");
1036#endif
1037
1038  map *getPath = getMapFromMaps (m, "main", "gettextPath");
1039  if (getPath != NULL)
1040    {
1041      bindtextdomain ("zoo-kernel", getPath->value);
1042      bindtextdomain ("zoo-services", getPath->value);
1043    }
1044  else
1045    {
1046      bindtextdomain ("zoo-kernel", LOCALEDIR);
1047      bindtextdomain ("zoo-services", LOCALEDIR);
1048    }
1049
1050  /**
1051   * Manage our own error log file (usefull to separate standard apache debug
1052   * messages from the ZOO-Kernel ones but also for IIS users to avoid wrong
1053   * headers messages returned by the CGI due to wrong redirection of stderr)
1054   */
1055  FILE *fstde = NULL;
1056  map *fstdem = getMapFromMaps (m, "main", "logPath");
1057  if (fstdem != NULL)
1058    fstde = freopen (fstdem->value, "a+", stderr);
1059
1060  r_inputs = getMap (request_inputs, "language");
1061  if (r_inputs == NULL)
1062    r_inputs = getMap (request_inputs, "AcceptLanguages");
1063  if (r_inputs == NULL)
1064    r_inputs = getMapFromMaps (m, "main", "language");
1065  if (r_inputs != NULL)
1066    {
1067      if (isValidLang (m, r_inputs->value) < 0)
1068        {
1069          char tmp[1024];
1070          sprintf (tmp,
1071                   _
1072                   ("The value %s is not supported for the <language> parameter"),
1073                   r_inputs->value);
1074          errorException (m, tmp, "InvalidParameterValue", "language");
1075          freeMaps (&m);
1076          free (m);
1077          free (REQUEST);
1078          return 1;
1079
1080        }
1081      char *tmp = zStrdup (r_inputs->value);
1082      setMapInMaps (m, "main", "language", tmp);
1083#ifdef DEB
1084      char tmp2[12];
1085      sprintf (tmp2, "%s.utf-8", tmp);
1086      translateChar (tmp2, '-', '_');
1087      setlocale (LC_ALL, tmp2);
1088#else
1089      translateChar (tmp, '-', '_');
1090      setlocale (LC_ALL, tmp);
1091#endif
1092#ifndef WIN32
1093      setenv ("LC_ALL", tmp, 1);
1094#else
1095      char tmp1[13];
1096      sprintf (tmp1, "LC_ALL=%s", tmp);
1097      putenv (tmp1);
1098#endif
1099      free (tmp);
1100    }
1101  else
1102    {
1103      setlocale (LC_ALL, "en_US");
1104#ifndef WIN32
1105      setenv ("LC_ALL", "en_US", 1);
1106#else
1107      char tmp1[13];
1108      sprintf (tmp1, "LC_ALL=en_US");
1109      putenv (tmp1);
1110#endif
1111      setMapInMaps (m, "main", "language", "en-US");
1112    }
1113  setlocale (LC_NUMERIC, "C");
1114#ifndef WIN32
1115  setenv ("LC_NUMERIC", "C", 1);
1116#else
1117  char tmp1[17];
1118  sprintf (tmp1, "LC_NUMERIC=C");
1119  putenv (tmp1);
1120#endif
1121  bind_textdomain_codeset ("zoo-kernel", "UTF-8");
1122  textdomain ("zoo-kernel");
1123  bind_textdomain_codeset ("zoo-services", "UTF-8");
1124  textdomain ("zoo-services");
1125
1126  map *lsoap = getMap (request_inputs, "soap");
1127  if (lsoap != NULL && strcasecmp (lsoap->value, "true") == 0)
1128    setMapInMaps (m, "main", "isSoap", "true");
1129  else
1130    setMapInMaps (m, "main", "isSoap", "false");
1131
1132  if(strlen(cgiServerName)>0)
1133    {
1134      char tmpUrl[1024];
1135       
1136      if ( getenv("HTTPS") != NULL && strncmp(getenv("HTTPS"), "on", 2) == 0 ) {
1137        // Knut: check if non-empty instead of "on"?           
1138        if ( strncmp(cgiServerPort, "443", 3) == 0 ) { 
1139          sprintf(tmpUrl, "https://%s%s", cgiServerName, cgiScriptName);
1140        }
1141        else {
1142          sprintf(tmpUrl, "https://%s:%s%s", cgiServerName, cgiServerPort, cgiScriptName);
1143        }
1144      }
1145      else {
1146        if ( strncmp(cgiServerPort, "80", 2) == 0 ) { 
1147          sprintf(tmpUrl, "http://%s%s", cgiServerName, cgiScriptName);
1148        }
1149        else {
1150          sprintf(tmpUrl, "http://%s:%s%s", cgiServerName, cgiServerPort, cgiScriptName);
1151        }
1152      }
1153#ifdef DEBUG
1154      fprintf(stderr,"*** %s ***\n",tmpUrl);
1155#endif
1156      setMapInMaps(m,"main","serverAddress",tmpUrl);
1157    }
1158
1159  // CORS Support
1160  if(strncasecmp(cgiRequestMethod,"OPTIONS",7)==0){
1161    map* cors=getMapFromMaps(m,"main","cors");
1162    if(cors!=NULL && strncasecmp(cors->value,"true",4)==0){
1163      char *encoding=getEncoding(m);
1164      printHeaders(m);
1165      printf("Content-Type: text/plain; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
1166      printf(_("CORS is enabled.\r\n"));
1167      freeMaps (&m);
1168      free (m);
1169      fflush (stdout);
1170      return 3;
1171    }
1172  }
1173
1174  //Check for minimum inputs
1175  map* version=getMap(request_inputs,"version");
1176  if(version==NULL)
1177    version=getMapFromMaps(m,"main","version");
1178  setMapInMaps(m,"main","rversion",version->value);
1179  int vid=getVersionId(version->value);
1180  if(vid<0)
1181    vid=0;
1182  map* err=NULL;
1183  const char **vvr=(const char**)requests[vid];
1184  checkValidValue(request_inputs,&err,"request",vvr,1);
1185  const char *vvs[]={
1186    "WPS",
1187    NULL
1188  };
1189  if(err!=NULL){
1190    checkValidValue(request_inputs,&err,"service",(const char**)vvs,1);
1191    printExceptionReportResponse (m, err);
1192    freeMap(&err);
1193    free(err);
1194    if (count (request_inputs) == 1)
1195      {
1196        freeMap (&request_inputs);
1197        free (request_inputs);
1198      }
1199    freeMaps (&m);
1200    free (m);
1201    return 1;
1202  }
1203  checkValidValue(request_inputs,&err,"service",(const char**)vvs,1);
1204
1205  const char *vvv[]={
1206    "1.0.0",
1207    "2.0.0",
1208    NULL
1209  };
1210  r_inputs = getMap (request_inputs, "Request");
1211  if(r_inputs!=NULL)
1212    REQUEST = zStrdup (r_inputs->value);
1213  int reqId=-1;
1214  if (strncasecmp (REQUEST, "GetCapabilities", 15) != 0){
1215    checkValidValue(request_inputs,&err,"version",(const char**)vvv,1);
1216    int j=0;
1217    for(j=0;j<nbSupportedRequests;j++){
1218      if(requests[vid][j]!=NULL && requests[vid][j+1]!=NULL){
1219        if(j<nbReqIdentifier && strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
1220          checkValidValue(request_inputs,&err,"identifier",NULL,1);
1221          reqId=j+1;
1222          break;
1223        }
1224        else
1225          if(j>=nbReqIdentifier && j<nbReqIdentifier+nbReqJob && 
1226             strncasecmp(REQUEST,requests[vid][j+1],strlen(requests[vid][j+1]))==0){
1227            checkValidValue(request_inputs,&err,"jobid",NULL,1);
1228            reqId=j+1;
1229            break;
1230          }
1231      }else
1232        break;
1233    }
1234  }else{
1235    checkValidValue(request_inputs,&err,"AcceptVersions",(const char**)vvv,-1);
1236    map* version1=getMap(request_inputs,"AcceptVersions");
1237    if(version1!=NULL){
1238      if(strstr(version1->value,schemas[1][0])!=NULL)
1239        addToMap(request_inputs,"version",schemas[1][0]);
1240      else
1241        addToMap(request_inputs,"version",version1->value);
1242      version=getMap(request_inputs,"version");
1243      setMapInMaps(m,"main","rversion",version->value);
1244      vid=getVersionId(version->value);
1245    }
1246  }
1247  if(err!=NULL){
1248    printExceptionReportResponse (m, err);
1249    freeMap(&err);
1250    free(err);
1251    if (count (request_inputs) == 1)
1252      {
1253        freeMap (&request_inputs);
1254        free (request_inputs);
1255      }
1256    free(REQUEST);
1257    freeMaps (&m);
1258    free (m);
1259    return 1;
1260  }
1261
1262  r_inputs = getMap (request_inputs, "serviceprovider");
1263  if (r_inputs == NULL)
1264    {
1265      addToMap (request_inputs, "serviceprovider", "");
1266    }
1267
1268  maps *request_output_real_format = NULL;
1269  map *tmpm = getMapFromMaps (m, "main", "serverAddress");
1270  if (tmpm != NULL)
1271    SERVICE_URL = zStrdup (tmpm->value);
1272  else
1273    SERVICE_URL = zStrdup (DEFAULT_SERVICE_URL);
1274
1275
1276
1277  service *s1;
1278  int scount = 0;
1279#ifdef DEBUG
1280  dumpMap (r_inputs);
1281#endif
1282  char conf_dir[1024];
1283  int t;
1284  char tmps1[1024];
1285
1286  r_inputs = NULL;
1287  r_inputs = getMap (request_inputs, "metapath");
1288  map* cwdMap0=getMapFromMaps(m,"main","servicePath");
1289  if (r_inputs != NULL)
1290    if(cwdMap0!=NULL)
1291      snprintf (conf_dir, 1024, "%s/%s", cwdMap0->value, r_inputs->value);
1292    else
1293      snprintf (conf_dir, 1024, "%s/%s", ntmp, r_inputs->value);
1294  else
1295    if(cwdMap0!=NULL)
1296      snprintf (conf_dir, 1024, "%s", cwdMap0->value);
1297    else
1298      snprintf (conf_dir, 1024, "%s", ntmp);
1299  map* reg = getMapFromMaps (m, "main", "registry");
1300  registry* zooRegistry=NULL;
1301  if(reg!=NULL){
1302    int saved_stdout = dup (fileno (stdout));
1303    dup2 (fileno (stderr), fileno (stdout));
1304    if(createRegistry (m,&zooRegistry,reg->value)<0){
1305      map *message=getMapFromMaps(m,"lenv","message");
1306      map *type=getMapFromMaps(m,"lenv","type");
1307      dup2 (saved_stdout, fileno (stdout));
1308      errorException (m, message->value,
1309                      type->value, NULL);
1310      return 0;
1311    }
1312    dup2 (saved_stdout, fileno (stdout));
1313    close(saved_stdout);
1314  }
1315
1316  if (strncasecmp (REQUEST, "GetCapabilities", 15) == 0)
1317    {
1318#ifdef DEBUG
1319      dumpMap (r_inputs);
1320#endif
1321      xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
1322      xmlNodePtr n=printGetCapabilitiesHeader(doc,m,(version!=NULL?version->value:"1.0.0"));
1323      /**
1324       * Here we need to close stdout to ensure that unsupported chars
1325       * has been found in the zcfg and then printed on stdout
1326       */
1327      int saved_stdout = dup (fileno (stdout));
1328      dup2 (fileno (stderr), fileno (stdout));
1329
1330      maps* imports = getMaps(m, IMPORTSERVICE);
1331      if (imports != NULL) {       
1332        map* zcfg = imports->content;
1333       
1334        while (zcfg != NULL) {
1335          if (zcfg->value != NULL) {
1336            service* svc = (service*) malloc(SERVICE_SIZE);
1337            if (svc == NULL || readServiceFile(m, zcfg->value, &svc, zcfg->name) < 0) {
1338              // pass over silently
1339              zcfg = zcfg->next;
1340              continue;
1341            }
1342            inheritance(zooRegistry, &svc);
1343            printGetCapabilitiesForProcess(zooRegistry, m, doc, n, svc);
1344            freeService(&svc);
1345            free(svc);                             
1346          }
1347          zcfg = zcfg->next;
1348        }           
1349      }
1350
1351      if (int res =               
1352          recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
1353                          printGetCapabilitiesForProcess) < 0)
1354        {
1355          freeMaps (&m);
1356          free (m);
1357          if(zooRegistry!=NULL){
1358            freeRegistry(&zooRegistry);
1359            free(zooRegistry);
1360          }
1361          free (REQUEST);
1362          free (SERVICE_URL);
1363          fflush (stdout);
1364          return res;
1365        }
1366      fflush (stdout);
1367      dup2 (saved_stdout, fileno (stdout));
1368#ifdef META_DB
1369      fetchServicesFromDb(zooRegistry,m,doc,n,printGetCapabilitiesForProcess,1);
1370      close_sql(m,0);
1371#endif     
1372      printDocument (m, doc, getpid ());
1373      freeMaps (&m);
1374      free (m);
1375      if(zooRegistry!=NULL){
1376        freeRegistry(&zooRegistry);
1377        free(zooRegistry);
1378      }
1379      free (REQUEST);
1380      free (SERVICE_URL);
1381      fflush (stdout);
1382      return 0;
1383    }
1384  else
1385    {
1386      r_inputs = getMap (request_inputs, "JobId");
1387      if(reqId>nbReqIdentifier){
1388        if (strncasecmp (REQUEST, "GetStatus", 9) == 0 ||
1389            strncasecmp (REQUEST, "GetResult", 9) == 0){
1390          runGetStatus(m,r_inputs->value,REQUEST);
1391#ifdef RELY_ON_DB
1392          map* dsNb=getMapFromMaps(m,"lenv","ds_nb");
1393          if(dsNb!=NULL && atoi(dsNb->value)>1)
1394            close_sql(m,1);
1395          close_sql(m,0);
1396#endif
1397         
1398          freeMaps (&m);
1399          free(m);
1400          if(zooRegistry!=NULL){
1401            freeRegistry(&zooRegistry);
1402            free(zooRegistry);
1403          }
1404          free (REQUEST);
1405          free (SERVICE_URL);
1406          return 0;
1407        }
1408        else
1409          if (strncasecmp (REQUEST, "Dismiss", strlen(REQUEST)) == 0){
1410            runDismiss(m,r_inputs->value);
1411            freeMaps (&m);
1412            free (m);
1413            if(zooRegistry!=NULL){
1414              freeRegistry(&zooRegistry);
1415              free(zooRegistry);
1416            }
1417            free (REQUEST);
1418            free (SERVICE_URL);
1419            return 0;
1420           
1421          }
1422        return 0;
1423      }
1424      if(reqId<=nbReqIdentifier){
1425        r_inputs = getMap (request_inputs, "Identifier");
1426
1427        struct dirent *dp;
1428        DIR *dirp = opendir (conf_dir);
1429        if (dirp == NULL)
1430          {
1431            errorException (m, _("The specified path does not exist."),
1432                            "InternalError", NULL);
1433            freeMaps (&m);
1434            free (m);
1435            if(zooRegistry!=NULL){
1436              freeRegistry(&zooRegistry);
1437              free(zooRegistry);
1438            }
1439            free (REQUEST);
1440            free (SERVICE_URL);
1441            return 0;
1442          }
1443        if (strncasecmp (REQUEST, "DescribeProcess", 15) == 0)
1444          {
1445            /**
1446             * Loop over Identifier list
1447             */
1448            xmlDocPtr doc = xmlNewDoc (BAD_CAST "1.0");
1449            r_inputs = NULL;
1450            r_inputs = getMap (request_inputs, "version");
1451            fprintf(stderr," ** DEBUG %s %d \n",__FILE__,__LINE__);
1452            fflush(stderr);
1453            xmlNodePtr n = printWPSHeader(doc,m,"DescribeProcess",
1454                                          root_nodes[vid][1],(version!=NULL?version->value:"1.0.0"),1);
1455
1456            r_inputs = getMap (request_inputs, "Identifier");
1457
1458            char *orig = zStrdup (r_inputs->value);
1459
1460            int saved_stdout = dup (fileno (stdout));
1461            dup2 (fileno (stderr), fileno (stdout));
1462            if (strcasecmp ("all", orig) == 0)
1463              {
1464                maps* imports = getMaps(m, IMPORTSERVICE); 
1465                if (imports != NULL) {       
1466                  map* zcfg = imports->content;
1467           
1468                  while (zcfg != NULL) {
1469                    if (zcfg->value != NULL) {
1470                      service* svc = (service*) malloc(SERVICE_SIZE);
1471                      if (svc == NULL || readServiceFile(m, zcfg->value, &svc, zcfg->name) < 0) {
1472                        // pass over silently
1473                        zcfg = zcfg->next;
1474                        continue;
1475                      }
1476                      inheritance(zooRegistry, &svc);
1477#ifdef USE_HPC
1478                      addNestedOutputs(&svc);
1479#endif
1480
1481                      printDescribeProcessForProcess(zooRegistry, m, doc, n, svc);
1482                      freeService(&svc);
1483                      free(svc);                             
1484                    }
1485                    zcfg = zcfg->next;
1486                  }           
1487                }
1488 
1489                if (int res =
1490                    recursReaddirF (m, zooRegistry, doc, n, conf_dir, NULL, saved_stdout, 0,
1491                                    printDescribeProcessForProcess) < 0)
1492                  return res;
1493#ifdef META_DB
1494                fetchServicesFromDb(zooRegistry,m,doc,n,printDescribeProcessForProcess,0);
1495                close_sql(m,0);
1496#endif     
1497
1498              }
1499            else
1500              {
1501                char *saveptr;
1502                char *tmps = strtok_r (orig, ",", &saveptr);
1503
1504                char buff[256];
1505                char buff1[1024];
1506                while (tmps != NULL)
1507                  {
1508                    int hasVal = -1;
1509                    char *corig = zStrdup (tmps);
1510                    map* import = getMapFromMaps (m, IMPORTSERVICE, corig);   
1511                    if (import != NULL && import->value != NULL) 
1512                      {
1513#ifdef META_DB                 
1514                        service* s2=extractServiceFromDb(m,import->name,0);
1515                        if(s2==NULL){
1516#endif
1517                          s1 = (service *) malloc (SERVICE_SIZE);
1518                          t = readServiceFile (m, import->value, &s1, import->name);
1519               
1520                          if (t < 0) // failure reading zcfg
1521                            {
1522                              map *tmp00 = getMapFromMaps (m, "lenv", "message");
1523                              char tmp01[1024];
1524                              if (tmp00 != NULL)
1525                                sprintf (tmp01, _("Unable to parse the ZCFG file: %s (%s)"), import->value, tmp00->value);
1526                              else
1527                                sprintf (tmp01, _("Unable to parse the ZCFG file: %s."), import->value);
1528                             
1529                              dup2 (saved_stdout, fileno (stdout));
1530                              errorException (m, tmp01, "InternalError", NULL);
1531                             
1532                              freeMaps (&m);
1533                              free (m);
1534
1535                              if(zooRegistry!=NULL){
1536                                freeRegistry(&zooRegistry);
1537                                free(zooRegistry);
1538                              }
1539                              free (orig);
1540                              free (REQUEST);
1541                              closedir (dirp);
1542                              //xmlFreeDoc (doc);
1543                              xmlCleanupParser ();
1544                              zooXmlCleanupNs ();
1545                   
1546                              return 1;
1547                            }
1548#ifdef DEBUG
1549                          dumpService (s1);
1550#endif
1551                          inheritance(zooRegistry,&s1);
1552#ifdef USE_HPC
1553                          addNestedOutputs(&s1);
1554#endif
1555                          printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
1556                          freeService (&s1);
1557                          free (s1);
1558                          s1 = NULL;
1559                          scount++;
1560                          hasVal = 1;               
1561#ifdef META_DB
1562                        }
1563#endif
1564                      }
1565                    else if (strstr (corig, ".") != NULL)
1566                      {
1567
1568                        parseIdentifier (m, conf_dir, corig, buff1);
1569                        map *tmpMap = getMapFromMaps (m, "lenv", "metapath");
1570                        if (tmpMap != NULL)
1571                          addToMap (request_inputs, "metapath", tmpMap->value);
1572                        map *tmpMapI = getMapFromMaps (m, "lenv", "Identifier");
1573                        /**
1574                         * No support for dot in service name stored in metadb!?
1575                         #ifdef META_DB
1576                         service* s2=extractServiceFromDb(m,tmpMapI->value,0);
1577                         if(s2==NULL){
1578                         #endif
1579                        */
1580                        s1 = (service *) malloc (SERVICE_SIZE);
1581                        t = readServiceFile (m, buff1, &s1, tmpMapI->value);
1582                        if (t < 0)
1583                          {
1584                            map *tmp00 = getMapFromMaps (m, "lenv", "message");
1585                            char tmp01[1024];
1586                            if (tmp00 != NULL)
1587                              sprintf (tmp01,
1588                                       _
1589                                       ("Unable to parse the ZCFG file for the following ZOO-Service: %s. Message: %s"),
1590                                       tmps, tmp00->value);
1591                            else
1592                              sprintf (tmp01,
1593                                       _
1594                                       ("Unable to parse the ZCFG file for the following ZOO-Service: %s."),
1595                                       tmps);
1596                            dup2 (saved_stdout, fileno (stdout));
1597                            errorException (m, tmp01, "InvalidParameterValue",
1598                                            "identifier");
1599                            freeMaps (&m);
1600                            free (m);
1601                            if(zooRegistry!=NULL){
1602                              freeRegistry(&zooRegistry);
1603                              free(zooRegistry);
1604                            }
1605                            free (REQUEST);
1606                            free (corig);
1607                            free (orig);
1608                            free (SERVICE_URL);
1609                            free (s1);
1610                            closedir (dirp);
1611                            //xmlFreeDoc (doc);
1612                            xmlCleanupParser ();
1613                            zooXmlCleanupNs ();
1614                            return 1;
1615                          }
1616#ifdef DEBUG
1617                        dumpService (s1);
1618#endif
1619                        inheritance(zooRegistry,&s1);
1620#ifdef USE_HPC
1621                        addNestedOutputs(&s1);
1622#endif
1623                        printDescribeProcessForProcess (zooRegistry, m, doc, n, s1);
1624                        freeService (&s1);
1625                        free (s1);
1626                        s1 = NULL;
1627                        scount++;
1628                        hasVal = 1;
1629                        setMapInMaps (m, "lenv", "level", "0");
1630                        /*
1631                          #ifdef META_DB
1632                          }
1633                          #endif
1634                        */
1635                      }
1636                    else
1637                      {
1638#ifdef META_DB
1639                        _init_sql(m,"metadb");
1640                        //FAILED CONNECTING DB
1641                        if(getMapFromMaps(m,"lenv","dbIssue")!=NULL){
1642                          fprintf(stderr,"ERROR CONNECTING METADB");
1643                        }
1644                        service* s2=extractServiceFromDb(m,corig,0);
1645                        if(s2!=NULL){
1646                          inheritance(zooRegistry,&s2);
1647#ifdef USE_HPC
1648                          addNestedOutputs(&s2);
1649#endif
1650                          printDescribeProcessForProcess (zooRegistry,m, doc, n, s2);
1651                          freeService (&s2);
1652                          free (s2);
1653                          s2 = NULL;
1654                          hasVal = 1;
1655                        }else /*TOTO*/{
1656#endif
1657                          memset (buff, 0, 256);
1658                          snprintf (buff, 256, "%s.zcfg", corig);
1659                          memset (buff1, 0, 1024);
1660#ifdef DEBUG
1661                          printf ("\n#######%s\n########\n", buff);
1662#endif
1663                          while ((dp = readdir (dirp)) != NULL)
1664                            {
1665                              if (strcasecmp (dp->d_name, buff) == 0)
1666                                {
1667                                  memset (buff1, 0, 1024);
1668                                  snprintf (buff1, 1024, "%s/%s", conf_dir,
1669                                            dp->d_name);
1670                                  s1 = (service *) malloc (SERVICE_SIZE);
1671                                  if (s1 == NULL)
1672                                    {
1673                                      dup2 (saved_stdout, fileno (stdout));
1674                                      return errorException (m,
1675                                                             _
1676                                                             ("Unable to allocate memory"),
1677                                                             "InternalError",
1678                                                             NULL);
1679                                    }
1680#ifdef DEBUG_SERVICE_CONF
1681                                  fprintf
1682                                    (stderr,"#################\n(%s) %s\n#################\n",
1683                                     r_inputs->value, buff1);
1684#endif
1685                                  char *tmp0 = zStrdup (dp->d_name);
1686                                  tmp0[strlen (tmp0) - 5] = 0;
1687                                  t = readServiceFile (m, buff1, &s1, tmp0);
1688                                  free (tmp0);
1689                                  if (t < 0)
1690                                    {
1691                                      map *tmp00 =
1692                                        getMapFromMaps (m, "lenv", "message");
1693                                      char tmp01[1024];
1694                                      if (tmp00 != NULL)
1695                                        sprintf (tmp01,
1696                                                 _
1697                                                 ("Unable to parse the ZCFG file: %s (%s)"),
1698                                                 dp->d_name, tmp00->value);
1699                                      else
1700                                        sprintf (tmp01,
1701                                                 _
1702                                                 ("Unable to parse the ZCFG file: %s."),
1703                                                 dp->d_name);
1704                                      dup2 (saved_stdout, fileno (stdout));
1705                                      errorException (m, tmp01, "InternalError",
1706                                                      NULL);
1707                                      freeMaps (&m);
1708                                      free (m);
1709                                      if(zooRegistry!=NULL){
1710                                        freeRegistry(&zooRegistry);
1711                                        free(zooRegistry);
1712                                      }
1713                                      free (orig);
1714                                      free (REQUEST);
1715                                      closedir (dirp);
1716                                      //xmlFreeDoc (doc);
1717                                      xmlCleanupParser ();
1718                                      zooXmlCleanupNs ();
1719                                      return 1;
1720                                    }
1721#ifdef DEBUG
1722                                  dumpService (s1);
1723#endif
1724                                  inheritance(zooRegistry,&s1);
1725#ifdef USE_HPC
1726                                  addNestedOutputs(&s1);
1727#endif
1728                                  json_object* jobj=serviceToJson(s1);
1729                                  const char* jsonStr=json_object_to_json_string_ext(jobj,JSON_C_TO_STRING_PLAIN);
1730                                  fprintf(stderr,"*** %s %d %s \n",__FILE__,__LINE__,jsonStr);
1731
1732                                  printDescribeProcessForProcess (zooRegistry,m, doc, n, s1);
1733                                  freeService (&s1);
1734                                  free (s1);
1735                                  s1 = NULL;
1736                                  scount++;
1737                                  hasVal = 1;
1738                                }
1739                            }
1740#ifdef META_DB
1741                        }
1742#endif
1743                      }               
1744                    if (hasVal < 0)
1745                      {
1746                        map *tmp00 = getMapFromMaps (m, "lenv", "message");
1747                        char tmp01[1024];
1748                        if (tmp00 != NULL)
1749                          sprintf (tmp01,
1750                                   _("Unable to parse the ZCFG file: %s (%s)"),
1751                                   buff, tmp00->value);
1752                        else
1753                          sprintf (tmp01,
1754                                   _("Unable to parse the ZCFG file: %s."),
1755                                   buff);
1756                        dup2 (saved_stdout, fileno (stdout));
1757                        errorException (m, tmp01, "InvalidParameterValue",
1758                                        "Identifier");
1759                        freeMaps (&m);
1760                        free (m);
1761                        if(zooRegistry!=NULL){
1762                          freeRegistry(&zooRegistry);
1763                          free(zooRegistry);
1764                        }
1765                        free (orig);
1766                        free (REQUEST);
1767                        closedir (dirp);
1768                        //xmlFreeDoc (doc);
1769                        xmlCleanupParser ();
1770                        zooXmlCleanupNs ();
1771                        return 1;
1772                      }
1773                    rewinddir (dirp);
1774                    tmps = strtok_r (NULL, ",", &saveptr);
1775                    if (corig != NULL)
1776                      free (corig);
1777                  }
1778              }
1779            closedir (dirp);
1780            fflush (stdout);
1781            dup2 (saved_stdout, fileno (stdout));
1782            free (orig);
1783            printDocument (m, doc, getpid ());
1784            freeMaps (&m);
1785            free (m);
1786            if(zooRegistry!=NULL){
1787              freeRegistry(&zooRegistry);
1788              free(zooRegistry);
1789            }
1790            free (REQUEST);
1791            free (SERVICE_URL);
1792            fflush (stdout);
1793#ifdef META_DB
1794            close_sql(m,0);
1795            //end_sql();
1796#endif
1797            return 0;
1798          }
1799        else if (strncasecmp (REQUEST, "Execute", strlen (REQUEST)) != 0)
1800          {
1801            map* version=getMapFromMaps(m,"main","rversion");
1802            int vid=getVersionId(version->value);           
1803            int len = 0;
1804            int j = 0;
1805            for(j=0;j<nbSupportedRequests;j++){
1806              if(requests[vid][j]!=NULL)
1807                len+=strlen(requests[vid][j])+2;
1808              else{
1809                len+=4;
1810                break;
1811              }
1812            }
1813            char *tmpStr=(char*)malloc(len*sizeof(char));
1814            int it=0;
1815            for(j=0;j<nbSupportedRequests;j++){
1816              if(requests[vid][j]!=NULL){
1817                if(it==0){
1818                  sprintf(tmpStr,"%s",requests[vid][j]);
1819                  it++;
1820                }else{
1821                  char *tmpS=zStrdup(tmpStr);
1822                  if(j+1<nbSupportedRequests && requests[vid][j+1]==NULL){
1823                    sprintf(tmpStr,"%s and %s",tmpS,requests[vid][j]);
1824                  }else{
1825                    sprintf(tmpStr,"%s, %s",tmpS,requests[vid][j]);
1826                 
1827                  }
1828                  free(tmpS);
1829                }
1830              }
1831              else{
1832                len+=4;
1833                break;
1834              }
1835            }
1836            char* message=(char*)malloc((61+len)*sizeof(char));
1837            sprintf(message,"The <request> value was not recognized. Allowed values are %s.",tmpStr);
1838            errorException (m,_(message),"InvalidParameterValue", "request");
1839#ifdef DEBUG
1840            fprintf (stderr, "No request found %s", REQUEST);
1841#endif
1842            closedir (dirp);
1843            freeMaps (&m);
1844            free (m);
1845            if(zooRegistry!=NULL){
1846              freeRegistry(&zooRegistry);
1847              free(zooRegistry);
1848            }
1849            free (REQUEST);
1850            free (SERVICE_URL);
1851            fflush (stdout);
1852            return 0;
1853          }
1854        closedir (dirp);
1855      }
1856    }
1857
1858  map *postRequest = NULL;
1859  postRequest = getMap (request_inputs, "xrequest");
1860 
1861  if(vid==1 && postRequest==NULL){
1862    errorException (m,_("Unable to run Execute request using the GET HTTP method"),"InvalidParameterValue", "request"); 
1863    freeMaps (&m);
1864    free (m);
1865    if(zooRegistry!=NULL){
1866      freeRegistry(&zooRegistry);
1867      free(zooRegistry);
1868    }
1869    free (REQUEST);
1870    free (SERVICE_URL);
1871    fflush (stdout);
1872    return 0;
1873  }
1874  s1 = NULL;
1875 
1876  r_inputs = getMap (request_inputs, "Identifier");
1877  map* import = getMapFromMaps (m, IMPORTSERVICE, r_inputs->value); 
1878  if (import != NULL && import->value != NULL) { 
1879    strncpy(tmps1, import->value, 1024);
1880    setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
1881    setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
1882  } 
1883  else {
1884    snprintf (tmps1, 1024, "%s/%s.zcfg", conf_dir, r_inputs->value);
1885#ifdef DEBUG
1886    fprintf (stderr, "Trying to load %s\n", tmps1);
1887#endif
1888    if (strstr (r_inputs->value, ".") != NULL)
1889      {
1890        char *identifier = zStrdup (r_inputs->value);
1891        parseIdentifier (m, conf_dir, identifier, tmps1);
1892        map *tmpMap = getMapFromMaps (m, "lenv", "metapath");
1893        if (tmpMap != NULL)
1894          addToMap (request_inputs, "metapath", tmpMap->value);
1895        free (identifier);
1896      }
1897    else
1898      {
1899        setMapInMaps (m, "lenv", "Identifier", r_inputs->value);
1900        setMapInMaps (m, "lenv", "oIdentifier", r_inputs->value);
1901      }
1902  }
1903
1904  r_inputs = getMapFromMaps (m, "lenv", "Identifier");
1905 
1906#ifdef META_DB
1907  int metadb_id=_init_sql(m,"metadb");
1908  //FAILED CONNECTING DB
1909  if(getMapFromMaps(m,"lenv","dbIssue")!=NULL || metadb_id<0){
1910    fprintf(stderr,"ERROR CONNECTING METADB\n");
1911  }
1912  if(metadb_id>=0)
1913    s1=extractServiceFromDb(m,r_inputs->value,0);
1914  //close_sql(m,0);
1915  if(s1!=NULL){
1916    inheritance(zooRegistry,&s1);
1917#ifdef USE_HPC
1918    addNestedOutputs(&s1);
1919#endif
1920    if(zooRegistry!=NULL){
1921      freeRegistry(&zooRegistry);
1922      free(zooRegistry);
1923    }
1924  }else /* Not found in MetaDB */{
1925#endif
1926    s1 = (service *) malloc (SERVICE_SIZE);
1927    if (s1 == NULL)
1928      {
1929        freeMaps (&m);
1930        free (m);
1931        if(zooRegistry!=NULL){
1932          freeRegistry(&zooRegistry);
1933          free(zooRegistry);
1934        }
1935        free (REQUEST);
1936        free (SERVICE_URL);
1937        return errorException (m, _("Unable to allocate memory"),
1938                               "InternalError", NULL);
1939      }
1940
1941    int saved_stdout = dup (fileno (stdout));
1942    dup2 (fileno (stderr), fileno (stdout));
1943    t = readServiceFile (m, tmps1, &s1, r_inputs->value);
1944    inheritance(zooRegistry,&s1);
1945#ifdef USE_HPC
1946    addNestedOutputs(&s1);
1947#endif
1948    if(zooRegistry!=NULL){
1949      freeRegistry(&zooRegistry);
1950      free(zooRegistry);
1951    }
1952    fflush (stdout);
1953    dup2 (saved_stdout, fileno (stdout));
1954    if (t < 0)
1955      {
1956        char *tmpMsg = (char *) malloc (2048 + strlen (r_inputs->value));
1957        sprintf (tmpMsg,
1958                 _
1959                 ("The value for <identifier> seems to be wrong (%s). Please specify one of the processes in the list returned by a GetCapabilities request."),
1960                 r_inputs->value);
1961        errorException (m, tmpMsg, "InvalidParameterValue", "identifier");
1962        free (tmpMsg);
1963        free (s1);
1964        freeMaps (&m);
1965        free (m);
1966        free (REQUEST);
1967        free (SERVICE_URL);
1968        return 0;
1969      }
1970    close (saved_stdout);
1971#ifdef META_DB
1972  }
1973#endif
1974 
1975#ifdef DEBUG
1976  dumpService (s1);
1977#endif
1978  int j;
1979
1980
1981  /**
1982   * Create the input and output maps data structure
1983   */
1984  int i = 0;
1985  HINTERNET hInternet;
1986  HINTERNET res;
1987  hInternet = InternetOpen (
1988#ifndef WIN32
1989                            (LPCTSTR)
1990#endif
1991                            "ZooWPSClient\0",
1992                            INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
1993
1994#ifndef WIN32
1995  if (!CHECK_INET_HANDLE (hInternet))
1996    fprintf (stderr, "WARNING : hInternet handle failed to initialize");
1997#endif
1998  maps *request_input_real_format = NULL;
1999  maps *tmpmaps = request_input_real_format;
2000
2001  if(parseRequest(&m,&request_inputs,s1,&request_input_real_format,&request_output_real_format,&hInternet)<0){
2002    freeMaps (&m);
2003    free (m);
2004    free (REQUEST);
2005    free (SERVICE_URL);
2006    InternetCloseHandle (&hInternet);
2007    freeService (&s1);
2008    free (s1);
2009    return 0;
2010  }
2011  //InternetCloseHandle (&hInternet);
2012 
2013  // Define each env variable in runing environment
2014  maps *curs = getMaps (m, "env");
2015  if (curs != NULL)
2016    {
2017      map *mapcs = curs->content;
2018      while (mapcs != NULLMAP)
2019        {
2020#ifndef WIN32
2021          setenv (mapcs->name, mapcs->value, 1);
2022#ifdef DEBUG
2023          fprintf (stderr, "[ZOO: setenv (%s=%s)]\n", mapcs->name,
2024                   mapcs->value);
2025#endif
2026#else
2027          if (mapcs->value[strlen (mapcs->value) - 2] == '\r')
2028            {
2029#ifdef DEBUG
2030              fprintf (stderr, "[ZOO: Env var finish with \r]\n");
2031#endif
2032              mapcs->value[strlen (mapcs->value) - 1] = 0;
2033            }
2034#ifdef DEBUG
2035          if (SetEnvironmentVariable (mapcs->name, mapcs->value) == 0)
2036            {
2037              fflush (stderr);
2038              fprintf (stderr, "setting variable... %s\n", "OK");
2039            }
2040          else
2041            {
2042              fflush (stderr);
2043              fprintf (stderr, "setting variable... %s\n", "OK");
2044            }
2045#else
2046          SetEnvironmentVariable (mapcs->name, mapcs->value);
2047#endif
2048          char *toto =
2049            (char *)
2050            malloc ((strlen (mapcs->name) + strlen (mapcs->value) +
2051                     2) * sizeof (char));
2052          sprintf (toto, "%s=%s", mapcs->name, mapcs->value);
2053          putenv (toto);
2054#ifdef DEBUG
2055          fflush (stderr);
2056#endif
2057#endif
2058#ifdef DEBUG
2059          fprintf (stderr, "[ZOO: setenv (%s=%s)]\n", mapcs->name,
2060                   mapcs->value);
2061          fflush (stderr);
2062#endif
2063          mapcs = mapcs->next;
2064        }
2065    }
2066
2067#ifdef DEBUG
2068  dumpMap (request_inputs);
2069#endif
2070
2071  map *status = getMap (request_inputs, "status");
2072  if(vid==0){
2073    // Need to check if we need to fork to load a status enabled
2074    r_inputs = NULL;
2075    map *store = getMap (request_inputs, "storeExecuteResponse");
2076    /**
2077     * 05-007r7 WPS 1.0.0 page 57 :
2078     * 'If status="true" and storeExecuteResponse is "false" then the service
2079     * shall raise an exception.'
2080     */
2081    if (status != NULL && strcmp (status->value, "true") == 0 &&
2082        store != NULL && strcmp (store->value, "false") == 0)
2083      {
2084        errorException (m,
2085                        _
2086                        ("The status parameter cannot be set to true if storeExecuteResponse is set to false. Please modify your request parameters."),
2087                        "InvalidParameterValue", "storeExecuteResponse");
2088        freeService (&s1);
2089        free (s1);
2090        freeMaps (&m);
2091        free (m);
2092       
2093        freeMaps (&request_input_real_format);
2094        free (request_input_real_format);
2095       
2096        freeMaps (&request_output_real_format);
2097        free (request_output_real_format);
2098
2099        free (REQUEST);
2100        free (SERVICE_URL);
2101        return 1;
2102      }
2103    r_inputs = getMap (request_inputs, "storeExecuteResponse");
2104  }else{
2105    // Define status depending on the WPS 2.0.0 mode attribute
2106    status = getMap (request_inputs, "mode");
2107    map* mode=getMap(s1->content,"mode");
2108    if(strcasecmp(status->value,"async")==0){
2109      if(mode!=NULL && strcasecmp(mode->value,"async")==0)
2110        addToMap(request_inputs,"status","true");
2111      else{
2112        if(mode!=NULL){
2113          // see ref. http://docs.opengeospatial.org/is/14-065/14-065.html#61
2114          errorException (m,_("The process does not permit the desired execution mode."),"NoSuchMode", mode->value); 
2115          fflush (stdout);
2116          freeMaps (&m);
2117          free (m);
2118          if(zooRegistry!=NULL){
2119            freeRegistry(&zooRegistry);
2120            free(zooRegistry);
2121          }
2122          freeMaps (&request_input_real_format);
2123          free (request_input_real_format);
2124          freeMaps (&request_output_real_format);
2125          free (request_output_real_format);
2126          free (REQUEST);
2127          free (SERVICE_URL);
2128          return 0;
2129        }else
2130          addToMap(request_inputs,"status","true");
2131      }
2132    }
2133    else{
2134      if(strcasecmp(status->value,"auto")==0){
2135        if(mode!=NULL){
2136          if(strcasecmp(mode->value,"async")==0)
2137            addToMap(request_inputs,"status","false");
2138          else
2139            addToMap(request_inputs,"status","true");
2140        }
2141        else
2142          addToMap(request_inputs,"status","false");
2143      }else
2144        addToMap(request_inputs,"status","false");
2145    }
2146    status = getMap (request_inputs, "status");
2147  }
2148
2149  int eres = SERVICE_STARTED;
2150  int cpid = getpid ();
2151
2152  // Create a map containing a copy of the request map
2153  maps *_tmpMaps = createMaps("request");
2154  addMapToMap(&_tmpMaps->content,request_inputs);
2155  addMapsToMaps (&m, _tmpMaps);
2156  freeMaps (&_tmpMaps);
2157  free (_tmpMaps);
2158  /**
2159   * Initialize the specific [lenv] section which contains runtime variables:
2160   *
2161   *  - usid : it is an universally unique identifier 
2162   *  - osid : it is an idenfitication number
2163   *  - sid : it is the process idenfitication number (OS)
2164   *  - uusid : it is an universally unique identifier
2165   *  - status : value between 0 and 100 to express the  completude of
2166   * the operations of the running service
2167   *  - message : is a string where you can store error messages, in case
2168   * service is failing, or o provide details on the ongoing operation.
2169   *  - cwd : the current working directory or servicePath if defined
2170   *  - soap : is a boolean value, true if the request was contained in a SOAP
2171   * Envelop
2172   *  - sessid : string storing the session identifier (only when cookie is
2173   * used)
2174   *  - cgiSid : only defined on Window platforms (for being able to identify
2175   * the created process)
2176   *
2177   */
2178  _tmpMaps = createMaps("lenv");
2179  char tmpBuff[100];
2180  struct ztimeval tp;
2181  if (zGettimeofday (&tp, NULL) == 0)
2182    sprintf (tmpBuff, "%i", (cpid + ((int) tp.tv_sec + (int) tp.tv_usec)));
2183  else
2184    sprintf (tmpBuff, "%i", (cpid + (int) time (NULL)));
2185  _tmpMaps->content = createMap ("osid", tmpBuff);
2186  sprintf (tmpBuff, "%i", cpid);
2187  addToMap (_tmpMaps->content, "sid", tmpBuff);
2188  char* tmpUuid=get_uuid();
2189  addToMap (_tmpMaps->content, "uusid", tmpUuid);
2190  addToMap (_tmpMaps->content, "usid", tmpUuid);
2191  free(tmpUuid);
2192  addToMap (_tmpMaps->content, "status", "0");
2193  if(cwdMap0!=NULL){
2194    addToMap (_tmpMaps->content, "cwd", cwdMap0->value);
2195    addToMap (_tmpMaps->content, "rcwd", ntmp);
2196  }
2197  else
2198    addToMap (_tmpMaps->content, "cwd", ntmp);
2199  addToMap (_tmpMaps->content, "message", _("No message provided"));
2200  map *ltmp = getMap (request_inputs, "soap");
2201  if (ltmp != NULL)
2202    addToMap (_tmpMaps->content, "soap", ltmp->value);
2203  else
2204    addToMap (_tmpMaps->content, "soap", "false");
2205
2206  // Parse the session file and add it to the main maps
2207  char* originalCookie=NULL;
2208  if (cgiCookie != NULL && strlen (cgiCookie) > 0)
2209    {
2210      int hasValidCookie = -1;
2211      char *tcook = originalCookie = zStrdup (cgiCookie);
2212      map *testing = getMapFromMaps (m, "main", "cookiePrefix");
2213      parseCookie(&m,originalCookie);
2214      map *sessId=getMapFromMaps(m,"cookies",(testing==NULL?"ID":testing->value));
2215      if (sessId!=NULL)
2216        {
2217          addToMap (_tmpMaps->content, "sessid", sessId->value);
2218          char session_file_path[1024];
2219          map *tmpPath = getMapFromMaps (m, "main", "sessPath");
2220          if (tmpPath == NULL)
2221            tmpPath = getMapFromMaps (m, "main", "tmpPath");
2222          char *tmp1 = strtok (tcook, ";");
2223          if (tmp1 != NULL)
2224            sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
2225                     sessId->value);
2226          else
2227            sprintf (session_file_path, "%s/sess_%s.cfg", tmpPath->value,
2228                     sessId->value);
2229          free (tcook);
2230          maps *tmpSess = (maps *) malloc (MAPS_SIZE);
2231          tmpSess->child=NULL;
2232          struct stat file_status;
2233          int istat = stat (session_file_path, &file_status);
2234          if (istat == 0 && file_status.st_size > 0)
2235            {
2236              int saved_stdout = dup (fileno (stdout));
2237              dup2 (fileno (stderr), fileno (stdout));
2238              conf_read (session_file_path, tmpSess);
2239              addMapsToMaps (&m, tmpSess);
2240              freeMaps (&tmpSess);
2241              fflush(stdout);
2242              dup2 (saved_stdout, fileno (stdout));
2243              close(saved_stdout);
2244            }
2245          free (tmpSess);
2246        }
2247    }
2248  addMapsToMaps (&m, _tmpMaps);
2249  freeMaps (&_tmpMaps);
2250  free (_tmpMaps);
2251  maps* bmap=NULL;
2252#ifdef DEBUG
2253  dumpMap (request_inputs);
2254#endif
2255  int ei = 1;
2256  char **orig = 
2257#ifdef WIN32
2258    GetEnvironmentStrings()
2259#else
2260    environ
2261#endif
2262    ;
2263  char *s=*orig;
2264  _tmpMaps = createMaps("renv");
2265  for (; s; ei++) {
2266    if(strstr(s,"=")!=NULL && strlen(strstr(s,"="))>1){
2267      int len=strlen(s);
2268      char* tmpName=zStrdup(s);
2269      char* tmpValue=strstr(s,"=")+1;
2270      char* tmpName1=(char*)malloc((1+(len-(strlen(tmpValue)+1)))*sizeof(char));
2271      snprintf(tmpName1,(len-strlen(tmpValue)),"%s",tmpName);
2272      if(_tmpMaps->content == NULL)
2273        _tmpMaps->content = createMap (tmpName1,tmpValue);
2274      else
2275        addToMap (_tmpMaps->content,tmpName1,tmpValue);
2276      free(tmpName1);
2277      free(tmpName);
2278    }
2279    s = *(orig+ei);
2280  }
2281  if(_tmpMaps->content!=NULL && getMap(_tmpMaps->content,"HTTP_COOKIE")!=NULL){
2282    addToMap(_tmpMaps->content,"HTTP_COOKIE1",&cgiCookie[0]);
2283  }
2284  addMapsToMaps (&m, _tmpMaps);
2285  freeMaps (&_tmpMaps);
2286  free (_tmpMaps);
2287  if(postRequest!=NULL)
2288    setMapInMaps (m, "renv", "xrequest", postRequest->value);
2289  //dumpMaps(m);
2290#ifdef WIN32
2291  char *cgiSidL = NULL;
2292  if (getenv ("CGISID") != NULL)
2293    addToMap (request_inputs, "cgiSid", getenv ("CGISID"));
2294
2295  char* usidp;
2296  if ( (usidp = getenv("USID")) != NULL ) {
2297    setMapInMaps (m, "lenv", "usid", usidp);
2298  }
2299
2300  map *test1 = getMap (request_inputs, "cgiSid");
2301  if (test1 != NULL){
2302    cgiSid = zStrdup(test1->value);
2303    addToMap (request_inputs, "storeExecuteResponse", "true");
2304    addToMap (request_inputs, "status", "true");
2305    setMapInMaps (m, "lenv", "osid", test1->value);
2306    status = getMap (request_inputs, "status");
2307  }
2308  test1 = getMap (request_inputs, "usid");
2309  if (test1 != NULL){
2310    setMapInMaps (m, "lenv", "usid", test1->value);
2311    setMapInMaps (m, "lenv", "uusid", test1->value);
2312  }
2313#endif
2314
2315  char *fbkp, *fbkpid, *fbkpres, *fbkp1, *flog;
2316  FILE *f0, *f1;
2317  if (status != NULL)
2318    if (strcasecmp (status->value, "false") == 0)
2319      status = NULLMAP;
2320  if (status == NULLMAP)
2321    {
2322      if(validateRequest(&m,s1,request_inputs, &request_input_real_format,&request_output_real_format,&hInternet)<0){
2323        freeService (&s1);
2324        free (s1);
2325        freeMaps (&m);
2326        free (m);
2327        free (REQUEST);
2328        free (SERVICE_URL);
2329        freeMaps (&request_input_real_format);
2330        free (request_input_real_format);
2331        freeMaps (&request_output_real_format);
2332        free (request_output_real_format);
2333        freeMaps (&tmpmaps);
2334        free (tmpmaps);
2335        return -1;
2336      }
2337      loadServiceAndRun (&m, s1, request_inputs, &request_input_real_format,
2338                         &request_output_real_format, &eres);
2339
2340#ifdef META_DB
2341      close_sql(m,0);     
2342#endif     
2343    }
2344  else
2345    {
2346      int pid;
2347#ifdef DEBUG
2348      fprintf (stderr, "\nPID : %d\n", cpid);
2349#endif
2350#ifndef WIN32
2351      pid = fork ();
2352#else
2353      if (cgiSid == NULL)
2354        {
2355          createProcess (m, request_inputs, s1, NULL, cpid,
2356                         request_input_real_format,
2357                         request_output_real_format);
2358          pid = cpid;
2359        }
2360      else
2361        {
2362          pid = 0;
2363          cpid = atoi (cgiSid);
2364          updateStatus(m,0,_("Initializing"));
2365        }
2366#endif
2367      if (pid > 0)
2368        {
2369          //
2370          // dady :
2371          // set status to SERVICE_ACCEPTED
2372          //
2373#ifdef DEBUG
2374          fprintf (stderr, "father pid continue (origin %d) %d ...\n", cpid,
2375                   getpid ());
2376#endif
2377          eres = SERVICE_ACCEPTED;
2378        }
2379      else if (pid == 0)
2380        {
2381          //
2382          // son : have to close the stdout, stdin and stderr to let the parent
2383          // process answer to http client.
2384          //
2385          map* usid = getMapFromMaps (m, "lenv", "uusid");
2386          map* tmpm = getMapFromMaps (m, "lenv", "osid");
2387          int cpid = atoi (tmpm->value);
2388          pid=cpid;
2389          r_inputs = getMapFromMaps (m, "main", "tmpPath");
2390          setMapInMaps (m, "lenv", "async","true");
2391          map* r_inputs1 = createMap("ServiceName", s1->name);
2392
2393          // Create the filename for the result file (.res)
2394          fbkpres =
2395            (char *)
2396            malloc ((strlen (r_inputs->value) +
2397                     strlen (usid->value) + 7) * sizeof (char));                   
2398          sprintf (fbkpres, "%s/%s.res", r_inputs->value, usid->value);
2399          bmap = createMaps("status");
2400          bmap->content=createMap("usid",usid->value);
2401          addToMap(bmap->content,"sid",tmpm->value);
2402          addIntToMap(bmap->content,"pid",getpid());
2403         
2404          // Create PID file referencing the OS process identifier
2405          fbkpid =
2406            (char *)
2407            malloc ((strlen (r_inputs->value) +
2408                     strlen (usid->value) + 7) * sizeof (char));
2409          sprintf (fbkpid, "%s/%s.pid", r_inputs->value, usid->value);
2410          setMapInMaps (m, "lenv", "file.pid", fbkpid);
2411
2412          f0 = freopen (fbkpid, "w+",stdout);
2413          printf("%d",getpid());
2414          fflush(stdout);
2415
2416          // Create SID file referencing the semaphore name
2417          fbkp =
2418            (char *)
2419            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
2420                     strlen (usid->value) + 7) * sizeof (char));
2421          sprintf (fbkp, "%s/%s.sid", r_inputs->value, usid->value);
2422          setMapInMaps (m, "lenv", "file.sid", fbkp);
2423          FILE* f2 = freopen (fbkp, "w+",stdout);
2424          printf("%s",tmpm->value);
2425          fflush(f2);
2426          free(fbkp);
2427
2428          fbkp =
2429            (char *)
2430            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
2431                     strlen (usid->value) + 7) * sizeof (char));
2432          sprintf (fbkp, "%s/%s_%s.xml", r_inputs->value, r_inputs1->value,
2433                   usid->value);
2434          setMapInMaps (m, "lenv", "file.responseInit", fbkp);
2435          flog =
2436            (char *)
2437            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
2438                     strlen (usid->value) + 13) * sizeof (char));
2439          sprintf (flog, "%s/%s_%s_error.log", r_inputs->value,
2440                   r_inputs1->value, usid->value);
2441          setMapInMaps (m, "lenv", "file.log", flog);
2442#ifdef DEBUG
2443          fprintf (stderr, "RUN IN BACKGROUND MODE \n");
2444          fprintf (stderr, "son pid continue (origin %d) %d ...\n", cpid,
2445                   getpid ());
2446          fprintf (stderr, "\nFILE TO STORE DATA %s\n", r_inputs->value);
2447#endif
2448          freopen (flog, "w+", stderr);
2449          fflush (stderr);
2450          f0 = freopen (fbkp, "w+", stdout);
2451          rewind (stdout);
2452#ifndef WIN32
2453          fclose (stdin);
2454#endif
2455#ifdef RELY_ON_DB
2456          init_sql(m);
2457          recordServiceStatus(m);
2458#endif
2459          invokeCallback(m,NULL,NULL,0,0);
2460          if(vid==0){
2461            //
2462            // set status to SERVICE_STARTED and flush stdout to ensure full
2463            // content was outputed (the file used to store the ResponseDocument).
2464            // Then, rewind stdout to restart writing from the begining of the file.
2465            // This way, the data will be updated at the end of the process run.
2466            //
2467            printProcessResponse (m, request_inputs, cpid, s1, r_inputs1->value,
2468                                  SERVICE_STARTED, request_input_real_format,
2469                                  request_output_real_format);
2470            fflush (stdout);
2471#ifdef RELY_ON_DB
2472            recordResponse(m,fbkp);
2473#endif
2474          }
2475
2476          fflush (stderr);
2477
2478          fbkp1 =
2479            (char *)
2480            malloc ((strlen (r_inputs->value) + strlen (r_inputs1->value) +
2481                     strlen (usid->value) + 13) * sizeof (char));
2482          sprintf (fbkp1, "%s/%s_final_%s.xml", r_inputs->value,
2483                   r_inputs1->value, usid->value);
2484          setMapInMaps (m, "lenv", "file.responseFinal", fbkp1);
2485
2486          f1 = freopen (fbkp1, "w+", stdout);
2487
2488          map* serviceTypeMap=getMap(s1->content,"serviceType");
2489          if(serviceTypeMap!=NULL)
2490            setMapInMaps (m, "lenv", "serviceType", serviceTypeMap->value);
2491
2492          char *flenv =
2493            (char *)
2494            malloc ((strlen (r_inputs->value) + 
2495                     strlen (usid->value) + 12) * sizeof (char));
2496          sprintf (flenv, "%s/%s_lenv.cfg", r_inputs->value, usid->value);
2497          maps* lenvMaps=getMaps(m,"lenv");
2498          dumpMapsToFile(lenvMaps,flenv,0);
2499          free(flenv);
2500
2501          invokeCallback(m,request_input_real_format,NULL,1,0);
2502          if(validateRequest(&m,s1,request_inputs, &request_input_real_format,&request_output_real_format,&hInternet)<0){
2503            freeService (&s1);
2504            free (s1);
2505            fflush (stdout);
2506            fflush (stderr);
2507            fclose (f0);
2508            fclose (f1);
2509            if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
2510              return -1;
2511#ifndef RELY_ON_DB
2512            dumpMapsToFile(bmap,fbkpres,1);
2513            removeShmLock (m, 1);
2514#else
2515            recordResponse(m,fbkp1);
2516            invokeCallback(m,NULL,NULL,7,0);
2517#endif
2518            unlink (fbkpid);
2519            unhandleStatus (m);
2520#ifdef RELY_ON_DB
2521#ifdef META_DB
2522            cleanupCallbackThreads();
2523            close_sql(m,1);
2524#endif
2525            close_sql(m,0);
2526#endif
2527            freeMaps (&m);
2528            free (m);
2529            free (REQUEST);
2530            free (SERVICE_URL);
2531            freeMaps (&request_input_real_format);
2532            free (request_input_real_format);
2533            freeMaps (&request_output_real_format);
2534            free (request_output_real_format);
2535            freeMaps (&tmpmaps);
2536            free (tmpmaps);
2537            return -1;
2538          }
2539          if(getMapFromMaps(m,"lenv","mapError")!=NULL){
2540            setMapInMaps(m,"lenv","message",_("Issue with geographic data"));
2541            invokeCallback(m,NULL,NULL,7,0);
2542            eres=-1;//SERVICE_FAILED;
2543          }else{
2544            loadServiceAndRun (&m, s1, request_inputs,
2545                               &request_input_real_format,
2546                               &request_output_real_format, &eres);
2547          }
2548        }
2549      else
2550        {
2551          /**
2552           * error server don't accept the process need to output a valid
2553           * error response here !!!
2554           */
2555          eres = -1;
2556          errorException (m, _("Unable to run the child process properly"),
2557                          "InternalError", NULL);
2558        }
2559    }
2560
2561#ifdef DEBUG
2562  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
2563  dumpMaps (request_output_real_format);
2564  fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
2565#endif
2566  fflush(stdout);
2567  rewind(stdout);
2568
2569  fprintf(stderr,"%s %d %d\n",__FILE__,__LINE__,eres);
2570
2571  if (eres != -1)
2572    outputResponse (s1, request_input_real_format,
2573                    request_output_real_format, request_inputs,
2574                    cpid, m, eres);
2575  fflush (stdout);
2576
2577  /**
2578   * Ensure that if error occurs when freeing memory, no signal will return
2579   * an ExceptionReport document as the result was already returned to the
2580   * client.
2581   */
2582#ifndef USE_GDB
2583  signal (SIGSEGV, donothing);
2584  signal (SIGTERM, donothing);
2585  signal (SIGINT, donothing);
2586  signal (SIGILL, donothing);
2587  signal (SIGFPE, donothing);
2588  signal (SIGABRT, donothing);
2589#endif
2590
2591  if (((int) getpid ()) != cpid || cgiSid != NULL)
2592    {
2593      if (eres == SERVICE_SUCCEEDED)
2594        invokeCallback(m,NULL,request_output_real_format,5,1);
2595
2596      fflush(stderr);
2597      fflush(stdout);
2598
2599      fclose (stdout);
2600
2601      fclose (f0);
2602      fclose (f1);
2603
2604      if(dumpBackFinalFile(m,fbkp,fbkp1)<0)
2605        return -1;
2606      unlink (fbkpid);
2607      switch(eres){
2608      default:
2609      case SERVICE_FAILED:
2610        setMapInMaps(bmap,"status","status",wpsStatus[1]);
2611        setMapInMaps(m,"lenv","fstate",wpsStatus[1]);
2612        break;
2613      case SERVICE_SUCCEEDED:
2614        setMapInMaps(bmap,"status","status",wpsStatus[0]);
2615        setMapInMaps(m,"lenv","fstate",wpsStatus[0]);
2616        break;
2617      }     
2618#ifndef RELY_ON_DB
2619      dumpMapsToFile(bmap,fbkpres,1);
2620      removeShmLock (m, 1);
2621#else
2622      recordResponse(m,fbkp1);
2623      if (eres == SERVICE_SUCCEEDED)
2624        invokeCallback(m,NULL,request_output_real_format,6,0);
2625#endif
2626      freeMaps(&bmap);
2627      free(bmap);
2628      unlink (fbkp1);
2629      unhandleStatus (m);
2630#ifdef RELY_ON_DB
2631#ifdef META_DB
2632      cleanupCallbackThreads();
2633      close_sql(m,1);
2634#endif
2635      close_sql(m,0);
2636      end_sql();
2637#endif
2638      free(fbkpid);
2639      free(fbkpres); 
2640      free (fbkp1);
2641      if(cgiSid!=NULL)
2642        free(cgiSid);
2643      //InternetCloseHandle (&hInternet);
2644      fprintf (stderr, "RUN IN BACKGROUND MODE %s %d \n",__FILE__,__LINE__);
2645      fflush(stderr);
2646      fclose (stderr);
2647      unlink (flog);
2648      free (flog);
2649    }
2650  else{
2651    //InternetCloseHandle (&hInternet); 
2652#ifdef META_DB
2653    close_sql(m,0);
2654#endif
2655  }
2656 
2657  freeService (&s1);
2658  free (s1);
2659  freeMaps (&m);
2660  free (m);
2661
2662  freeMaps (&request_input_real_format);
2663  free (request_input_real_format);
2664
2665  freeMaps (&request_output_real_format);
2666  free (request_output_real_format);
2667
2668  free (REQUEST);
2669  free (SERVICE_URL);
2670#ifdef DEBUG
2671  fprintf (stderr, "Processed response \n");
2672  fflush (stdout);
2673  fflush (stderr);
2674#endif
2675
2676  if (((int) getpid ()) != cpid || cgiSid != NULL)
2677    {
2678      exit (0);
2679    }
2680
2681  return 0;
2682}
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png