~ubuntu-branches/ubuntu/trusty/mpeg4ip/trusty

« back to all changes in this revision

Viewing changes to player/lib/rtsp/rtsp_command.c

  • Committer: Bazaar Package Importer
  • Author(s): Mario Limonciello
  • Date: 2008-01-12 15:59:56 UTC
  • Revision ID: james.westby@ubuntu.com-20080112155956-1vznw5njidvrh649
Tags: upstream-1.6dfsg
ImportĀ upstreamĀ versionĀ 1.6dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * The contents of this file are subject to the Mozilla Public
 
3
 * License Version 1.1 (the "License"); you may not use this file
 
4
 * except in compliance with the License. You may obtain a copy of
 
5
 * the License at http://www.mozilla.org/MPL/
 
6
 * 
 
7
 * Software distributed under the License is distributed on an "AS
 
8
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
9
 * implied. See the License for the specific language governing
 
10
 * rights and limitations under the License.
 
11
 * 
 
12
 * The Original Code is MPEG4IP.
 
13
 * 
 
14
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 
15
 * Portions created by Cisco Systems Inc. are
 
16
 * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
 
17
 * 
 
18
 * Contributor(s): 
 
19
 *              Bill May        wmay@cisco.com
 
20
 */
 
21
/*
 
22
 * rtsp_command.c - process API calls to send/receive rtsp commands
 
23
 */
 
24
#include "rtsp_private.h"
 
25
#include <math.h>
 
26
 
 
27
 
 
28
static const char *UserAgent = "Cisco RTSP 1.0";
 
29
 
 
30
/*
 
31
 * rtsp_build_common()
 
32
 * Builds a common header based on rtsp_command_t information.
 
33
 */
 
34
static int rtsp_build_common (char *buffer,
 
35
                              uint32_t maxlen,
 
36
                              uint32_t *at,
 
37
                              rtsp_client_t *info,
 
38
                              rtsp_command_t *cmd,
 
39
                              const char *session)
 
40
{
 
41
  int ret;
 
42
 
 
43
  /*
 
44
   * The below is ugly, but it will allow us to remove a lot of lines
 
45
   * of code.  SNPRINTF_CHECK makes sure (for this routine), that we
 
46
   * don't have more data in the buffer than allowed - it will return
 
47
   * an error code if that happens.
 
48
   */
 
49
#define SNPRINTF_CHECK(fmt, value) \
 
50
  ret = snprintf(buffer + *at, maxlen - *at, (fmt), (value)); \
 
51
  if (ret == -1) { \
 
52
    return (-1); \
 
53
  }\
 
54
  *at += ret;
 
55
 
 
56
  SNPRINTF_CHECK("CSeq: %u\r\n", info->next_cseq);
 
57
  if (info->cookie) {
 
58
    SNPRINTF_CHECK("Cookie: %s\r\n", info->cookie);
 
59
  }
 
60
 
 
61
  if (cmd && cmd->accept) {
 
62
    SNPRINTF_CHECK("Accept: %s\r\n", cmd->accept);
 
63
  }
 
64
  if (cmd && cmd->accept_encoding) {
 
65
    SNPRINTF_CHECK("Accept-Encoding: %s\r\n", cmd->accept_encoding);
 
66
  }
 
67
  if (cmd && cmd->accept_language) {
 
68
    SNPRINTF_CHECK("Accept-Language: %s\r\n", cmd->accept_language);
 
69
  }
 
70
  if (cmd && cmd->authorization) {
 
71
    SNPRINTF_CHECK("Authorization: %s\r\n", cmd->authorization);
 
72
  }
 
73
  if (cmd && cmd->bandwidth != 0) {
 
74
    SNPRINTF_CHECK("Bandwidth: %u\r\n", cmd->bandwidth);
 
75
  }
 
76
  if (cmd && cmd->blocksize != 0) {
 
77
    SNPRINTF_CHECK("Blocksize: %u\r\n", cmd->blocksize);
 
78
  }
 
79
  if (cmd && cmd->cachecontrol) {
 
80
    SNPRINTF_CHECK("Cache-Control: %s\r\n", cmd->cachecontrol);
 
81
  }
 
82
  if (cmd && cmd->conference) {
 
83
    SNPRINTF_CHECK("Conference: %s\r\n", cmd->conference);
 
84
  }
 
85
  if (cmd && cmd->from) {
 
86
    SNPRINTF_CHECK("From: %s\r\n", cmd->from);
 
87
  }
 
88
  if (cmd && cmd->proxyauth) {
 
89
    SNPRINTF_CHECK("Proxy-Authorization: %s\r\n", cmd->proxyauth);
 
90
  }
 
91
  if (cmd && cmd->proxyrequire) {
 
92
    SNPRINTF_CHECK("Proxy-Require: %s\r\n", cmd->proxyrequire);
 
93
  }
 
94
  if (cmd && cmd->range) {
 
95
    SNPRINTF_CHECK("Range: %s\r\n", cmd->range);
 
96
  }
 
97
  if (cmd && cmd->referer) {
 
98
    SNPRINTF_CHECK("Referer: %s\r\n", cmd->referer);
 
99
  }
 
100
  if (cmd && cmd->scale != 0.0) {
 
101
    SNPRINTF_CHECK("Scale: %f\r\n", cmd->scale);
 
102
  }
 
103
  if (session) {
 
104
    SNPRINTF_CHECK("Session: %s\r\n", session);
 
105
  } else if (cmd && cmd->session) {
 
106
    SNPRINTF_CHECK("Session: %s\r\n", cmd->session);
 
107
  }
 
108
  if (cmd && cmd->speed != 0.0) {
 
109
    SNPRINTF_CHECK("Speed: %f\r\n", cmd->speed);
 
110
  }
 
111
  if (cmd && cmd->transport) {
 
112
    SNPRINTF_CHECK("Transport: %s\r\n", cmd->transport);
 
113
  }
 
114
    
 
115
  SNPRINTF_CHECK("User-Agent: %s\r\n",
 
116
              (cmd && cmd->useragent != NULL ?  cmd->useragent : UserAgent));
 
117
  if (cmd && cmd->User) {
 
118
    SNPRINTF_CHECK("%s", cmd->User);
 
119
  }
 
120
#undef SNPRINTF_CHECK
 
121
  return (0);
 
122
}
 
