nfs-ganesha 1.4

rpc_tools.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 <sys/types.h>
00046 #include <ctype.h>              /* for having isalnum */
00047 #include <stdlib.h>             /* for having atoi */
00048 #include <dirent.h>             /* for having MAXNAMLEN */
00049 #include <netdb.h>
00050 #include <netinet/in.h>
00051 #include <arpa/inet.h>
00052 #include <string.h>
00053 #include <pthread.h>
00054 #include <fcntl.h>
00055 #include <sys/file.h>           /* for having FNDELAY */
00056 #include <pwd.h>
00057 #include <grp.h>
00058 
00059 #include "rpcal.h"
00060 #include "LRU_List.h"
00061 #include "HashData.h"
00062 #include "HashTable.h"
00063 #include "log.h"
00064 #include "nfs_core.h"
00065 #include "nfs23.h"
00066 #include "nfs4.h"
00067 #include "fsal.h"
00068 #include "nfs_tools.h"
00069 #include "nfs_exports.h"
00070 #include "nfs_file_handle.h"
00071 #include "nfs_dupreq.h"
00072 
00073 const char *str_sock_type(int st)
00074 {
00075   static char buf[16];
00076   switch (st)
00077     {
00078       case SOCK_STREAM: return "SOCK_STREAM";
00079       case SOCK_DGRAM:  return "SOCK_DGRAM ";
00080       case SOCK_RAW:    return "SOCK_RAW   ";
00081     }
00082   sprintf(buf, "%d", st);
00083   return buf;
00084 }
00085 
00086 const char *str_ip_proto(int p)
00087 {
00088   static char buf[16];
00089   switch (p)
00090     {
00091       case IPPROTO_IP:  return "IPPROTO_IP ";
00092       case IPPROTO_TCP: return "IPPROTO_TCP";
00093       case IPPROTO_UDP: return "IPPROTO_UDP";
00094     }
00095   sprintf(buf, "%d", p);
00096   return buf;
00097 }
00098 
00099 const char *str_af(int af)
00100 {
00101   static char buf[16];
00102   switch (af)
00103     {
00104       case AF_INET:  return "AF_INET ";
00105       case AF_INET6: return "AF_INET6";
00106     }
00107   sprintf(buf, "%d", af);
00108   return buf;
00109 }
00110 
00111 const char *xprt_type_to_str(xprt_type_t type)
00112 {
00113   switch(type)
00114     {
00115       case XPRT_UDP:        return "udp";
00116       case XPRT_TCP:        return "tcp";
00117       case XPRT_TCP_RENDEZVOUS: return "tcp rendezvous";
00118       case XPRT_UNKNOWN:    return "UNKNOWN";
00119       case XPRT_SCTP:       return "sctp";
00120       case XPRT_RDMA:       return "rdma";
00121     }
00122   return "INVALID";
00123 }
00124 
00137 int copy_xprt_addr(sockaddr_t *addr, SVCXPRT *xprt)
00138 #ifdef _USE_TIRPC
00139 {
00140   struct netbuf *phostaddr = svc_getcaller_netbuf(xprt);
00141   if(phostaddr->len > sizeof(sockaddr_t) || phostaddr->buf == NULL)
00142     return 0;
00143   memcpy(addr, phostaddr->buf, phostaddr->len);
00144   return 1;
00145 }
00146 #else
00147 {
00148   struct sockaddr_in *phostaddr = svc_getcaller(xprt);
00149 
00150   memcpy(addr, phostaddr, sizeof(sockaddr_t));
00151   return 1;
00152 }
00153 #endif
00154 
00155 
00170 unsigned long hash_sockaddr(sockaddr_t *addr, ignore_port_t ignore_port)
00171 {
00172   unsigned long addr_hash = 0;
00173   int port;
00174 #ifdef _USE_TIRPC
00175   switch(addr->ss_family)
00176     {
00177       case AF_INET:
00178         {
00179           struct sockaddr_in *paddr = (struct sockaddr_in *)addr;
00180           addr_hash = paddr->sin_addr.s_addr;
00181           if(ignore_port == CHECK_PORT)
00182             {
00183               port = paddr->sin_port;
00184               addr_hash ^= (port<<16);
00185             }
00186           break;
00187         }
00188       case AF_INET6:
00189         {
00190           struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)addr;
00191 
00192           addr_hash = paddr->sin6_addr.s6_addr32[0] ^
00193                       paddr->sin6_addr.s6_addr32[1] ^
00194                       paddr->sin6_addr.s6_addr32[2] ^
00195                       paddr->sin6_addr.s6_addr32[3];
00196           if(ignore_port == CHECK_PORT)
00197             {
00198               port = paddr->sin6_port;
00199               addr_hash ^= (port<<16);
00200             }
00201           break;
00202         }
00203       default:
00204         break;
00205     }
00206 #else
00207   addr_hash = addr->sin_addr.s_addr;
00208   if(ignore_port == CHECK_PORT)
00209     {
00210       port = addr->sin_port;
00211       addr_hash ^= (port<<16);
00212     }
00213 #endif
00214 
00215   return addr_hash;
00216 }
00217 
00218 int sprint_sockaddr(sockaddr_t *addr, char *buf, int len)
00219 {
00220   const char *name = NULL;
00221   int port, alen;
00222 
00223   buf[0] = '\0';
00224 
00225 #ifdef _USE_TIRPC
00226   switch(addr->ss_family)
00227     {
00228       case AF_INET:
00229         name = inet_ntop(addr->ss_family, &(((struct sockaddr_in *)addr)->sin_addr), buf, len);
00230         port = ntohs(((struct sockaddr_in *)addr)->sin_port);
00231         break;
00232       case AF_INET6:
00233         name = inet_ntop(addr->ss_family, &(((struct sockaddr_in6 *)addr)->sin6_addr), buf, len);
00234         port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
00235         break;
00236       case AF_LOCAL:
00237         strncpy(buf, ((struct sockaddr_un *)addr)->sun_path, len);
00238         name = buf;
00239         port = -1;
00240         break;
00241       default:
00242         port = -1;
00243     }
00244 #else
00245   name = inet_ntop(addr->sin_family, &addr->sin_addr, buf, len);
00246   port = ntohs(addr->sin_port);
00247 #endif
00248 
00249   alen = strlen(buf);
00250 
00251   if(name == NULL)
00252     {
00253       strncpy(buf, "<unknown>", len);
00254       return 0;
00255     }
00256 
00257   if(port >= 0 && alen < len)
00258     snprintf(buf + alen, len - alen, ":%d", port);
00259   return 1;
00260 }
00261 
00262 int sprint_sockip(sockaddr_t *addr, char *buf, int len)
00263 {
00264   const char *name = NULL;
00265 
00266   memset(buf, 0, len);
00267 
00268 #ifdef _USE_TIRPC
00269   switch(addr->ss_family)
00270     {
00271       case AF_INET:
00272         name = inet_ntop(addr->ss_family, &(((struct sockaddr_in *)addr)->sin_addr), buf, len);
00273         break;
00274       case AF_INET6:
00275         name = inet_ntop(addr->ss_family, &(((struct sockaddr_in6 *)addr)->sin6_addr), buf, len);
00276         break;
00277       case AF_LOCAL:
00278         strncpy(buf, ((struct sockaddr_un *)addr)->sun_path, len);
00279         name = buf;
00280     }
00281 #else
00282   name = inet_ntop(addr->sin_family, &addr->sin_addr, buf, len);
00283 #endif
00284 
00285   if(name == NULL)
00286     {
00287       strncpy(buf, "<unknown>", len);
00288       return 0;
00289     }
00290   return 1;
00291 }
00292 
00305 int cmp_sockaddr(sockaddr_t *addr_1,
00306                  sockaddr_t *addr_2,
00307                  ignore_port_t ignore_port)
00308 {
00309 #ifdef _USE_TIRPC
00310   if(addr_1->ss_family != addr_2->ss_family)
00311     return 0;
00312 #else
00313   if(addr_1->sin_family != addr_2->sin_family)
00314     return 0;
00315 #endif
00316 
00317 #ifdef _USE_TIRPC
00318   switch (addr_1->ss_family)
00319 #else
00320   switch (addr_1->sin_family)
00321 #endif
00322     {
00323       case AF_INET:
00324         {
00325           struct sockaddr_in *paddr1 = (struct sockaddr_in *)addr_1;
00326           struct sockaddr_in *paddr2 = (struct sockaddr_in *)addr_2;
00327 
00328           return (paddr1->sin_addr.s_addr == paddr2->sin_addr.s_addr
00329                   && (ignore_port == IGNORE_PORT || paddr1->sin_port == paddr2->sin_port));
00330         }
00331 #ifdef _USE_TIRPC
00332       case AF_INET6:
00333         {
00334           struct sockaddr_in6 *paddr1 = (struct sockaddr_in6 *)addr_1;
00335           struct sockaddr_in6 *paddr2 = (struct sockaddr_in6 *)addr_2;
00336 
00337           return (memcmp(
00338                          paddr1->sin6_addr.s6_addr,
00339                          paddr2->sin6_addr.s6_addr,
00340                          sizeof(paddr2->sin6_addr.s6_addr)) == 0)
00341                   && (ignore_port == IGNORE_PORT || paddr1->sin6_port == paddr2->sin6_port);
00342         }
00343 #endif
00344       default:
00345         return 0;
00346     }
00347 }
00348 
00349 in_addr_t get_in_addr(sockaddr_t *addr)
00350 {
00351 #ifdef _USE_TIRPC
00352   if(addr->ss_family == AF_INET)
00353     return ((struct sockaddr_in *)addr)->sin_addr.s_addr;
00354   else
00355     return 0;
00356 #else
00357   return addr->sin_addr.s_addr;
00358 #endif
00359 }
00360 
00361 int get_port(sockaddr_t *addr)
00362 {
00363 #ifdef _USE_TIRPC
00364   switch(addr->ss_family)
00365     {
00366       case AF_INET:
00367         return ntohs(((struct sockaddr_in *)addr)->sin_port);
00368       case AF_INET6:
00369         return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
00370       default:
00371         return -1;
00372     }
00373 #else
00374   return ntohs(addr->sin_port);
00375 #endif
00376 }
00377 
00378 void socket_setoptions(int socketFd)
00379 {
00380   unsigned int SbMax = (1 << 30);       /* 1GB */
00381 
00382   while(SbMax > 1048576)
00383     {
00384       if((setsockopt(socketFd, SOL_SOCKET, SO_SNDBUF, (char *)&SbMax, sizeof(SbMax)) < 0)
00385          || (setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, (char *)&SbMax, sizeof(SbMax)) <
00386              0))
00387         {
00388           SbMax >>= 1;          /* SbMax = SbMax/2 */
00389           continue;
00390         }
00391 
00392       break;
00393     }
00394 
00395   return;
00396 }                               /* socket_setoptions_ctrl */
00397 
00398 #ifdef _USE_TIRPC
00399 #define SIZE_AI_ADDR sizeof(struct sockaddr)
00400 #else
00401 #define SIZE_AI_ADDR sizeof(struct sockaddr_in)
00402 #endif
00403 
00404 int ipstring_to_sockaddr(const char *str, sockaddr_t *addr)
00405 {
00406   struct addrinfo *info, hints, *p;
00407   int rc;
00408   char ipname[SOCK_NAME_MAX];
00409 
00410   memset(&hints, 0, sizeof(hints));
00411   hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST;
00412 #ifdef _USE_TIRPC
00413   hints.ai_family = AF_UNSPEC;
00414 #else
00415   hints.ai_family = AF_INET;
00416 #endif
00417   hints.ai_socktype = SOCK_RAW;
00418   hints.ai_protocol = 0;
00419   rc = getaddrinfo(str, NULL, &hints, &info);
00420   if (rc == 0 && info != NULL)
00421     {
00422       p = info;
00423       if(isFullDebug(COMPONENT_RPC))
00424         {
00425           while (p != NULL)
00426             {
00427               sprint_sockaddr((sockaddr_t *)p->ai_addr, ipname, sizeof(ipname));
00428               LogFullDebug(COMPONENT_RPC,
00429                            "getaddrinfo %s returned %s family=%s socktype=%s protocol=%s",
00430                            str, ipname,
00431                            str_af(p->ai_family),
00432                            str_sock_type(p->ai_socktype),
00433                            str_ip_proto(p->ai_protocol));
00434               p = p->ai_next;
00435             }
00436         }
00437       memcpy(addr, info->ai_addr, SIZE_AI_ADDR);
00438       freeaddrinfo(info);
00439     }
00440   else
00441     {
00442       switch (rc)
00443         {
00444           case EAI_SYSTEM:
00445             LogFullDebug(COMPONENT_RPC,
00446                          "getaddrinfo %s returned %d(%s)",
00447                          str, errno, strerror(errno));
00448           default:
00449             LogFullDebug(COMPONENT_RPC,
00450                          "getaddrinfo %s returned %d(%s)",
00451                          str, rc, gai_strerror(rc));
00452         }
00453     }
00454   return rc;
00455 }
00456 
00457 pthread_mutex_t clnt_create_mutex = PTHREAD_MUTEX_INITIALIZER;
00458 
00459 CLIENT *Clnt_create(char *host,
00460                     unsigned long prog,
00461                     unsigned long vers,
00462                     char *proto)
00463 {
00464   CLIENT *clnt;
00465   pthread_mutex_lock(&clnt_create_mutex);
00466   clnt = clnt_create(host, prog, vers, proto);
00467   if(clnt == NULL)
00468     {
00469       const char *err = clnt_spcreateerror("clnt_create failed");
00470       LogDebug(COMPONENT_RPC, "%s", err);
00471     }
00472   pthread_mutex_unlock(&clnt_create_mutex);
00473   return clnt;
00474 }
00475 
00476 void Clnt_destroy(CLIENT *clnt)
00477 {
00478   pthread_mutex_lock(&clnt_create_mutex);
00479   clnt_destroy(clnt);
00480   pthread_mutex_unlock(&clnt_create_mutex);
00481 }
00482 
00483 void InitRPC(int num_sock)
00484 {
00485 
00486 #if 0 /* XXXX todo:  pkginit new style */
00487   /* Allocate resources that are based on the maximum number of open file descriptors */
00488   Xports = gsh_calloc(num_sock, sizeof(SVCXPRT *));
00489   if(Xports == NULL)
00490     LogFatal(COMPONENT_RPC,
00491              "Xports array allocation failed");
00492 
00493   mutex_cond_xprt = gsh_calloc(num_sock, sizeof(pthread_mutex_t));
00494   condvar_xprt = gsh_calloc(num_sock, sizeof(pthread_cond_t));
00495 
00496   FD_ZERO(&Svc_fdset);
00497 
00498 #ifdef _USE_TIRPC
00499   /* RW_lock need to be initialized */
00500   rw_lock_init(&Svc_fd_lock);
00501 #endif
00502 #endif /* 0 */
00503 
00504 }