rtp_ssrc_queue.c

Go to the documentation of this file.
00001 /* * 
00002  * This file is part of libnemesi
00003  *
00004  * Copyright (C) 2007 by LScube team <team@streaming.polito.it>
00005  * See AUTHORS for more details
00006  * 
00007  * libnemesi is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * libnemesi is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with libnemesi; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  *  
00021  * */
00022 
00027 #include "rtp.h"
00028 #include "bufferpool.h"
00029 #include "utils.h"
00030 
00037 rtp_ssrc *rtp_active_ssrc_queue(rtp_session * rtp_sess_head)
00038 {
00039     rtp_session *rtp_sess;
00040 
00041     for (rtp_sess = rtp_sess_head;
00042          rtp_sess && !rtp_sess->active_ssrc_queue;
00043          rtp_sess = rtp_sess->next);
00044 
00045     return rtp_sess ? rtp_sess->active_ssrc_queue : NULL;
00046 }
00047 
00053 rtp_ssrc *rtp_next_active_ssrc(rtp_ssrc * ssrc)
00054 {
00055     rtp_session *rtp_sess;
00056 
00057     if (!ssrc)
00058         return NULL;
00059 
00060     if (ssrc->next_active)
00061         return ssrc->next_active;
00062 
00063     for (rtp_sess = ssrc->rtp_sess->next; rtp_sess;
00064          rtp_sess = rtp_sess->next)
00065         if (rtp_sess->active_ssrc_queue)
00066             return rtp_sess->active_ssrc_queue;
00067 
00068     return NULL;
00069 }
00070 
00071 /*
00072  * Connect local client to oremote rtcp input port in order to send our rtcp statistics.
00073  *
00074  * @param stm_src the stream source whose statistics are.
00075  * @param remoteaddr sockaddr of remote address.
00076  * @param port remote rtcp port.
00077  * @return 0 on OK, 1 if connection went wrong, -1 on internal fatal error.
00078  * */
00079 static int rtcp_to_connect(rtp_ssrc * stm_src, nms_addr * remoteaddr, in_port_t port)
00080 {
00081     char addr[128];        /* Unix domain is largest */
00082     char port_str[16];
00083     struct sockaddr_storage rtcp_to_addr_s;
00084     nms_sockaddr rtcp_to_addr =
00085         { (struct sockaddr *) &rtcp_to_addr_s, sizeof(rtcp_to_addr_s) };
00086 
00087     if (port > 0)
00088         // snprintf(port_str, sizeof(port_str),"%d", ntohs(port));
00089         snprintf(port_str, sizeof(port_str), "%d", port);
00090     else
00091         return nms_printf(NMSML_ERR,
00092                   "RTCP: Cannot connect to port (%d)\n", port);
00093 
00094     if (!nms_addr_ntop(remoteaddr, addr, sizeof(addr))) {
00095         nms_printf(NMSML_WARN,
00096                "RTP: Cannot get address from source\n");
00097         stm_src->no_rtcp = 1;
00098         return 1;
00099     } else
00100         nms_printf(NMSML_DBG2, "RTCP to host=%s\n", addr);
00101 
00102     /*if (sock_connect(addr, port_str, &(stm_src->rtp_sess->transport.RTCP.fd), UDP)) {
00103         nms_printf(NMSML_WARN,
00104                "Cannot connect to remote RTCP destination %s:%s\n",
00105                addr, port_str);
00106         stm_src->no_rtcp = 1;
00107     }*/
00108     getsockname(stm_src->rtp_sess->transport.RTCP.sock.fd, rtcp_to_addr.addr,
00109             &rtcp_to_addr.addr_len);
00110     nms_sockaddr_dup(&stm_src->rtcp_to, &rtcp_to_addr);
00111 
00112     return 0;
00113 }
00114 
00125 int rtp_ssrc_init(rtp_session * rtp_sess, rtp_ssrc ** stm_src, uint32_t ssrc,
00126           nms_sockaddr * recfrom, enum rtp_protos proto_type)
00127 {
00128     int addrcmp_err;
00129     nms_addr nms_address;
00130 
00131     if (((*stm_src) = (rtp_ssrc *) calloc(1, sizeof(rtp_ssrc))) == NULL)
00132         return -nms_printf(NMSML_FATAL, "Cannot allocate memory\n");
00133 
00134     (*stm_src)->po = calloc(1, sizeof(playout_buff));
00135 
00136     (*stm_src)->next = rtp_sess->ssrc_queue;
00137     rtp_sess->ssrc_queue = *stm_src;
00138 
00139     (*stm_src)->ssrc = ssrc;
00140     (*stm_src)->no_rtcp = 0; //flag for connection errors
00141     (*stm_src)->rtp_sess = rtp_sess;
00142 
00143     if (proto_type == RTP) {
00144         nms_sockaddr_dup(&(*stm_src)->rtp_from, recfrom);
00145         nms_printf(NMSML_DBG2, "RTP/rtp_ssrc_init: proto RTP\n");
00146     } else if (proto_type == RTCP) {
00147         nms_sockaddr_dup(&(*stm_src)->rtcp_from, recfrom);
00148         nms_printf(NMSML_DBG2, "RTP/rtp_ssrc_init: proto RTCP\n");
00149     }
00150 
00151     if (rtp_sess->transport.type != UDP) {
00152         /*It is not needed to check addresses because data is received
00153         as interleaved or multistream from RTSP socket */    
00154         return 0;
00155     }
00156 
00157     if (sockaddr_get_nms_addr(recfrom->addr, &nms_address))
00158         return -nms_printf(NMSML_ERR,
00159                    "Address of received packet not valid\n");
00160     if (!
00161         (addrcmp_err =
00162          nms_addr_cmp(&nms_address, &rtp_sess->transport.RTP.u.udp.srcaddr))) {
00163         /* If the address from which we are receiving data is the
00164          * same to that announced in RTSP session, then we use RTSP
00165          * informations to set transport address for RTCP connection */
00166         if (rtcp_to_connect
00167             (*stm_src, &rtp_sess->transport.RTP.u.udp.srcaddr,
00168              (rtp_sess->transport).RTCP.sock.remote_port) < 0)
00169             return -1;
00170         nms_printf(NMSML_DBG2, "RTP/rtp_ssrc_init: from RTSP\n");
00171 
00172     } else if (proto_type == RTCP) {
00173         /* If we lack of informations we assume that net address of
00174          * RTCP destination is the same of RTP address and port is that
00175          * specified in RTSP*/
00176         if (rtcp_to_connect
00177             (*stm_src, &nms_address,
00178              (rtp_sess->transport).RTCP.sock.remote_port) < 0)
00179             return -1;
00180         nms_printf(NMSML_DBG2, "RTP/rtp_ssrc_init: from RTP\n");
00181     } else {
00182         switch (addrcmp_err) {
00183         case WSOCK_ERRFAMILY:
00184             nms_printf(NMSML_DBG2, "WSOCK_ERRFAMILY (%d!=%d)\n",
00185                    nms_address.family,
00186                    rtp_sess->transport.RTP.u.udp.srcaddr.family);
00187             break;
00188         case WSOCK_ERRADDR:
00189             nms_printf(NMSML_DBG2, "WSOCK_ERRADDR\n");
00190             break;
00191         case WSOCK_ERRFAMILYUNKNOWN:
00192             nms_printf(NMSML_DBG2, "WSOCK_ERRFAMILYUNKNOWN\n");
00193             break;
00194         }
00195         nms_printf(NMSML_DBG2,
00196                "RTP/rtp_ssrc_init: rtcp_to NOT set!!!\n");
00197         // return -1;
00198     }
00199 
00200     return 0;
00201 }
00202 
00214 int rtp_ssrc_check(rtp_session * rtp_sess, uint32_t ssrc, rtp_ssrc ** stm_src,
00215            nms_sockaddr * recfrom, enum rtp_protos proto_type)
00216 {
00217     struct rtp_conflict *stm_conf = rtp_sess->conf_queue;
00218     struct sockaddr_storage sockaddr;
00219     nms_sockaddr sock =
00220         { (struct sockaddr *) &sockaddr, sizeof(sockaddr) };
00221     int local_collision;
00222 
00223 
00224     local_collision = (rtp_sess->local_ssrc == ssrc) ? SSRC_COLLISION : 0;
00225     pthread_mutex_lock(&rtp_sess->syn);
00226     pthread_mutex_unlock(&rtp_sess->syn);
00227     for (*stm_src = rtp_sess->ssrc_queue;
00228          !local_collision && *stm_src && ((*stm_src)->ssrc != ssrc);
00229          *stm_src = (*stm_src)->next);
00230     if (!*stm_src && !local_collision) {
00231         /* new SSRC */
00232         pthread_mutex_lock(&rtp_sess->syn);
00233         nms_printf(NMSML_DBG3, "new SSRC\n");
00234         if (rtp_ssrc_init(rtp_sess, stm_src, ssrc, recfrom, proto_type)
00235             < 0) {
00236             pthread_mutex_unlock(&rtp_sess->syn);
00237             return -nms_printf(NMSML_ERR,
00238                        "Error while setting new Stream Source\n");
00239         }
00240 
00241         poinit((*stm_src)->po, rtp_sess->bp);
00242         pthread_mutex_unlock(&rtp_sess->syn);
00243         return SSRC_NEW;
00244     } else {
00245         if (local_collision) {
00246 
00247             if (proto_type == RTP)
00248                 getsockname(rtp_sess->transport.RTP.sock.fd, sock.addr,
00249                         &sock.addr_len);
00250             else
00251                 getsockname(rtp_sess->transport.RTCP.sock.fd, sock.addr,
00252                         &sock.addr_len);
00253 
00254         } else if (proto_type == RTP) {
00255 
00256             if (!(*stm_src)->rtp_from.addr) {
00257                 nms_sockaddr_dup(&(*stm_src)->rtp_from, recfrom);
00258                 nms_printf(NMSML_DBG3, "new SSRC for RTP\n");
00259                 local_collision = SSRC_RTPNEW;
00260             }
00261             sock.addr = (*stm_src)->rtp_from.addr;
00262             sock.addr_len = (*stm_src)->rtp_from.addr_len;
00263 
00264         } else {    /* if (proto_type == RTCP) */
00265 
00266 
00267             if (!(*stm_src)->rtcp_from.addr) {
00268                 nms_sockaddr_dup(&(*stm_src)->rtcp_from, recfrom);
00269                 nms_printf(NMSML_DBG3, "new SSRC for RTCP\n");
00270                 local_collision = SSRC_RTCPNEW;
00271             }
00272             sock.addr = (*stm_src)->rtcp_from.addr;
00273             sock.addr_len = (*stm_src)->rtcp_from.addr_len;
00274 
00275             if (rtp_sess->transport.type != UDP)
00276                 return local_collision;
00277 
00278             if (!(*stm_src)->rtcp_to.addr) {
00279                 nms_addr nms_address;
00280 
00281                 if (sockaddr_get_nms_addr(recfrom->addr, &nms_address))
00282                     return -nms_printf(NMSML_ERR,
00283                                "Invalid address for received packet\n");
00284 
00285                 // if ( rtcp_to_connect(*stm_src, recfrom, (rtp_sess->transport).RTCP.remote_port) < 0 )
00286                 if (rtcp_to_connect
00287                     (*stm_src, &nms_address,
00288                      (rtp_sess->transport).RTCP.sock.remote_port) < 0)
00289                     return -1;
00290             }
00291         }
00292 
00293         if ((rtp_sess->transport.type == UDP) && sockaddr_cmp
00294             (sock.addr, sock.addr_len, recfrom->addr,
00295              recfrom->addr_len)) {
00296             nms_printf(NMSML_ERR,
00297                    "An identifier collision or a loop is indicated\n");
00298 
00299             /* An identifier collision or a loop is indicated */
00300 
00301             if (ssrc != rtp_sess->local_ssrc) {
00302                 /* OPTIONAL error counter step not implemented */
00303                 nms_printf(NMSML_VERB,
00304                        "Warning! An identifier collision or a loop is indicated.\n");
00305                 return SSRC_COLLISION;
00306             }
00307 
00308             /* A collision or loop of partecipants's own packets */
00309 
00310             else {
00311                 while (stm_conf
00312                        && sockaddr_cmp(stm_conf->transaddr.addr,
00313                               stm_conf->transaddr.
00314                               addr_len, recfrom->addr,
00315                               recfrom->addr_len))
00316                     stm_conf = stm_conf->next;
00317 
00318                 if (stm_conf) {
00319 
00320                     /* OPTIONAL error counter step not implemented */
00321 
00322                     stm_conf->time = time(NULL);
00323                     return SSRC_COLLISION;
00324                 } else {
00325 
00326                     /* New collision, change SSRC identifier */
00327 
00328                     nms_printf(NMSML_VERB,
00329                            "SSRC collision detected: getting new!\n");
00330 
00331 
00332                     /* Send RTCP BYE pkt */
00333                     /*       TODO        */
00334 
00335                     /* choosing new ssrc */
00336                     rtp_sess->local_ssrc = random32(0);
00337                     rtp_sess->transport.ssrc =
00338                         rtp_sess->local_ssrc;
00339 
00340                     /* New entry in SSRC queue with conflicting ssrc */
00341                     if ((stm_conf = (struct rtp_conflict *)
00342                          malloc(sizeof
00343                             (struct rtp_conflict))) ==
00344                         NULL)
00345                         return -nms_printf(NMSML_FATAL,
00346                                    "Cannot allocate memory!\n");
00347 
00348                     /* insert at the beginning of Stream Sources queue */
00349                     pthread_mutex_lock(&rtp_sess->syn);
00350                     if (rtp_ssrc_init
00351                         (rtp_sess, stm_src, ssrc, recfrom,
00352                          proto_type) < 0) {
00353                         pthread_mutex_unlock
00354                             (&rtp_sess->syn);
00355                         return -nms_printf(NMSML_ERR,
00356                                    "Error while setting new Stream Source\n");
00357                     }
00358                     poinit((*stm_src)->po, rtp_sess->bp);
00359                     pthread_mutex_unlock(&rtp_sess->syn);
00360 
00361                     /* New entry in SSRC rtp_conflict queue */
00362                     nms_sockaddr_dup(&stm_conf->transaddr,
00363                             &sock);
00364                     stm_conf->time = time(NULL);
00365                     stm_conf->next = rtp_sess->conf_queue;
00366                     rtp_sess->conf_queue = stm_conf;
00367                 }
00368 
00369             }
00370         }
00371     }
00372 
00373     return local_collision;
00374 }

Generated on Tue Feb 3 03:10:02 2009 for libnemesi by  doxygen 1.5.4