123
 
 
124
/*
 
125
 * rtsp_send_describe - send the describe info to a server
 
126
 */
 
127
int rtsp_send_describe (rtsp_client_t *info,
 
128
                        rtsp_command_t *cmd,
 
129
                        rtsp_decode_t **decode_result)
 
130
{
 
131
  char buffer[2048];
 
132
  uint32_t maxlen, buflen;
 
133
  int ret;
 
134
  rtsp_decode_t *decode;
 
135
 
 
136
  *decode_result = NULL;
 
137
  info->redirect_count = 0;
 
138
 
 
139
  do {
 
140
    maxlen = sizeof(buffer);
 
141
    buflen = snprintf(buffer, maxlen, "DESCRIBE %s RTSP/1.0\r\n", info->url);
 
142
 
 
143
    if (rtsp_build_common(buffer, maxlen, &buflen, info, cmd, NULL) == -1) {
 
144
      return (RTSP_RESPONSE_RECV_ERROR);
 
145
    }
 
146
    
 
147
    ret = snprintf(buffer + buflen, maxlen - buflen, "\r\n");
 
148
    if (ret == -1) {
 
149
      return (RTSP_RESPONSE_RECV_ERROR);
 
150
    }
 
151
    buflen += ret;
 
152
 
 
153
    rtsp_debug(LOG_INFO, "Sending DESCRIBE %s", info->url);
 
154
    rtsp_debug(LOG_DEBUG, "%s", buffer);
 
155
 
 
156
    ret = rtsp_send_and_get(info, buffer, buflen);
 
157
    decode = info->decode_response;
 
158
    
 
159
    if (ret == RTSP_RESPONSE_GOOD) {
 
160
      rtsp_debug(LOG_INFO, "DESCRIBE returned correctly");
 
161
      *decode_result = info->decode_response;
 
162
      info->decode_response = NULL;
 
163
      return (RTSP_RESPONSE_GOOD);
 
164
    } else if (ret != RTSP_RESPONSE_REDIRECT) {
 
165
      
 
166
      rtsp_debug(LOG_ERR, "DESCRIBE return code %d", ret);
 
167
      if (ret != RTSP_RESPONSE_RECV_ERROR &&
 
168
          decode != NULL) {
 
169
        *decode_result = info->decode_response;
 
170
        info->decode_response = NULL;
 
171
        rtsp_debug(LOG_ERR, "Error code %s %s",
 
172
                   decode->retcode,
 
173
                   decode->retresp);
 
174
      }
 
175
      return (ret);
 
176
    }
 
177
    /*
 
178
     * Handle this through the redirects
 
179
     */
 
180
  }  while (ret == RTSP_RESPONSE_REDIRECT);
 
181
  
 
182
  return (RTSP_RESPONSE_RECV_ERROR);
 
183
}
 
