Statistics
| Branch: | Tag: | Revision:

dvbd / src / lobby.cpp @ e386e4be

History | View | Annotate | Download (4.91 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 "lobby.h"
20
#include "unixserversocket.h"
21
#include "controlledconnection.h"
22
#include "connectionmanager.h"
23
#include "stringutil.h"
24
#include "utils.h"
25
#include "dvbd.h"
26

    
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <cerrno>
32
#include <cstring>
33
#include <cstdio>
34
#include <cstdlib>
35
#include <fcntl.h>
36
#include <time.h>
37
#include <iostream>
38
#include <unistd.h>
39

    
40
Lobby::Lobby(const std::string &socketFilename,
41
             const std::string &socketUid,
42
             const std::string &socketGid,
43
             const std::string &socketMode,
44
             TunerManager *tm, 
45
             ConnectionManager *cm, 
46
             Scheduler *scheduler)
47
  : tm(tm), cm(cm), scheduler(scheduler)
48
{
49
  server = new UnixServerSocket(socketFilename, socketUid, socketGid, socketMode);
50
  server->setNonBlocking();
51
  setRandomSeed();
52
}
53

    
54
Lobby::~Lobby()
55
{
56
  delete server;
57
}
58

    
59
void Lobby::addSelectFDs(Select &s) const
60
{
61
  server->addSelectFDs(s);
62
  for (ClientList::const_iterator i = clients.begin(); i != clients.end(); i++)
63
    s.addReadFD(*i);
64
  for (ControlList::const_iterator i = controllers.begin(); i != controllers.end(); i++)
65
    s.addReadFD(i->getFD());
66
}
67

    
68
bool Lobby::isReady(const Select &s) const
69
{
70
  if (server->isReady(s))
71
    return true;
72

    
73
  for (ClientList::const_iterator i = clients.begin(); i != clients.end(); i++) 
74
    if (s.readyToRead(*i))
75
      return true;
76

    
77
  for (ControlList::const_iterator i = controllers.begin(); i != controllers.end(); i++)
78
    if (s.readyToRead(i->getFD()))
79
      return true;
80

    
81
  return false;
82
}
83

    
84
void Lobby::processReady(Select &s)
85
{
86
  if (server->isReady(s)) {
87
    int fd = server->accept();
88
    if (fd >= 0) {
89
      // ALRM signal can interrupt the accept causing it to return -1
90
      // and errno = EAGAIN
91
      ::setNonBlocking(fd);
92
      clients.push_back(fd);
93
    }
94
  }
95

    
96
  for (ControlList::iterator i = controllers.begin(); i != controllers.end();) {
97
    int fd = i->getFD();
98
    if (s.readyToRead(fd)) {
99
      std::cerr << "Controller sent data before establishing connection.\n"
100
                << "(Hint: wait for welcome messagae)\n"
101
                << "Closing connection.\n";
102
      // Controllers are not supposed to be saying anything at this
103
      // time. Close the connection.
104
      ::close(fd);
105
      i = controllers.erase(i);
106
    }
107
    i++;
108
  }
109

    
110
  for (ClientList::iterator i = clients.begin(); i != clients.end(); ) {
111
    int fd = *i;
112
    if (s.readyToRead(fd)) {
113
      std::string command;
114
      int bytesread = readLineStripTrailingWS(fd, command);
115

    
116
      if (bytesread <= 0) {
117
        // Close the connection
118
        ::close(fd);
119
        i = clients.erase(i);
120
        continue;
121
      }
122

    
123
      if (command == "CONTROL") {
124

    
125
        if (debugLevel > 2)
126
          std::cerr << "Control socket registered\n";
127
        // Upgrade this connection to a Controller
128
        std::string id = generateId();
129
        controllers.push_back(Control(fd, id));
130
        i = clients.erase(i);
131
        writeString(fd, id + "\n");
132
        continue;
133
      }
134
      else if (command.substr(0, 5) == "DATA ") {
135
        if (debugLevel > 2)
136
          std::cerr << "Data socket registered\n";
137
        // Upgrade this connection to a Data connection
138
        std::string key = command.substr(5);
139
        bool success = false;
140

    
141
        for (ControlList::iterator j = controllers.begin(); j != controllers.end(); j++) {
142
          Control &c = *j;
143
          if (c.matches(key)) {
144
            cm->add(new ControlledConnection(tm, scheduler, cm, c.getFD(), fd));
145
            controllers.erase(j);
146
            success = true;
147
            break;
148
          }
149
        }
150

    
151
        if (success) {
152
          if (debugLevel > 1)
153
            std::cerr << "Data socket paired with control socket\n";
154
          i = clients.erase(i);
155
          continue;
156
        }
157
        else {
158
          std::cerr << "Failed to pair data socket with control socket\n";
159

    
160
          // Close the connection
161
          ::close(fd);
162
          i = clients.erase(i);
163
          continue;
164
        }
165
      }
166
      else
167
        std::cerr << "Unknown lobby command: " << command << "\n";
168
    }
169
    i++;
170
  }
171
}
172

    
173
void Lobby::setRandomSeed()
174
{
175
  int fd = open("/dev/random", O_RDONLY);
176
  if (fd < 0) 
177
    srandom((unsigned) time(NULL));
178
  else {
179
    union {
180
      char data[4];
181
      unsigned seed;
182
    } x;
183

    
184
    read(fd, x.data, 4);
185
    srandom(x.seed);
186
    close(fd);
187
  }
188
}
189

    
190
std::string Lobby::generateId()
191
{
192
  static unsigned serial = 0;
193

    
194
  char key[65];
195
  for (int i = 0; i < 64; i++)
196
    key[i] = 'A' + random() % 26;
197

    
198
  key[64] = '\x0';
199

    
200
  serial++;
201

    
202
  return toString(serial) + "_" + key;
203
}