| 1 | /*
 | 
|---|
| 2 |  * rtspbase.cpp - very basic RTSP client/server
 | 
|---|
| 3 |  * Copyright (C) 2004  Justin Karneges
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  * This library is free software; you can redistribute it and/or
 | 
|---|
| 6 |  * modify it under the terms of the GNU Lesser General Public
 | 
|---|
| 7 |  * License as published by the Free Software Foundation; either
 | 
|---|
| 8 |  * version 2.1 of the License, or (at your option) any later version.
 | 
|---|
| 9 |  *
 | 
|---|
| 10 |  * This library is distributed in the hope that it will be useful,
 | 
|---|
| 11 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 12 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
|---|
| 13 |  * Lesser General Public License for more details.
 | 
|---|
| 14 |  *
 | 
|---|
| 15 |  * You should have received a copy of the GNU Lesser General Public
 | 
|---|
| 16 |  * License along with this library; if not, write to the Free Software
 | 
|---|
| 17 |  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
|---|
| 18 |  *
 | 
|---|
| 19 |  */
 | 
|---|
| 20 | 
 | 
|---|
| 21 | #include "rtspbase.h"
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #include <qtimer.h>
 | 
|---|
| 24 | #include <qguardedptr.h>
 | 
|---|
| 25 | #include "bsocket.h"
 | 
|---|
| 26 | #include "servsock.h"
 | 
|---|
| 27 | 
 | 
|---|
| 28 | #ifdef Q_OS_WIN
 | 
|---|
| 29 | # include <windows.h>
 | 
|---|
| 30 | #else
 | 
|---|
| 31 | # include <netinet/in.h>
 | 
|---|
| 32 | #endif
 | 
|---|
| 33 | 
 | 
|---|
| 34 | #define MAX_CONTENT_LENGTH 32767
 | 
|---|
| 35 | 
 | 