184
 
 
185
/*
 
186
 * rtsp_send_setup - When we get the describe, this will set up a
 
187
 * particular stream.  Use the session handle for all further commands for
 
188
 * the stream (play, pause, teardown).
 
189
 */
 
190
int rtsp_send_setup (rtsp_client_t *info,
 
191
                     const char *url,
 
192
                     rtsp_command_t *cmd,
 
193
                     rtsp_session_t **session_result,
 
194
                     rtsp_decode_t **decode_result,
 
195
                     int is_aggregate)
 
196
{
 
197
  char buffer[2048], *temp;
 
198
  uint32_t maxlen, buflen;
 
199
  int ret;
 
200
  rtsp_decode_t *decode;
 
201
  rtsp_session_t *sptr;
 
202
  
 
203
  *decode_result = NULL;
 
204
  *session_result = NULL;
 
205
  info->redirect_count = 0;
 
206
 
 
207
  if (cmd == NULL || cmd->transport == NULL || url == NULL) {
 
208
    return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
 
209
  }
 
210
 
 
211
  if (strncmp(url, "rtsp://", strlen("rtsp://")) != 0) {
 
212
    return (RTSP_RESPONSE_BAD_URL);
 
213
  }
 
214
 
 
215
  temp = strchr(url + strlen("rtsp://"), '/');
 
216
  if (temp == NULL) {
 
217
    return (RTSP_RESPONSE_BAD_URL);
 
218
  }
 
219
  if (strncmp(url, info->url, temp - url) != 0) {
 
220
    rtsp_debug(LOG_ALERT, "Bad url %s", url);
 
221
    rtsp_debug(LOG_ALERT, "Should be %s", info->url);
 
222
    return (RTSP_RESPONSE_BAD_URL);
 
223
  }
 
224
 
 
225
  maxlen = sizeof(buffer);
 
226
  buflen = snprintf(buffer, maxlen, "SETUP %s RTSP/1.0\r\n", url);
 
227
 
 
228
  // always use the session here...
 
229
  if (rtsp_build_common(buffer,
 
230
                        maxlen,
 
231
                        &buflen,
 
232
                        info,
 
233
                        cmd,
 
234
                        info->session) == -1) {
 
235
    return (RTSP_RESPONSE_RECV_ERROR);
 
236
  }
 
237
  ret = snprintf(buffer + buflen, maxlen - buflen, "\r\n");
 
238
  if (ret == -1) {
 
239
    return (RTSP_RESPONSE_RECV_ERROR);
 
240
  }
 
241
  buflen += ret;
 
242
 
 
243
  rtsp_debug(LOG_INFO, "Sending SETUP %s", url);
 
244
  rtsp_debug(LOG_DEBUG, "%s", buffer);
 
245
 
 
246
  ret = rtsp_send_and_get(info, buffer, buflen);
 
247
  decode = info->decode_response;
 
248
    
 
249
  if (ret == RTSP_RESPONSE_GOOD) {
 
250
    rtsp_debug(LOG_INFO, "SETUP returned correctly");
 
251
    *decode_result = info->decode_response;
 
252
    info->decode_response = NULL;
 
253
#ifndef IPTV_COMPATIBLE
 
254
    if ((*decode_result)->session == NULL) {
 
255
      return (RTSP_RESPONSE_BAD);
 
256
    }
 
257
#endif
 
258
    if (is_aggregate && info->session != NULL) {
 
259
      if (strcmp(info->session, (*decode_result)->session) != 0) {
 
260
        rtsp_debug(LOG_ALERT, "Session for %s returned different %s %s",
 
261
                   url, info->session, (*decode_result)->session);
 
262
        return (RTSP_RESPONSE_BAD);
 
263
      }
 
264
    }
 
265
    sptr = info->session_list;
 
266
    // we really need to seperate out the session from the
 
267
    // rest of the Session: header
 
268
    while (sptr != NULL) {
 
269
      if (strcmp(sptr->url, url) == 0)
 
270
        break;
 
271
      sptr = sptr->next;
 
272
    }
 
273
    if (sptr == NULL) {
 
274
      sptr = malloc(sizeof(rtsp_session_t));
 
275
      if (sptr == NULL) {
 
276
        return (RTSP_RESPONSE_RECV_ERROR);
 
277
      }
 
278
      sptr->url = strdup(url);
 
279
      if ((*decode_result)->session != NULL)
 
280
        sptr->session = strdup((*decode_result)->session);
 
281
      else
 
282
        sptr->session = NULL;
 
283
      sptr->parent = info;
 
284
      sptr->next = info->session_list;
 
285
      info->session_list = sptr;
 
286
      info->session = sptr->session;
 
287
    }
 
288
    *session_result = sptr;
 
289
    return (RTSP_RESPONSE_GOOD);
 
290
  } else {
 
291
    rtsp_debug(LOG_ERR, "SETUP return code %d", ret);
 
292
    if (ret != RTSP_RESPONSE_RECV_ERROR &&
 
293
        decode != NULL) {
 
294
      *decode_result = info->decode_response;
 
295
      info->decode_response = NULL;
 
296
      rtsp_debug(LOG_ERR, "Error code %s %s",
 
297
                 decode->retcode,
 
298
                 decode->retresp);
 
299
    }
 
300
    return (ret);
 
301
  }
 
302
  
 
303
  return (RTSP_RESPONSE_RECV_ERROR);
 
304
}
 
