Statistics
| Branch: | Tag: | Revision:

dvbd / src / unixserversocket.cpp @ bcb74979

History | View | Annotate | Download (4.15 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
#include <sys/stat.h>
34

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

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

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

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

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

    
79
  umask(oldMask);
80

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

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

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

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

    
140

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

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

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