|---|
| 36 | namespace RTSP {
 | 
|---|
| 37 | 
 | 
|---|
| 38 | //----------------------------------------------------------------------------
 | 
|---|
| 39 | // HeaderList
 | 
|---|
| 40 | //----------------------------------------------------------------------------
 | 
|---|
| 41 | HeaderList::HeaderList()
 | 
|---|
| 42 | :QValueList<Var>()
 | 
|---|
| 43 | {
 | 
|---|
| 44 | }
 | 
|---|
| 45 | 
 | 
|---|
| 46 | bool HeaderList::has(const QString &var) const
 | 
|---|
| 47 | {
 | 
|---|
| 48 |         QString low = var.lower();
 | 
|---|
| 49 |         for(ConstIterator it = begin(); it != end(); ++it)
 | 
|---|
| 50 |         {
 | 
|---|
| 51 |                 if((*it).name.lower() == low)
 | 
|---|
| 52 |                         return true;
 | 
|---|
| 53 |         }
 | 
|---|
| 54 |         return false;
 | 
|---|
| 55 | }
 | 
|---|
| 56 | 
 | 
|---|
| 57 | QString HeaderList::get(const QString &var) const
 | 
|---|
| 58 | {
 | 
|---|
| 59 |         QString low = var.lower();
 | 
|---|
| 60 |         for(ConstIterator it = begin(); it != end(); ++it)
 | 
|---|
| 61 |         {
 | 
|---|
| 62 |                 if((*it).name.lower() == low)
 | 
|---|
| 63 |                         return (*it).value;
 | 
|---|
| 64 |         }
 | 
|---|
| 65 |         return QString::null;
 | 
|---|
| 66 | }
 | 
|---|
| 67 | 
 | 
|---|
| 68 | void HeaderList::set(const QString &var, const QString &val)
 | 
|---|
| 69 | {
 | 
|---|
| 70 |         QString low = var.lower();
 | 
|---|
| 71 |         for(Iterator it = begin(); it != end(); ++it)
 | 
|---|
| 72 |         {
 | 
|---|
| 73 |                 if((*it).name.lower() == low)
 | 
|---|
| 74 |                 {
 | 
|---|
| 75 |                         (*it).value = val;
 | 
|---|
| 76 |                         return;
 | 
|---|
| 77 |                 }
 | 
|---|
| 78 |         }
 | 
|---|
| 79 |         Var v;
 | 
|---|
| 80 |         v.name = var;
 | 
|---|
| 81 |         v.value = val;
 | 
|---|
| 82 |         append(v);
 | 
|---|
| 83 | }
 | 
|---|
| 84 | 
 | 
|---|
| 85 | void HeaderList::remove(const QString &var)
 | 
|---|
| 86 | {
 | 
|---|
| 87 |         QString low = var.lower();
 | 
|---|
| 88 |         for(Iterator it = begin(); it != end(); ++it)
 | 
|---|
| 89 |         {
 | 
|---|
| 90 |                 if((*it).name.lower() == low)
 | 
|---|
| 91 |                 {
 | 
|---|
| 92 |                         QValueList<Var>::remove(it);
 | 
|---|
| 93 |                         return;
 | 
|---|
| 94 |                 }
 | 
|---|
| 95 |         }
 | 
|---|
| 96 | }
 | 
|---|
| 97 | 
 | 
|---|
| 98 | //----------------------------------------------------------------------------
 | 
|---|
| 99 | // Transport
 | 
|---|
| 100 | //----------------------------------------------------------------------------
 | 
|---|
| 101 | static int findOneOf(const QString &s, const QString &list, int i, QChar *found)
 | 
|---|
| 102 | {
 | 
|---|
| 103 |         for(int n = i; n < (int)s.length(); ++n)
 | 
|---|
| 104 |         {
 | 
|---|
| 105 |                 for(int k = 0; k < (int)list.length(); ++k)
 | 
|---|
| 106 |                 {
 | 
|---|
| 107 |                         if(s[n] == list[k])
 | 
|---|
| 108 |                         {
 | 
|---|
| 109 |                                 if(found)
 | 
|---|
| 110 |                                         *found = list[k];
 | 
|---|
| 111 |                                 return n;
 | 
|---|
| 112 |                         }
 | 
|---|
| 113 |                 }
 | 
|---|
| 114 |         }
 | 
|---|
| 115 |         return -1;
 | 
|---|
| 116 | }
 | 
|---|
| 117 | 
 | 
|---|
| 118 | Transport::Transport()
 | 
|---|
| 119 | {
 | 
|---|
| 120 | }
 | 
|---|
| 121 | 
 | 
|---|
| 122 | QString Transport::name() const
 | 
|---|
| 123 | {
 | 
|---|
| 124 |         return _name;
 | 
|---|
| 125 | }
 | 
|---|
| 126 | 
 | 
|---|
| 127 | TransportArgs Transport::arguments() const
 | 
|---|
| 128 | {
 | 
|---|
| 129 |         return _args;
 | 
|---|
| 130 | }
 | 
|---|
| 131 | 
 | 
|---|
| 132 | QString Transport::argument(const QString &name) const
 | 
|---|
| 133 | {
 | 
|---|
| 134 |         for(TransportArgs::ConstIterator it = _args.begin(); it != _args.end(); ++it)
 | 
|---|
| 135 |         {
 | 
|---|
| 136 |                 const Var &v = *it;
 | 
|---|
| 137 |                 if(v.name == name)
 | 
|---|
| 138 |                         return v.value;
 | 
|---|
| 139 |         }
 | 
|---|
| 140 |         return QString::null;
 | 
|---|
| 141 | }
 | 
|---|
| 142 | 
 | 
|---|
| 143 | void Transport::setArguments(const TransportArgs &list)
 | 
|---|
| 144 | {
 | 
|---|
| 145 |         _args = list;
 | 
|---|
| 146 | }
 | 
|---|
| 147 | 
 | 
|---|
| 148 | void Transport::setArgument(const QString &name, const QString &value)
 | 
|---|
| 149 | {
 | 
|---|
| 150 |         for(TransportArgs::Iterator it = _args.begin(); it != _args.end(); ++it)
 | 
|---|
| 151 |         {
 | 
|---|
| 152 |                 Var &v = *it;
 | 
|---|
| 153 |                 if(v.name == name)
 | 
|---|
| 154 |                 {
 | 
|---|
| 155 |                         v.value = value;
 | 
|---|
| 156 |                         return;
 | 
|---|
| 157 |                 }
 | 
|---|
| 158 |         }
 | 
|---|
| 159 | }
 | 
|---|
| 160 | 
 | 
|---|
| 161 | QString Transport::toString() const
 | 
|---|
| 162 | {
 | 
|---|
| 163 |         QString s;
 | 
|---|
| 164 |         s += _name;
 | 
|---|
| 165 |         if(!_args.isEmpty())
 | 
|---|
| 166 |         {
 | 
|---|
| 167 |                 for(TransportArgs::ConstIterator it = _args.begin(); it != _args.end(); ++it)
 | 
|---|
| 168 |                 {
 | 
|---|
| 169 |                         s += ';';
 | 
|---|
| 170 |                         s += (*it).name;
 | 
|---|
| 171 |                         if(!(*it).value.isNull())
 | 
|---|
| 172 |                         {
 | 
|---|
| 173 |                                 s += '=';
 | 
|---|
| 174 |                                 s += (*it).value;
 | 
|---|
| 175 |                         }
 | 
|---|
| 176 |                 }
 | 
|---|
| 177 |         }
 | 
|---|
| 178 |         return s;
 | 
|---|
| 179 | }
 | 
|---|
| 180 | 
 | 
|---|
| 181 | Transport::ReadStatus Transport::readFromString(QString *sp)
 | 
|---|
| 182 | {
 | 
|---|
| 183 |         const QString &s = *sp;
 | 
|---|
| 184 |         QString tname;
 | 
|---|
| 185 |         QValueList<Var> targs;
 | 
|---|
| 186 | 
 | 
|---|
| 187 |         // first read the name
 | 
|---|
| 188 |         int at = 0;
 | 
|---|
| 189 |         QChar c;
 | 
|---|
| 190 |         int n = findOneOf(s, ",;", at, &c);
 | 
|---|
| 191 |         if(n == -1)
 | 
|---|
| 192 |         {
 | 
|---|
| 193 |                 tname = s.mid(at);
 | 
|---|
| 194 |                 // empty at end means nothing left
 | 
|---|
| 195 |                 if(tname.isEmpty())
 | 
|---|
| 196 |                         return Done;
 | 
|---|
| 197 | 
 | 
|---|
| 198 |                 at = s.length();
 | 
|---|
| 199 |         }
 | 
|---|
| 200 |         else if(c == ',')
 | 
|---|
| 201 |         {
 | 
|---|
| 202 |                 tname = s.mid(at, n - at);
 | 
|---|
| 203 |                 // empty with separator is bad
 | 
|---|
| 204 |                 if(tname.isEmpty())
 | 
|---|
| 205 |                         return Error;
 | 
|---|
| 206 | 
 | 
|---|
| 207 |                 at = n + 1;
 | 
|---|
| 208 |         }
 | 
|---|
| 209 |         else if(c == ';')
 | 
|---|
| 210 |         {
 | 
|---|
| 211 |                 tname = s.mid(at, n - at);
 | 
|---|
| 212 |                 // empty with separator is bad
 | 
|---|
| 213 |                 if(tname.isEmpty())
 | 
|---|
| 214 |                         return Error;
 | 
|---|
| 215 | 
 | 
|---|
| 216 |                 at = n + 1;
 | 
|---|
| 217 | 
 | 
|---|
| 218 |                 // read args
 | 
|---|
| 219 |                 QString targ, tval;
 | 
|---|
| 220 |                 bool last = false;
 | 
|---|
| 221 |                 while(!last)
 | 
|---|
| 222 |                 {
 | 
|---|
| 223 |                         // get arg
 | 
|---|
| 224 |                         n = findOneOf(s, ",;=", at, &c);
 | 
|---|
| 225 |                         if(n == -1)
 | 
|---|
| 226 |                         {
 | 
|---|
| 227 |                                 targ = s.mid(at);
 | 
|---|
| 228 |                                 // empty at end means nothing left
 | 
|---|
| 229 |                                 if(targ.isEmpty())
 | 
|---|
| 230 |                                         break;
 | 
|---|
| 231 | 
 | 
|---|
| 232 |                                 at = s.length();
 | 
|---|
| 233 |                                 last = true;
 | 
|---|
| 234 |                         }
 | 
|---|
| 235 |                         else if(c == ',')
 | 
|---|
| 236 |                         {
 | 
|---|
| 237 |                                 targ = s.mid(at, n - at);
 | 
|---|
| 238 |                                 // empty with separator is bad
 | 
|---|
| 239 |                                 if(targ.isEmpty())
 | 
|---|
| 240 |                                         return Error;
 | 
|---|
| 241 | 
 | 
|---|
| 242 |                                 at = n + 1;
 | 
|---|
| 243 |                                 last = true;
 | 
|---|
| 244 |                         }
 | 
|---|
| 245 |                         else if(c == ';')
 | 
|---|
| 246 |                         {
 | 
|---|
| 247 |                                 targ = s.mid(at, n - at);
 | 
|---|
| 248 |                                 // empty with separator is bad
 | 
|---|
| 249 |                                 if(targ.isEmpty())
 | 
|---|
| 250 |                                         return Error;
 | 
|---|
| 251 | 
 | 
|---|
| 252 |                                 at = n + 1;
 | 
|---|
| 253 |                         }
 | 
|---|
| 254 |                         else if(c == '=')
 | 
|---|
| 255 |                         {
 | 
|---|
| 256 |                                 // this arg has a value
 | 
|---|
| 257 |                                 targ = s.mid(at, n - at);
 | 
|---|
| 258 |                                 // empty with value is bad
 | 
|---|
| 259 |                                 if(targ.isEmpty())
 | 
|---|
| 260 |                                         return Error;
 | 
|---|
| 261 | 
 | 
|---|
| 262 |                                 at = n + 1;
 | 
|---|
| 263 | 
 | 
|---|
| 264 |                                 // is next char a quote?
 | 
|---|
| 265 |                                 if(at < (int)s.length() && s[at] == '\"')
 | 
|---|
| 266 |                                 {
 | 
|---|
| 267 |                                         n = s.find('\"', at + 1);
 | 
|---|
| 268 |                                         if(n == -1)
 | 
|---|
| 269 |                                                 return Error;
 | 
|---|
| 270 |                                         tval = s.mid(at, n - at + 1);
 | 
|---|
| 271 |                                         at = n + 1;
 | 
|---|
| 272 | 
 | 
|---|
| 273 |                                         if(at < (int)s.length())
 | 
|---|
| 274 |                                         {
 | 
|---|
| 275 |                                                 // if not at end, the next char better be a separator
 | 
|---|
| 276 |                                                 if(s[at] != ',' && s[at] != ';')
 | 
|---|
| 277 |                                                         return Error;
 | 
|---|
| 278 | 
 | 
|---|
| 279 |                                                 if(s[at] == ',')
 | 
|---|
| 280 |                                                         last = true;
 | 
|---|
| 281 | 
 | 
|---|
| 282 |                                                 // skip over it
 | 
|---|
| 283 |                                                 ++at;
 | 
|---|
| 284 |                                         }
 | 
|---|
| 285 |                                         else
 | 
|---|
| 286 |                                                 last = true;
 | 
|---|
| 287 |                                 }
 | 
|---|
| 288 |                                 else
 | 
|---|
| 289 |                                 {
 | 
|---|
| 290 |                                         // find next separator
 | 
|---|
| 291 |                                         n = findOneOf(s, ",;", at, &c);
 | 
|---|
| 292 |                                         if(n == -1)
 | 
|---|
| 293 |                                         {
 | 
|---|
| 294 |                                                 tval = s.mid(at);
 | 
|---|
| 295 |                                                 at = s.length();
 | 
|---|
| 296 |                                                 last = true;
 | 
|---|
| 297 |                                         }
 | 
|---|
| 298 |                                         else if(c == ',')
 | 
|---|
| 299 |                                         {
 | 
|---|
| 300 |                                                 tval = s.mid(at, n - at);
 | 
|---|
| 301 |                                                 at = n + 1;
 | 
|---|
| 302 |                                                 last = true;
 | 
|---|
| 303 |                                         }
 | 
|---|
| 304 |                                         else if(c == ';')
 | 
|---|
| 305 |                                         {
 | 
|---|
| 306 |                                                 tval = s.mid(at, n - at);
 | 
|---|
| 307 |                                                 at = n + 1;
 | 
|---|
| 308 |                                         }
 | 
|---|
| 309 |                                 }
 | 
|---|
| 310 |                         }
 | 
|---|
| 311 | 
 | 
|---|
| 312 |                         Var v;
 | 
|---|
| 313 |                         v.name = targ;
 | 
|---|
| 314 |                         v.value = tval;
 | 
|---|
| 315 |                         targs.append(v);
 | 
|---|
| 316 |                 }
 | 
|---|
| 317 |         }
 | 
|---|
| 318 | 
 | 
|---|
| 319 |         _name = tname;
 | 
|---|
| 320 |         _args = targs;
 | 
|---|
| 321 | 
 | 
|---|
| 322 |         // remove what we just parsed
 | 
|---|
| 323 |         (*sp) = sp->mid(at);
 | 
|---|
| 324 |         return Ok;
 | 
|---|
| 325 | }
 | 
|---|
| 326 | 
 | 
|---|
| 327 | //----------------------------------------------------------------------------
 | 
|---|
| 328 | // TransportList
 | 
|---|
| 329 | //----------------------------------------------------------------------------
 | 
|---|
| 330 | TransportList::TransportList()
 | 
|---|
| 331 | :QValueList<Transport>()
 | 
|---|
| 332 | {
 | 
|---|
| 333 | }
 | 
|---|
| 334 | 
 | 
|---|
| 335 | QString TransportList::toString() const
 | 
|---|
| 336 | {
 | 
|---|
| 337 |         QStringList list;
 | 
|---|
| 338 |         for(ConstIterator it = begin(); it != end(); ++it)
 | 
|---|
| 339 |                 list.append((*it).toString());
 | 
|---|
| 340 |         return list.join(",");
 | 
|---|
| 341 | }
 | 
|---|
| 342 | 
 | 
|---|
| 343 | bool TransportList::fromString(const QString &s)
 | 
|---|
| 344 | {
 | 
|---|
| 345 |         QString tmp = s;
 | 
|---|
| 346 |         clear();
 | 
|---|
| 347 | 
 | 
|---|
| 348 |         while(1)
 | 
|---|
| 349 |         {
 | 
|---|
| 350 |                 Transport t;
 | 
|---|
| 351 |                 Transport::ReadStatus r = t.readFromString(&tmp);
 | 
|---|
| 352 |                 if(r == Transport::Error)
 | 
|---|
| 353 |                         return false;
 | 
|---|
| 354 |                 if(r == Transport::Done)
 | 
|---|
| 355 |                         break;
 | 
|---|
| 356 |                 append(t);
 | 
|---|
| 357 |         }
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         return true;
 | 
|---|
| 360 | }
 | 
|---|
| 361 | 
 | 
|---|
| 362 | //----------------------------------------------------------------------------
 | 
|---|
| 363 | // Packet
 | 
|---|
| 364 | //----------------------------------------------------------------------------
 | 
|---|
| 365 | Packet::Packet()
 | 
|---|
| 366 | {
 | 
|---|
| 367 |         t = Empty;
 | 
|---|
| 368 | }
 | 
|---|
| 369 | 
 | 
|---|
| 370 | Packet::Packet(const QString &command, const QString &resource, const HeaderList &headers)
 | 
|---|
| 371 | {
 | 
|---|
| 372 |         cmd = command;
 | 
|---|
| 373 |         res = resource;
 | 
|---|
| 374 |         _headers = headers;
 | 
|---|
| 375 |         ver = "1.0";
 | 
|---|
| 376 | }
 | 
|---|
| 377 | 
 | 
|---|
| 378 | Packet::Packet(int responseCode, const QString &responseString, const HeaderList &headers)
 | 
|---|
| 379 | {
 | 
|---|
| 380 |         rcode = responseCode;
 | 
|---|
| 381 |         rstr = responseString;
 | 
|---|
| 382 |         _headers = headers;
 | 
|---|
| 383 |         ver = "1.0";
 | 
|---|
| 384 | }
 | 
|---|
| 385 | 
 | 
|---|
| 386 | Packet::~Packet()
 | 
|---|
| 387 | {
 | 
|---|
| 388 | }
 | 
|---|
| 389 | 
 | 
|---|
| 390 | bool Packet::isNull() const
 | 
|---|
| 391 | {
 | 
|---|
| 392 |         return (t == Empty);
 | 
|---|
| 393 | }
 | 
|---|
| 394 | 
 | 
|---|
| 395 | Packet::Type Packet::type() const
 | 
|---|
| 396 | {
 | 
|---|
| 397 |         return t;
 | 
|---|
| 398 | }
 | 
|---|
| 399 | 
 | 
|---|
| 400 | QString Packet::version() const
 | 
|---|
| 401 | {
 | 
|---|
| 402 |         return ver;
 | 
|---|
| 403 | }
 | 
|---|
| 404 | 
 | 
|---|
| 405 | QString Packet::command() const
 | 
|---|
| 406 | {
 | 
|---|
| 407 |         return cmd;
 | 
|---|
| 408 | }
 | 
|---|
| 409 | 
 | 
|---|
| 410 | QString Packet::resource() const
 | 
|---|
| 411 | {
 | 
|---|
| 412 |         return res;
 | 
|---|
| 413 | }
 | 
|---|
| 414 | 
 | 
|---|
| 415 | int Packet::responseCode() const
 | 
|---|
| 416 | {
 | 
|---|
| 417 |         return rcode;
 | 
|---|
| 418 | }
 | 
|---|
| 419 | 
 | 
|---|
| 420 | QString Packet::responseString() const
 | 
|---|
| 421 | {
 | 
|---|
| 422 |         return rstr;
 | 
|---|
| 423 | }
 | 
|---|
| 424 | 
 | 
|---|
| 425 | int Packet::channel() const
 | 
|---|
| 426 | {
 | 
|---|
| 427 |         return chan;
 | 
|---|
| 428 | }
 | 
|---|
| 429 | 
 | 
|---|
| 430 | QByteArray Packet::data() const
 | 
|---|
| 431 | {
 | 
|---|
| 432 |         return _data;
 | 
|---|
| 433 | }
 | 
|---|
| 434 | 
 | 
|---|
| 435 | HeaderList & Packet::headers()
 | 
|---|
| 436 | {
 | 
|---|
| 437 |         return _headers;
 | 
|---|
| 438 | }
 | 
|---|
| 439 | 
 | 
|---|
| 440 | const HeaderList & Packet::headers() const
 | 
|---|
| 441 | {
 | 
|---|
| 442 |         return _headers;
 | 
|---|
| 443 | }
 | 
|---|
| 444 | 
 | 
|---|
| 445 | TransportList Packet::transports() const
 | 
|---|
| 446 | {
 | 
|---|
| 447 |         TransportList list;
 | 
|---|
| 448 |         list.fromString(_headers.get("Transport"));
 | 
|---|
| 449 |         return list;
 | 
|---|
| 450 | }
 | 
|---|
| 451 | 
 | 
|---|
| 452 | void Packet::setTransports(const TransportList &list)
 | 
|---|
| 453 | {
 | 
|---|
| 454 |         _headers.set("Transport", list.toString());
 | 
|---|
| 455 | }
 | 
|---|
| 456 | 
 | 
|---|
| 457 | void Packet::setResource(const QString &s)
 | 
|---|
| 458 | {
 | 
|---|
| 459 |         res = s;
 | 
|---|
| 460 | }
 | 
|---|
| 461 | 
 | 
|---|
| 462 | QByteArray Packet::toArray() const
 | 
|---|
| 463 | {
 | 
|---|
| 464 |         QByteArray buf;
 | 
|---|
| 465 | 
 | 
|---|
| 466 |         if(t == Data)
 | 
|---|
| 467 |         {
 | 
|---|
| 468 |                 buf.resize(4 + _data.size());
 | 
|---|
| 469 | 
 | 
|---|
| 470 |                 buf[0] = '$';
 | 
|---|
| 471 |                 buf[1] = chan;
 | 
|---|
| 472 |                 ushort ssa = _data.size();
 | 
|---|
| 473 |                 ushort ssb = htons(ssa);
 | 
|---|
| 474 |                 memcpy(buf.data() + 2, &ssb, 2);
 | 
|---|
| 475 |                 memcpy(buf.data() + 4, _data.data(), _data.size());
 | 
|---|
| 476 |         }
 | 
|---|
| 477 |         else
 | 
|---|
| 478 |         {
 | 
|---|
| 479 |                 QString str;
 | 
|---|
| 480 | 
 | 
|---|
| 481 |                 if(t == Request)
 | 
|---|
| 482 |                 {
 | 
|---|
| 483 |                         str += cmd + ' ' + res + " RTSP/" + ver + '\n';
 | 
|---|
| 484 |                         for(HeaderList::ConstIterator it = _headers.begin(); it != _headers.end(); ++it)
 | 
|---|
| 485 |                                 str += (*it).name + ": " + (*it).value + '\n';
 | 
|---|
| 486 |                         str += '\n';
 | 
|---|
| 487 |                 }
 | 
|---|
| 488 |                 else if(t == Response)
 | 
|---|
| 489 |                 {
 | 
|---|
| 490 |                         str += "RTSP/" + ver + ' ' + QString::number(rcode) + ' ' + rstr + '\n';
 | 
|---|
| 491 |                         for(HeaderList::ConstIterator it = _headers.begin(); it != _headers.end(); ++it)
 | 
|---|
| 492 |                                 str += (*it).name + ": " + (*it).value + '\n';
 | 
|---|
| 493 |                         str += '\n';
 | 
|---|
| 494 |                 }
 | 
|---|
| 495 | 
 | 
|---|
| 496 |                 QCString cs = str.utf8();
 | 
|---|
| 497 |                 buf.resize(cs.length());
 | 
|---|
| 498 |                 memcpy(buf.data(), cs.data(), buf.size());
 | 
|---|
| 499 |                 ByteStream::appendArray(&buf, _data);
 | 
|---|
| 500 |         }
 | 
|---|
| 501 | 
 | 
|---|
| 502 |         return buf;
 | 
|---|
| 503 | }
 | 
|---|
| 504 | 
 | 
|---|
| 505 | //----------------------------------------------------------------------------
 | 
|---|
| 506 | // Parser
 | 
|---|
| 507 | //----------------------------------------------------------------------------
 | 
|---|
| 508 | Parser::Parser()
 | 
|---|
| 509 | {
 | 
|---|
| 510 | }
 | 
|---|
| 511 | 
 | 
|---|
| 512 | void Parser::reset(Mode _mode)
 | 
|---|
| 513 | {
 | 
|---|
| 514 |         mode = _mode;
 | 
|---|
| 515 |         in.resize(0);
 | 
|---|
| 516 |         cur.clear();
 | 
|---|
| 517 |         tmp = Packet();
 | 
|---|
| 518 |         list.clear();
 | 
|---|
| 519 | }
 | 
|---|
| 520 | 
 | 
|---|
| 521 | void Parser::appendData(const QByteArray &a)
 | 
|---|
| 522 | {
 | 
|---|
| 523 |         ByteStream::appendArray(&in, a);
 | 
|---|
| 524 | }
 | 
|---|
| 525 | 
 | 
|---|
| 526 | Packet Parser::read(bool *ok)
 | 
|---|
| 527 | {
 | 
|---|
| 528 |         if(ok)
 | 
|---|
| 529 |                 *ok = true;
 | 
|---|
| 530 | 
 | 
|---|
| 531 |         if(list.isEmpty())
 | 
|---|
| 532 |         {
 | 
|---|
| 533 |                 if(!readPacket())
 | 
|---|
| 534 |                 {
 | 
|---|
| 535 |                         if(ok)
 | 
|---|
| 536 |                                 *ok = false;
 | 
|---|
| 537 |                 }
 | 
|---|
| 538 |         }
 | 
|---|
| 539 | 
 | 
|---|
| 540 |         Packet p;
 | 
|---|
| 541 |         if(!list.isEmpty())
 | 
|---|
| 542 |         {
 | 
|---|
| 543 |                 p = list.first();
 | 
|---|
| 544 |                 list.remove(list.begin());
 | 
|---|
| 545 |         }
 | 
|---|
| 546 |         return p;
 | 
|---|
| 547 | }
 | 
|---|
| 548 | 
 | 
|---|
| 549 | bool Parser::readPacket()
 | 
|---|
| 550 | {
 | 
|---|
| 551 |         bool interleaved = false;
 | 
|---|
| 552 |         bool done = false;
 | 
|---|
| 553 | 
 | 
|---|
| 554 |         // don't know what it is yet?  let's have a look
 | 
|---|
| 555 |         if(tmp.t == Packet::Empty)
 | 
|---|
| 556 |         {
 | 
|---|
| 557 |                 // need at least 1 byte
 | 
|---|
| 558 |                 if(in.isEmpty())
 | 
|---|
| 559 |                         return true;
 | 
|---|
| 560 | 
 | 
|---|
| 561 |                 if(in[0] == '$')
 | 
|---|
| 562 |                 {
 | 
|---|
| 563 |                         // interleaved data
 | 
|---|
| 564 |                         if(in.size() < 4)
 | 
|---|
| 565 |                                 return true;
 | 
|---|
| 566 |                         ushort ss;
 | 
|---|
| 567 |                         memcpy(&ss, in.data() + 2, 2);
 | 
|---|
| 568 |                         int size = ntohs(ss);
 | 
|---|
| 569 |                         if((int)in.size() < 4 + size)
 | 
|---|
| 570 |                                 return true;
 | 
|---|
| 571 | 
 | 
|---|
| 572 |                         QByteArray buf = ByteStream::takeArray(&in, 4 + size);
 | 
|---|
| 573 |                         tmp.t = Packet::Data;
 | 
|---|
| 574 |                         tmp.chan = buf[1];
 | 
|---|
| 575 |                         tmp._data.resize(size);
 | 
|---|
| 576 |                         memcpy(tmp._data.data(), buf.data() + 4, size);
 | 
|---|
| 577 | 
 | 
|---|
| 578 |                         interleaved = true;
 | 
|---|
| 579 |                         done = true;
 | 
|---|
| 580 |                 }
 | 
|---|
| 581 |                 else
 | 
|---|
| 582 |                 {
 | 
|---|
| 583 |                         // regular request/response
 | 
|---|
| 584 |                         if(mode == Client)
 | 
|---|
| 585 |                                 tmp.t = Packet::Request;
 | 
|---|
| 586 |                         else
 | 
|---|
| 587 |                                 tmp.t = Packet::Response;
 | 
|---|
| 588 |                         readingContent = false;
 | 
|---|
| 589 |                 }
 | 
|---|
| 590 |         }
 | 
|---|
| 591 | 
 | 
|---|
| 592 |         if(!interleaved)
 | 
|---|
| 593 |         {
 | 
|---|
| 594 |                 if(!readingContent)
 | 
|---|
| 595 |                 {
 | 
|---|
| 596 |                         // read the lines
 | 
|---|
| 597 |                         QStringList lines = readPacketLines();
 | 
|---|
| 598 |                         if(lines.isEmpty())
 | 
|---|
| 599 |                                 return true;
 | 
|---|
| 600 |                         if(!packetFromLines(lines))
 | 
|---|
| 601 |                                 return false;
 | 
|---|
| 602 |                         if(tmp._headers.has("Content-length"))
 | 
|---|
| 603 |                         {
 | 
|---|
| 604 |                                 clen = tmp._headers.get("Content-length").toInt();
 | 
|---|
| 605 |                                 if(clen > MAX_CONTENT_LENGTH)
 | 
|---|
| 606 |                                         return false;
 | 
|---|
| 607 |                         }
 | 
|---|
| 608 |                         else
 | 
|---|
| 609 |                                 clen = 0;
 | 
|---|
| 610 |                         readingContent = true;
 | 
|---|
| 611 |                 }
 | 
|---|
| 612 | 
 | 
|---|
| 613 |                 if(readingContent)
 | 
|---|
| 614 |                 {
 | 
|---|
| 615 |                         if(clen > 0)
 | 
|---|
| 616 |                         {
 | 
|---|
| 617 |                                 int need = clen - tmp._data.size();
 | 
|---|
| 618 |                                 QByteArray a;
 | 
|---|
| 619 |                                 if((int)in.size() >= need)
 | 
|---|
| 620 |                                         a = ByteStream::takeArray(&in, need);
 | 
|---|
| 621 |                                 else
 | 
|---|
| 622 |                                         a = ByteStream::takeArray(&in);
 | 
|---|
| 623 |                                 ByteStream::appendArray(&tmp._data, a);
 | 
|---|
| 624 |                         }
 | 
|---|
| 625 | 
 | 
|---|
| 626 |                         if(clen == 0 || (int)tmp._data.size() == clen)
 | 
|---|
| 627 |                                 done = true;
 | 
|---|
| 628 |                 }
 | 
|---|
| 629 |         }
 | 
|---|
| 630 | 
 | 
|---|
| 631 |         if(done)
 | 
|---|
| 632 |         {
 | 
|---|
| 633 |                 list.append(tmp);
 | 
|---|
| 634 |                 tmp = Packet();
 | 
|---|
| 635 |         }
 | 
|---|
| 636 | 
 | 
|---|
| 637 |         return true;
 | 
|---|
| 638 | }
 | 
|---|
| 639 | 
 | 
|---|
| 640 | bool Parser::packetFromLines(const QStringList &lines)
 | 
|---|
| 641 | {
 | 
|---|
| 642 |         if(mode == Client)
 | 
|---|
| 643 |         {
 | 
|---|
| 644 |                 if(lines.isEmpty())
 | 
|---|
| 645 |                         return false;
 | 
|---|
| 646 |                 QString str = lines[0];
 | 
|---|
| 647 |                 int n = str.find(' ');
 | 
|---|
| 648 |                 if(n == -1)
 | 
|---|
| 649 |                         return false;
 | 
|---|
| 650 |                 QString c = str.mid(0, n);
 | 
|---|
| 651 |                 int at = n + 1;
 | 
|---|
| 652 |                 n = str.find(' ', at);
 | 
|---|
| 653 |                 if(n == -1)
 | 
|---|
| 654 |                         return false;
 | 
|---|
| 655 |                 QString r = str.mid(at, n - at);
 | 
|---|
| 656 |                 QString v = str.mid(n + 1);
 | 
|---|
| 657 | 
 | 
|---|
| 658 |                 if(v.left(5) != "RTSP/")
 | 
|---|
| 659 |                         return false;
 | 
|---|
| 660 | 
 | 
|---|
| 661 |                 HeaderList headers;
 | 
|---|
| 662 |                 if(!readHeaders(lines, &headers))
 | 
|---|
| 663 |                         return false;
 | 
|---|
| 664 | 
 | 
|---|
| 665 |                 tmp.cmd = c;
 | 
|---|
| 666 |                 tmp.res = r;
 | 
|---|
| 667 |                 tmp.ver = v.mid(5);
 | 
|---|
| 668 |                 tmp._headers = headers;
 | 
|---|
| 669 |                 return true;
 | 
|---|
| 670 |         }
 | 
|---|
| 671 |         else
 | 
|---|
| 672 |         {
 | 
|---|
| 673 |                 if(lines.isEmpty())
 | 
|---|
| 674 |                         return false;
 | 
|---|
| 675 |                 QString str = lines[0];
 | 
|---|
| 676 |                 int n = str.find(' ');
 | 
|---|
| 677 |                 if(n == -1)
 | 
|---|
| 678 |                         return false;
 | 
|---|
| 679 |                 QString v = str.mid(0, n);
 | 
|---|
| 680 |                 int at = n + 1;
 | 
|---|
| 681 |                 n = str.find(' ', at);
 | 
|---|
| 682 |                 if(n == -1)
 | 
|---|
| 683 |                         return false;
 | 
|---|
| 684 |                 QString c = str.mid(at, n - at);
 | 
|---|
| 685 |                 QString s = str.mid(n + 1);
 | 
|---|
| 686 |                 if(v.left(5) != "RTSP/")
 | 
|---|
| 687 |                         return false;
 | 
|---|
| 688 | 
 | 
|---|
| 689 |                 HeaderList headers;
 | 
|---|
| 690 |                 if(!readHeaders(lines, &headers))
 | 
|---|
| 691 |                         return false;
 | 
|---|
| 692 | 
 | 
|---|
| 693 |                 tmp.ver = v.mid(5);
 | 
|---|
| 694 |                 tmp.rcode = c.toInt();
 | 
|---|
| 695 |                 tmp.rstr = s;
 | 
|---|
| 696 |                 tmp._headers = headers;
 | 
|---|
| 697 |                 return true;
 | 
|---|
| 698 |         }
 | 
|---|
| 699 | }
 | 
|---|
| 700 | 
 | 
|---|
| 701 | bool Parser::readHeaders(const QStringList &lines, HeaderList *headers)
 | 
|---|
| 702 | {
 | 
|---|
| 703 |         // skip the first line
 | 
|---|
| 704 |         QStringList::ConstIterator it = lines.begin();
 | 
|---|
| 705 |         ++it;
 | 
|---|
| 706 | 
 | 
|---|
| 707 |         headers->clear();
 | 
|---|
| 708 |         for(; it != lines.end(); ++it)
 | 
|---|
| 709 |         {
 | 
|---|
| 710 |                 const QString &s = *it;
 | 
|---|
| 711 |                 int n = s.find(':');
 | 
|---|
| 712 |                 if(n == -1)
 | 
|---|
| 713 |                         return false;
 | 
|---|
| 714 |                 Var v;
 | 
|---|
| 715 |                 v.name = s.mid(0, n).stripWhiteSpace();
 | 
|---|
| 716 |                 v.value = s.mid(n + 1).stripWhiteSpace();
 | 
|---|
| 717 |                 headers->append(v);
 | 
|---|
| 718 |         }
 | 
|---|
| 719 |         return true;
 | 
|---|
| 720 | }
 | 
|---|
| 721 | 
 | 
|---|
| 722 | QStringList Parser::readPacketLines()
 | 
|---|
| 723 | {
 | 
|---|
| 724 |         QStringList lines;
 | 
|---|
| 725 |         while(1)
 | 
|---|
| 726 |         {
 | 
|---|
| 727 |                 QString str = tryReadLine();
 | 
|---|
| 728 |                 if(str.isNull())
 | 
|---|
| 729 |                         break;
 | 
|---|
| 730 | 
 | 
|---|
| 731 |                 if(str.isEmpty())
 | 
|---|
| 732 |                 {
 | 
|---|
| 733 |                         lines = cur;
 | 
|---|
| 734 |                         cur.clear();
 | 
|---|
| 735 |                         break;
 | 
|---|
| 736 |                 }
 | 
|---|
| 737 | 
 | 
|---|
| 738 |                 cur.append(str);
 | 
|---|
| 739 |         }
 | 
|---|
| 740 |         return lines;
 | 
|---|
| 741 | }
 | 
|---|
| 742 | 
 | 
|---|
| 743 | QString Parser::tryReadLine()
 | 
|---|
| 744 | {
 | 
|---|
| 745 |         for(int n = 0; n < (int)in.size(); ++n)
 | 
|---|
| 746 |         {
 | 
|---|
| 747 |                 if(in[n] == '\n')
 | 
|---|
| 748 |                 {
 | 
|---|
| 749 |                         int eat = n + 1;
 | 
|---|
| 750 |                         if(n > 0 && in[n-1] == '\r')
 | 
|---|
| 751 |                                 --n;
 | 
|---|
| 752 |                         QByteArray buf = ByteStream::takeArray(&in, eat);
 | 
|---|
| 753 |                         QCString cs;
 | 
|---|
| 754 |                         cs.resize(n + 1);
 | 
|---|
| 755 |                         memcpy(cs.data(), buf.data(), n);
 | 
|---|
| 756 |                         return QString::fromUtf8(cs);
 | 
|---|
| 757 |                 }
 | 
|---|
| 758 |         }
 | 
|---|
| 759 |         return QString::null;
 | 
|---|
| 760 | }
 | 
|---|
| 761 | 
 | 
|---|
| 762 | //----------------------------------------------------------------------------
 | 
|---|
| 763 | // Client
 | 
|---|
| 764 | //----------------------------------------------------------------------------
 | 
|---|
| 765 | class Client::Private
 | 
|---|
| 766 | {
 | 
|---|
| 767 | public:
 | 
|---|
| 768 |         Private()
 | 
|---|
| 769 |         {
 | 
|---|
| 770 |                 bs = 0;
 | 
|---|
| 771 |                 using_sock = false;
 | 
|---|
| 772 |                 conn = false;
 | 
|---|
| 773 |                 active = false;
 | 
|---|
| 774 |         }
 | 
|---|
| 775 | 
 | 
|---|
| 776 |         ByteStream *bs;
 | 
|---|
| 777 |         bool using_sock;
 | 
|---|
| 778 |         bool conn;
 | 
|---|
| 779 |         bool active;
 | 
|---|
| 780 |         Parser parser;
 | 
|---|
| 781 |         QValueList<int> trackQueue;
 | 
|---|
| 782 | };
 | 
|---|
| 783 | 
 | 
|---|
| 784 | Client::Client(QObject *parent)
 | 
|---|
| 785 | :QObject(parent)
 | 
|---|
| 786 | {
 | 
|---|
| 787 |         d = new Private;
 | 
|---|
| 788 | }
 | 
|---|
| 789 | 
 | 
|---|
| 790 | Client::Client(int socket)
 | 
|---|
| 791 | {
 | 
|---|
| 792 |         d = new Private;
 | 
|---|
| 793 |         d->using_sock = true;
 | 
|---|
| 794 |         BSocket *sock = new BSocket;
 | 
|---|
| 795 |         d->bs = sock;
 | 
|---|
| 796 |         d->conn = false;
 | 
|---|
| 797 |         hook();
 | 
|---|
| 798 |         d->parser.reset(Parser::Client); // as a server, we want to parse client requests
 | 
|---|
| 799 |         sock->setSocket(socket);
 | 
|---|
| 800 | }
 | 
|---|
| 801 | 
 | 
|---|
| 802 | Client::~Client()
 | 
|---|
| 803 | {
 | 
|---|
| 804 |         delete d->bs;
 | 
|---|
| 805 |         delete d;
 | 
|---|
| 806 | }
 | 
|---|
| 807 | 
 | 
|---|
| 808 | void Client::hook()
 | 
|---|
| 809 | {
 | 
|---|
| 810 |         connect(d->bs, SIGNAL(connectionClosed()), SLOT(bs_connectionClosed()));
 | 
|---|
| 811 |         connect(d->bs, SIGNAL(readyRead()), SLOT(bs_readyRead()));
 | 
|---|
| 812 |         connect(d->bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int)));
 | 
