nfs-ganesha 1.4
|
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 }