Statistics
| Branch: | Tag: | Revision:

dvbd / src / unixserversocket.cpp @ 904d298f

History | View | Annotate | Download (4.13 KB)

1
/*
2
  Copyright 2003 John Knottenbelt
3
  
4
  This program is free software; you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation; either version 2 of the License, or
7
  (at your option) any later version.
8
 
9
  This program is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
 
14
  You should have received a copy of the GNU General Public License
15
  along with this program; if not, write to the Free Software
16
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17
*/
18

    
19
#include "config.h"
20
#include "unixserversocket.h"
21
#include <iostream>
22
#include <cstring>
23
#include <cstdlib>
24
#include <cerrno>
25
#include <cstdio>
26
#include <unistd.h>
27
#include <sys/types.h>
28
#include <sys/socket.h>
29
#include <sys/un.h>
30
#include <fcntl.h>
31
#include <pwd.h>
32
#include <grp.h>
33

    
34
UnixServerSocket::UnixServerSocket(const std::string &filename,
35
                                   const std::string &socketUid,
36
                                   const std::string &socketGid,
37
                                   const std::string &socketMode)
38
  : filename(filename)
39
{
40
  fd = socket(PF_UNIX, SOCK_STREAM, 0);
41

    
42
  if (!fd) {
43
    std::cerr << "Fatal error: failed to create socket for listening:\n"
44
              << strerror(errno) << std::endl;
45
    exit(1);
46
  }
47

    
48
  struct sockaddr_un addr;
49
  addr.sun_family = AF_UNIX;
50
  strcpy(addr.sun_path, filename.c_str());
51

    
52
  mode_t oldMask = umask(007);
53
  while (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
54
    if (errno == EADDRINUSE) {
55
      // Possibly old socket
56
      if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) {
57
        close(fd);
58
        std::cerr << "Fatal error: dvbd already running on socket " << filename << std::endl;
59
        exit(1);
60
      }
61
      else 
62
        unlink(filename.c_str());
63
    }
64
    else {
65
      // Some other error
66
      std::cerr << "Fatal error: failed to bind socket to " << filename << "\n"
67
              << strerror(errno) << std::endl;
68
      exit(1);
69
    }
70
  }
71

    
72
  if (listen(fd, 5) < 0) {
73
    std::cerr << "Fatal error: failed to listen on socket " << filename << "\n"
74
              << strerror(errno) << std::endl;
75
    exit(1);
76
  }
77

    
78
  umask(oldMask);
79

    
80
  // set the mode
81
  if (socketMode != "") {
82
    int mode = 0;
83
    sscanf(socketMode.c_str(), "%o", &mode);
84
    if (chmod(filename.c_str(), mode) != 0) {
85
      std::cerr << "Fatal error: failed to set mode on socket " << filename << "\n"
86
                << strerror(errno) << std::endl;
87
      exit(1);
88
    }
89
  }
90

    
91
  // set the owner
92
  if (socketUid != "") {
93
    uid_t owner;
94
    if (!sscanf(socketUid.c_str(), "%d", &owner)) {
95
      struct passwd *p = getpwnam(socketUid.c_str());
96
      if (p == NULL) {
97
        std::cerr << "Fatal error: failed to lookup user " << socketUid << " in password database\n"
98
                  << strerror(errno) << std::endl;
99
        exit(1);
100
      }
101
      owner = p->pw_uid;
102
    }
103
      
104
    if (chown(filename.c_str(), owner, (gid_t) -1) != 0) {
105
      std::cerr << "Fatal error: failed to set socket ownership " << socketUid << " on " << filename << "\n"
106
                << strerror(errno) << std::endl;
107
      exit(1);
108
    }
109
  }
110

    
111
  // set the group
112
  if (socketGid != "") {
113
    uid_t group;
114
    if (!sscanf(socketGid.c_str(), "%d", &group)) {
115
      struct group *p = getgrnam(socketGid.c_str());
116
      if (p == NULL) {
117
        std::cerr << "Fatal error: failed to lookup user " << socketGid << " in group database\n"
118
                  << strerror(errno) << std::endl;
119
        exit(1);
120
      }
121
      group = p->gr_gid;
122
    }
123
      
124
    if (chown(filename.c_str(), (uid_t) -1, group) != 0) {
125
      std::cerr << "Fatal error: failed to set socket group " << socketGid << " on " << filename << "\n"
126
                << strerror(errno) << std::endl;
127
      exit(1);
128
    }
129
  }
130
}
131

    
132
void UnixServerSocket::setNonBlocking()
133
{
134
  long flags = fcntl(fd, F_GETFL, 0); 
135
  flags |= O_NONBLOCK;
136
  fcntl(fd, F_SETFL, flags);
137
}
138

    
139

    
140
UnixServerSocket::~UnixServerSocket()
141
{
142
  close(fd);
143
  unlink(filename.c_str());
144
}
145

    
146
void UnixServerSocket::addSelectFDs(Select &s) const
147
{
148
  s.addReadFD(fd);
149
}
150

    
151
bool UnixServerSocket::isReady(const Select &s) const
152
{
153
  return s.readyToRead(fd);
154
}
155
  
156
int UnixServerSocket::accept()
157
{
158
  return ::accept(fd, NULL, 0);
159
}