|---|
| 813 |         connect(d->bs, SIGNAL(error(int)), SLOT(bs_error(int)));
 | 
|---|
| 814 | }
 | 
|---|
| 815 | 
 | 
|---|
| 816 | void Client::processPackets()
 | 
|---|
| 817 | {
 | 
|---|
| 818 |         QGuardedPtr<QObject> self = this;
 | 
|---|
| 819 |         while(1)
 | 
|---|
| 820 |         {
 | 
|---|
| 821 |                 bool ok;
 | 
|---|
| 822 |                 Packet p = d->parser.read(&ok);
 | 
|---|
| 823 |                 if(!ok)
 | 
|---|
| 824 |                 {
 | 
|---|
| 825 |                         delete d->bs;
 | 
|---|
| 826 |                         d->bs = 0;
 | 
|---|
| 827 |                         error(ErrParse);
 | 
|---|
| 828 |                         return;
 | 
|---|
| 829 |                 }
 | 
|---|
| 830 | 
 | 
|---|
| 831 |                 if(p.isNull())
 | 
|---|
| 832 |                         break;
 | 
|---|
| 833 | 
 | 
|---|
| 834 |                 packetReady(p);
 | 
|---|
| 835 |                 if(!self)
 | 
|---|
| 836 |                         return;
 | 
|---|
| 837 |         }
 | 
|---|
| 838 | }
 | 
