net.cxx

Go to the documentation of this file.
00001 // @(#)root/rpdutils:$Id: net.cxx 36128 2010-10-06 15:19:27Z ganis $
00002 // Author: Fons Rademakers   12/08/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // net                                                                  //
00015 //                                                                      //
00016 // Set of network routines for rootd daemon process.                    //
00017 //                                                                      //
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 #include "RConfig.h"
00021 
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <unistd.h>
00026 #include <signal.h>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <netinet/tcp.h>
00030 #include <arpa/inet.h>
00031 #include <netdb.h>
00032 #include <errno.h>
00033 
00034 #if (defined(R__AIX) && !defined(_AIX43)) || \
00035     (defined(R__SUNGCC3) && !defined(__arch64__))
00036 #   define USE_SIZE_T
00037 #elif defined(R__GLIBC) || defined(R__FBSD) || \
00038      (defined(R__SUNGCC3) && defined(__arch64__)) || \
00039      defined(R__OBSD) || defined(MAC_OS_X_VERSION_10_4) || \
00040      (defined(R__AIX) && defined(_AIX43))
00041 #   define USE_SOCKLEN_T
00042 #endif
00043 
00044 #include "rpdp.h"
00045 #include "rpderr.h"
00046 
00047 extern int     gDebug;
00048 
00049 namespace ROOT {
00050 
00051 extern std::string gServName[3];
00052 
00053 extern ErrorHandler_t gErrSys;
00054 extern ErrorHandler_t gErrFatal;
00055 
00056 static double  gBytesSent = 0;
00057 static double  gBytesRecv = 0;
00058 
00059 static std::string gOpenhost = "????";
00060 
00061 static int                gTcpSrvSock;
00062 static struct sockaddr_in gTcpSrvAddr;
00063 static struct sockaddr_in gTcpCliAddr;
00064 
00065 static int  gSockFd             = -1;
00066 static SigPipe_t   gSigPipeHook = 0;
00067 extern int  gParallel;
00068 
00069 //______________________________________________________________________________
00070 double NetGetBytesRecv()
00071 {
00072    // return received bytes
00073    return gBytesRecv;
00074 }
00075 
00076 //______________________________________________________________________________
00077 double NetGetBytesSent()
00078 {
00079    // return sent bytes
00080    return gBytesSent;
00081 }
00082 
00083 //______________________________________________________________________________
00084 void NetGetRemoteHost(std::string &OpenHost)
00085 {
00086    // Return name of connected host
00087    OpenHost = gOpenhost;
00088 }
00089 
00090 //______________________________________________________________________________
00091 int NetGetSockFd()
00092 {
00093    // return open socket descriptor
00094    return gSockFd;
00095 }
00096 
00097 //______________________________________________________________________________
00098 void NetResetByteCount()
00099 {
00100    // reset byte counts
00101    gBytesRecv = 0;
00102    gBytesSent = 0;
00103 }
00104 
00105 //______________________________________________________________________________
00106 void NetSetSigPipeHook(SigPipe_t Hook)
00107 {
00108    // Set hook for SIGPIPE calls
00109    gSigPipeHook = Hook;
00110 }
00111 
00112 //______________________________________________________________________________
00113 static int Sendn(int sock, const void *buffer, int length)
00114 {
00115    // Send exactly length bytes from buffer.
00116 
00117    if (sock < 0) return -1;
00118 
00119    int n, nsent = 0;
00120    const char *buf = (const char *)buffer;
00121 
00122    for (n = 0; n < length; n += nsent) {
00123       if ((nsent = send(sock, buf+n, length-n, 0)) <= 0) {
00124          Error(gErrFatal, -1, "Sendn: error (sock: %d): errno: %d",
00125                sock, GetErrno());
00126          return nsent;
00127       }
00128    }
00129 
00130    gBytesSent += n;
00131 
00132    return n;
00133 }
00134 
00135 //______________________________________________________________________________
00136 static int Recvn(int sock, void *buffer, int length)
00137 {
00138    // Receive exactly length bytes into buffer. Returns number of bytes
00139    // received or 0 in case connection is closed. Returns -1 in case of error.
00140 
00141    if (sock < 0) return -1;
00142 
00143    int n, nrecv = 0;
00144    char *buf = (char *)buffer;
00145 
00146    for (n = 0; n < length; n += nrecv) {
00147       while ((nrecv = recv(sock, buf+n, length-n, 0)) == -1 && GetErrno() == EINTR)
00148          ResetErrno();   // probably a SIGCLD that was caught
00149       if (nrecv == 0)
00150          break;          // EOF
00151       if (nrecv < 0) {
00152          Error(gErrFatal,-1,"Recvn: error (sock: %d): errno: %d",sock,GetErrno());
00153          return nrecv;
00154       }
00155    }
00156 
00157    gBytesRecv += n;
00158 
00159    return n;
00160 }
00161 
00162 //______________________________________________________________________________
00163 int NetSendRaw(const void *buf, int len)
00164 {
00165    // Send buffer of len bytes.
00166 
00167    if (gParallel > 0) {
00168 
00169       if (NetParSend(buf, len) != len) {
00170          Error(gErrFatal,-1,"NetSendRaw: NetParSend error");
00171       }
00172 
00173    } else {
00174 
00175       if (gSockFd == -1) return -1;
00176       if (Sendn(gSockFd, buf, len) != len) {
00177          Error(gErrFatal,-1,"NetSendRaw: Sendn error");
00178       }
00179    }
00180 
00181    return len;
00182 }
00183 
00184 //______________________________________________________________________________
00185 int NetRecvRaw(void *buf, int len)
00186 {
00187    // Receive a buffer of maximum len bytes.
00188 
00189    if (gParallel > 0) {
00190 
00191       if (NetParRecv(buf, len) != len) {
00192          Error(gErrFatal,-1,"NetRecvRaw: NetParRecv error");
00193       }
00194 
00195    } else {
00196 
00197       if (gSockFd == -1) return -1;
00198       if (Recvn(gSockFd, buf, len) < 0) {
00199          Error(gErrFatal,-1,"NetRecvRaw: Recvn error (gSockFd: %d)",gSockFd);
00200       }
00201    }
00202 
00203    return len;
00204 }
00205 
00206 //______________________________________________________________________________
00207 int NetRecvRaw(int sock, void *buf, int len)
00208 {
00209    // Receive a buffer of maximum len bytes from generic socket sock.
00210 
00211    if (sock == -1) return -1;
00212 
00213    if (Recvn(sock, buf, len) < 0) {
00214       Error(gErrFatal,-1,"NetRecvRaw: Recvn error (sock: %d, errno: %d)",sock,GetErrno());
00215    }
00216 
00217    return len;
00218 }
00219 
00220 //______________________________________________________________________________
00221 int NetSend(const void *buf, int len, EMessageTypes kind)
00222 {
00223    // Send buffer of len bytes. Message will be of type "kind".
00224 
00225    int hdr[2];
00226    int hlen = sizeof(int) + len;
00227    hdr[0] = htonl(hlen);
00228    hdr[1] = htonl(kind);
00229    if (NetSendRaw(hdr, sizeof(hdr)) < 0)
00230       return -1;
00231 
00232    return NetSendRaw(buf, len);
00233 }
00234 
00235 //______________________________________________________________________________
00236 int NetSend(int code, EMessageTypes kind)
00237 {
00238    // Send integer. Message will be of type "kind".
00239 
00240    int hdr[3];
00241    int hlen = sizeof(int) + sizeof(int);
00242    hdr[0] = htonl(hlen);
00243    hdr[1] = htonl(kind);
00244    hdr[2] = htonl(code);
00245    return NetSendRaw(hdr, sizeof(hdr));
00246 }
00247 
00248 //______________________________________________________________________________
00249 int NetSend(const char *msg, EMessageTypes kind)
00250 {
00251    // Send a string. Message will be of type "kind".
00252 
00253    int len = 0;
00254 
00255    if (msg)
00256       len = strlen(msg)+1;
00257 
00258    return NetSend(msg, len, kind);
00259 }
00260 
00261 //______________________________________________________________________________
00262 int NetSendAck()
00263 {
00264    return NetSend(0, kROOTD_ACK);
00265 }
00266 
00267 //______________________________________________________________________________
00268 int NetSendError(ERootdErrors err)
00269 {
00270    return NetSend(err, kROOTD_ERR);
00271 }
00272 
00273 //______________________________________________________________________________
00274 int NetRecvAllocate(void *&buf, int &len, EMessageTypes &kind)
00275 {
00276    // Receive a buffer. Returns the newly allocated buffer, the length
00277    // of the buffer and message type in kind.
00278 
00279    int hdr[2] = { 0, 0 };
00280 
00281    if (NetRecvRaw(hdr, sizeof(hdr)) < 0)
00282       return -1;
00283 
00284    len = ntohl(hdr[0]) - sizeof(int);
00285    if (len < 0) len = 0;
00286    kind = (EMessageTypes) ntohl(hdr[1]);
00287    if (len) {
00288       buf = new char* [len];
00289       return NetRecvRaw(buf, len);
00290    }
00291    buf = 0;
00292    return 0;
00293 }
00294 
00295 //______________________________________________________________________________
00296 int NetRecv(char *msg, int len, EMessageTypes &kind)
00297 {
00298    // Receive a string of maximum len length. Returns message type in kind.
00299    // Return value is msg length.
00300 
00301    int   mlen;
00302 
00303    void *tmpbuf = 0;
00304    if (NetRecvAllocate(tmpbuf, mlen, kind) < 0)
00305       return -1;
00306    char *buf = static_cast<char *>(tmpbuf);
00307 
00308    if (mlen == 0) {
00309       msg[0] = 0;
00310       return 0;
00311    } else if (mlen > len-1) {
00312       strncpy(msg, buf, len-1);
00313       msg[len-1] = 0;
00314       mlen = len;
00315    } else {
00316       strncpy(msg, buf, mlen);
00317       msg[mlen] = 0;
00318    }
00319 
00320    delete [] buf;
00321 
00322    return mlen - 1;
00323 }
00324 
00325 //______________________________________________________________________________
00326 int NetRecv(char *msg, int max)
00327 {
00328    // Simulate TSocket::Recv(char *str, int max).
00329 
00330    EMessageTypes kind;
00331 
00332    return NetRecv((char *)msg, max, kind);
00333 }
00334 
00335 //______________________________________________________________________________
00336 int NetOpen(int inetdflag, EService service)
00337 {
00338    // Initialize the server's end.
00339    // We are passed a flag that says whether or not we are started
00340    // by a "master daemon" such as inetd. A master daemon will have
00341    // already waited for a message to arrive for us and will have
00342    // already set up the connection to the client. If we weren't
00343    // started by a master daemon, then we must wait for a client's
00344    // request to arrive.
00345 
00346 #if defined(USE_SIZE_T)
00347    size_t clilen = sizeof(gTcpCliAddr);
00348 #elif defined(USE_SOCKLEN_T)
00349    socklen_t clilen = sizeof(gTcpCliAddr);
00350 #else
00351    int clilen = sizeof(gTcpCliAddr);
00352 #endif
00353 
00354    if (inetdflag) {
00355 
00356       // When we're fired up by inetd, file decriptors 0, 1 and 2
00357       // are sockets to the client.
00358 
00359       gSockFd = 0;
00360       if (!getpeername(gSockFd, (struct sockaddr *)&gTcpCliAddr, &clilen)) {
00361          struct hostent *hp;
00362          if ((hp = gethostbyaddr((const char *)&gTcpCliAddr.sin_addr,
00363                                  sizeof(gTcpCliAddr.sin_addr), AF_INET)))
00364             gOpenhost = std::string(hp->h_name);
00365          else {
00366             struct in_addr *host_addr = (struct in_addr*)&gTcpCliAddr.sin_addr;
00367             gOpenhost = std::string(inet_ntoa(*host_addr));
00368          }
00369       }
00370 
00371       // Notify, if requested ...
00372       if (gDebug > 1)
00373          ErrorInfo("NetOpen: fired by inetd: connection from host %s"
00374                    " via socket %d", gOpenhost.data(),gSockFd);
00375 
00376       // Set several general performance network options
00377       NetSetOptions(service,gSockFd, 65535);
00378 
00379       return 0;
00380    }
00381 
00382    // For the concurrent server that's not initiated by inetd,
00383    // we have to wait for a connection request to arrive, then
00384    // fork a child to handle the client's request.
00385    // Beware that the accept() can be interrupted, such as by
00386    // a previously spawned child process that has terminated
00387    // (for which we caught the SIGCLD signal).
00388 
00389 again:
00390    int newsock = accept(gTcpSrvSock, (struct sockaddr *)&gTcpCliAddr, &clilen);
00391    if (newsock < 0) {
00392       if (GetErrno() == EINTR) {
00393          ResetErrno();
00394          goto again;   // probably a SIGCLD that was caught
00395       }
00396       Error(gErrSys,kErrFatal, "NetOpen: accept error (errno: %d) ... socket %d",
00397                     GetErrno(),gTcpSrvSock);
00398       return 0;
00399    }
00400 
00401    struct hostent *hp;
00402    if ((hp = gethostbyaddr((const char *)&gTcpCliAddr.sin_addr,
00403                            sizeof(gTcpCliAddr.sin_addr), AF_INET)))
00404       gOpenhost = std::string(hp->h_name);
00405    else {
00406       struct in_addr *host_addr = (struct in_addr*)&gTcpCliAddr.sin_addr;
00407       gOpenhost = std::string(inet_ntoa(*host_addr));
00408    }
00409 
00410    // Fork a child process to handle the client's request.
00411    // The parent returns the child pid to the caller, which is
00412    // probably a concurrent server that'll call us again, to wait
00413    // for the next client request to this well-known port.
00414 
00415    int childpid;
00416    if ((childpid = fork()) < 0)
00417       Error(gErrSys,kErrFatal, "NetOpen: server can't fork");
00418    else if (childpid > 0) {    // parent
00419       close(newsock);
00420       return childpid;
00421    }
00422 
00423    // Child process continues here.
00424    // First close the original socket so that the parent
00425    // can accept any further requests that arrive there.
00426    // Then set "gSockFd" in our process to be the descriptor
00427    // that we are going to process.
00428 
00429    close(gTcpSrvSock);
00430 
00431    gSockFd = newsock;
00432 
00433    // Notify, if requested ...
00434    if (gDebug > 1)
00435       ErrorInfo("NetOpen: concurrent server: connection from host %s"
00436                 " via socket %d", gOpenhost.data(), gSockFd);
00437 
00438    return 0;
00439 }
00440 
00441 //______________________________________________________________________________
00442 void NetClose()
00443 {
00444    // Close the network connection.
00445 
00446    if (gParallel > 0) {
00447 
00448       NetParClose();
00449 
00450    } else {
00451 
00452       close(gSockFd);
00453       if (gDebug > 0)
00454          ErrorInfo("NetClose: host = %s, fd = %d",
00455                    gOpenhost.data(), gSockFd);
00456       gSockFd = -1;
00457    }
00458 }
00459 
00460 //______________________________________________________________________________
00461 int NetInit(EService servtype, int port1, int port2, int tcpwindowsize)
00462 {
00463    // Initialize the network connection for the server, when it has *not*
00464    // been invoked by inetd. Used by rootd.
00465 
00466    // We weren't started by a master daemon.
00467    // We have to create a socket ourselves and bind our well-known
00468    // address to it.
00469 
00470    std::string service = gServName[servtype];
00471 
00472    if (port1 <= 0) {
00473       if (service.length()) {
00474          struct servent *sp = getservbyname(service.data(), "tcp");
00475          if (!sp) {
00476             if (servtype == kROOTD) {
00477                port1 = 1094;
00478             } else if (servtype == kPROOFD) {
00479                port1 = 1093;
00480             } else {
00481                fprintf(stderr,"NetInit: unknown service: %s/tcp\n", service.data());
00482                Error(gErrFatal, kErrFatal,
00483                      "NetInit: unknown service: %s/tcp", service.data());
00484             }
00485          } else {
00486             port1 = ntohs(sp->s_port);
00487          }
00488          port2 += port1;   // in this case, port2 is relative to service port
00489       } else {
00490          fprintf(stderr, "NetInit: must specify either service or port\n");
00491          Error(gErrFatal,kErrFatal,
00492                          "NetInit: must specify either service or port");
00493       }
00494    }
00495 
00496    // Create the socket and bind our local address so that any client can
00497    // send to us.
00498 
00499    if ((gTcpSrvSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00500       fprintf(stderr,     "NetInit: can't create socket\n");
00501       Error(gErrSys,kErrFatal, "NetInit: can't create socket");
00502       return gTcpSrvSock;
00503    }
00504 
00505    int val = 1;
00506    if (setsockopt(gTcpSrvSock, SOL_SOCKET, SO_REUSEADDR, (char*) &val,
00507                   sizeof(val)) == -1) {
00508       fprintf(stderr,     "NetInit: can't set SO_REUSEADDR socket option\n");
00509       Error(gErrSys, kErrFatal, "NetInit: can't set SO_REUSEADDR socket option");
00510    }
00511 
00512    // Set several general performance network options
00513    NetSetOptions(kROOTD,gTcpSrvSock, tcpwindowsize);
00514 
00515    memset(&gTcpSrvAddr, 0, sizeof(gTcpSrvAddr));
00516    gTcpSrvAddr.sin_family      = AF_INET;
00517    gTcpSrvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00518 
00519    int port;
00520    for (port= port1; port <= port2; port++) {
00521       gTcpSrvAddr.sin_port = htons(port);
00522       if (bind(gTcpSrvSock, (struct sockaddr *) &gTcpSrvAddr,
00523                sizeof(gTcpSrvAddr)) == 0) break;
00524    }
00525 
00526    if (port > port2) {
00527       fprintf(stderr, "NetInit: can't bind local address to ports %d-%d\n", port1, port2);
00528       Error(gErrSys, kErrFatal, "NetInit: can't bind local address to ports %d-%d", port1, port2);
00529    }
00530 
00531    printf("ROOTD_PORT=%d\n", port);
00532    port1 = port;
00533 
00534    // And set the listen parameter, telling the system that we're
00535    // ready to accept incoming connection requests.
00536 
00537    //   listen(gTcpSrvSock, 5);
00538    if (listen(gTcpSrvSock, 5)==-1) {
00539       ErrorInfo("NetInit: listen: error (errno: %d)",GetErrno());
00540    }
00541 
00542    if (gDebug > 0)
00543       ErrorInfo("NetInit: socket %d listening on port %d", gTcpSrvSock,
00544                 ntohs(gTcpSrvAddr.sin_port));
00545 
00546    return gTcpSrvSock;
00547 }
00548 
00549 //______________________________________________________________________________
00550 void NetSetOptions(EService serv, int sock, int tcpwindowsize)
00551 {
00552    // Set some options for network socket.
00553 
00554    int val = 1;
00555 
00556    if (serv == kROOTD) {
00557       if (!setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char *)&val,sizeof(val)))
00558          if (gDebug > 0)
00559             ErrorInfo("NetSetOptions: set TCP_NODELAY");
00560       if (!setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&val,sizeof(val))) {
00561          if (gDebug > 0)
00562             ErrorInfo("NetSetOptions: set SO_KEEPALIVE");
00563          if (gSigPipeHook != 0)
00564             signal(SIGPIPE, (*gSigPipeHook));   // handle SO_KEEPALIVE failure
00565       }
00566    }
00567 
00568    val = tcpwindowsize;
00569    if (!setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char *)&val,sizeof(val)))
00570       if (gDebug > 0)
00571          ErrorInfo("NetSetOptions: set SO_SNDBUF %d", val);
00572    if (!setsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&val,sizeof(val)))
00573       if (gDebug > 0)
00574          ErrorInfo("NetSetOptions: set SO_RCVBUF %d", val);
00575 
00576    if (gDebug > 0) {
00577 #if defined(USE_SIZE_T)
00578       size_t optlen = sizeof(val);
00579 #elif defined(USE_SOCKLEN_T)
00580       socklen_t optlen = sizeof(val);
00581 #else
00582       int optlen = sizeof(val);
00583 #endif
00584       if (serv == kROOTD) {
00585          getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&val, &optlen);
00586          ErrorInfo("NetSetOptions: get TCP_NODELAY: %d", val);
00587          getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, &optlen);
00588          ErrorInfo("NetSetOptions: get SO_KEEPALIVE: %d", val);
00589       }
00590       getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&val, &optlen);
00591       ErrorInfo("NetSetOptions: get SO_SNDBUF: %d", val);
00592       getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&val, &optlen);
00593       ErrorInfo("NetSetOptions: get SO_RCVBUF: %d", val);
00594    }
00595 }
00596 
00597 } // namespace ROOT

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