transport_udp.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 705 行 · 第 1/2 页
C
705 行
/* $Id: transport_udp.c 974 2007-02-19 01:13:53Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjmedia/transport_udp.h>#include <pj/addr_resolv.h>#include <pj/assert.h>#include <pj/errno.h>#include <pj/ioqueue.h>#include <pj/log.h>#include <pj/rand.h>#include <pj/string.h>/* Maximum size of incoming RTP packet */#define RTP_LEN 1500/* Maximum size of incoming RTCP packet */#define RTCP_LEN 600/* Maximum pending write operations */#define MAX_PENDING 4/* Pending write buffer */typedef struct pending_write{ char buffer[RTP_LEN]; pj_ioqueue_op_key_t op_key;} pending_write;struct transport_udp{ pjmedia_transport base; /**< Base transport. */ pj_pool_t *pool; /**< Memory pool */ unsigned options; /**< Transport options. */ void *user_data; /**< Only valid when attached */ pj_bool_t attached; /**< Has attachment? */ pj_sockaddr_in rem_rtp_addr; /**< Remote RTP address */ pj_sockaddr_in rem_rtcp_addr; /**< Remote RTCP address */ void (*rtp_cb)( void*, /**< To report incoming RTP. */ const void*, pj_ssize_t); void (*rtcp_cb)( void*, /**< To report incoming RTCP. */ const void*, pj_ssize_t); unsigned tx_drop_pct; /**< Percent of tx pkts to drop. */ unsigned rx_drop_pct; /**< Percent of rx pkts to drop. */ pj_sock_t rtp_sock; /**< RTP socket */ pj_sockaddr_in rtp_addr_name; /**< Published RTP address. */ pj_ioqueue_key_t *rtp_key; /**< RTP socket key in ioqueue */ pj_ioqueue_op_key_t rtp_read_op; /**< Pending read operation */ unsigned rtp_write_op_id;/**< Next write_op to use */ pending_write rtp_pending_write[MAX_PENDING]; /**< Pending write */ pj_sockaddr_in rtp_src_addr; /**< Actual packet src addr. */ unsigned rtp_src_cnt; /**< How many pkt from this addr. */ int rtp_addrlen; /**< Address length. */ char rtp_pkt[RTP_LEN];/**< Incoming RTP packet buffer */ pj_sock_t rtcp_sock; /**< RTCP socket */ pj_sockaddr_in rtcp_addr_name; /**< Published RTCP address. */ pj_sockaddr_in rtcp_src_addr; /**< Actual source RTCP address. */ int rtcp_addr_len; /**< Length of RTCP src address. */ pj_ioqueue_key_t *rtcp_key; /**< RTCP socket key in ioqueue */ pj_ioqueue_op_key_t rtcp_read_op; /**< Pending read operation */ pj_ioqueue_op_key_t rtcp_write_op; /**< Pending write operation */ char rtcp_pkt[RTCP_LEN];/**< Incoming RTCP packet buffer */};static void on_rx_rtp( pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read);static void on_rx_rtcp(pj_ioqueue_key_t *key, pj_ioqueue_op_key_t *op_key, pj_ssize_t bytes_read);static pj_status_t transport_attach( pjmedia_transport *tp, void *user_data, const pj_sockaddr_t *rem_addr, const pj_sockaddr_t *rem_rtcp, unsigned addr_len, void (*rtp_cb)(void*, const void*, pj_ssize_t), void (*rtcp_cb)(void*, const void*, pj_ssize_t));static void transport_detach( pjmedia_transport *tp, void *strm);static pj_status_t transport_send_rtp( pjmedia_transport *tp, const void *pkt, pj_size_t size);static pj_status_t transport_send_rtcp(pjmedia_transport *tp, const void *pkt, pj_size_t size);static pjmedia_transport_op transport_udp_op = { &transport_attach, &transport_detach, &transport_send_rtp, &transport_send_rtcp, &pjmedia_transport_udp_close};/** * Create UDP stream transport. */PJ_DEF(pj_status_t) pjmedia_transport_udp_create( pjmedia_endpt *endpt, const char *name, int port, unsigned options, pjmedia_transport **p_tp){ return pjmedia_transport_udp_create2(endpt, name, NULL, port, options, p_tp);}/** * Create UDP stream transport. */PJ_DEF(pj_status_t) pjmedia_transport_udp_create2(pjmedia_endpt *endpt, const char *name, const pj_str_t *addr, int port, unsigned options, pjmedia_transport **p_tp){ pjmedia_sock_info si; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && port && p_tp, PJ_EINVAL); pj_bzero(&si, sizeof(pjmedia_sock_info)); si.rtp_sock = si.rtcp_sock = PJ_INVALID_SOCKET; /* Create RTP socket */ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &si.rtp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind RTP socket */ pj_sockaddr_in_init(&si.rtp_addr_name, addr, (pj_uint16_t)port); status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name, sizeof(si.rtp_addr_name)); if (status != PJ_SUCCESS) goto on_error; /* Create RTCP socket */ status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &si.rtcp_sock); if (status != PJ_SUCCESS) goto on_error; /* Bind RTCP socket */ pj_sockaddr_in_init(&si.rtcp_addr_name, addr, (pj_uint16_t)(port+1)); status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name, sizeof(si.rtcp_addr_name)); if (status != PJ_SUCCESS) goto on_error; /* Create UDP transport by attaching socket info */ return pjmedia_transport_udp_attach( endpt, name, &si, options, p_tp);on_error: if (si.rtp_sock != PJ_INVALID_SOCKET) pj_sock_close(si.rtp_sock); if (si.rtcp_sock != PJ_INVALID_SOCKET) pj_sock_close(si.rtcp_sock); return status;}/** * Create UDP stream transport from existing socket info. */PJ_DEF(pj_status_t) pjmedia_transport_udp_attach( pjmedia_endpt *endpt, const char *name, const pjmedia_sock_info *si, unsigned options, pjmedia_transport **p_tp){ struct transport_udp *tp; pj_pool_t *pool; pj_ioqueue_t *ioqueue; pj_ioqueue_callback rtp_cb, rtcp_cb; pj_ssize_t size; unsigned i; pj_status_t status; /* Sanity check */ PJ_ASSERT_RETURN(endpt && si && p_tp, PJ_EINVAL); /* Check name */ if (!name) name = "udpmedia"; /* Get ioqueue instance */ ioqueue = pjmedia_endpt_get_ioqueue(endpt); /* Create transport structure */ pool = pjmedia_endpt_create_pool(endpt, name, 4000, 4000); if (!pool) return PJ_ENOMEM; tp = pj_pool_zalloc(pool, sizeof(struct transport_udp)); tp->pool = pool; tp->options = options; pj_ansi_strcpy(tp->base.name, name); tp->base.op = &transport_udp_op; /* Copy socket infos */ tp->rtp_sock = si->rtp_sock; tp->rtp_addr_name = si->rtp_addr_name; tp->rtcp_sock = si->rtcp_sock; tp->rtcp_addr_name = si->rtcp_addr_name; /* If address is 0.0.0.0, use host's IP address */ if (tp->rtp_addr_name.sin_addr.s_addr == 0) { pj_in_addr hostip; status = pj_gethostip(&hostip); if (status != PJ_SUCCESS) goto on_error; tp->rtp_addr_name.sin_addr = hostip; } /* Same with RTCP */ if (tp->rtcp_addr_name.sin_addr.s_addr == 0) { tp->rtcp_addr_name.sin_addr.s_addr = tp->rtp_addr_name.sin_addr.s_addr; } /* Setup RTP socket with the ioqueue */ pj_bzero(&rtp_cb, sizeof(rtp_cb)); rtp_cb.on_read_complete = &on_rx_rtp; status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtp_sock, tp, &rtp_cb, &tp->rtp_key); if (status != PJ_SUCCESS) goto on_error; pj_ioqueue_op_key_init(&tp->rtp_read_op, sizeof(tp->rtp_read_op)); for (i=0; i<PJ_ARRAY_SIZE(tp->rtp_pending_write); ++i) pj_ioqueue_op_key_init(&tp->rtp_pending_write[i].op_key, sizeof(tp->rtp_pending_write[i].op_key)); /* Kick of pending RTP read from the ioqueue */ tp->rtp_addrlen = sizeof(tp->rtp_src_addr); size = sizeof(tp->rtp_pkt); status = pj_ioqueue_recvfrom(tp->rtp_key, &tp->rtp_read_op, tp->rtp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC, &tp->rtp_src_addr, &tp->rtp_addrlen); if (status != PJ_EPENDING) goto on_error; /* Setup RTCP socket with ioqueue */ pj_bzero(&rtcp_cb, sizeof(rtcp_cb)); rtcp_cb.on_read_complete = &on_rx_rtcp; status = pj_ioqueue_register_sock(pool, ioqueue, tp->rtcp_sock, tp, &rtcp_cb, &tp->rtcp_key); if (status != PJ_SUCCESS) goto on_error; pj_ioqueue_op_key_init(&tp->rtcp_read_op, sizeof(tp->rtcp_read_op)); pj_ioqueue_op_key_init(&tp->rtcp_write_op, sizeof(tp->rtcp_write_op)); /* Kick of pending RTCP read from the ioqueue */ size = sizeof(tp->rtcp_pkt); tp->rtcp_addr_len = sizeof(tp->rtcp_src_addr); status = pj_ioqueue_recvfrom( tp->rtcp_key, &tp->rtcp_read_op, tp->rtcp_pkt, &size, PJ_IOQUEUE_ALWAYS_ASYNC, &tp->rtcp_src_addr, &tp->rtcp_addr_len); if (status != PJ_EPENDING) goto on_error; /* Done */ *p_tp = &tp->base; return PJ_SUCCESS;on_error: pjmedia_transport_udp_close(&tp->base); return status;}/* * Get media socket info. */PJ_DEF(pj_status_t) pjmedia_transport_udp_get_info( pjmedia_transport *tp, pjmedia_transport_udp_info *inf){ struct transport_udp *udp = (struct transport_udp*)tp; PJ_ASSERT_RETURN(tp && inf, PJ_EINVAL); inf->skinfo.rtp_sock = udp->rtp_sock; inf->skinfo.rtp_addr_name = udp->rtp_addr_name; inf->skinfo.rtcp_sock = udp->rtcp_sock; inf->skinfo.rtcp_addr_name = udp->rtcp_addr_name; return PJ_SUCCESS;}/** * Close UDP transport. */PJ_DEF(pj_status_t) pjmedia_transport_udp_close(pjmedia_transport *tp){ struct transport_udp *udp = (struct transport_udp*) tp; /* Sanity check */ PJ_ASSERT_RETURN(tp, PJ_EINVAL); /* Must not close while application is using this */ PJ_ASSERT_RETURN(!udp->attached, PJ_EINVALIDOP); if (udp->rtp_key) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?