|---|
| 839 | 
 | 
|---|
| 840 | void Client::connectToHost(const QString &host, int port)
 | 
|---|
| 841 | {
 | 
|---|
| 842 |         BSocket *sock = new BSocket;
 | 
|---|
| 843 |         connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
 | 
|---|
| 844 |         d->bs = sock;
 | 
|---|
| 845 |         d->conn = true;
 | 
|---|
| 846 |         hook();
 | 
|---|
| 847 |         sock->connectToHost(host, port);
 | 
|---|
| 848 | }
 | 
|---|
| 849 | 
 | 
|---|
| 850 | void Client::setByteStream(ByteStream *bs, Mode mode)
 | 
|---|
| 851 | {
 | 
|---|
| 852 |         d->bs = bs;
 | 
|---|
| 853 |         d->conn = false;
 | 
|---|
| 854 |         hook();
 | 
|---|
| 855 |         d->parser.reset(mode == MClient ? Parser::Server : Parser::Client);
 | 
|---|
| 856 | }
 | 
|---|
| 857 | 
 | 
|---|
| 858 | void Client::close()
 | 
|---|
| 859 | {
 | 
|---|
| 860 |         if(d->bs)
 | 
|---|
| 861 |                 d->bs->close();
 | 
|---|
| 862 | }
 | 