305
 
 
306
/*
 
307
 * check_session - make sure that the session is correct for that command
 
308
 */
 
309
static int check_session (rtsp_session_t *session,
 
310
                           rtsp_command_t *cmd)
 
311
{
 
312
  rtsp_session_t *sptr;
 
313
  rtsp_client_t *info;
 
314
 
 
315
  info = session->parent;
 
316
  if (info == NULL) {
 
317
    rtsp_debug(LOG_ALERT, "Session doesn't point to parent");
 
318
    return (FALSE);
 
319
  }
 
320
  
 
321
  sptr = info->session_list;
 
322
  while (sptr != session && sptr != NULL) sptr = sptr->next;
 
323
  if (sptr == NULL) {
 
324
    rtsp_debug(LOG_ALERT, "session not found in info list");
 
325
    return (FALSE);
 
326
  }
 
327
  
 
328
  if ((cmd != NULL) &&
 
329
      (cmd->session != NULL) &&
 
330
      (strcmp(cmd->session, session->session) != 0)) {
 
331
    rtsp_debug(LOG_ALERT, "Have cmd->session set wrong");
 
332
    return (FALSE);
 
333
  }
 
334
  return (TRUE);
 
335
}
 
336
 
 
337
static int rtsp_send_play_or_pause (const char *command,
 
338
                                    const char *url,
 
339
                                    const char *session,
 
340
                                    rtsp_client_t *info,
 
341
                                    rtsp_command_t *cmd,
 
342
                                    rtsp_decode_t **decode_result)
 
