/Users/maurits/Documents/studie/afstuderen/biosphere/daemon/service.c

Go to the documentation of this file.
00001 /*
00002  * Author: MA Hartman
00003  * Date: feb 26, 2007
00004  * 
00005  * Function:
00006  * Service handling subsystem.
00007  * 
00008  * License information:
00009  * 
00010  * Copyright (c) 2006 Maurits Hartman
00011  *
00012  * Permission is hereby granted, free of charge, to any person
00013  * obtaining a copy of this software and associated documentation
00014  * files (the "Software"), to deal in the Software without
00015  * restriction, including without limitation the rights to use,
00016  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00017  * copies of the Software, and to permit persons to whom the
00018  * Software is furnished to do so, subject to the following
00019  * conditions:
00020  * 
00021  * The above copyright notice and this permission notice shall be
00022  * included in all copies or substantial portions of the Software.
00023  * 
00024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00026  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00028  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00029  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00030  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00031  * OTHER DEALINGS IN THE SOFTWARE.
00032  * 
00033  */
00034 
00035 #include "service.h"
00036 #include "core_services.h"
00037 #include "mutex.h"
00038 #include "node.h"
00039 #include "settings.h"
00040 #include <copy.h>
00041 #include <list.h>
00042 #include <http_common.h>
00043 #include <io.h>
00044 #include <str.h>
00045 #include <type.h>
00046 #include <xml.h>
00047 
00048 #include <assert.h>
00049 #include <apr_pools.h>
00050 #include <apr_file_io.h>
00051 #include <apr_strings.h>
00052 #include <stdio.h>
00053 
00054 extern apr_pool_t *global_mp;
00055 
00059 static bs_list *services_pool = NULL;
00060 
00064 typedef struct service_info
00065 {
00066         bs_definition *def;             
00067         service_request_handler handler;        
00068 } service_info;
00069 
00070 
00071 bs_status init_service(apr_pool_t *mp)
00072 {
00073         bs_status rv;
00074         bs_uint64 len;
00075         bs_definition *def = NULL;
00076         char *buf, *fname;
00077         unsigned type;
00078         
00079         services_pool = new_list(mp);
00080         
00081         /* Read the core services definition file and add to pool: */
00082         fname = apr_pstrcat(mp, BIOSPHERED_PREFIX, "/bin/",
00083                         CORE_SERVICES_DEFINITION_FILE, NULL);
00084         rv = read_file_into_buf(fname, &buf, &len, mp);
00085         if (rv != BS_OK) {
00086                 fprintf(stderr, "%d Error while reading core services definition file: %s\n", rv, fname);
00087                 return rv;
00088         }
00089         
00090         /* Parse the wsdl file and add to the service pool: */
00091         rv = xlate_from_xml(buf, len, (void **) &def, &type, mp);
00092         if (rv != BS_OK) {
00093                 fprintf(stderr, "%d Error while parsing core services definition file: %s\n", rv, fname);
00094                 return rv;
00095         }
00096         rv = add_service(def, &core_service_request_handler);
00097         if (rv != BS_OK) {
00098                 fprintf(stderr, "%d Error while adding core services\n", rv);
00099                 return rv;      
00100         }
00101         return BS_OK;   
00102 }
00103 
00104 
00105 bs_status add_service(bs_definition *def, service_request_handler handler)
00106 {
00107         service_info *info;
00108         unsigned i;
00109         
00110         /* Check if the service is not already in the pool: */
00111         lock_service_mux();
00112         for (i = 0; i < list_size(services_pool); i++) {
00113                 bs_definition *tmp = ((service_info *) list_index(services_pool, i))->def;
00114                 if (streq(def->name, tmp->name)) {
00115                         fprintf(stderr, "Service with the same name already exists: %s\n", def->name);
00116                         unlock_service_mux();
00117                         return BS_SERVICE_DOUBLE;
00118                 }
00119         }
00120         unlock_service_mux();
00121         
00122         /* Add the service to the pool: */
00123         lock_pool_mux();
00124         info = (service_info *) apr_pcalloc(global_mp, sizeof(service_info));
00125         unlock_pool_mux();
00126         info->def = def;
00127         info->handler = handler;
00128         lock_service_mux();
00129         list_append(services_pool, info);
00130         unlock_service_mux();
00131         
00132         return BS_OK;
00133 }
00134 
00135 
00136 bs_status remove_service(const char *name)
00137 {
00138         unsigned i;
00139         
00140         lock_service_mux();
00141         for (i = 0; i < list_size(services_pool); i++) {        
00142                 bs_definition *def = ((service_info *) list_index(services_pool, i))->def;
00143                 if (streq(name, def->name)) {
00144                         list_remove(services_pool, i);
00145                         unlock_service_mux();
00146                         return BS_OK;   
00147                 }
00148         }
00149         unlock_service_mux();
00150         return BS_OK;
00151 }
00152 
00153 
00154 bs_status get_services(bs_definition **def, apr_pool_t *mp)
00155 {
00156         bs_definition *result = NULL;
00157         unsigned i;
00158         
00159         lock_service_mux();
00160         result = new_bs_definition(mp, "service_definitions", 0, 0, 0, 0);
00161         for (i = 0; i < list_size(services_pool); i++) {
00162                 bs_status rv;
00163                 service_info *info = list_index(services_pool, i);
00164                 rv = merge_def_with_def(mp, result, info->def);
00165                 if (rv != BS_OK) {
00166                         unlock_service_mux();
00167                         return BS_ERROR;
00168                 }
00169         }
00170         
00171         unlock_service_mux();
00172         *def = result;
00173         return BS_OK;
00174 }
00175 
00176 
00184 static bs_status handle_service_request_remotely(
00185                 const bs_service_request *request,
00186                 bs_service_response **response, apr_pool_t *mp)
00187 {
00188         bs_service_response *resp;
00189         node_info *ni;
00190         bs_status rv;
00191         
00192         /* Look for the first node that can service the request: */
00193         ni = get_servicing_node(request);
00194         if (!ni) return BS_NO_SERVICE;
00195         
00196         /* Forward the request to that node: */
00197         rv = connect_and_post(request, &resp, ni->address->address,
00198                         ni->address->port, mp);
00199         if (rv != BS_OK) return rv;
00200         *response = resp;
00201         return BS_OK;
00202 }
00203 
00204 
00205 bs_status handle_service_request(const bs_service_request *request,
00206                 bs_service_response **response, void *mp)
00207 {
00208         bs_status rv;
00209         bs_service_response *resp;
00210         apr_pool_t *pool;
00211         unsigned i;
00212         assert(request != NULL);
00213         
00214         /* If no pool is given, we use a temporary pool allocated
00215          * from the global pool for allocation. The response will
00216          * be a malloced copy from this temporary pool. It is the
00217          * responsibility of the caller to clean up this copy. */
00218         if (mp == NULL) {
00219                 apr_status_t rv2;
00220                 lock_pool_mux();
00221                 rv2 = apr_pool_create(&pool, global_mp);
00222                 unlock_pool_mux();
00223                 if (rv2 != APR_SUCCESS) {
00224                         fprintf(stderr, "could not create memory pool");
00225                         return BS_ERROR;        
00226                 }
00227         }
00228         else pool = mp;
00229         
00230         /* Look if the service is available locally by going through the
00231          * services list. Since the core services will be added first,
00232          * they we will considered first: */
00233         lock_service_mux();
00234         for (i = 0; i < list_size(services_pool); i++) {
00235                 service_info *si = list_index(services_pool, i);
00236                 if (request_corresponds_with_definition(request, si->def)) {
00237                         unlock_service_mux();
00238                         rv = si->handler(request, &resp, pool);
00239                         if (rv == BS_OK) {
00240                                 if (mp == NULL) {
00241                                         /* We are using a temporary pool so we must
00242                                          * make a malloced copy of this pool-alloced
00243                                          * response before destroying the temp pool: */
00244                                         *response = copy_response(resp);
00245                                         apr_pool_destroy(pool);
00246                                 }
00247                                 else {
00248                                         /* We were given a valid pool, so it is the
00249                                          * callers responsibility to look after the
00250                                          * validity of allocated objects from that
00251                                          * pool: */
00252                                         *response = resp;
00253                                 }
00254                         }
00255                         return rv;
00256                 }
00257         }
00258         unlock_service_mux();
00259         
00260         /* Try to see if it can be serviced remotely. This follows the
00261          * same pattern as with the local servicing: */
00262         rv = handle_service_request_remotely(request, &resp, pool);
00263         if (rv == BS_OK) {
00264                 if (mp == NULL) {
00265                         *response = copy_response(resp);
00266                         apr_pool_destroy(pool);
00267                 }
00268                 else {
00269                         *response = resp;
00270                 }
00271         }
00272         
00273         return rv;
00274 }

Generated on Tue Jul 17 09:50:52 2007 for Bio-SPHERE by  doxygen 1.5.1