|---|
| 863 | 
 | 
|---|
| 864 | void Client::write(const Packet &p)
 | 
|---|
| 865 | {
 | 
|---|
| 866 |         QByteArray buf = p.toArray();
 | 
|---|
| 867 |         d->trackQueue.append(buf.size());
 | 
|---|
| 868 |         d->bs->write(buf);
 | 
|---|
| 869 | }
 | 
|---|
| 870 | 
 | 
|---|
| 871 | QHostAddress Client::peerAddress() const
 | 
|---|
| 872 | {
 | 
|---|
| 873 |         QHostAddress addr;
 | 
|---|
| 874 |         if(d->using_sock)
 | 
|---|
| 875 |                 addr = ((BSocket *)d->bs)->peerAddress();
 | 
|---|
| 876 |         return addr;
 | 
|---|
| 877 | }
 | 
|---|
| 878 | 
 | 
|---|
| 879 | void Client::sock_connected()
 | 
|---|
| 880 | {
 | 
|---|
| 881 |         d->using_sock = true;
 | 
|---|
| 882 |         d->active = true;
 | 
|---|
| 883 |         d->parser.reset(Parser::Server); // as a client, we want to parse server responses
 | 
|---|
| 884 |         connected();
 | 
|---|
| 885 | }
 | 
