Statistics
| Branch: | Tag: | Revision:

dvbd / src / lobby.cpp @ 870b7082

History | View | Annotate | Download (4.61 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, TunerManager *tm, 
40
             ConnectionManager *cm, Scheduler *scheduler)
41
  : tm(tm), cm(cm), scheduler(scheduler)
42
{
43
  server = new UnixServerSocket(socketFilename);
44
  server->setNonBlocking();
45
  setRandomSeed();
46
}
47

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

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

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

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

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

    
75
  return false;
76
}
77

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
190
  serial++;
191

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