Statistics
| Branch: | Tag: | Revision:

dvbd / connection.cpp @ bfdb7446

History | View | Annotate | Download (5.57 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 "connection.h"
21
#include "demuxer.h"
22
#include "utils.h"
23
#include "stringutil.h"
24
#include "inputbuffer.h"
25
#include "outputbuffer.h"
26
#include "scheduler.h"
27

    
28
#include <iostream>
29
#include <cstring>
30
#include <vector>
31
#include <unistd.h>
32
#include <cerrno>
33
#include <ctime>
34
#include <algorithm>
35

    
36
Connection::Connection(TunerManager *tm, int dataFD)
37
  : dataFD(dataFD), priority(0), 
38
    tuned(false), retuning(false), 
39
    tm(tm), removeMe(false),
40
    stopTime(0),
41
    interrupted(false)
42
{
43
  if (debugLevel > 1)
44
    std::cerr << "New client connection" << std::endl;
45

    
46
  dataOutput = new OutputBuffer(dataFD, 16384, 65536);
47
}
48

    
49
Connection::~Connection()
50
{
51
  if (debugLevel > 1)
52
    std::cerr << "Client connection closed" << std::endl;
53

    
54
  retuning=true;
55
  doUnsubscribe();
56
  
57
  delete dataOutput;
58

    
59
  close(dataFD);
60
}
61

    
62
void Connection::doUnsubscribe()
63
{
64
  DemuxerList copy = demuxers;
65
  for (DemuxerList::iterator i = copy.begin(); i != copy.end(); i++)
66
    (*i)->unsubscribe(this);
67
}
68

    
69
bool Connection::doSubscribe()
70
{
71
  bool result = true;
72

    
73
  for (DemuxerList::iterator i = demuxers.begin(); i != demuxers.end(); i++)
74
    result = (*i)->subscribe(this) && result;
75

    
76
  if (!result) {
77
    doUnsubscribe();
78
    return false;
79
  }
80
  return true;
81
}
82

    
83
void Connection::notifyUnsubscribe(Source *s)
84
{
85
  Demuxer *d = (Demuxer *) s;
86
  demuxers.remove(d);
87
  interrupted = true;
88
}
89

    
90
time_t Connection::getCurrentTime() const
91
{
92
  return time(NULL);
93
}
94

    
95
void Connection::addSelectFDs(Select &s) const
96
{
97
  dataOutput->addSelectFDs(s);
98

    
99
  if (stopTime != 0)
100
    s.addAlarm(std::max(0L, stopTime - getCurrentTime()), 0);
101
}
102

    
103
bool Connection::isReady(const Select &s) const
104
{
105
  if (removeMe)
106
    return true;
107

    
108
  return dataOutput->isReady(s);
109
}
110

    
111
int Connection::getPriority() const
112
{
113
  return priority;
114
}
115

    
116
void Connection::setPriority(int p)
117
{
118
  priority = p;
119
}
120

    
121
void Connection::setStopTime(time_t newStopTime)
122
{
123
  stopTime = newStopTime;
124
}
125

    
126
time_t Connection::getStopTime() const
127
{
128
  return stopTime;
129
}
130

    
131
bool Connection::isValidType(const std::string &type ) const
132
{
133
  return tm->validType(type);
134
}
135

    
136
bool Connection::isValidChannel(const std::string &type, const std::string &channel) const
137
{
138
  return tm->validChannel(type, channel);
139
}
140

    
141
bool Connection::canTune(const std::string &newType, const std::string &newChannel, int p) const
142
{
143
  SavePriority save(const_cast<Connection *>(this), p - 1);
144
  
145
  return tm->canGetDemuxers(newType, newChannel, p);
146
}
147

    
148
void Connection::getTunableChannels(const std::string &type, int priority, StringList &channels) const
149
{
150
  tm->getTunableChannels(type, priority, channels);
151
}
152

    
153
bool Connection::isRetuning() const {
154
  return retuning;
155
}
156

    
157
bool Connection::numDemuxers() const
158
{
159
  return demuxers.empty();
160
}
161

    
162
bool Connection::getInterrupted() const {
163
  return interrupted;
164
}
165

    
166
void Connection::setRemoveMe(bool status)
167
{
168
  removeMe = status;
169
}
170

    
171

    
172
bool Connection::tune(const std::string &newType, const std::string &newChannel, int p)
173
{
174
  if (tuned) {
175
    if (type == newType && channel == newChannel) {
176
      setPriority(p);
177
      return true;
178
    }
179
  }
180

    
181
  if (debugLevel > 1) {
182
    std::cerr << "Tuning to " << newType << " " << newChannel 
183
              << " priority " << p << std::endl;
184
  }
185

    
186
  // The retuning variable prevents the client from being notified
187
  // that he has lost a subscription. The loss of subscription is to
188
  // be expected since the request is to change the channel!
189
  retuning = true;
190
  
191
  DemuxerList newDemuxers;
192

    
193
  // Set the priority of the current channel
194
  // to be less than the specified priority
195
  {
196
    SavePriority save(this, p - 1);
197

    
198
    // Try to allocate the new demuxers
199
    tm->getDemuxers(newType, newChannel, newDemuxers, p);
200
    retuning = false;
201

    
202
    if (newDemuxers.empty()) 
203
      return false;      // We remain subscribed to the old channel.
204
  }
205

    
206
  // Unsubscribe (if necessary) from the old and subscribe to the new
207

    
208
  doUnsubscribe();
209
  demuxers = newDemuxers;
210
  type = newType;
211
  channel = newChannel;
212
  bool result = doSubscribe();
213
  setPriority(p);
214
  tuned = true;
215
  interrupted = false;
216
  return result;
217
}
218

    
219
bool Connection::processReady(const Select &s)
220
{
221
  if (stopTime != 0 && getCurrentTime() > stopTime) {
222
    if (debugLevel > 0) {
223
      std::cerr << "Stop time reached (stopTime = " << stopTime 
224
                << ", now = " << getCurrentTime() << ")\n";
225
    }
226
    return false;
227
  }
228

    
229
  if (removeMe)
230
    return false;
231

    
232
  if (dataOutput->isReady(s)) {
233
    if (!dataOutput->process()) 
234
      return false;
235
  }
236

    
237
  return true;
238
}
239

    
240
void Connection::receiveData(unsigned char *data, unsigned size)
241
{
242
  // Receive data from the Demuxers and forward it to the clients
243
  if (!dataOutput->write((char *) data, size)) {
244
    std::cerr << "Client not reading data connection" << std::endl;
245
    removeMe = true;
246
  }
247
}
248

    
249
std::ostream& Connection::printOn(std::ostream &o) const
250
{
251
  if (!tuned) 
252
    return o << "UNTUNED";
253
  else
254
    return o << priority << " " << type << " " << escapeWS(channel);
255
}