XrdNet.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                             X r d N e t . c c                              */
00004 /*                                                                            */
00005 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*       All Rights Reserved. See XrdInfo.cc for complete License Terms       */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC03-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010  
00011 //         $Id: XrdNet.cc 25932 2008-10-23 10:58:11Z ganis $
00012 
00013 const char *XrdNetCVSID = "$Id: XrdNet.cc 25932 2008-10-23 10:58:11Z ganis $";
00014 
00015 #include <errno.h>
00016 #include <stdio.h>
00017 #include <string.h>
00018 #ifndef WIN32
00019 #include <poll.h>
00020 #include <unistd.h>
00021 #include <sys/types.h>
00022 #include <sys/socket.h>
00023 #else
00024 #include "XrdSys/XrdWin32.hh"
00025 #endif
00026 
00027 #include "XrdNet/XrdNet.hh"
00028 #include "XrdNet/XrdNetDNS.hh"
00029 #include "XrdNet/XrdNetOpts.hh"
00030 #include "XrdNet/XrdNetPeer.hh"
00031 #include "XrdNet/XrdNetSecurity.hh"
00032 #include "XrdNet/XrdNetSocket.hh"
00033 
00034 #include "XrdSys/XrdSysPlatform.hh"
00035 #include "XrdSys/XrdSysError.hh"
00036 
00037 /******************************************************************************/
00038 /*                               G l o b a l s                                */
00039 /******************************************************************************/
00040   
00041 #define XRDNET_UDPBUFFSZ 32768
00042   
00043 /******************************************************************************/
00044 /*                           C o n s t r u c t o r                            */
00045 /******************************************************************************/
00046   
00047 XrdNet::XrdNet(XrdSysError *erp, XrdNetSecurity *secp)
00048 {
00049    iofd   = PortType = -1;
00050    eDest  = erp;
00051    Police = secp;
00052    Domlen = Portnum = Windowsz = netOpts = 0;
00053    Domain = 0;
00054    BuffQ  = 0;
00055 }
00056  
00057 /******************************************************************************/
00058 /*                            D e s t r u c t o r                             */
00059 /******************************************************************************/
00060   
00061 XrdNet::~XrdNet()
00062 {
00063    unBind();
00064    if (Domain) free(Domain);
00065 }
00066 
00067 /******************************************************************************/
00068 /*                                A c c e p t                                 */
00069 /******************************************************************************/
00070 
00071 int XrdNet::Accept(XrdNetPeer &myPeer, int opts, int timeout)
00072 {
00073    int retc;
00074 
00075 // Make sure we are bound to a port
00076 //
00077    if (iofd < 0) 
00078       {eDest->Emsg("Accept", "Network not bound to a port.");
00079        return 0;
00080       }
00081 
00082 // Setup up the poll structure to wait for new connections
00083 //
00084   do {if (timeout >= 0)
00085          {struct pollfd sfd = {iofd,
00086                                POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI|POLLHUP,0};
00087           do {retc = poll(&sfd, 1, timeout*1000);}
00088              while(retc < 0 && (errno == EAGAIN || errno == EINTR));
00089           if (!retc)
00090              {if (!(opts & XRDNET_NOEMSG))
00091                  eDest->Emsg("Accept", "Accept timed out.");
00092               return 0;
00093              }
00094          }
00095      } while(!(PortType == SOCK_STREAM ? do_Accept_TCP(myPeer, opts)
00096                                        : do_Accept_UDP(myPeer, opts)));
00097 
00098 // Accept completed, trim the host name if a domain has been specified,
00099 //
00100    if (Domain && !(opts & XRDNET_NODNTRIM)) Trim(myPeer.InetName);
00101    return 1;
00102 }
00103   
00104 /******************************************************************************/
00105 /*                                  B i n d                                   */
00106 /******************************************************************************/
00107   
00108 int XrdNet::Bind(int bindport, const char *contype)
00109 {
00110     XrdNetSocket mySocket(eDest);
00111     int opts = XRDNET_SERVER | netOpts;
00112     int buffsz = Windowsz;
00113 
00114 // Close any open socket here
00115 //
00116    unBind();
00117 
00118 // Get correct option settings
00119 //
00120    if (*contype != 'u') PortType = SOCK_STREAM;
00121       else {PortType = SOCK_DGRAM;
00122             opts |= XRDNET_UDPSOCKET;
00123             if (!buffsz) buffsz = XRDNET_UDPBUFFSZ;
00124            }
00125 
00126 // Try to open and bind to this port
00127 //
00128    if (mySocket.Open(0, bindport, opts, buffsz) < 0)
00129       return -mySocket.LastError();
00130 
00131 // Success, get the socket number and return
00132 //
00133    iofd = mySocket.Detach();
00134 
00135 // Obtain port number of generic port being used
00136 //
00137    Portnum = (bindport ? bindport : XrdNetDNS::getPort(iofd));
00138 
00139 // For udp sockets, we must allocate a buffer queue object
00140 //
00141    if (PortType == SOCK_DGRAM)
00142       {BuffSize = buffsz;
00143        BuffQ = new XrdNetBufferQ(buffsz);
00144       }
00145    return 0;
00146 }
00147   
00148 /******************************************************************************/
00149 
00150 int XrdNet::Bind(char *path, const char *contype)
00151 {
00152     XrdNetSocket mySocket(eDest);
00153     int opts = XRDNET_SERVER | netOpts;
00154     int buffsz = Windowsz;
00155 
00156 // Make sure this is a path and not a host name
00157 //
00158    if (*path != '/')
00159       {eDest->Emsg("Bind", "Invalid bind path -", path);
00160        return -EINVAL;
00161       }
00162 
00163 // Close any open socket here
00164 //
00165    unBind();
00166 
00167 // Get correct option settings
00168 //
00169    if (*contype != 'd') PortType = SOCK_STREAM;
00170       else {PortType = SOCK_DGRAM;
00171             opts |= XRDNET_UDPSOCKET;
00172             if (!buffsz) buffsz = XRDNET_UDPBUFFSZ;
00173            }
00174 
00175 // Try to open and bind to this path
00176 //
00177    if (mySocket.Open(path, -1, opts, buffsz) < 0) return -mySocket.LastError();
00178 
00179 // Success, get the socket number and return
00180 //
00181    iofd = mySocket.Detach();
00182 
00183 // For udp sockets, we must allocate a buffer queue object
00184 //
00185    if (PortType == SOCK_DGRAM)
00186       {BuffSize = buffsz;
00187        BuffQ = new XrdNetBufferQ(buffsz);
00188       }
00189    return 0;
00190 }
00191 
00192 /******************************************************************************/
00193 /*                               C o n n e c t                                */
00194 /******************************************************************************/
00195 
00196 int XrdNet::Connect(XrdNetPeer &myPeer,
00197                     const char *host, int port, int opts, int tmo)
00198 {
00199    XrdNetSocket mySocket(opts & XRDNET_NOEMSG ? 0 : eDest);
00200    struct sockaddr *sap;
00201    int buffsz = Windowsz;
00202 
00203 // Determine appropriate options
00204 //
00205    if (!opts) opts = netOpts;
00206    if ((opts & XRDNET_UDPSOCKET) && !buffsz) buffsz = XRDNET_UDPBUFFSZ;
00207    if (tmo > 0) opts = (opts & ~XRDNET_TOUT) | (tmo > 255 ? 255 : tmo);
00208 
00209 // Now perform the connect and return the peer structure if successful
00210 //
00211    if (mySocket.Open(host, port, opts, buffsz) < 0) return 0;
00212    if (myPeer.InetName) free(myPeer.InetName);
00213    if ((opts & XRDNET_UDPSOCKET) || !host) 
00214       {myPeer.InetName = strdup("n/a");
00215        memset((void *)&myPeer.InetAddr, 0, sizeof(myPeer.InetAddr));
00216       } else {
00217        const char *pn = mySocket.Peername(&sap);
00218        if (pn) {memcpy((void *)&myPeer.InetAddr, sap, sizeof(myPeer.InetAddr));
00219                 myPeer.InetName = strdup(pn);
00220                 if (Domain && !(opts & XRDNET_NODNTRIM)) Trim(myPeer.InetName);
00221                } else {
00222                 memset((void *)&myPeer.InetAddr, 0, sizeof(myPeer.InetAddr));
00223                 myPeer.InetName = strdup("unknown");
00224                }
00225       }
00226    myPeer.fd = mySocket.Detach();
00227    return 1;
00228 }
00229 
00230 /******************************************************************************/
00231 /*                                 R e l a y                                  */
00232 /******************************************************************************/
00233   
00234 int XrdNet::Relay(XrdNetPeer &Peer, const char *dest, int opts)
00235 {
00236    return Connect(Peer, dest, -1, opts | XRDNET_UDPSOCKET);
00237 }
00238   
00239 /******************************************************************************/
00240 /*                                S e c u r e                                 */
00241 /******************************************************************************/
00242   
00243 void XrdNet::Secure(XrdNetSecurity *secp)
00244 {
00245 
00246 // If we don't have a Police object then use the one supplied. Otherwise
00247 // merge the supplied object into the existing object.
00248 //
00249    if (Police) Police->Merge(secp);
00250       else     Police = secp;
00251 }
00252 
00253 /******************************************************************************/
00254 /*                                  T r i m                                   */
00255 /******************************************************************************/
00256   
00257 void XrdNet::Trim(char *hname)
00258 {
00259   int k = strlen(hname);
00260   char *hnp;
00261 
00262   if (Domlen && k > Domlen)
00263      {hnp = hname + (k - Domlen);
00264       if (!strcmp(Domain, hnp)) *hnp = '\0';
00265      }
00266 }
00267 
00268 /******************************************************************************/
00269 /*                                u n B i n d                                 */
00270 /******************************************************************************/
00271   
00272 void XrdNet::unBind()
00273 {
00274    if (iofd >= 0) {close(iofd); iofd=-1; Portnum=0;}
00275    if (BuffQ) {delete BuffQ; BuffQ = 0;}
00276 }
00277 
00278 /******************************************************************************/
00279 /*                                 W S i z e                                  */
00280 /******************************************************************************/
00281   
00282 int XrdNet::WSize()
00283 {
00284   int wsz;
00285 
00286   if (iofd >= 0 && !XrdNetSocket::getWindow(iofd, wsz, eDest)) return wsz;
00287   return 0;
00288 }
00289 
00290 /******************************************************************************/
00291 /*                       P r i v a t e   M e t h o d s                        */
00292 /******************************************************************************/
00293 /******************************************************************************/
00294 /*                         d o _ A c c e p t _ T C P                          */
00295 /******************************************************************************/
00296   
00297 int XrdNet::do_Accept_TCP(XrdNetPeer &myPeer, int opts)
00298 {
00299   static int noAcpt = 0;
00300   int        newfd;
00301   char      *hname;
00302   struct sockaddr addr;
00303   SOCKLEN_t  addrlen = sizeof(addr);
00304 
00305 // Accept a connection
00306 //
00307    do {newfd = accept(iofd, &addr, &addrlen);}
00308       while(newfd < 0 && errno == EINTR);
00309 
00310    if (newfd < 0)
00311       {if (errno != EMFILE || !(0x1ff & noAcpt++))
00312           eDest->Emsg("Accept", errno, "perform accept");
00313        return 0;
00314       }
00315 
00316 // Authorize by ip address or full (slow) hostname format
00317 //
00318    if (Police)
00319       {if (!(hname = Police->Authorize(&addr)))
00320           {eDest->Emsg("Accept", EACCES, "accept TCP connection from",
00321                       (hname = XrdNetDNS::getHostName(addr)));
00322            free(hname);
00323            close(newfd);
00324            return 0;
00325           }
00326       } else hname = (opts & XRDNET_NORLKUP ? XrdNetDNS::getHostID(addr)
00327                                             : XrdNetDNS::getHostName(addr));
00328 
00329 // Set all required fd options are set
00330 //
00331    XrdNetSocket::setOpts(newfd, (opts ? opts : netOpts));
00332 
00333 // Fill out the peer structure and success
00334 //
00335    myPeer.fd       = newfd;
00336    memcpy(&(myPeer.InetAddr), &addr, sizeof(myPeer.InetAddr));
00337    if (myPeer.InetName) free(myPeer.InetName);
00338    myPeer.InetName = hname;
00339    return 1;
00340 }
00341 
00342 /******************************************************************************/
00343 /*                         d o _ A c c e p t _ U D P                          */
00344 /******************************************************************************/
00345   
00346 int XrdNet::do_Accept_UDP(XrdNetPeer &myPeer, int opts)
00347 {
00348   char           *hname = 0;
00349   int             dlen;
00350   struct sockaddr addr;
00351   SOCKLEN_t       addrlen = sizeof(addr);
00352   XrdNetBuffer   *bp;
00353 
00354 // For UDP connections, get a buffer for the message. To be thread-safe, we
00355 // must actually receive the message to maintain the host-datagram pairing.
00356 //
00357    if (!(bp = BuffQ->Alloc()))
00358       {eDest->Emsg("Accept", ENOMEM, "accept UDP message");
00359        return 0;
00360       }
00361 
00362 // Read the message and get the host address
00363 //
00364    do {dlen = recvfrom(iofd,(Sokdata_t)bp->data,BuffSize-1,0,&addr,&addrlen);
00365       } while(dlen < 0 && errno == EINTR);
00366 
00367    if (dlen < 0)
00368       {eDest->Emsg("Receive", errno, "perform UDP recvfrom()");
00369        BuffQ->Recycle(bp);
00370        return 0;
00371       } else bp->data[dlen] = '\0';
00372 
00373 // Authorize this connection. We don't accept messages that set the
00374 // loopback address since this can be trivially spoofed in UDP packets.
00375 //
00376    if (XrdNetDNS::isLoopback(addr)
00377    || (Police && !(hname = Police->Authorize(&addr))))
00378       {eDest->Emsg("Accept", -EACCES, "accept connection from",
00379                      (hname = XrdNetDNS::getHostName(addr)));
00380        free(hname);
00381        BuffQ->Recycle(bp);
00382        return 0;
00383       } else {
00384        if (!hname) hname=(opts & XRDNET_NORLKUP ? XrdNetDNS::getHostID(addr)
00385                                                 : XrdNetDNS::getHostName(addr));
00386       }
00387 
00388 // Fill in the peer structure. We use our base FD for outgoing messages.
00389 // Note that XrdNetLink object never closes this FDS for UDP messages.
00390 //
00391    myPeer.fd = (opts & XRDNET_NEWFD ? dup(iofd) : iofd);
00392    memcpy(&(myPeer.InetAddr), &addr, sizeof(myPeer.InetAddr));
00393    if (myPeer.InetName) free(myPeer.InetName);
00394    myPeer.InetName = hname;
00395    if (myPeer.InetBuff) myPeer.InetBuff->Recycle();
00396    myPeer.InetBuff = bp;
00397    return 1;
00398 }

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