|---|
| 886 | 
 | 
|---|
| 887 | void Client::bs_connectionClosed()
 | 
|---|
| 888 | {
 | 
|---|
| 889 |         connectionClosed();
 | 
|---|
| 890 | }
 | 
|---|
| 891 | 
 | 
|---|
| 892 | void Client::bs_readyRead()
 | 
|---|
| 893 | {
 | 
|---|
| 894 |         QByteArray buf = d->bs->read();
 | 
|---|
| 895 |         d->parser.appendData(buf);
 | 
|---|
| 896 |         if(d->active)
 | 
|---|
| 897 |                 processPackets();
 | 
|---|
| 898 | }
 | 
|---|
| 899 | 
 | 
|---|
| 900 | void Client::bs_bytesWritten(int bytes)
 | 
|---|
| 901 | {
 | 
|---|
| 902 |         int written = 0;
 | 
|---|
| 903 |         for(QValueList<int>::Iterator it = d->trackQueue.begin(); it != d->trackQueue.end();)
 | 
|---|
| 904 |         {
 | 
|---|
| 905 |                 int &i = *it;
 | 
|---|
| 906 | 
 | 
|---|
| 907 |                 // enough bytes?
 | 
|---|
| 908 |                 if(bytes < i) {
 | 
|---|
| 909 |                         i -= bytes;
 | 
|---|
| 910 |                         break;
 | 
|---|
| 911 |                 }
 | 
|---|
| 912 |                 bytes -= i;
 | 
|---|
| 913 |                 it = d->trackQueue.remove(it);
 | 
|---|
| 914 |                 ++written;
 | 
|---|
| 915 |         }
 | 
|---|
| 916 | 
 | 
|---|
| 917 |         for(int n = 0; n < written; ++n)
 | 
|---|
| 918 |                 packetWritten();
 | 
|---|
| 919 | }
 | 
