nfs-ganesha 1.4

nfs_stat_exporter_thread.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 3 of the License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  *
00022  * ---------------------------------------
00023  */
00024 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <pthread.h>
00047 #include <sys/stat.h>
00048 #include <time.h>
00049 #include <stdlib.h>
00050 #include <unistd.h>
00051 #include <errno.h>
00052 #include <sys/types.h>
00053 #include <sys/socket.h>
00054 #include <netinet/in.h>
00055 #include <netdb.h>
00056 #include <arpa/inet.h>
00057 #include <sys/wait.h>
00058 #include <signal.h>
00059 #include "nfs_core.h"
00060 #include "nfs_stat.h"
00061 #include "nfs_exports.h"
00062 #include "nodelist.h"
00063 #include "fsal.h"
00064 #include "ganesha_rpc.h"
00065 #include "abstract_mem.h"
00066 
00067 #define DEFAULT_PORT "10401"
00068 
00069 #define BACKLOG 10
00070 
00071 #define  CONF_STAT_EXPORTER_LABEL  "STAT_EXPORTER"
00072 #define STRCMP   strcasecmp
00073 
00074 /* Make sure this is <= the same macro in support/exports.c */
00075 #define EXPORT_MAX_CLIENTS 20
00076 #define EXPORT_MAX_CLIENTLEN 256        /* client name len */
00077 
00078 int stat_export_check_access(struct sockaddr_storage *pssaddr,
00079                              exportlist_client_t *clients,
00080                              exportlist_client_entry_t * pclient_found)
00081 {
00082   sockaddr_t *psockaddr_in;
00083 #ifdef _USE_TIRPC_IPV6
00084   struct sockaddr_in6 *psockaddr_in6;
00085   static char ten_bytes_all_0[10];
00086   static unsigned two_bytes_all_1 = 0xFFFF;
00087   char ip6string[MAXHOSTNAMELEN];
00088   memset(ten_bytes_all_0, 0, 10);
00089 #endif
00090   char ipstring[SOCK_NAME_MAX];
00091 
00092   psockaddr_in = (sockaddr_t *)pssaddr;
00093 
00094   /* For now, no matching client is found */
00095   memset(pclient_found, 0, sizeof(exportlist_client_entry_t));
00096 
00097 #ifdef _USE_TIPRC_IPV6
00098   if(psockaddr_in->sin_family == AF_INET)
00099     {
00100 #endif                          /* _USE_TIRPC_IPV6 */
00101       /* Convert IP address into a string for wild character access checks. */
00102       sprint_sockip(psockaddr_in, ipstring, sizeof(ipstring));
00103       if(ipstring == NULL)
00104         {
00105           LogCrit(COMPONENT_MAIN,
00106                   "Stat Export Check Access: Could not convert the IPv4 address to a character string.");
00107           return FALSE;
00108         }
00109       if(export_client_match
00110          (psockaddr_in, ipstring, clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS))
00111         return TRUE;
00112 #ifdef _USE_TIRPC_IPV6
00113     }
00114   else
00115     {
00116       psockaddr_in6 = (struct sockaddr_in6 *)pssaddr;
00117       if(isFulldebug(COMPONENT_MAIN))
00118         {
00119           char txtaddrv6[100];
00120 
00121           inet_ntop(psockaddr_in6->sin6_family,
00122                     psockaddr_in6->sin6_addr.s6_addr, txtaddrv6, 100);
00123           LogFullDebug(COMPONENT_MAIN,
00124                        "Client has IPv6 adress = %s", txtaddrv6);
00125         }
00126       /* If the client socket is IPv4, then it is wrapped into a   ::ffff:a.b.c.d IPv6 address. We check this here
00127        * This kind of adress is shaped like this:
00128        * |---------------------------------------------------------------|
00129        * |   80 bits = 10 bytes  | 16 bits = 2 bytes | 32 bits = 4 bytes |
00130        * |---------------------------------------------------------------|
00131        * |            0          |        FFFF       |    IPv4 address   |
00132        * |---------------------------------------------------------------|   */
00133       if(!memcmp(psockaddr_in6->sin6_addr.s6_addr, ten_bytes_all_0, 10) &&
00134          !memcmp((char *)(psockaddr_in6->sin6_addr.s6_addr + 10),
00135                  (char *)&two_bytes_all_1, 2))
00136         {
00137           /* Convert IP address into a string for wild character access checks. */
00138           inet_ntop(psockaddr_in->sin6_family, &psockaddr_in->sin6_addr,
00139                     ip6string, INET6_ADDRSTRLEN);
00140           if(ip6string == NULL)
00141             {
00142               LogCrit(COMPONENT_MAIN,
00143                       "Error: Could not convert the IPv6 address to a character string.");
00144               return FALSE;
00145             }
00146           /* This is an IPv4 address mapped to an IPv6 one. Extract the IPv4 address and proceed with IPv4 autentication */
00147           memcpy((char *)&addr, (char *)(psockaddr_in6->sin6_addr.s6_addr + 12), 4);
00148 
00149           /* Proceed with IPv4 dedicated function */
00150           /* else, check if any access only export matches this client */
00151           if(export_client_match
00152              (addr, ip6string, clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS))
00153             return TRUE;
00154         }
00155       if(export_client_matchv6
00156          (&(psockaddr_in6->sin6_addr), clients, pclient_found, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS))
00157         return TRUE;
00158     }
00159 #endif                          /* _USE_TIRPC_IPV6 */
00160   /* If this point is reached, no matching entry was found */
00161   return FALSE;
00162 
00163 }                               /* stat_export_check_access */
00164 
00165 static int parseAccessParam_for_statexporter(char *var_name, char *var_value,
00166                                              exportlist_client_t *clients)
00167 {
00168   int rc = 0, err_flag __attribute__((unused)) = FALSE;
00169   char *expended_node_list;
00170 
00171   /* temp array of clients */
00172   char *client_list[EXPORT_MAX_CLIENTS];
00173   int idx;
00174   int count;
00175 
00176   /* expends host[n-m] notations */
00177   count =
00178     nodelist_common_condensed2extended_nodelist(var_value, &expended_node_list);
00179 
00180   if(count <= 0)
00181     {
00182       err_flag = TRUE;
00183       LogCrit(COMPONENT_CONFIG,
00184               "STAT_EXPORT_ACCESS: ERROR: Invalid format for client list in EXPORT::%s definition",
00185               var_name);
00186 
00187       return -1;
00188     }
00189   else if(count > EXPORT_MAX_CLIENTS)
00190     {
00191       err_flag = TRUE;
00192       LogCrit(COMPONENT_CONFIG,
00193               "STAT_EXPORT_ACCESS: ERROR: Client list too long (%d>%d)",
00194               count, EXPORT_MAX_CLIENTS);
00195       return -1;
00196     }
00197 
00198   /* allocate clients strings  */
00199   for(idx = 0; idx < count; idx++)
00200     {
00201       client_list[idx] = gsh_malloc(EXPORT_MAX_CLIENTLEN);
00202       client_list[idx][0] = '\0';
00203     }
00204 
00205   /*
00206    * Search for coma-separated list of hosts, networks and netgroups
00207    */
00208   rc = nfs_ParseConfLine(client_list, count,
00209                          expended_node_list, find_comma, find_endLine);
00210 
00211   /* free the buffer the nodelist module has allocated */
00212   free(expended_node_list);
00213 
00214   if(rc < 0)
00215     {
00216       err_flag = TRUE;
00217       LogCrit(COMPONENT_CONFIG,
00218               "STAT_EXPORT_ACCESS: ERROR: Client list too long (>%d)", count);
00219 
00220       /* free client strings */
00221       for(idx = 0; idx < count; idx++)
00222         gsh_free(client_list[idx]);
00223 
00224       return rc;
00225     }
00226 
00227   rc = nfs_AddClientsToClientArray( clients, rc,
00228                                     (char **)client_list, EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS);
00229   if(rc != 0)
00230     {
00231       err_flag = TRUE;
00232       LogCrit(COMPONENT_CONFIG,
00233               "STAT_EXPORT_ACCESS: ERROR: Invalid client found in \"%s\"",
00234               var_value);
00235 
00236       /* free client strings */
00237       for(idx = 0; idx < count; idx++)
00238         gsh_free(client_list[idx]);
00239 
00240       return rc;
00241     }
00242 
00243   /* everything is OK */
00244 
00245   /* free client strings */
00246   for(idx = 0; idx < count; idx++)
00247     gsh_free(client_list[idx]);
00248 
00249   return rc;
00250 }
00251 
00252 
00253 int get_stat_exporter_conf(config_file_t in_config, external_tools_parameter_t * out_parameter)
00254 {
00255   int err;
00256   int var_max, var_index;
00257   char *key_name;
00258   char *key_value;
00259   config_item_t block;
00260   config_item_t item;
00261 
00262   strncpy(out_parameter->stat_export.export_stat_port, DEFAULT_PORT, MAXPORTLEN);
00263 
00264    /* Get the config BLOCK */
00265  if((block = config_FindItemByName(in_config, CONF_STAT_EXPORTER_LABEL)) == NULL)
00266     {
00267       /* cannot read item */
00268       LogCrit(COMPONENT_CONFIG,
00269               "STAT_EXPORTER: Cannot read item \"%s\" from configuration file",
00270               CONF_STAT_EXPORTER_LABEL);
00271       /* Expected to be a block */
00272       return ENOENT;
00273     }
00274   else if(config_ItemType(block) != CONFIG_ITEM_BLOCK)
00275      {
00276        LogCrit(COMPONENT_CONFIG,
00277                "STAT_EXPORTER: Cannot read item \"%s\" from configuration file",
00278                CONF_STAT_EXPORTER_LABEL);
00279       /* Expected to be a block */
00280        return ENOENT;
00281      }
00282 
00283   /* makes an iteration on the (key, value) couplets */
00284   var_max = config_GetNbItems(block);
00285 
00286   for(var_index = 0; var_index < var_max; var_index++)
00287     {
00288        /* retrieve key's name */
00289       item = config_GetItemByIndex(block, var_index);
00290       err = config_GetKeyValue(item, &key_name, &key_value);
00291 
00292       if(err)
00293         {
00294           LogCrit(COMPONENT_CONFIG,
00295                   "STAT_EXPORTER: ERROR reading key[%d] from section \"%s\" of configuration file.",
00296                   var_index, CONF_LABEL_FS_SPECIFIC);
00297           return err;
00298         }
00299 
00300       if(!STRCMP(key_name, "Access"))
00301         {
00302           parseAccessParam_for_statexporter(key_name, key_value,
00303                                             &(out_parameter->stat_export.allowed_clients));
00304         }
00305       else if(!STRCMP(key_name, "Port"))
00306         {
00307           strncpy(out_parameter->stat_export.export_stat_port, key_value, MAXPORTLEN);
00308         }
00309       else
00310         {
00311           LogCrit(COMPONENT_CONFIG,
00312                   "STAT_EXPORTER LOAD PARAMETER: ERROR: Unknown or unsettable key: %s (item %s)",
00313                   key_name, CONF_LABEL_FS_SPECIFIC);
00314           return EINVAL;
00315         }
00316     }
00317   return 0;
00318 }
00319 
00320 int merge_stats(nfs_request_stat_item_t *global_stat_items,
00321                 nfs_request_stat_item_t **workers_stat_items, int function_index, int detail_flag)
00322 {
00323   int rc = ERR_STAT_NO_ERROR;
00324   unsigned int i = 0;
00325 
00326   for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00327     {
00328       if(i == 0)
00329         {
00330           global_stat_items[function_index].total =
00331               workers_stat_items[i][function_index].total;
00332           global_stat_items[function_index].success =
00333               workers_stat_items[i][function_index].success;
00334           global_stat_items[function_index].dropped =
00335               workers_stat_items[i][function_index].dropped;
00336           global_stat_items[function_index].tot_latency =
00337               workers_stat_items[i][function_index].tot_latency;
00338           global_stat_items[function_index].min_latency =
00339               workers_stat_items[i][function_index].min_latency;
00340           global_stat_items[function_index].max_latency =
00341               workers_stat_items[i][function_index].max_latency;
00342           if(detail_flag)
00343             {
00344               global_stat_items[function_index].tot_await_time =
00345                   workers_stat_items[i][function_index].tot_await_time;
00346             }
00347         }
00348       else
00349         {
00350           global_stat_items[function_index].total +=
00351               workers_stat_items[i][function_index].total;
00352           global_stat_items[function_index].success +=
00353               workers_stat_items[i][function_index].success;
00354           global_stat_items[function_index].dropped +=
00355               workers_stat_items[i][function_index].dropped;
00356           global_stat_items[function_index].tot_latency +=
00357               workers_stat_items[i][function_index].tot_latency;
00358           set_min_latency(&(global_stat_items[function_index]),
00359               workers_stat_items[i][function_index].min_latency);
00360           set_max_latency(&(global_stat_items[function_index]),
00361               workers_stat_items[i][function_index].max_latency);
00362           if(detail_flag)
00363             {
00364               global_stat_items[function_index].tot_await_time +=
00365                   workers_stat_items[i][function_index].tot_await_time;
00366             }
00367         }
00368     }
00369 
00370   return rc;
00371 }
00372 
00373 int write_stats(char *stat_buf, int num_cmds, char **function_names, nfs_request_stat_item_t *global_stat_items, int detail_flag)
00374 {
00375   int rc = ERR_STAT_NO_ERROR;
00376 
00377   char *offset = NULL;
00378   unsigned int i = 0;
00379   unsigned int tot_calls =0, tot_latency = 0;
00380   unsigned int tot_await_time = 0;
00381   float tot_latency_ms = 0;
00382   float tot_await_time_ms = 0;
00383   char *name = NULL;
00384   char *ver __attribute__((unused)) = NULL;
00385   char *call = NULL;
00386   char *saveptr = NULL;
00387 
00388   offset = stat_buf;
00389   for(i = 0; i < num_cmds; i++)
00390     {
00391       tot_calls = global_stat_items[i].total;
00392       tot_latency = global_stat_items[i].tot_latency;
00393       tot_latency_ms = (float)((float)tot_latency / (float)1000);
00394       if(detail_flag)
00395         {
00396           tot_await_time = global_stat_items[i].tot_await_time;
00397           tot_await_time_ms = (float)((float)tot_await_time / (float)1000);
00398         }
00399 
00400       /* Extract call name from function name. */
00401       name = strdup(function_names[i]);
00402       ver = strtok_r(name, "_", &saveptr);
00403       call = strtok_r(NULL, "_", &saveptr);
00404 
00405       if(detail_flag)
00406         sprintf(offset, "_%s_ %u %.2f %.2f", call, tot_calls, tot_latency_ms, tot_await_time_ms);
00407       else
00408         sprintf(offset, "_%s_ %u %.2f", call, tot_calls, tot_latency_ms);
00409       offset += strlen(stat_buf);
00410       if(i != num_cmds - 1)
00411         {
00412           sprintf(offset, "%s", " ");
00413           offset += 1;
00414         }
00415 
00416       free(name);
00417     }
00418 
00419   return rc;
00420 }
00421 
00422 int merge_nfs_stats_by_share(char *stat_buf, nfs_stat_client_req_t *stat_client_req,
00423                              nfs_worker_stat_t *global_data,
00424                              nfs_worker_stat_t *workers_stat)
00425 {
00426   int rc = ERR_STAT_NO_ERROR;
00427 
00428   unsigned int i = 0;
00429   unsigned int num_cmds = 0;
00430   nfs_request_stat_item_t *global_stat_items = NULL;
00431   nfs_request_stat_item_t *workers_stat_items[nfs_param.core_param.nb_worker];
00432   char **function_names = NULL;
00433 
00434   switch(stat_client_req->nfs_version)
00435     {
00436       case 2:
00437         num_cmds = NFS_V2_NB_COMMAND;
00438         global_stat_items = (global_data->stat_req.stat_req_nfs2);
00439         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00440           {
00441             workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs2);
00442           }
00443         function_names = nfsv2_function_names;
00444       break;
00445 
00446       case 3:
00447         num_cmds = NFS_V3_NB_COMMAND;
00448         global_stat_items = (global_data->stat_req.stat_req_nfs3);
00449         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00450           {
00451             workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs3);
00452           }
00453         function_names = nfsv3_function_names;
00454       break;
00455 
00456       case 4:
00457         num_cmds = NFS_V4_NB_COMMAND;
00458         global_stat_items = (global_data->stat_req.stat_req_nfs4);
00459         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00460           {
00461             workers_stat_items[i] = (workers_stat[i].stat_req.stat_req_nfs4);
00462           }
00463         function_names = nfsv4_function_names;
00464       break;
00465 
00466       default:
00467         // TODO: Invalid NFS version handling
00468         LogCrit(COMPONENT_MAIN, "Error: Invalid NFS version.");
00469       break;
00470     }
00471 
00472   switch(stat_client_req->stat_type)
00473     {
00474       case PER_SERVER:
00475       case PER_SHARE:
00476         for(i = 0; i < num_cmds; i++)
00477           {
00478             rc = merge_stats(global_stat_items, workers_stat_items, i, 0);
00479           }
00480         rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 0);
00481       break;
00482 
00483       case PER_SERVER_DETAIL:
00484       case PER_SHARE_DETAIL:
00485         for(i = 0; i < num_cmds; i++)
00486           {
00487             rc = merge_stats(global_stat_items, workers_stat_items, i, 1);
00488           }
00489         rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 1);
00490       break;
00491 
00492       case PER_CLIENT:
00493       break;
00494 
00495       case PER_CLIENTSHARE:
00496       break;
00497 
00498       default:
00499         // TODO: Invalid stat type handling
00500         LogCrit(COMPONENT_MAIN, "Error: Invalid stat type.");
00501       break;
00502         }
00503 
00504   return rc;
00505 }
00506 
00507 
00508 int merge_nfs_stats(char *stat_buf, nfs_stat_client_req_t *stat_client_req,
00509                     nfs_worker_stat_t *global_data, nfs_worker_data_t *workers_data)
00510 {
00511   int rc = ERR_STAT_NO_ERROR;
00512 
00513   unsigned int i = 0;
00514   unsigned int num_cmds = 0;
00515   nfs_request_stat_item_t *global_stat_items = NULL;
00516   nfs_request_stat_item_t *workers_stat_items[nfs_param.core_param.nb_worker];
00517   char **function_names = NULL;
00518 
00519   switch(stat_client_req->nfs_version)
00520     {
00521       case 2:
00522         num_cmds = NFS_V2_NB_COMMAND;
00523         global_stat_items = (global_data->stat_req.stat_req_nfs2);
00524         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00525           {
00526             workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs2);
00527           }
00528         function_names = nfsv2_function_names;
00529       break;
00530 
00531       case 3:
00532         num_cmds = NFS_V3_NB_COMMAND;
00533         global_stat_items = (global_data->stat_req.stat_req_nfs3);
00534         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00535           {
00536             workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs3);
00537           }
00538         function_names = nfsv3_function_names;
00539       break;
00540 
00541       case 4:
00542         num_cmds = NFS_V4_NB_COMMAND;
00543         global_stat_items = (global_data->stat_req.stat_req_nfs4);
00544         for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00545           {
00546             workers_stat_items[i] = (workers_data[i].stats.stat_req.stat_req_nfs4);
00547           }
00548         function_names = nfsv4_function_names;
00549       break;
00550 
00551       default:
00552         // TODO: Invalid NFS version handling
00553         LogCrit(COMPONENT_MAIN, "Error: Invalid NFS version.");
00554       break;
00555     }
00556 
00557   switch(stat_client_req->stat_type)
00558     {
00559       case PER_SERVER:
00560       case PER_SHARE:
00561         for(i = 0; i < num_cmds; i++)
00562           {
00563             rc = merge_stats(global_stat_items, workers_stat_items, i, 0);
00564           }
00565         rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 0);
00566       break;
00567 
00568       case PER_SERVER_DETAIL:
00569       case PER_SHARE_DETAIL:
00570         for(i = 0; i < num_cmds; i++)
00571           {
00572             rc = merge_stats(global_stat_items, workers_stat_items, i, 1);
00573           }
00574         rc = write_stats(stat_buf, num_cmds, function_names, global_stat_items, 1);
00575       break;
00576 
00577       case PER_CLIENT:
00578       break;
00579 
00580       case PER_CLIENTSHARE:
00581       break;
00582 
00583       default:
00584         // TODO: Invalid stat type handling
00585         LogCrit(COMPONENT_MAIN, "Error: Invalid stat type.");
00586       break;
00587         }
00588 
00589   return rc;
00590 }
00591 
00592 int process_stat_request(int new_fd)
00593 {
00594   int rc = ERR_STAT_NO_ERROR;
00595 
00596   char cmd_buf[4096];
00597 
00598   char stat_buf[4096];
00599   char *token = NULL;
00600   char *key = NULL;
00601   char *value = NULL;
00602   char *saveptr1 = NULL;
00603   char *saveptr2 = NULL;
00604 
00605   exportlist_t *pexport = NULL;
00606 
00607   nfs_worker_stat_t global_worker_stat;
00608   nfs_stat_client_req_t stat_client_req;
00609   memset(&stat_client_req, 0, sizeof(nfs_stat_client_req_t));
00610   memset(cmd_buf, 0, 4096);
00611 
00612   if((rc = recv(new_fd, cmd_buf, 4096, 0)) == -1)
00613     LogError(COMPONENT_MAIN, ERR_SYS, errno, rc);
00614 
00615   /* Parse command options. */
00616   token = strtok_r(cmd_buf, ",", &saveptr1);
00617   while(token != NULL)
00618   {
00619     key = strtok_r(token, "=", &saveptr2);
00620     value = strtok_r(NULL, "=", &saveptr2);
00621 
00622     if(key != NULL && value != NULL)
00623     {
00624       if(strcmp(key, "version") == 0)
00625       {
00626         stat_client_req.nfs_version = atoi(value);
00627       }
00628       else if(strcmp(key, "type") == 0)
00629       {
00630         if(strcmp(value, "all") == 0)
00631           {
00632             stat_client_req.stat_type = PER_SERVER;
00633           }
00634         else if(strcmp(value, "all_detail") == 0)
00635           {
00636             stat_client_req.stat_type = PER_SERVER_DETAIL;
00637           }
00638         else if(strcmp(value, "share") == 0)
00639           {
00640             stat_client_req.stat_type = PER_SHARE;
00641           }
00642         else if(strcmp(value, "share_detail") == 0)
00643           {
00644             stat_client_req.stat_type = PER_SHARE_DETAIL;
00645           }
00646       }
00647       else if(strcmp(key, "path") == 0)
00648         {
00649           strcpy(stat_client_req.share_path, value);
00650       }
00651     }
00652 
00653     token = strtok_r(NULL, ",", &saveptr1);
00654   }
00655 
00656   memset(stat_buf, 0, 4096);
00657 
00658   if(stat_client_req.stat_type == PER_SHARE ||
00659      stat_client_req.stat_type == PER_SHARE_DETAIL)
00660     {
00661       LogDebug(COMPONENT_MAIN, "share path %s",
00662                stat_client_req.share_path);
00663 
00664       // Get export entry
00665       pexport = GetExportEntry(stat_client_req.share_path);
00666       if(!pexport)
00667         {
00668           LogEvent(COMPONENT_MAIN, "Invalid export, discard stat request");
00669           goto exit;
00670         }
00671       else
00672         LogDebug(COMPONENT_MAIN, "Got export entry, pexport %p", pexport);
00673 
00674       merge_nfs_stats_by_share(stat_buf, &stat_client_req, &global_worker_stat,
00675                                pexport->worker_stats);
00676     }
00677   else
00678     {
00679       merge_nfs_stats(stat_buf, &stat_client_req, &global_worker_stat,
00680                       workers_data);
00681     }
00682 
00683   if((rc = send(new_fd, stat_buf, 4096, 0)) == -1)
00684     LogError(COMPONENT_MAIN, ERR_SYS, errno, rc);
00685 
00686 exit:
00687   close(new_fd);
00688 
00689   return rc;
00690 }
00691 
00692 int check_permissions() {
00693   return 0;
00694 }
00695 
00696 void *stat_exporter_thread(void *UnusedArg)
00697 {
00698   int sockfd, new_fd;
00699   struct addrinfo hints, *servinfo, *p;
00700   struct sockaddr_storage their_addr;
00701   socklen_t sin_size;
00702   int yes = 1;
00703   char s[INET6_ADDRSTRLEN];
00704   int rc;
00705   exportlist_client_entry_t pclient_found;
00706 
00707   SetNameFunction("statistics_exporter");
00708 
00709   memset(&hints, 0, sizeof hints);
00710 
00711 #ifndef _USE_TIRPC_IPV6
00712   hints.ai_family = AF_INET;
00713 #else
00714   hints.ai_family = AF_INET6;
00715 #endif
00716   hints.ai_socktype = SOCK_STREAM;
00717   hints.ai_flags = AI_PASSIVE;
00718 
00719   if((rc = getaddrinfo(NULL, nfs_param.extern_param.stat_export.export_stat_port, &hints, &servinfo)) != 0)
00720     {
00721       LogCrit(COMPONENT_MAIN, "getaddrinfo: %s", gai_strerror(rc));
00722       return NULL;
00723     }
00724   for(p = servinfo; p != NULL; p = p->ai_next)
00725     {
00726       if((sockfd = socket(p->ai_family, p->ai_socktype,
00727                           p->ai_protocol)) == -1)
00728         {
00729           LogError(COMPONENT_MAIN, ERR_SYS, errno, sockfd);
00730           continue;
00731         }
00732 
00733       if((rc = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
00734                           sizeof(int))) == -1)
00735         {
00736           LogError(COMPONENT_MAIN, ERR_SYS, errno, rc);
00737           freeaddrinfo(servinfo);
00738           return NULL;
00739         }
00740 
00741       if((rc = bind(sockfd, p->ai_addr, p->ai_addrlen)) == -1)
00742         {
00743           close(sockfd);
00744           LogError(COMPONENT_MAIN, ERR_SYS, errno, rc);
00745           continue;
00746         }
00747 
00748       break;
00749     }
00750 
00751   if(p == NULL)
00752     {
00753       LogCrit(COMPONENT_MAIN, "server: failed to bind");
00754       freeaddrinfo(servinfo);
00755       return NULL;
00756     }
00757 
00758   freeaddrinfo(servinfo);
00759   if((rc = listen(sockfd, BACKLOG)) == -1)
00760     {
00761       LogError(COMPONENT_MAIN, ERR_SYS, errno, rc);
00762       return NULL;
00763     }
00764   LogInfo(COMPONENT_MAIN, "Stat export server: Waiting for connections...");
00765 
00766   while(1)
00767     {
00768       sin_size = sizeof their_addr;
00769       new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
00770       if(new_fd == -1)
00771         {
00772           LogError(COMPONENT_MAIN, ERR_SYS, errno, new_fd);
00773           continue;
00774         }
00775 
00776       sprint_sockip((sockaddr_t *)&their_addr, s, sizeof s);
00777 
00778       if (stat_export_check_access(&their_addr,
00779                                    &(nfs_param.extern_param.stat_export.allowed_clients),
00780                                    &pclient_found)) {
00781         LogDebug(COMPONENT_MAIN, "Stat export server: Access granted to %s", s);
00782         process_stat_request(new_fd);
00783       } else {
00784         LogWarn(COMPONENT_MAIN, "Stat export server: Access denied to %s", s);
00785       }
00786     }                           /* while ( 1 ) */
00787 
00788   return NULL;
00789 }                               /* stat_exporter_thread */
00790 
00791 void *long_processing_thread(void *UnusedArg)
00792 {
00793   struct timeval timer_end;
00794   struct timeval timer_diff;
00795   int i;
00796 
00797   SetNameFunction("long_processing");
00798 
00799   while(1)
00800     {
00801       sleep(1);
00802       gettimeofday(&timer_end, NULL);
00803 
00804       for(i = 0; i < nfs_param.core_param.nb_worker; i++)
00805         {
00806           P(workers_data[i].request_pool_mutex);
00807           if(workers_data[i].timer_start.tv_sec == 0)
00808             {
00809               V(workers_data[i].request_pool_mutex);
00810               continue;
00811             }
00812           timer_diff = time_diff(workers_data[i].timer_start, timer_end);
00813           V(workers_data[i].request_pool_mutex);
00814           if(timer_diff.tv_sec == nfs_param.core_param.long_processing_threshold ||
00815              timer_diff.tv_sec == nfs_param.core_param.long_processing_threshold * 10)
00816             LogEvent(COMPONENT_DISPATCH,
00817                      "Worker#%d: Function %s has been running for %llu.%.6llu seconds",
00818                      i, workers_data[i].pfuncdesc->funcname,
00819                      (unsigned long long)timer_diff.tv_sec,
00820                      (unsigned long long)timer_diff.tv_usec);
00821         }
00822     }
00823 
00824   return NULL;
00825 }                               /* long_processing_thread */