Statistics
| Branch: | Tag: | Revision:

dvbd / src / connection.cpp @ 59be6a47

History | View | Annotate | Download (5.63 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
{
44
  if (debugLevel > 1)
45
    std::cerr << "New client connection" << std::endl;
46

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

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

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

    
60
  close(dataFD);
61
}
62

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

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

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

    
83
  return true;
84
}
85

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
174

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

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

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

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

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

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

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

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

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

    
232
  if (removeMe)
233
    return false;
234

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

    
240
  return true;
241
}
242

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

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