343
{
 
344
  char buffer[2048];
 
345
  uint32_t maxlen, buflen;
 
346
  int ret;
 
347
  rtsp_decode_t *decode;
 
348
 
 
349
  *decode_result = NULL;
 
350
  if (info->server_socket < 0) {
 
351
    return (RTSP_RESPONSE_CLOSED_SOCKET);
 
352
  }
 
353
 
 
354
  maxlen = sizeof(buffer);
 
355
  buflen = snprintf(buffer, maxlen, "%s %s RTSP/1.0\r\n", command, url);
 
356
 
 
357
  if (rtsp_build_common(buffer, maxlen, &buflen,
 
358
                        info, cmd, session) == -1) {
 
359
    return (RTSP_RESPONSE_RECV_ERROR);
 
360
  }
 
361
    
 
362
  ret = snprintf(buffer + buflen, maxlen - buflen, "\r\n");
 
363
  if (ret == -1) {
 
364
    return (RTSP_RESPONSE_RECV_ERROR);
 
365
  }
 
366
  buflen += ret;
 
367
 
 
368
  rtsp_debug(LOG_INFO, "Sending %s %s", command, url);
 
369
  rtsp_debug(LOG_DEBUG, "%s", buffer);
 
370
 
 
371
  ret = rtsp_send_and_get(info, buffer, buflen);
 
372
  decode = info->decode_response;
 
373
    
 
374
  if (ret == RTSP_RESPONSE_GOOD) {
 
375
    rtsp_debug(LOG_ERR, "%s returned correctly", command);
 
376
    *decode_result = info->decode_response;
 
377
    info->decode_response = NULL;
 
378
 
 
379
    return (RTSP_RESPONSE_GOOD);
 
380
  } else {
 
381
    rtsp_debug(LOG_ERR, "%s return code %d", command, ret);
 
382
    if (ret != RTSP_RESPONSE_RECV_ERROR &&
 
383
        decode != NULL) {
 
384
      *decode_result = info->decode_response;
 
385
      info->decode_response = NULL;
 
386
      rtsp_debug(LOG_ERR, "Error code %s %s",
 
387
                 decode->retcode,
 
388
                 decode->retresp);
 
389
    }
 
390
    return (ret);
 
391
  }
 
392
  
 
393
  return (RTSP_RESPONSE_RECV_ERROR);
 
394
}
 
395
 
 
396
/*
 
397
 * rtsp_send_play - send play command.  It helps if Range is set
 
398
 */
 
399
int rtsp_send_play (rtsp_session_t *session,
 
400
                    rtsp_command_t *cmd,
 
401
                    rtsp_decode_t **decode_result)
 
402
{
 
403
  if (check_session(session, cmd) == FALSE) {
 
404
    return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
 
405
  }
 
406
 
 
407
  return (rtsp_send_play_or_pause("PLAY",
 
408
                                  session->url,
 
409
                                  session->session,
 
410
                                  session->parent,
 
411
                                  cmd,
 
412
                                  decode_result));
 
413
}
 
414
 
 
415
/*
 
416
 * rtsp_send_pause - send a pause on a particular session
 
417
 */
 
418
int rtsp_send_pause (rtsp_session_t *session,
 
419
                     rtsp_command_t *cmd,
 
420
                     rtsp_decode_t **decode_result)
 
421
{
 
422
  if (check_session(session, cmd) == FALSE) {
 
423
    return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
 
424
  }
 
425
 
 
426
  return (rtsp_send_play_or_pause("PAUSE",
 
427
                                  session->url,
 
428
                                  session->session,
 
429
                                  session->parent,
 
430
                                  cmd,
 
431
                                  decode_result));
 
432
}
 
433
 
 
434
int rtsp_send_aggregate_play (rtsp_client_t *info,
 
435
                              const char *aggregate_url,
 
436
                              rtsp_command_t *cmd,
 
437
                              rtsp_decode_t **decode_result)
 
438
{
 
439
  return (rtsp_send_play_or_pause("PLAY",
 
440
                                  aggregate_url,
 
441
                                  info->session,
 
442
                                  info,
 
443
                                  cmd,
 
444
                                  decode_result));
 
445
}
 
446
 
 
447
int rtsp_send_aggregate_pause (rtsp_client_t *info,
 
448
                               const char *aggregate_url,
 
449
                               rtsp_command_t *cmd,
 
450
                               rtsp_decode_t **decode_result)
 
451
{
 
452
  return (rtsp_send_play_or_pause("PAUSE",
 
453
                                  aggregate_url,
 
454
                                  info->session,
 
455
                                  info,
 
456
                                  cmd,
 
457
                                  decode_result));
 
458
}
 
459
 
 
460
static int rtsp_send_teardown_common (rtsp_client_t *info,
 
461
                                      const char *url,
 
462
                                      const char *session,
 
463
                                      rtsp_command_t *cmd,
 
464
                                      rtsp_decode_t **decode_result)
 
