Statistics
| Branch: | Tag: | Revision:

dvbd / src / lobby.cpp @ 904d298f

History | View | Annotate | Download (4.76 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 <fcntl.h>
34
#include <cstdlib>
35
#include <time.h>
36
#include <iostream>
37
#include <unistd.h>
38

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

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

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

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

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

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

    
80
  return false;
81
}
82

    
83
void Lobby::processReady(Select &s)
84
{
85
  if (server->isReady(s)) {
86
    int fd = server->accept();
87
    ::setNonBlocking(fd);
88
    clients.push_back(fd);
89
  }
90

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

    
105
  for (ClientList::iterator i = clients.begin(); i != clients.end(); ) {
106
    int fd = *i;
107
    if (s.readyToRead(fd)) {
108
      std::string command;
109
      int bytesread = readLineStripTrailingWS(fd, command);
110

    
111
      if (bytesread <= 0) {
112
        // Close the connection
113
        ::close(fd);
114
        i = clients.erase(i);
115
        continue;
116
      }
117

    
118
      if (command == "CONTROL") {
119

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

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

    
146
        if (success) {
147
          if (debugLevel > 1)
148
            std::cerr << "Data socket paired with control socket\n";
149
          i = clients.erase(i);
150
          continue;
151
        }
152
        else {
153
          std::cerr << "Failed to pair data socket with control socket\n";
154

    
155
          // Close the connection
156
          ::close(fd);
157
          i = clients.erase(i);
158
          continue;
159
        }
160
      }
161
      else
162
        std::cerr << "Unknown lobby command: " << command << "\n";
163
    }
164
    i++;
165
  }
166
}
167

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

    
179
    read(fd, x.data, 4);
180
    srandom(x.seed);
181
    close(fd);
182
  }
183
}
184

    
185
std::string Lobby::generateId()
186
{
187
  static unsigned serial = 0;
188

    
189
  char key[65];
190
  for (int i = 0; i < 64; i++)
191
    key[i] = 'A' + random() % 26;
192

    
193
  key[64] = '\x0';
194

    
195
  serial++;
196

    
197
  return toString(serial) + "_" + key;
198
}