|---|
| 920 | 
 | 
|---|
| 921 | void Client::bs_error(int x)
 | 
|---|
| 922 | {
 | 
|---|
| 923 |         delete d->bs;
 | 
|---|
| 924 |         d->bs = 0;
 | 
|---|
| 925 | 
 | 
|---|
| 926 |         if(d->conn)
 | 
|---|
| 927 |         {
 | 
|---|
| 928 |                 if(x == BSocket::ErrConnectionRefused || x == BSocket::ErrHostNotFound)
 | 
|---|
| 929 |                 {
 | 
|---|
| 930 |                         error(ErrConnect);
 | 
|---|
| 931 |                         return;
 | 
|---|
| 932 |                 }
 | 
|---|
| 933 |         }
 | 
|---|
| 934 | 
 | 
|---|
| 935 |         error(ErrStream);
 | 
|---|
| 936 |         return;
 | 
|---|
| 937 | }
 | 
|---|
| 938 | 
 | 
|---|
| 939 | void Client::serve()
 | 
|---|
| 940 | {
 | 
|---|
| 941 |         d->active = true;
 | 
|---|
| 942 |         processPackets();
 | 
|---|
| 943 | }
 | 
|---|
| 944 | 
 | 
|---|
| 945 | //----------------------------------------------------------------------------
 | 
