Statistics
| Branch: | Tag: | Revision:

dvbd / src / connection.cpp @ f9b7ce06

History | View | Annotate | Download (5.75 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
#include <cassert>
36

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

    
48
  dataOutput = new OutputBuffer(dataFD, 16384, 262144);
49
}
50

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

    
56
  retuning=true;
57
  doUnsubscribe();
58
  
59
  delete dataOutput;
60

    
61
  close(dataFD);
62
}
63

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

    
71
bool Connection::doSubscribe()
72
{
73
  bool result = true;
74
  int n = 0;
75

    
76
  for (SourceList::iterator i = demuxers.begin(); i != demuxers.end(); i++) 
77
    result = (*i)->subscribe(this) && result;
78
   
79
  if (!result) {
80
    doUnsubscribe();
81
    return false;
82
  }
83

    
84
  return true;
85
}
86

    
87
void Connection::notifyUnsubscribe(Source *s)
88
{
89
  Demuxer *d = (Demuxer *) s;
90
  demuxers.remove(d);
91
  interrupted = true;
92
}
93

    
94
time_t Connection::getCurrentTime() const
95
{
96
  return time(NULL);
97
}
98

    
99
void Connection::addSelectFDs(Select &s) const
100
{
101
  dataOutput->addSelectFDs(s);
102

    
103
  if (stopTime != 0)
104
    s.addAlarm(std::max(0L, stopTime - getCurrentTime()), 0);
105
}
106

    
107
bool Connection::isReady(const Select &s) const
108
{
109
  if (removeMe)
110
    return true;
111

    
112
  return dataOutput->isReady(s);
113
}
114

    
115
int Connection::getPriority() const
116
{
117
  return priority;
118
}
119

    
120
void Connection::setPriority(int p)
121
{
122
  priority = p;
123
}
124

    
125
void Connection::setStopTime(time_t newStopTime)
126
{
127
  stopTime = newStopTime;
128
}
129

    
130
time_t Connection::getStopTime() const
131
{
132
  return stopTime;
133
}
134

    
135
bool Connection::isValidType(const std::string &type ) const
136
{
137
  return tm->validType(type);
138
}
139

    
140
bool Connection::isValidChannel(const std::string &type, const std::string &channel) const
141
{
142
  return tm->validChannel(type, channel);
143
}
144

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

    
152
void Connection::getTunableChannels(const std::string &type, int priority, StringList &channels) const
153
{
154
  tm->getTunableChannels(type, priority, channels);
155
}
156

    
157
bool Connection::isRetuning() const {
158
  return retuning;
159
}
160

    
161
bool Connection::numDemuxers() const
162
{
163
  return demuxers.empty();
164
}
165

    
166
bool Connection::getInterrupted() const {
167
  return interrupted;
168
}
169

    
170
void Connection::setRemoveMe(bool status)
171
{
172
  removeMe = status;
173
}
174

    
175

    
176
bool Connection::tune(const std::string &newType, const std::string &newChannel, bool convertToPS, int p)
177
{
178
  if (tuned) {
179
    if (type == newType && channel == newChannel) {
180
      setPriority(p);
181
      return true;
182
    }
183
  }
184

    
185
  if (debugLevel > 1) {
186
    std::cerr << "Tuning to " << newType << " " << newChannel 
187
              << " priority " << p << std::endl;
188
  }
189

    
190
  // The retuning variable prevents the client from being notified
191
  // that he has lost a subscription. The loss of subscription is to
192
  // be expected since the request is to change the channel!
193
  retuning = true;
194
  
195
  SourceList newDemuxers;
196

    
197
  // Set the priority of the current channel
198
  // to be less than the specified priority
199
  {
200
    SavePriority save(this, p - 1);
201

    
202
    // Try to allocate the new demuxers
203
    tm->getDemuxers(newType, newChannel, convertToPS, newDemuxers, p);
204
    retuning = false;
205

    
206
    if (newDemuxers.empty()) 
207
      return false;      // We remain subscribed to the old channel.
208
  }
209

    
210
  // Unsubscribe (if necessary) from the old and subscribe to the new
211

    
212
  doUnsubscribe();
213
  demuxers = newDemuxers;
214
  type = newType;
215
  channel = newChannel;
216
  bool result = doSubscribe();
217
  setPriority(p);
218
  tuned = true;
219
  interrupted = false;
220
  lostPacket = false;
221
  return result;
222
}
223

    
224
bool Connection::processReady(const Select &s)
225
{
226
  if (stopTime != 0 && getCurrentTime() > stopTime) {
227
    if (debugLevel > 0) {
228
      std::cerr << "Stop time reached (stopTime = " << stopTime 
229
                << ", now = " << getCurrentTime() << ")\n";
230
    }
231
    return false;
232
  }
233

    
234
  if (removeMe)
235
    return false;
236

    
237
  if (dataOutput->isReady(s)) {
238
    if (!dataOutput->process()) 
239
      return false;
240
  }
241

    
242
  return true;
243
}
244

    
245
void Connection::receiveData(unsigned char *data, unsigned size)
246
{
247
  // Receive data from the Demuxers and forward it to the clients
248
  if (!dataOutput->write((char *) data, size)) {
249
    if (!lostPacket) {
250
      std::cerr << "Warning: client not reading data connection fast enough (dropping packets)" << std::endl;
251
      lostPacket = true;
252
    }
253
  }
254
}
255

    
256
std::ostream& Connection::printOn(std::ostream &o) const
257
{
258
  if (!tuned) 
259
    return o << "UNTUNED";
260
  else
261
    return o << priority << " " << type << " " << escapeWS(channel);
262
}