## modules/up/src/Core/sys/File.cc

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. private_strerror
2. File
3. File
4. setHandlers
5. read
6. write
7. DatagramSocket
8. DatagramSocket
9. recvFrom
10. sendTo
11. defaultInterface
12. RawSocket
13. RawSocket
14. recvFrom
15. sendTo
16. join
17. MulticastSocket
18. MulticastSocket
19. defaultInterface
20. setTTL
21. StreamSocket
22. StreamSocket
23. StreamSocket
24. ListenSocket
25. ListenSocket
26. accept
27. DiskFile
28. DiskFile
29. seekTo
30. seekEnd
31. lock
32. truncate
33. createDir
34. openPidFile
35. closePidFile
36. daemonize

       1 //
       2 // $Id: File.cc,v 1.1.1.1 2000/03/10 16:32:20 engin Exp $
       3 //
       4 // system.cc
       5 // Author: Ramesh Govindan <govindan@isi.edu>
       6 //
       7 // Abstracted OS facilities for file system access and
       8 // for communication primitives. This file contains implementations of:
       9 //      - network addresses (Address class)
      10 //      - OS file descriptors and descriptor sets
      11 //      - a common time representation
      12 //
      13
      14 #ifdef HAVE_CONFIG_H
      15 #include <config.h>
      16 #endif
      17
      18 #include <cstdio>
      19 #include <cstdlib>
      20 #include <cerrno>
      21
      22 extern "C" {
      23 #if HAVE_UNISTD_H
      24 #include <unistd.h>
      25 #endif // HAVE_UNISTD_H
      26
      27 #include <sys/types.h>
      28 #include <sys/socket.h>
      29 #include <sys/time.h>
      30 #include <sys/file.h>
      31 #include <sys/resource.h>
      32 #include <sys/termios.h>
      33 #include <sys/ioctl.h>
      34 #include <netinet/in.h>
      35 #include <sys/socket.h>
      36 #include <arpa/inet.h>
      37 #include <sys/stat.h>
      38 #include <fcntl.h>
      39 #include <signal.h>
      40
      41 #ifdef HOST_OS_IS_SOLARIS
      42 #include <sys/systeminfo.h>
      43 #include <netdb.h>
      44 #endif
      45 }
      46
      47 #include "util/Types.hh"
      48 #include "util/List.hh"
      49 #include "util/Handler.hh"
      50 #include "util/Trail.hh"
      51
      52 #include "sys/Address.hh"
      53 #include "sys/File.hh"
      54 #include "sys/Signal.hh"
      55 #include "sched/Dispatcher.hh"
      56 #include "network/Headers.hh"
      57
      58 // Added by wlee to port to FreeBSD and BSDI
      59 #ifndef INADDR_LOOPBACK
      60 #define INADDR_LOOPBACK         (u_long)0x7F000001
      61 #endif
      62
      63 extern "C" {
      64 #ifndef STDC_HEADERS
      65 extern int socket(...);
      66 extern int bind(...);
      67 extern int connect(...);
      68 extern int read(...);
      69 extern int write(...);
      70 extern int setsockopt(...);
      71 extern int getsockname(...);
      72 extern int close(...);
      73 extern int recvfrom(...);
      74 extern int sendto(...);
      75 extern int listen(...);
      76 extern int accept(...);
      77 extern off_t lseek(...);
      78 extern int flock(...);
      79 extern int ftruncate(...);
      80 extern int stat(...);
      81 #endif
      82 }
      83
      84 // For printing out system error messages: from GNU textutils lib
      85 #if HAVE_STRERROR
      86 #ifndef strerror
      87 extern "C" char *strerror(int);
      88 #endif
      89 #else
      90 extern int sys_nerr;
      91 extern char* sys_errlist[];
      92
      93 static char*
      94 private_strerror(int errnum)
         /* [<][>][^][v][top][bottom][index][help] */
      95 {
      96     if (errnum > 0 && errnum <= sys_nerr)
      97         return sys_errlist[errnum];
      98     return "Unknown system error";
      99 }
     100 #define strerror private_strerror
     101 #endif // HAVE_STRERROR
     102
     103 #ifdef ACCEPT_USES_SOCKLEN_T
     104 #define SOCKLEN_T socklen_t
     105 #elif ACCEPT_USES_SIZE_T
     106 #define SOCKLEN_T size_t
     107 #else
     108 #define SOCKLEN_T int
     109 #endif
     110
     111 // File local variables
     112 static TraceCode        traceFile("file");
     113 static Handler          nullHandler(NULL, NULL);
     114 static int              pidDescriptor = -1;
     115
     116 File::File(int fd,
         /* [<][>][^][v][top][bottom][index][help] */
     117            FileMode m,
     118            const Handler& rh,
     119            const Handler& wh)
     120         : ListNode()
     121 {
     122     descriptor_ = fd;
     123     mode_ = m;
     124
     125     if (descriptor_ < 0) {
     126         FATAL("couldn't open file descriptor: %s\n",
     127               strerror(errno));
     128         // NotReached
     129     }
     130
     131     readHandler = rh;
     132     writeHandler = wh;
     133     dispatcher.files.inset(this);
     134 }
     135
     136 File::~File()
         /* [<][>][^][v][top][bottom][index][help] */
     137 {
     138     TRACE(traceFile,
     139           "closing file %d\n",
     140           descriptor_);
     141     close(descriptor_);
     142     dispatcher.files.outset(this);
     143 }
     144
     145 void
     146 File::setHandlers(Handler& rh,
         /* [<][>][^][v][top][bottom][index][help] */
     147                   Handler& wh)
     148 {
     149     dispatcher.files.outset(this);
     150     readHandler = rh;
     151     writeHandler = wh;
     152     dispatcher.files.inset(this);
     153 }
     154
     155 int
     156 File::read(char *buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     157            int  bufferLength)
     158 {
     159     int retval;
     160
     161     if (mode_ != FileModeReadOnly
     162         && mode_ != FileModeReadWrite) {
     163         ERROR("illegal attempt to read from descriptor\n");
     164         return FileOpHardError;
     165     }
     166
     167     TRACE(traceFile,
     168           "read file %d length %d\n",
     169           descriptor_,
     170           bufferLength);
     171
     172     retval = ::read(descriptor_,
     173                     buffer,
     174                     bufferLength);
     175     if (retval < 0) {
     176         switch (errno) {
     177             case EWOULDBLOCK:
     178 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     179             case EAGAIN:
     180 #endif
     181             case EINTR:
     182                 return FileOpSoftError;
     183             default:
     184                 return FileOpHardError;
     185         }
     186     }
     187     return retval;
     188 }
     189
     190 int
     191 File::write(char *buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     192             int  bufferLength)
     193 {
     194     int retval;
     195
     196     if (mode_ != FileModeReadWrite) {
     197         ERROR("attempt to write on read-only file descriptor\n");
     198         return FileOpHardError;
     199     }
     200
     201     TRACE(traceFile,
     202           "write file %d length %d\n",
     203           descriptor_,
     204           bufferLength);
     205
     206     retval = ::write(descriptor_,
     207                      buffer,
     208                      bufferLength);
     209     if (retval < 0) {
     210         switch (errno) {
     211             case EWOULDBLOCK:
     212 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     213             case EAGAIN:
     214 #endif
     215             case EINTR:
     216                 return FileOpSoftError;
     217             default:
     218                 return FileOpHardError;
     219         }
     220     }
     221     return retval;
     222 }
     223
     224 DatagramSocket::DatagramSocket(const Handler& rh,
         /* [<][>][^][v][top][bottom][index][help] */
     225                                const Handler& wh)
     226         : File(::socket(AF_INET, SOCK_DGRAM, 0),
     227                FileModeReadWrite,
     228                rh,
     229                wh)
     230 {
     231     // Empty
     232 }
     233
     234 DatagramSocket::~DatagramSocket()
         /* [<][>][^][v][top][bottom][index][help] */
     235 {
     236     // Empty
     237 }
     238
     239 int
     240 DatagramSocket::recvFrom(char* buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     241                          int bufferLength,
     242                          Address& addr,
     243                          Port *port)
     244 {
     245     struct sockaddr_in sin;
     246     int retval;
     247     size_t socklen = sizeof(sin);
     248
     249     retval = ::recvfrom(descriptor_,
     250                         buffer,
     251                         bufferLength,
     252                         0,
     253                         (struct sockaddr *) &sin,
     254                         (SOCKLEN_T*)&socklen);
     255
     256     if (retval < 0) {
     257         switch (errno) {
     258             case EWOULDBLOCK:
     259 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     260             case EAGAIN:
     261 #endif
     262             case EINTR:
     263                 return FileOpSoftError;
     264             default:
     265                 return FileOpHardError;
     266         }
     267     }
     268
     269     addr.set((U32) ntohl(sin.sin_addr.s_addr));
     270     *port = ntohs(sin.sin_port);
     271     TRACE(traceFile,
     272           "read %d bytes on socket %d from %s\n",
     273           retval,
     274           descriptor_,
     275           addr.name());
     276     return retval;
     277 }
     278
     279 int
     280 DatagramSocket::sendTo(char* buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     281                        int bufferLength,
     282                        Address& addr,
     283                        Port port)
     284 {
     285     struct sockaddr_in sin;
     286     int retval;
     287
     288     sin.sin_family = AF_INET;
     289     sin.sin_addr.s_addr = htonl(addr.get());
     290     sin.sin_port = htons(port);
     291     retval = ::sendto(descriptor_,
     292                       buffer,
     293                       bufferLength,
     294                       0,
     295                       (struct sockaddr *) &sin,
     296                       sizeof(sin));
     297     if (retval < 0) {
     298         switch (errno) {
     299             case EWOULDBLOCK:
     300 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     301             case EAGAIN:
     302 #endif
     303             case EINTR:
     304                 return FileOpSoftError;
     305             default:
     306                 return FileOpHardError;
     307         }
     308     }
     309
     310     TRACE(traceFile,
     311           "wrote %d bytes on socket %d from %s\n",
     312           retval,
     313           descriptor_,
     314           addr.name());
     315
     316     return retval;
     317 }
     318
     319 int
     320 DatagramSocket::defaultInterface(Address& localAddress, const Address &dst) {
         /* [<][>][^][v][top][bottom][index][help] */
     321 #ifndef ALLOW_MULTIPLE_IFACES
     322         static bool hashed= false;
     323         static Address myOnlyIface;
     324         if (hashed)
     325                 localAddress.set(myOnlyIface.get());
     326         return FileOpOK;
     327 #endif
     328     int sock;
     329     struct sockaddr_in sin;
     330     size_t socklen = sizeof(sin);
     331
     332     sin.sin_family = AF_INET;
     333     sin.sin_addr.s_addr = htonl(dst.get());
     334     //xxx: sin.sin_port = htons(port);          // We can then use write
     335
     336     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
     337         ERROR("couldn't open socket for getting local address: %s\n",
     338               strerror(errno));
     339         return FileOpHardError;
     340     }
     341
     342     if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
     343         ERROR("couldn't connect for getting local address: %s\n",
     344               strerror(errno));
     345         return FileOpHardError;
     346     }
     347
     348     if (getsockname(sock,
     349                     (struct sockaddr *) &sin,
     350                     (SOCKLEN_T*)&socklen) < 0) {
     351         ERROR("couldn't get local address: %s\n",
     352               strerror(errno));
     353         return FileOpHardError;
     354     }
     355
     356 #ifdef HOST_OS_IS_SOLARIS
     357     if (sin.sin_addr.s_addr == 0) {
     358         char myhostname[256];
     359         struct hostent *hp;
     360         int error;
     361
     362         error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
     363         if (error == -1) {
     364             ERROR("failed on sysinfo: %s\n",
     365                   strerror(errno));
     366             exit(-1);
     367         }
     368
     369         hp = gethostbyname(myhostname);
     370         if (hp == NULL || hp->h_addrtype != AF_INET ||
     371             hp->h_length != sizeof(sin.sin_addr)) {
     372             ERROR("failed on gethostbyname: %s\n",
     373                   strerror(errno));
     374             exit(-1);
     375         }
     376         memcpy((char *)&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
     377     }
     378 #endif
     379
     380     localAddress.set(ntohl(sin.sin_addr.s_addr));
     381     close(sock);
     382     TRACE(traceFile,
     383           "default interface for dst %s is %s\n",
     384           dst.name(),
     385           localAddress.name());
     386 #ifndef ALLOW_MULTIPLE_IFACES
     387     myOnlyIface= localAddress.get();
     388     hashed= true;
     389 #endif
     390     return FileOpOK;
     391 }
     392
     393 RawSocket::RawSocket(Handler& rh,
         /* [<][>][^][v][top][bottom][index][help] */
     394                      Handler& wh,
     395                      RawSocketType type)
     396         : File(::socket(AF_INET, SOCK_RAW, type),
     397                FileModeReadWrite,
     398                rh,
     399                wh)
     400 {
     401     int bufSize = 48*1024;
     402     int bval = 1;
     403
     404 #ifdef  IP_HDRINCL
     405     if(setsockopt(descriptor_, IPPROTO_IP, IP_HDRINCL,
     406                   (char *)&bval, sizeof(bval)) < 0) {
     407         FATAL("setsockopt IP_HDRINCL %u", bval);
     408         // Not Reached
     409     }
     410 #endif
     411     if(setsockopt(descriptor_, SOL_SOCKET, SO_RCVBUF, (char *)&bufSize,
     412                   sizeof(bufSize)) < 0) {
     413         FATAL("setsockopt SO_RCVBUF %u", bufSize);
     414         // Not Reached
     415     }
     416 }
     417
     418 RawSocket::~RawSocket()
         /* [<][>][^][v][top][bottom][index][help] */
     419 {
     420     // Empty
     421 }
     422
     423 int
     424 RawSocket::recvFrom(char* buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     425                     int bufferLength,
     426                     Address& addr,
     427                     Port *port)
     428 {
     429     struct sockaddr_in sin;
     430     int retval;
     431     size_t socklen = sizeof(sin);
     432
     433     retval = ::recvfrom(descriptor_,
     434                         buffer,
     435                         bufferLength,
     436                         0,
     437                         (struct sockaddr *) &sin,
     438                         (SOCKLEN_T*)&socklen);
     439     if (retval < 0) {
     440         switch (errno) {
     441             case EWOULDBLOCK:
     442 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     443             case EAGAIN:
     444 #endif
     445             case EINTR:
     446                 return FileOpSoftError;
     447             default:
     448                 return FileOpHardError;
     449         }
     450     }
     451
     452     addr.set((U32) ntohl(sin.sin_addr.s_addr));
     453     *port = ntohs(sin.sin_port);
     454     TRACE(traceFile,
     455           "read %d bytes on raw socket %d from %s\n",
     456           retval,
     457           descriptor_,
     458           addr.name());
     459 #ifdef HOST_OS_IS_FREEBSD
     460     IP* iph= (IP*) buffer;
     461     iph->totalLength+= sizeof(IP);
     462 #endif
     463     return retval;
     464 }
     465
     466 int
     467 RawSocket::sendTo(char* buffer,
         /* [<][>][^][v][top][bottom][index][help] */
     468                   int bufferLength,
     469                   Address& addr,
     470                   Port port) const
     471 {
     472     struct sockaddr_in sin;
     473     int retval;
     474
     475     sin.sin_family = AF_INET;
     476     sin.sin_addr.s_addr = htonl(addr.get());
     477     sin.sin_port = htons(port);
     478     retval = ::sendto(descriptor_,
     479                       buffer,
     480                       bufferLength,
     481                       0,
     482                       (struct sockaddr *) &sin,
     483                       sizeof(sin));
     484     if (retval < 0) {
     485         switch (errno) {
     486             case EWOULDBLOCK:
     487 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     488             case EAGAIN:
     489 #endif
     490             case EINTR:
     491                 return FileOpSoftError;
     492             default:
     493                 return FileOpHardError;
     494         }
     495     }
     496
     497     TRACE(traceFile,
     498           "wrote %d bytes on socket %d from %s\n",
     499           retval,
     500           descriptor_,
     501           addr.name());
     502
     503     return retval;
     504 }
     505
     506 int
     507 RawSocket::join(Address& group)
         /* [<][>][^][v][top][bottom][index][help] */
     508 {
     509     struct ip_mreq mreq;
     510
     511     mreq.imr_multiaddr.s_addr = htonl(group.get());
     512     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
     513
     514     TRACE(traceFile,
     515           "joining group %s on %d\n",
     516           group.name(),
     517           descriptor_);
     518
     519     if (::setsockopt(descriptor_,
     520                      IPPROTO_IP,
     521                      IP_ADD_MEMBERSHIP,
     522                      (char *) &mreq,
     523                      sizeof(mreq)) < 0) {
     524         FATAL("failed group join on %d: %s\n",
     525               descriptor_,
     526               strerror(errno));
     527         // NotReached
     528     }
     529
     530     return FileOpOK;
     531 }
     532
     533 MulticastSocket::MulticastSocket(const Address& addr,
         /* [<][>][^][v][top][bottom][index][help] */
     534                                  Port localPort,
     535                                  const Handler& rh,
     536                                  const Handler& wh)
     537         : DatagramSocket(rh, wh)
     538 {
     539     struct ip_mreq mreq;
     540     struct sockaddr_in sin;
     541     char loop;
     542
     543     group = addr;
     544     port = localPort;
     545     sin.sin_family = AF_INET;
     546     sin.sin_port = htons(localPort);
     547     sin.sin_addr.s_addr = htonl(INADDR_ANY);
     548
     549     TRACE(traceFile,
     550           "binding socket %d to port %d\n",
     551           descriptor_,
     552           localPort);
     553
     554     if (::bind(descriptor_,
     555                (struct sockaddr *) &sin,
     556                sizeof(sin)) < 0) {
     557         FATAL("failed bind on %d: %s\n",
     558               descriptor_,
     559               strerror(errno));
     560         // NotReached
     561     }
     562
     563     mreq.imr_multiaddr.s_addr = htonl(group.get());
     564     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
     565
     566     TRACE(traceFile,
     567           "joining group %s on %d\n",
     568           group.name(),
     569           descriptor_);
     570
     571     if (::setsockopt(descriptor_,
     572                      IPPROTO_IP,
     573                      IP_ADD_MEMBERSHIP,
     574                      (char *) &mreq,
     575                      sizeof(mreq)) < 0) {
     576         FATAL("failed group join on %d: %s\n",
     577               descriptor_,
     578               strerror(errno));
     579         // NotReached
     580     }
     581
     582     // Disable loopback of packets
     583     loop = 0;
     584     if (::setsockopt(descriptor_,
     585                      IPPROTO_IP,
     586                      IP_MULTICAST_LOOP,
     587                      &loop,
     588                      sizeof(loop)) < 0) {
     589         FATAL("unable to disable multicast loopback on %d: %s\n",
     590               descriptor_,
     591               strerror(errno));
     592         // NotReached
     593     }
     594 }
     595
     596 MulticastSocket::~MulticastSocket()
         /* [<][>][^][v][top][bottom][index][help] */
     597 {
     598     struct ip_mreq mreq;
     599
     600     mreq.imr_multiaddr.s_addr = htonl(group.get());
     601     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
     602
     603     TRACE(traceFile,
     604           "deleting multicast socket for group %s on %d\n",
     605           group.name(),
     606           descriptor_);
     607
     608     (void) ::setsockopt(descriptor_,
     609                         IPPROTO_IP,
     610                         IP_DROP_MEMBERSHIP,
     611                         (char *) &mreq,
     612                         sizeof(mreq));
     613     return;
     614 }
     615
     616 int
     617 MulticastSocket::defaultInterface(Address& localAddress)
         /* [<][>][^][v][top][bottom][index][help] */
     618 {
     619     int sock;
     620     struct sockaddr_in sin;
     621     size_t socklen = sizeof(sin);
     622
     623     sin.sin_family = AF_INET;
     624     sin.sin_addr.s_addr = htonl(group.get());
     625     sin.sin_port = htons(port);         // We can then use write
     626
     627     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
     628         ERROR("couldn't open socket for getting local address: %s\n",
     629               strerror(errno));
     630         return FileOpHardError;
     631     }
     632
     633     if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
     634         ERROR("couldn't connect for getting local address: %s\n",
     635               strerror(errno));
     636         return FileOpHardError;
     637     }
     638
     639     if (getsockname(sock,
     640                     (struct sockaddr *) &sin,
     641                     (SOCKLEN_T*)&socklen) < 0) {
     642         ERROR("couldn't get local address: %s\n",
     643               strerror(errno));
     644         return FileOpHardError;
     645     }
     646
     647 #ifdef HOST_OS_IS_SOLARIS
     648     if (sin.sin_addr.s_addr == 0) {
     649         char myhostname[256];
     650         struct hostent *hp;
     651         int error;
     652
     653         error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
     654         if (error == -1) {
     655             ERROR("failed on sysinfo: %s\n",
     656                   strerror(errno));
     657             exit(-1);
     658         }
     659
     660         hp = gethostbyname(myhostname);
     661         if (hp == NULL || hp->h_addrtype != AF_INET ||
     662             hp->h_length != sizeof(sin.sin_addr)) {
     663             ERROR("failed on gethostbyname: %s\n",
     664                   strerror(errno));
     665             exit(-1);
     666         }
     667         memcpy((char *)&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
     668     }
     669 #endif
     670
     671     localAddress.set(ntohl(sin.sin_addr.s_addr));
     672     close(sock);
     673     TRACE(traceFile,
     674           "default interface for group %s is %s\n",
     675           group.name(),
     676           localAddress.name());
     677
     678     return FileOpOK;
     679 }
     680
     681 int
     682 MulticastSocket::setTTL(int ttl)
         /* [<][>][^][v][top][bottom][index][help] */
     683 {
     684     char t = ttl;
     685
     686     TRACE(traceFile,
     687           "setting ttl %d on %d\n",
     688           ttl,
     689           descriptor_);
     690
     691     if (::setsockopt(descriptor_,
     692                      IPPROTO_IP,
     693                      IP_MULTICAST_TTL,
     694                      (char *) &t,
     695                      sizeof(t)) < 0) {
     696         ERROR("failed ttl set on %d: %s\n",
     697               descriptor_,
     698               strerror(errno));
     699         return FileOpHardError;
     700     }
     701     return FileOpOK;
     702 }
     703
     704 StreamSocket::StreamSocket(Address& addr,
         /* [<][>][^][v][top][bottom][index][help] */
     705                            Port port,
     706                            Handler& rh,
     707                            Handler& wh)
     708         : File(::socket(AF_INET, SOCK_STREAM, 0),
     709                FileModeReadWrite,
     710                rh,
     711                wh)
     712 {
     713     struct sockaddr_in sin;
     714     int retval;
     715
     716     // Only stream sockets are non-blocking
     717     if (fcntl(descriptor_,
     718               F_SETFL,
     719               O_NDELAY) < 0) {
     720         FATAL("non-blocking descriptor error: %s\n",
     721               strerror(errno));
     722         // Not Reached
     723     }
     724
     725     sin.sin_family = AF_INET;
     726     sin.sin_addr.s_addr = htonl(addr.get());
     727     sin.sin_port = htons(port);
     728
     729     retval = ::connect(descriptor_,
     730                        (struct sockaddr *) &sin,
     731                        sizeof(sin));
     732     //    ASSERT((retval < 0) && (errno == EWOULDBLOCK));       // XXX
     733 }
     734
     735 StreamSocket::StreamSocket(int d,
         /* [<][>][^][v][top][bottom][index][help] */
     736                            Handler& rh,
     737                            Handler& wh)
     738         : File(d, FileModeReadWrite, rh, wh)
     739 {
     740     // Only stream sockets are non-blocking
     741     if (fcntl(descriptor_,
     742               F_SETFL,
     743               O_NDELAY) < 0) {
     744         FATAL("non-blocking descriptor error: %s\n",
     745               strerror(errno));
     746         // Not Reached
     747     }
     748 }
     749
     750 StreamSocket::~StreamSocket()
         /* [<][>][^][v][top][bottom][index][help] */
     751 {
     752     // Empty
     753 }
     754
     755 ListenSocket::ListenSocket(Port port,
         /* [<][>][^][v][top][bottom][index][help] */
     756                            Handler& lh,
     757                            Boolean local)
     758         : File(::socket(AF_INET, SOCK_STREAM, 0),
     759                FileModeReadWrite,
     760                lh,
     761                nullHandler)
     762 {
     763     int         retval;
     764     int         reuse;
     765     sockaddr_in sin;
     766
     767     sin.sin_family = AF_INET;
     768     sin.sin_port = htons(port);
     769     if (local) {
     770         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     771     } else {
     772         sin.sin_addr.s_addr = htonl(INADDR_ANY);
     773     }
     774
     775     TRACE(traceFile,
     776           "binding socket %d to port %d\n",
     777           descriptor_,
     778           port);
     779
     780     reuse = 1;
     781     if (::setsockopt(descriptor_,
     782                      SOL_SOCKET,
     783                      SO_REUSEADDR,
     784                      (char*) &reuse,
     785                      sizeof(reuse)) < 0) {
     786         FATAL("failed to set %d to be reusable: %s\n",
     787               descriptor_,
     788               strerror(errno));
     789         // NotReached
     790     }
     791
     792     if (::bind(descriptor_,
     793                (struct sockaddr *) &sin,
     794                sizeof(sin)) < 0) {
     795         FATAL("failed bind on %d: %s\n",
     796               descriptor_,
     797               strerror(errno));
     798         // NotReached
     799     }
     800
     801     TRACE(traceFile,
     802           "setting file %d to listen\n",
     803           descriptor_);
     804
     805     retval = ::listen(descriptor_, 5);
     806     if (retval < 0) {
     807         FATAL("listen failed on file %d\n",
     808               descriptor_);
     809         // NotReached
     810     }
     811     return;
     812 }
     813
     814 ListenSocket::~ListenSocket()
         /* [<][>][^][v][top][bottom][index][help] */
     815 {
     816     // Empty
     817 }
     818
     819 int
     820 ListenSocket::accept(StreamSocket** sock,
         /* [<][>][^][v][top][bottom][index][help] */
     821                      Address& remote,
     822                      Port *remotePort,
     823                      Handler& read,
     824                      Handler& write)
     825 {
     826     int retval;
     827     struct sockaddr_in sin;
     828     size_t socklen;
     829
     830     TRACE(traceFile,
     831           "accepting incoming connection on file %d\n",
     832           descriptor_);
     833
     834     socklen = sizeof(sin);
     835     retval = ::accept(descriptor_,
     836                       (struct sockaddr *) &sin,
     837                       (SOCKLEN_T*)&socklen);
     838     if (retval < 0) {
     839         switch (errno) {
     840             case EWOULDBLOCK:
     841 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     842             case EAGAIN:
     843 #endif
     844             case EINTR:
     845                 return FileOpSoftError;
     846             default:
     847                 return FileOpHardError;
     848         }
     849     }
     850
     851     remote.set(ntohl(sin.sin_addr.s_addr));
     852     *remotePort = ntohs(sin.sin_port);
     853
     854     *sock = new StreamSocket(retval, read, write);
     855     return FileOpOK;
     856 }
     857
     858 DiskFile::DiskFile(char* fileName,
         /* [<][>][^][v][top][bottom][index][help] */
     859                    Boolean readOnly,
     860                    Handler& rh,
     861                    Handler& wh)
     862         : File(::open(fileName,
     863                       (readOnly) ? O_RDONLY : (O_CREAT | O_RDWR),
     864                       0644),
     865                (readOnly) ? FileModeReadOnly : FileModeReadWrite,
     866                rh,
     867                wh)
     868 {
     869     // Empty
     870 }
     871
     872 DiskFile::~DiskFile()
         /* [<][>][^][v][top][bottom][index][help] */
     873 {
     874     // Empty
     875 }
     876
     877 int
     878 DiskFile::seekTo(u_long offset)
         /* [<][>][^][v][top][bottom][index][help] */
     879 {
     880     int retval;
     881
     882     TRACE(traceFile,
     883           "seeking to off %u on descriptor %d\n",
     884           offset,
     885           descriptor_);
     886
     887     retval = ::lseek(descriptor_, (off_t) offset, SEEK_SET);
     888     if (retval < 0) {
     889         return FileOpHardError;
     890     }
     891     return retval;
     892 }
     893
     894 int
     895 DiskFile::seekEnd()
         /* [<][>][^][v][top][bottom][index][help] */
     896 {
     897     int retval;
     898
     899     TRACE(traceFile,
     900           "seeking to end on descriptor %d\n",
     901           descriptor_);
     902
     903     retval = ::lseek(descriptor_, (off_t) 0, SEEK_END);
     904     if (retval < 0) {
     905         return FileOpHardError;
     906     }
     907     return retval;
     908 }
     909
     910 int
     911 DiskFile::lock()
         /* [<][>][^][v][top][bottom][index][help] */
     912 {
     913     int retval;
     914
     915 #ifdef HAVE_FLOCK
     916     retval = ::flock(descriptor_, LOCK_EX|LOCK_NB);
     917 #elif HAVE_LOCKF
     918     retval = ::lockf(descriptor_, F_LOCK, 0);
     919 #else
     920     retval = 0;
     921 #endif
     922
     923     if (retval < 0) {
     924         switch (errno) {
     925             case EWOULDBLOCK:
     926 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
     927             case EAGAIN:
     928 #endif
     929                 TRACE(traceFile,
     930                       "descriptor %d already locked\n",
     931                       descriptor_);
     932
     933                 return FileOpSoftError;
     934             default:
     935                 break;
     936         }
     937         return FileOpHardError;
     938     }
     939
     940     TRACE(traceFile,
     941           "descriptor %d not locked by another process\n",
     942           descriptor_);
     943
     944     return FileOpOK;
     945 }
     946
     947 int
     948 DiskFile::truncate(u_int size)
         /* [<][>][^][v][top][bottom][index][help] */
     949 {
     950     int retval;
     951
     952     retval = ::ftruncate(descriptor_, size);
     953     if (retval < 0) {
     954         return FileOpHardError;
     955     }
     956
     957     TRACE(traceFile,
     958           "truncated descriptor %d to size %u\n",
     959           descriptor_,
     960           size);
     961     return FileOpOK;
     962 }
     963
     964 void
     965 createDir(char* name)
         /* [<][>][^][v][top][bottom][index][help] */
     966 {
     967     int retval;
     968     struct stat statbuf;
     969
     970     retval = stat(name, &statbuf);
     971     if (retval < 0) {   // Name doesn't exist
     972         retval = mkdir(name, 0755);
     973         if (retval < 0) {
     974             FATAL("couldn't create directory %s: %s\n", name,
     975                   strerror(errno));
     976             // NotReached
     977         }
     978         return;
     979     }
     980     if (!S_ISDIR(statbuf.st_mode)) {
     981         FATAL("expected %s to be a directory, it isn't\n",
     982               name);
     983         // NotReached
     984     }
     985 }
     986
     987 static char*    pidFileName = NULL;
     988
     989 void
     990 openPidFile(const char* name)
         /* [<][>][^][v][top][bottom][index][help] */
     991 {
     992     int         retval;
     993     char        buf[20];
     994     int         pid;
     995     int         len;
     996
     997     pidFileName = new char[strlen(name) + 1];
     998     memcpy(pidFileName, name, strlen(name) + 1);
     999
    1000     pidDescriptor = open(name, O_RDWR | O_CREAT |
    1001 #ifdef HOST_OS_IS_FREEBSD
    1002                          O_FSYNC
    1003 #else
    1004                          O_SYNC
    1005 #endif
    1006                          , 0664);
    1007     if (pidDescriptor < 0) {
    1008         ERROR("couldn't open pid file %s: %s\n", name, strerror(errno));
    1009         exit(2);
    1010     }
    1011
    1012 #ifdef HAVE_FLOCK
    1013     retval = ::flock(pidDescriptor, LOCK_EX|LOCK_NB);
    1014 #elif HAVE_LOCKF
    1015     retval = ::lockf(pidDescriptor, F_LOCK, 0);
    1016 #else
    1017     retval = 0;
    1018 #endif
    1019
    1020     if (retval < 0) {
    1021         switch (errno) {
    1022             case EWOULDBLOCK:
    1023 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
    1024             case EAGAIN:
    1025 #endif
    1026                 len = read(pidDescriptor, buf, sizeof buf);
    1027                 if (len > 0 &&  (pid = atoi(buf))) {
    1028                     ERROR("another already running, pid %d\n",
    1029                           pid);
    1030                 } else {
    1031                     ERROR("is some other %s running?");
    1032                 }
    1033                 break;
    1034
    1035             default:
    1036                 ERROR("flock failed: %s\n", strerror(errno));
    1037         }
    1038         close(pidDescriptor);
    1039         pidDescriptor = -1;
    1040         exit(2);
    1041     }
    1042
    1043     (void) sprintf(buf, "%d\n", getpid());
    1044     len = strlen(buf);
    1045
    1046 #ifndef SEEK_SET
    1047 #define SEEK_SET        L_SET
    1048 #endif  /* SEEK_SET */
    1049     /* Back up to the beginning and truncate the file */
    1050     if (lseek(pidDescriptor, (off_t) 0, SEEK_SET) < 0
    1051         || ftruncate(pidDescriptor, (off_t) 0) < 0
    1052         || write(pidDescriptor, buf, len) != len) {
    1053         ERROR("couldn't write to %s: %s\n", name, strerror(errno));
    1054         exit(2);
    1055     }
    1056
    1057     return;
    1058 }
    1059
    1060 void
    1061 closePidFile()
         /* [<][>][^][v][top][bottom][index][help] */
    1062 {
    1063     if (!pidFileName) {
    1064         return;
    1065     }
    1066
    1067     if (pidDescriptor > -1) {
    1068         if (close(pidDescriptor) == -1
    1069             || unlink(pidFileName) == -1) {
    1070             ERROR("could not close or remove %s: %s\n",
    1071                   pidFileName, strerror(errno));
    1072             exit(2);
    1073         }
    1074         pidDescriptor = -1;
    1075     }
    1076
    1077     delete [] pidFileName;
    1078     return;
    1079 }
    1080
    1081 void
    1082 daemonize()
         /* [<][>][^][v][top][bottom][index][help] */
    1083 {
    1084     int         t;
    1085     Signal*     sig;
    1086
    1087     // Ignore several signals
    1088     sig = new Signal("ttou", NULL);
    1089     sig = new Signal("ttin", NULL);
    1090     sig = new Signal("tstp", NULL);
    1091
    1092     // Fork once
    1093     switch (fork()) {
    1094         case 0:
    1095             break;
    1096         case -1:
    1097             perror("daemonize: fork");
    1098             exit(1);
    1099         default:
    1100             exit(0);
    1101     }
    1102
    1103 #ifdef SETPGRP_VOID
    1104     t = setpgrp();
    1105     if (t < 0) {
    1106         perror("daemonize: setprgp");
    1107         exit(1);
    1108     }
    1109
    1110     sig = new Signal("hup", NULL);
    1111
    1112     switch (fork()) {
    1113         case 0:
    1114             break;
    1115         case -1:
    1116             perror("daemonize: fork");
    1117             exit(1);
    1118         default:
    1119             exit(0);
    1120     }
    1121 #else // SETPRGP_VOID
    1122     t = setpgrp(0, getpid());
    1123     if (t < 0) {
    1124         perror("daemonize: setpgrp");
    1125         exit(1);
    1126     }
    1127
    1128     while ((t = open("/dev/tty", O_RDWR, 0)) == -1 && errno == EINTR);
    1129     if (t >= 0) {
    1130         if (ioctl(t, TIOCNOTTY, (caddr_t) 0) < 0) {
    1131             perror("daemonize: ioctl(TIOCNOTTY)");
    1132             exit(1);
    1133         }
    1134         close(t);
    1135     }
    1136 #endif // SETPGRP_VOID
    1137
    1138     // Can close all open files, and reset umask
    1139     {
    1140 #ifndef NOFILE
    1141 #ifdef  _NFILE
    1142 #define NOFILE  _NFILE
    1143 #else   /* _NFILE */
    1144 #ifdef  OPEN_MAX
    1145 #define NOFILE  OPEN_MAX
    1146 #else   /* OPEN_MAX */
    1147 #define NOFILE  20
    1148 #endif  /* OPEN_MAX */
    1149 #endif  /* _NFILE */
    1150 #endif  /* NOFILE */
    1151         t = NOFILE;
    1152         do {
    1153             (void) close(t);
    1154         } while (--t);
    1155
    1156     }
    1157
    1158     /* Reset umask */
    1159     umask(022);
    1160 }
    1161
    1162 //
    1163 //  Copyright (c) 1994 by the University of Southern California.
    1164 //  All rights reserved.
    1165 //
    1166 //  Permission to use, copy, modify, and distribute this software and
    1167 //  its documentation in source and binary forms for lawful
    1168 //  non-commercial purposes and without fee is hereby granted, provided
    1169 //  that the above copyright notice appear in all copies and that both
    1170 //  the copyright notice and this permission notice appear in supporting
    1171 //  documentation, and that any documentation, advertising materials,
    1172 //  and other materials related to such distribution and use acknowledge
    1173 //  that the software was developed by the University of Southern
    1174 //  California and/or Information Sciences Institute.
    1175 //  The name of the University of Southern California may not
    1176 //  be used to endorse or promote products derived from this software
    1177 //  without specific prior written permission.
    1178 //
    1179 //  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
    1180 //  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
    1181 //  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
    1182 //  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
    1183 //  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
    1184 //  NON-INFRINGEMENT.
    1185 //
    1186 //  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
    1187 //  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
    1188 //  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
    1189 //  THE USE OR PERFORMANCE OF THIS SOFTWARE.
    1190 //
    1191 //  Questions concerning this software should be directed to
    1192 //  info-ra@isi.edu.
    1193 //

/* [<][>][^][v][top][bottom][index][help] */