|---|
| 946 | // Server
 | 
|---|
| 947 | //----------------------------------------------------------------------------
 | 
|---|
| 948 | class Server::Private
 | 
|---|
| 949 | {
 | 
|---|
| 950 | public:
 | 
|---|
| 951 |         Private() {}
 | 
|---|
| 952 | 
 | 
|---|
| 953 |         ServSock serv;
 | 
|---|
| 954 |         QPtrList<Client> incomingConns;
 | 
|---|
| 955 | };
 | 
|---|
| 956 | 
 | 
|---|
| 957 | Server::Server(QObject *parent)
 | 
|---|
| 958 | :QObject(parent)
 | 
|---|
| 959 | {
 | 
|---|
| 960 |         d = new Private;
 | 
|---|
| 961 |         connect(&d->serv, SIGNAL(connectionReady(int)), SLOT(connectionReady(int)));
 | 
|---|
| 962 | }
 | 
|---|
| 963 | 
 | 
|---|
| 964 | Server::~Server()
 | 
|---|
| 965 | {
 | 
|---|
| 966 |         d->incomingConns.setAutoDelete(true);
 | 
|---|
| 967 |         d->incomingConns.clear();
 | 
|---|
| 968 |         delete d;
 | 
|---|
| 969 | }
 | 
|---|
| 970 | 
 | 
|---|
| 971 | bool Server::isActive() const
 | 
|---|
| 972 | {
 | 
|---|
| 973 |         return d->serv.isActive();
 | 
|---|
| 974 | }
 | 
|---|
| 975 | 
 | 
|---|
| 976 | bool Server::start(int port)
 | 
|---|
| 977 | {
 | 
|---|
| 978 |         return d->serv.listen(port);
 | 
|---|
| 979 | }
 | 
|---|
| 980 | 
 | 
|---|
| 981 | void Server::stop()
 | 
|---|
| 982 | {
 | 
|---|
| 983 |         d->serv.stop();
 | 
|---|
| 984 | }
 | 
|---|
| 985 | 
 | 
|---|
| 986 | int Server::port() const
 | 
|---|
| 987 | {
 | 
|---|
| 988 |         return d->serv.port();
 | 
|---|
| 989 | }
 | 
|---|
| 990 | 
 | 
|---|
| 991 | QHostAddress Server::address() const
 | 
|---|
| 992 | {
 | 
|---|
| 993 |         return d->serv.address();
 | 
|---|
| 994 | }
 | 
|---|
| 995 | 
 | 
|---|
| 996 | Client *Server::takeIncoming()
 | 
|---|
| 997 | {
 | 
|---|
| 998 |         if(d->incomingConns.isEmpty())
 | 
|---|
| 999 |                 return 0;
 | 
|---|
| 1000 | 
 | 
|---|
| 1001 |         Client *c = d->incomingConns.getFirst();
 | 
|---|
| 1002 |         d->incomingConns.removeRef(c);
 | 
|---|
| 1003 | 
 | 
|---|
| 1004 |         // we don't care about errors anymore
 | 
|---|
| 1005 |         disconnect(c, SIGNAL(error(int)), this, SLOT(connectionError()));
 | 
|---|
| 1006 | 
 | 
|---|
| 1007 |         // don't serve the connection until the event loop, to give the caller a chance to map signals
 | 
|---|
| 1008 |         QTimer::singleShot(0, c, SLOT(serve()));
 | 
|---|
| 1009 | 
 | 
|---|
| 1010 |         return c;
 | 
|---|
| 1011 | }
 | 
|---|
| 1012 | 
 | 
|---|
| 1013 | void Server::connectionReady(int s)
 | 
|---|
| 1014 | {
 | 
|---|
| 1015 |         Client *c = new Client(s);
 | 
|---|
| 1016 |         connect(c, SIGNAL(error(int)), this, SLOT(connectionError()));
 | 
|---|
| 1017 |         d->incomingConns.append(c);
 | 
|---|
| 1018 |         incomingReady();
 | 
|---|
| 1019 | }
 | 
|---|
| 1020 | 
 | 
|---|
| 1021 | void Server::connectionError()
 | 
|---|
| 1022 | {
 | 
|---|
| 1023 |         Client *c = (Client *)sender();
 | 
|---|
| 1024 |         d->incomingConns.removeRef(c);
 | 
|---|
| 1025 |         c->deleteLater();
 | 
|---|
| 1026 | }
 | 
|---|
| 1027 | 
 | 
|---|
| 1028 | }
 | 
|---|