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

Last change on this file since 861 was 861, checked in by djay, 7 years ago

Add missing flag. Remove debug messages.

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