Statistics
| Branch: | Tag: | Revision:

dvbd / lobby.cpp @ bfdb7446

History | View | Annotate | Download (4.59 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

    
38
Lobby::Lobby(const std::string &socketFilename, TunerManager *tm, 
39
             ConnectionManager *cm, Scheduler *scheduler)
40
  : tm(tm), cm(cm), scheduler(scheduler)
41
{
42
  server = new UnixServerSocket(socketFilename);
43
  server->setNonBlocking();
44
  setRandomSeed();
45
}
46

    
47
Lobby::~Lobby()
48
{
49
  delete server;
50
}
51

    
52
void Lobby::addSelectFDs(Select &s) const
53
{
54
  server->addSelectFDs(s);
55
  for (ClientList::const_iterator i = clients.begin(); i != clients.end(); i++)
56
    s.addReadFD(*i);
57
  for (ControlList::const_iterator i = controllers.begin(); i != controllers.end(); i++)
58
    s.addReadFD(i->getFD());
59
}
60

    
61
bool Lobby::isReady(const Select &s) const
62
{
63
  if (server->isReady(s))
64
    return true;
65

    
66
  for (ClientList::const_iterator i = clients.begin(); i != clients.end(); i++) 
67
    if (s.readyToRead(*i))
68
      return true;
69

    
70
  for (ControlList::const_iterator i = controllers.begin(); i != controllers.end(); i++)
71
    if (s.readyToRead(i->getFD()))
72
      return true;
73

    
74
  return false;
75
}
76

    
77
void Lobby::processReady(Select &s)
78
{
79
  if (server->isReady(s)) {
80
    int fd = server->accept();
81
    ::setNonBlocking(fd);
82
    clients.push_back(fd);
83
  }
84

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

    
99
  for (ClientList::iterator i = clients.begin(); i != clients.end(); ) {
100
    int fd = *i;
101
    if (s.readyToRead(fd)) {
102
      std::string command;
103
      int bytesread = readLineStripTrailingWS(fd, command);
104

    
105
      if (bytesread <= 0) {
106
        // Close the connection
107
        ::close(fd);
108
        i = clients.erase(i);
109
        continue;
110
      }
111

    
112
      if (command == "CONTROL") {
113

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

    
130
        for (ControlList::iterator j = controllers.begin(); j != controllers.end(); j++) {
131
          Control &c = *j;
132
          if (c.matches(key)) {
133
            cm->add(new ControlledConnection(tm, scheduler, cm, c.getFD(), fd));
134
            controllers.erase(j);
135
            success = true;
136
            break;
137
          }
138
        }
139

    
140
        if (success) {
141
          if (debugLevel > 1)
142
            std::cerr << "Data socket paired with control socket\n";
143
          i = clients.erase(i);
144
          continue;
145
        }
146
        else {
147
          std::cerr << "Failed to pair data socket with control socket\n";
148

    
149
          // Close the connection
150
          ::close(fd);
151
          i = clients.erase(i);
152
          continue;
153
        }
154
      }
155
      else
156
        std::cerr << "Unknown lobby command: " << command << "\n";
157
    }
158
    i++;
159
  }
160
}
161

    
162
void Lobby::setRandomSeed()
163
{
164
  int fd = open("/dev/random", O_RDONLY);
165
  if (fd < 0) 
166
    srandom((unsigned) time(NULL));
167
  else {
168
    union {
169
      char data[4];
170
      unsigned seed;
171
    } x;
172

    
173
    read(fd, x.data, 4);
174
    srandom(x.seed);
175
    close(fd);
176
  }
177
}
178

    
179
std::string Lobby::generateId()
180
{
181
  static unsigned serial = 0;
182

    
183
  char key[65];
184
  for (int i = 0; i < 64; i++)
185
    key[i] = 'A' + random() % 26;
186

    
187
  key[64] = '\x0';
188

    
189
  serial++;
190

    
191
  return toString(serial) + "_" + key;
192
}