465
{
 
466
  char buffer[2048];
 
467
  uint32_t maxlen, buflen;
 
468
  int ret;
 
469
  rtsp_decode_t *decode;
 
470
  
 
471
  *decode_result = NULL;
 
472
  if (info->server_socket < 0) {
 
473
    return (RTSP_RESPONSE_CLOSED_SOCKET);
 
474
  }
 
475
 
 
476
  maxlen = sizeof(buffer);
 
477
  buflen = snprintf(buffer, maxlen, "TEARDOWN %s RTSP/1.0\r\n", url);
 
478
 
 
479
  if (rtsp_build_common(buffer, maxlen, &buflen,
 
480
                        info, cmd, session) == -1) {
 
481
    return (RTSP_RESPONSE_RECV_ERROR);
 
482
  }
 
483
    
 
484
  ret = snprintf(buffer + buflen, maxlen - buflen, "\r\n");
 
485
  if (ret == -1) {
 
486
    return (RTSP_RESPONSE_RECV_ERROR);
 
487
  }
 
488
  buflen += ret;
 
489
 
 
490
  rtsp_debug(LOG_INFO, "Sending TEARDOWN %s", url);
 
491
  rtsp_debug(LOG_DEBUG, "%s", buffer);
 
492
 
 
493
  ret = rtsp_send_and_get(info, buffer, buflen);
 
494
  decode = info->decode_response;
 
495
    
 
496
  if (ret == RTSP_RESPONSE_GOOD) {
 
497
    rtsp_debug(LOG_INFO, "TEARDOWN returned correctly");
 
498
    *decode_result = info->decode_response;
 
499
    info->decode_response = NULL;
 
500
    return (RTSP_RESPONSE_GOOD);
 
501
  } else {
 
502
    rtsp_debug(LOG_ERR, "TEARDOWN return code %d", ret);
 
503
    if (ret != RTSP_RESPONSE_RECV_ERROR &&
 
504
        decode != NULL) {
 
505
      *decode_result = info->decode_response;
 
506
      info->decode_response = NULL;
 
507
      rtsp_debug(LOG_ERR, "Error code %s %s",
 
508
                 decode->retcode,
 
509
                 decode->retresp);
 
510
    }
 
511
    return (ret);
 
512
  }
 
513
  
 
514
  return (RTSP_RESPONSE_RECV_ERROR);
 
515
}
 
516
/*
 
517
 * rtsp_send_teardown.  Sends a teardown for a session.  We might eventually
 
518
 * want to provide a teardown for the base url, rather than one for each
 
519
 * session
 
520
 */
 
521
int rtsp_send_teardown (rtsp_session_t *session,
 
522
                        rtsp_command_t *cmd,
 
523
                        rtsp_decode_t **decode_result)
 
524
{
 
525
  int ret;
 
526
  rtsp_client_t *info;
 
527
  rtsp_session_t *sptr;
 
528
  if (check_session(session, cmd) == FALSE) {
 
529
    return (RTSP_RESPONSE_MISSING_OR_BAD_PARAM);
 
530
  }
 
531
  info = session->parent;
 
532
 
 
533
  ret = rtsp_send_teardown_common(info,
 
534
                                  session->url,
 
535
                                  session->session,
 
536
                                  cmd,
 
537
                                  decode_result);
 
538
  if (ret == RTSP_RESPONSE_GOOD) {
 
539
    if (info->session_list == session) {
 
540
      info->session_list = session->next;
 
541
    } else {
 
542
      sptr = info->session_list;
 
543
      while (sptr->next != session) sptr = sptr->next;
 
544
      sptr->next = session->next;
 
545
    }
 
546
    free_session_info(session);
 
547
  }
 
548
  return (ret);
 
549
}
 
550
 
 
551
int rtsp_send_aggregate_teardown (rtsp_client_t *info,
 
552
                                  const char *url,
 
553
                                  rtsp_command_t *cmd,
 
554
                                  rtsp_decode_t **decode_result)
 
555
{
 
556
  int ret;
 
557
  rtsp_session_t *p;
 
558
  ret = rtsp_send_teardown_common(info,
 
559
                                  url,
 
560
                                  info->session,
 
561
                                  cmd,
 
562
                                  decode_result);
 
563
  if (ret == RTSP_RESPONSE_GOOD) {
 
564
    while (info->session_list != NULL) {
 
565
      p = info->session_list;
 
566
      info->session_list = info->session_list->next;
 
567
      free_session_info(p);
 
568
    }
 
569
  }
 
570
  return (ret);
 
571
}
 
572
  
 
573
 
 
574