XrdNetSocket.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d N e t S o c k e t . c c                        */
00004 /*                                                                            */
00005 /* (C) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                          All Rights Reserved                               */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC03-76-SFO0515 with the Deprtment of Energy               */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdNetSocket.cc 35287 2010-09-14 21:19:35Z ganis $
00012 
00013 const char *XrdNetSocketCVSID = "$Id: XrdNetSocket.cc 35287 2010-09-14 21:19:35Z ganis $";
00014 
00015 #ifndef WIN32
00016 #include <unistd.h>
00017 #include <errno.h>
00018 #include <fcntl.h>
00019 #include <poll.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <strings.h>
00023 #include <netinet/in.h>
00024 #include <netinet/tcp.h>
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <sys/stat.h>
00028 #include <sys/un.h>
00029 #else
00030 #include <errno.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <Winsock2.h>
00037 #include "XrdSys/XrdWin32.hh"
00038 #endif
00039 
00040 #include "XrdNet/XrdNetConnect.hh"
00041 #include "XrdNet/XrdNetDNS.hh"
00042 #include "XrdNet/XrdNetOpts.hh"
00043 #include "XrdNet/XrdNetSocket.hh"
00044 #include "XrdSys/XrdSysError.hh"
00045 #include "XrdOuc/XrdOucUtils.hh"
00046 #include "XrdSys/XrdSysPlatform.hh"
00047 
00048 /******************************************************************************/
00049 /*                         l o c a l   d e f i n e s                          */
00050 /******************************************************************************/
00051   
00052 #define XRDNETSOCKET_MAXBKLG 255
00053 #define XRDNETSOCKET_LINGER    3
00054 
00055 #define Err(p,a,b,c) (ErrCode = (eroute ? eroute->Emsg(#p, a, b, c) : ErrCode),-1)
00056 
00057 /******************************************************************************/
00058 /*                           C o n s t r u c t o r                            */
00059 /******************************************************************************/
00060 
00061 XrdNetSocket::XrdNetSocket(XrdSysError *erobj, int SockFileDesc)
00062 {
00063    ErrCode  = 0;
00064    PeerName = 0;
00065    SockFD   = SockFileDesc;
00066    eroute   = erobj;
00067 }
00068 
00069 /******************************************************************************/
00070 /*                                A c c e p t                                 */
00071 /******************************************************************************/
00072   
00073 int XrdNetSocket::Accept(int timeout)
00074 {
00075    int retc, ClientSock;
00076 
00077    ErrCode = 0;
00078 
00079    // Check if a timeout was requested
00080    //
00081    if (timeout >= 0)
00082       {struct pollfd sfd = {SockFD,
00083                             POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI|POLLHUP, 0};
00084        do {retc = poll(&sfd, 1, timeout);}
00085                   while(retc < 0 && (errno == EAGAIN || errno == EINTR));
00086        if (!sfd.revents) return -1;
00087       }
00088 
00089    do {ClientSock = accept(SockFD, (struct sockaddr *)0, 0);}
00090       while(ClientSock < 0 && errno == EINTR);
00091 
00092    if (ClientSock < 0 && eroute) eroute->Emsg("Accept",errno,"accept connection");
00093 
00094    // Return the socket number.
00095    //
00096    return ClientSock;
00097 }
00098 
00099 /******************************************************************************/
00100 /*                                 C l o s e                                  */
00101 /******************************************************************************/
00102 
00103 void XrdNetSocket::Close()
00104 {
00105      // Close any open file descriptor.
00106      //
00107      if (SockFD >= 0) {close(SockFD); SockFD=-1;} 
00108 
00109      // Free any previous peername pointer
00110      //
00111      if (PeerName) {free(PeerName); PeerName = 0;}
00112 
00113      // Reset values and return.
00114      //
00115      ErrCode=0;
00116 }
00117 
00118 /******************************************************************************/
00119 /*                                C r e a t e                                 */
00120 /******************************************************************************/
00121 
00122 XrdNetSocket *XrdNetSocket::Create(XrdSysError *Say, const char *path, 
00123                                    const char *fn, mode_t mode, int opts)
00124 {
00125    XrdNetSocket *ASock;
00126    int pflags    = (opts & XRDNET_FIFO ? S_IFIFO : S_IFSOCK);
00127    int sflags    = (opts & XRDNET_UDPSOCKET) | XRDNET_SERVER;
00128    int rc = 0;
00129    mode_t myMode = (mode & (S_IRWXU | S_IRWXG));
00130    const char *eMsg = 0;
00131    char fnbuff[1024] = {0};
00132 
00133 // Setup the path
00134 //
00135    if (!socketPath(Say, fnbuff, path, fn, mode|pflags))
00136       return (XrdNetSocket *)0;
00137 
00138 // Connect to the path
00139 //
00140    ASock = new XrdNetSocket(Say);
00141 #ifndef WIN32
00142    if (opts & XRDNET_FIFO)
00143       {if ((ASock->SockFD = mkfifo(fnbuff, mode)) < 0 && errno != EEXIST)
00144          {eMsg = "create fifo"; rc = errno;}
00145          else if ((ASock->SockFD = open(fnbuff, O_RDWR, myMode)) < 0)
00146                  {eMsg = "open fifo"; rc = ASock->LastError();}
00147       } else if (ASock->Open(fnbuff, -1, sflags) < 0) 
00148                 {eMsg = "create socket"; rc = ASock->LastError();}
00149 #else
00150    if (ASock->Open(fnbuff, -1, sflags) < 0)
00151       {eMsg = "create socket"; rc = ASock->LastError();}
00152 #endif
00153 
00154 // Return the result
00155 //
00156    if (eMsg) {Say->Emsg("Create", rc, eMsg, fnbuff);
00157               delete ASock; ASock = 0;
00158              }
00159    return ASock;
00160 }
00161 
00162 /******************************************************************************/
00163 /*                                D e t a c h                                 */
00164 /******************************************************************************/
00165   
00166 int XrdNetSocket::Detach()
00167 {  int oldFD = SockFD;
00168    SockFD = -1;
00169    if (PeerName) {free(PeerName); PeerName = 0;}
00170    return oldFD;
00171 }
00172 
00173 /******************************************************************************/
00174 /*                             g e t W i n d o w                              */
00175 /******************************************************************************/
00176   
00177 int XrdNetSocket::getWindow(int fd, int &Windowsz, XrdSysError *eDest)
00178 {
00179    socklen_t szb = (socklen_t)sizeof(Windowsz);
00180 
00181    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (Sokdata_t)&Windowsz, &szb))
00182       {if (eDest) eDest->Emsg("setWindow", errno, "set socket RCVBUF");
00183        return -1;
00184       }
00185     return 0;
00186 }
00187 
00188 /******************************************************************************/
00189 /*                                  O p e n                                   */
00190 /******************************************************************************/
00191   
00192 int XrdNetSocket::Open(const char *inpath, int port, int flags, int windowsz)
00193 {
00194    struct sockaddr_in InetAddr;
00195    struct sockaddr_un UnixAddr;
00196    struct sockaddr *SockAddr;
00197    char *errtxt = 0, pbuff[128];
00198    const char *action = "configure socket";
00199    const char *path = (inpath ? inpath : "");
00200    const char *epath= (inpath ? inpath : pbuff);
00201    int myEC, SockSize, backlog;
00202    int SockType = (flags & XRDNET_UDPSOCKET ? SOCK_DGRAM : SOCK_STREAM);
00203    const int one = 1;
00204    const SOCKLEN_t szone = (SOCKLEN_t)sizeof(one);
00205 
00206 // Supply actual port number in error messages
00207 //
00208    if (!inpath) sprintf(pbuff, "port %d", port);
00209 
00210 // Make sure this object is available for a new socket
00211 //
00212    if (SockFD >= 0) return Err(Open, EBUSY, "create socket for", epath);
00213 
00214 // Save the request flags, sometimes we need to check them from the local copy
00215 //
00216    myEC = ErrCode = 0;
00217 
00218 // Allocate a socket descriptor and bind connection address, if requested.
00219 // In most OS's we must unlink the corresponding Unix path name or bind will
00220 // fail. In some OS's, this creates a problem (e.g., Solaris) since the
00221 // file inode is used to identify the socket and will likely change. This
00222 // means that connects occuring before the bind will hang up to 3 minutes.
00223 // So, the client better be prepared to timeout connects and try again.
00224 //
00225    if (port < 0 && *path == '/')
00226       {if (strlen(path) >= sizeof(UnixAddr.sun_path))
00227           return Err(Open, ENAMETOOLONG, "create unix socket ", epath);
00228        if ((SockFD = socket(PF_UNIX, SockType, 0)) < 0)
00229           return Err(Open, errno, "create unix socket ", epath);
00230        UnixAddr.sun_family = AF_UNIX;
00231        strcpy(UnixAddr.sun_path, path);
00232        SockAddr = (struct sockaddr *)&UnixAddr;
00233        SockSize = sizeof(UnixAddr);
00234        if (flags & XRDNET_SERVER) unlink((const char *)path);
00235       } else {
00236        if ((SockFD = socket(PF_INET, SockType, 0)) < 0)
00237           return Err(Open, errno, "create inet socket to", epath);
00238        if (port < 0 && *path)
00239                      XrdNetDNS::Host2Dest(inpath,(sockaddr &)InetAddr,&errtxt);
00240              else   {XrdNetDNS::getHostAddr(path,(sockaddr &)InetAddr,&errtxt);
00241                      XrdNetDNS::setPort((sockaddr &)InetAddr, port);
00242                     }
00243           if (errtxt)
00244              {if(eroute) eroute->Emsg("Open", "Unable to obtain address for",
00245                                      epath, errtxt);
00246               Close();
00247               ErrCode = EHOSTUNREACH;
00248               return -1;
00249              }
00250        SockAddr = (struct sockaddr *)&InetAddr;
00251        SockSize = sizeof(InetAddr);
00252       }
00253 
00254 // Set the options and window size, as needed (ignore errors)
00255 //
00256    setOpts(SockFD, (flags | (*path == '/' ? XRDNET_UDPSOCKET : 0)), eroute);
00257    if (windowsz) setWindow(SockFD, windowsz, eroute);
00258 
00259 // Make sure the local endpoint can be reused
00260 //
00261    if ((*path != '/') && setsockopt(SockFD,SOL_SOCKET,SO_REUSEADDR,
00262                                    (Sokdata_t)&one, szone) && eroute)
00263       eroute->Emsg("open", errno, "set socket REUSEADDR");
00264 
00265 // Either do a connect or a bind.
00266 //
00267    if (flags & XRDNET_SERVER)
00268       {action = "bind socket to";
00269        if ( bind(SockFD, SockAddr, SockSize) ) myEC = errno;
00270           else if (SockType == SOCK_STREAM)
00271                   {action = "listen on stream";
00272                    if (!(backlog = flags & XRDNET_BKLG))
00273                       backlog = XRDNETSOCKET_MAXBKLG;
00274                    if (listen(SockFD, backlog)) myEC = errno;
00275                   }
00276        if (*path == '/') chmod(path, S_IRWXU);
00277       } else {
00278        if (SockType == SOCK_STREAM)
00279           {int tmo = flags & XRDNET_TOUT;
00280            action = "connect socket to";
00281            if (tmo) myEC = XrdNetConnect::Connect(SockFD,SockAddr,SockSize,tmo);
00282               else if (connect(SockFD, SockAddr, SockSize)) myEC = errno;
00283           }
00284        if (!myEC) {PeerName = strdup((path ? path : "?"));
00285                    if (*path == '/') XrdNetDNS::getHostAddr(0, PeerAddr);
00286                       else memcpy((void *)&PeerAddr,SockAddr,sizeof(PeerAddr));
00287                   }
00288       }
00289 
00290 // Check for any errors and return.
00291 //
00292    if (myEC)
00293       {Close(); 
00294        ErrCode = myEC;
00295        if (!(flags & XRDNET_NOEMSG) && eroute)
00296           eroute->Emsg("Open", ErrCode, action, epath);
00297        return -1;
00298       }
00299    return SockFD;
00300 }
00301 
00302 /******************************************************************************/
00303 /*                              P e e r n a m e                               */
00304 /******************************************************************************/
00305   
00306 const char *XrdNetSocket::Peername(struct sockaddr **InetAddr)
00307 {
00308    char *errtxt;
00309 
00310 // Make sure  we have something to look at
00311 //
00312    if (SockFD < 0) 
00313       {if (eroute) eroute->Emsg("Peername", 
00314                                 "Unable to obtain peer name; socket not open");
00315        return (char *)0;
00316       }
00317 
00318 // Get the host name on the other side of this socket
00319 //
00320    if (!PeerName 
00321    &&  !(PeerName = XrdNetDNS::Peername(SockFD, &PeerAddr, &errtxt)))
00322       {if (eroute) 
00323           eroute->Emsg("Peername", "Unable to obtain peer name;",errtxt);
00324        ErrCode = ESRCH;
00325       }
00326 
00327 // Return possible address and the name
00328 //
00329      if (InetAddr) *InetAddr = &PeerAddr;
00330      return PeerName;
00331 }
00332 
00333 /******************************************************************************/
00334 /*                               s e t O p t s                                */
00335 /******************************************************************************/
00336   
00337 int XrdNetSocket::setOpts(int xfd, int opts, XrdSysError *eDest)
00338 {
00339    int rc = 0;
00340    const int one = 1;
00341    const SOCKLEN_t szone = (SOCKLEN_t)sizeof(one);
00342    static int tcpprotid = XrdNetDNS::getProtoID("tcp");
00343    static struct linger liopts = {1, XRDNETSOCKET_LINGER};
00344    const SOCKLEN_t szlio = (SOCKLEN_t)sizeof(liopts);
00345 
00346    if (!(opts & XRDNET_NOCLOSEX) && fcntl(xfd, F_SETFD, FD_CLOEXEC))
00347       {rc = 1;
00348        if (eDest) eDest->Emsg("setOpts", errno, "set fd close on exec");
00349       }
00350 
00351    if (opts & XRDNET_UDPSOCKET) return rc;
00352 
00353    if (!(opts & XRDNET_NOLINGER)
00354    &&  setsockopt(xfd,SOL_SOCKET,SO_LINGER,(Sokdata_t)&liopts,szlio))
00355       {rc = 1;
00356        if (eDest) eDest->Emsg("setOpts", errno, "set socket LINGER");
00357       }
00358 
00359    if ((opts & XRDNET_KEEPALIVE)
00360    &&  setsockopt(xfd,SOL_SOCKET,SO_KEEPALIVE,(Sokdata_t)&one,szone))
00361       {rc = 1;
00362        if (eDest) eDest->Emsg("setOpts", errno, "set socket KEEPALIVE");
00363       }
00364 
00365    if (!(opts & XRDNET_DELAY)
00366    &&  setsockopt(xfd, tcpprotid, TCP_NODELAY, (Sokdata_t)&one,szone))
00367       {rc = 1;
00368        if (eDest) eDest->Emsg("setOpts", errno, "set socket NODELAY");
00369       }
00370 
00371    return rc;
00372 }
00373 
00374 /******************************************************************************/
00375 /*                             s e t W i n d o w                              */
00376 /******************************************************************************/
00377   
00378 int XrdNetSocket::setWindow(int xfd, int Windowsz, XrdSysError *eDest)
00379 {
00380    int rc = 0;
00381    const SOCKLEN_t szwb  = (SOCKLEN_t)sizeof(Windowsz);
00382 
00383    if (setsockopt(xfd, SOL_SOCKET, SO_SNDBUF,
00384                        (Sokdata_t)&Windowsz, szwb))
00385       {rc = 1;
00386        if (eDest) eDest->Emsg("setWindow", errno, "set socket SNDBUF");
00387       }
00388 
00389    if (setsockopt(xfd, SOL_SOCKET, SO_RCVBUF,
00390                        (Sokdata_t)&Windowsz, szwb))
00391       {rc = 1;
00392        if (eDest) eDest->Emsg("setWindow", errno, "set socket RCVBUF");
00393       }
00394    return rc;
00395 }
00396 
00397 /******************************************************************************/
00398 /*                            s o c k e t A d d r                             */
00399 /******************************************************************************/
00400   
00401 const char *XrdNetSocket::socketAddr(XrdSysError *Say, const char *dest,
00402                                      struct sockaddr **sockAP, int &sockAL)
00403 {
00404    struct sockaddr_in InetAddr;
00405    struct sockaddr_un UnixAddr;
00406    struct sockaddr *SockAddr;
00407    char *errtxt = 0;
00408    int port = 0, SockSize;
00409 
00410    if (*dest == '/')
00411       {if (strlen(dest) >= sizeof(UnixAddr.sun_path))
00412           {if (Say) Say->Emsg("Net", ENAMETOOLONG, "generate addr from", dest);
00413            return "socket address path too long";
00414           }
00415        UnixAddr.sun_family = AF_UNIX;
00416        strcpy(UnixAddr.sun_path, dest);
00417        SockAddr = (struct sockaddr *)&UnixAddr;
00418        SockSize = sizeof(UnixAddr);
00419       } else {
00420        if (*dest && *dest != ':')
00421                      XrdNetDNS::Host2Dest(dest,(sockaddr &)InetAddr,&errtxt);
00422           else      {XrdNetDNS::getHostAddr(dest,(sockaddr &)InetAddr,&errtxt);
00423                      if (*dest && *dest == ':') port = atoi(dest+1);
00424                      XrdNetDNS::setPort((sockaddr &)InetAddr, port);
00425                     }
00426        if (errtxt)
00427           {if (Say) Say->Emsg("Net","Unable to obtain address for",dest,errtxt);
00428            return errtxt;
00429           }
00430        SockAddr = (struct sockaddr *)&InetAddr;
00431        SockSize = sizeof(InetAddr);
00432       }
00433 
00434     sockAL = SockSize;
00435    *sockAP = (struct sockaddr *)malloc(SockSize);
00436    memcpy(*sockAP, SockAddr, SockSize);
00437    return 0;
00438 }
00439 
00440 /******************************************************************************/
00441 /*                            s o c k e t P a t h                             */
00442 /******************************************************************************/
00443 
00444 char *XrdNetSocket::socketPath(XrdSysError *Say, char *fnbuff,
00445                                const char *path, const char *fn, mode_t mode)
00446 {
00447    const int srchOK = S_IXUSR | S_IXGRP;
00448    const int sfMask = (S_IFIFO | S_IFSOCK);
00449    int rc, i, fnlen = strlen(fnbuff);
00450    mode_t myMode = (mode & (S_IRWXU | S_IRWXG)) | srchOK;
00451    struct stat buf;
00452    char *sp = 0;
00453 
00454 // Copy the const char path because makePath modifies it
00455 //
00456    i = strlen(path);
00457    if (strlcpy(fnbuff, path, 1024) >= 1024 || (i + fnlen + 1) >= 1024)
00458       {Say->Emsg("createPath", "Socket path", path, "too long");
00459        return 0;
00460       }
00461 
00462 // Check if we should separate the filename from the path
00463 //
00464    if (!fn)
00465       {if (fnbuff[i-1] == '/') fnbuff[i-1] = '\0';
00466        if ((sp = rindex(fnbuff, '/'))) *sp = '\0';
00467       }
00468    
00469 // Create the directory if it is not already there
00470 //
00471    if ((rc = XrdOucUtils::makePath(fnbuff, myMode)))
00472       {Say->Emsg("createPath", errno, "create path", path);
00473        return 0;
00474       }
00475 
00476 // Construct full filename
00477 //
00478    if (sp) *sp = '/';
00479       else {if (path[i-1] != '/') fnbuff[i++] = '/';
00480             if (fn) strcpy(fnbuff+i, fn);
00481            }
00482 
00483 // Check is we have already created it and whether we can access
00484 //
00485    if (!stat(fnbuff,&buf))
00486       {if ((buf.st_mode & S_IFMT) != (mode & sfMask))
00487           {Say->Emsg("createPath","Path",fnbuff,
00488                      (mode & S_IFSOCK) ? "exists but is not a socket"
00489                                        : "exists but is not a pipe");
00490            return 0;
00491           }
00492        if (access(fnbuff, W_OK))
00493           {Say->Emsg("cratePath", errno, "access path", fnbuff);
00494            return 0;
00495           }
00496       } else chmod(fnbuff, mode); // This may fail on some platforms
00497 
00498 // All set now
00499 //
00500    return fnbuff;
00501 }

Generated on Tue Jul 5 14:46:43 2011 for ROOT_528-00b_version by  doxygen 1.5.1