📄 tport.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE tport.c Transport interface implementation. * * See tport.docs for more detailed description of tport interface. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * @author Ismo Puustinen <Ismo.H.Puustinen@nokia.com> * @author Tat Chan <Tat.Chan@nokia.com> * @author Kai Vehmanen <kai.vehmanen@nokia.com> * @author Martti Mela <Martti.Mela@nokia.com> * * @date Created: Thu Jul 20 12:54:32 2000 ppessi */#include "config.h"#include <sofia-sip/string0.h>#include <sofia-sip/su.h>#include <sofia-sip/su_errno.h>#include <sofia-sip/su_alloc.h>#include <sofia-sip/su_tagarg.h>#include <sofia-sip/su_localinfo.h>typedef struct tport_nat_s tport_nat_t;#define SU_WAKEUP_ARG_T struct tport_s#define SU_TIMER_ARG_T struct tport_s#define SU_MSG_ARG_T union tport_su_msg_arg#include <sofia-sip/su_wait.h>#include <sofia-sip/msg.h>#include <sofia-sip/msg_addr.h>#include <sofia-sip/hostdomain.h>#include <stdlib.h>#include <time.h>#include <assert.h>#include <errno.h>#include <limits.h>#ifndef IPPROTO_SCTP#define IPPROTO_SCTP (132)#endif#include "sofia-sip/tport.h"#include "sofia-sip/su_uniqueid.h"#include <sofia-sip/rbtree.h>#include "tport_internal.h"#if HAVE_FUNC#elif HAVE_FUNCTION#define __func__ __FUNCTION__#elsestatic char const __func__[] = "tport";#endif#define STACK_RECV(tp, msg, now) \ (tp)->tp_master->mr_tpac->tpac_recv((tp)->tp_master->mr_stack, (tp), \ (msg), (tp)->tp_magic, (now))#define STACK_ERROR(tp, errcode, dstname) \ (tp)->tp_master->mr_tpac->tpac_error((tp)->tp_master->mr_stack, (tp), \ (errcode), (dstname))#define STACK_ADDRESS(tp) \ (tp)->tp_master->mr_tpac->tpac_address((tp)->tp_master->mr_stack, (tp))#define TP_STACK tp_master->mr_stack/* Define macros for rbtree implementation */#define TP_LEFT(tp) ((tp)->tp_left)#define TP_RIGHT(tp) ((tp)->tp_right)#define TP_PARENT(tp) ((tp)->tp_dad)#define TP_SET_RED(tp) ((tp)->tp_black = 0)#define TP_SET_BLACK(tp) ((tp)->tp_black = 1)#define TP_IS_RED(tp) ((tp) && (tp)->tp_black == 0)#define TP_IS_BLACK(tp) (!(tp) || (tp)->tp_black == 1)#define TP_COPY_COLOR(dst, src) ((dst)->tp_black = (src)->tp_black)#define TP_INSERT(tp) ((void)0)#define TP_REMOVE(tp) ((tp)->tp_left = (tp)->tp_right = (tp)->tp_dad = NULL)su_inline int tp_cmp(tport_t const *a, tport_t const *b){ if (a == b) return 0; if (a->tp_addrlen != b->tp_addrlen) return (int)(a->tp_addrlen - b->tp_addrlen); return memcmp(a->tp_addr, b->tp_addr, a->tp_addrlen);}su_inline int tprb_is_inserted(tport_t const *a){ return a->tp_dad != 0 || a->tp_left != 0 || a->tp_right != 0;}RBTREE_PROTOS(su_inline, tprb, tport_t);RBTREE_BODIES(su_inline, tprb, tport_t, TP_LEFT, TP_RIGHT, TP_PARENT, TP_IS_RED, TP_SET_RED, TP_IS_BLACK, TP_SET_BLACK, TP_COPY_COLOR, tp_cmp, TP_INSERT, TP_REMOVE);static void tplist_insert(tport_t **list, tport_t *tp){ if (*list == NULL) *list = tp; else tp->tp_right = *list, (*list)->tp_left = tp, *list = tp; for (tp = *list; tp; tp = tp->tp_right) { assert(tp->tp_left == NULL || tp == tp->tp_left->tp_right); assert(tp->tp_right == NULL || tp == tp->tp_right->tp_left); }}static void tplist_remove(tport_t **list, tport_t *tp){ if (*list == tp) { *list = tp->tp_right; assert(tp->tp_left == NULL); } else if (tp->tp_left) { tp->tp_left->tp_right = tp->tp_right; } if (tp->tp_right) { tp->tp_right->tp_left = tp->tp_left; } TP_REMOVE(tp);}enum { /** Default per-thread read queue length */ THRP_PENDING = 8};struct tport_pending_s { /* tport_pending_t *p_left, *p_right, *p_parent; */ void *p_client; tport_pending_error_f *p_callback; msg_t *p_msg; unsigned short p_reported; unsigned short p_on_success;};/** Return true if transport is master. */int tport_is_master(tport_t const *self){ return self && self->tp_master->mr_master == self;}/** Return true if transport is primary. */int tport_is_primary(tport_t const *self){ return self && self->tp_pri->pri_primary == self;}/** Return true if transport is secondary. */int tport_is_secondary(tport_t const *self){ return self && self->tp_master->mr_master != self && self->tp_pri->pri_primary != self;}/** Test if transport has been registered to su_root_t */int tport_is_registered(tport_t const *self){ return self->tp_index != 0;}/** Test if transport is stream. */int tport_is_stream(tport_t const *self){ return self->tp_addrinfo->ai_socktype == SOCK_STREAM;} /** Test if transport is dgram. */int tport_is_dgram(tport_t const *self){ return self->tp_addrinfo->ai_socktype == SOCK_DGRAM;} /** Test if transport is udp. */int tport_is_udp(tport_t const *self){ return self->tp_addrinfo->ai_protocol == IPPROTO_UDP;} /** Test if transport is tcp. */int tport_is_tcp(tport_t const *self){ return self->tp_addrinfo->ai_protocol == IPPROTO_TCP;} /** Return 1 if transport is reliable, 0 otherwise. * * (Note that this is part of external API). */int tport_is_reliable(tport_t const *self){ return self != NULL && (self->tp_addrinfo->ai_socktype == SOCK_STREAM || self->tp_addrinfo->ai_socktype == SOCK_SEQPACKET);}/** Return 0 if self is local, nonzero otherwise. * * The return valu is the tport_via enum. * * @sa TPTAG_PUBLIC(), enum tport_via. */int tport_is_public(tport_t const *self){ return self->tp_pri->pri_public;}/** Return true if transport supports IPv4 */int tport_has_ip4(tport_t const *self){ return self && (self->tp_addrinfo->ai_family == 0 || self->tp_addrinfo->ai_family == AF_INET);}#if SU_HAVE_IN6/** Return true if transport supports IPv6 */int tport_has_ip6(tport_t const *self){ return self && (self->tp_addrinfo->ai_family == 0 || self->tp_addrinfo->ai_family == AF_INET6);}#endif/** Return true if transport supports TLS. */int tport_has_tls(tport_t const *self){ return self && self->tp_pri->pri_has_tls;}/** Return true if transport is being updated. */int tport_is_updating(tport_t const *self){ tport_primary_t *pri; if (tport_is_master(self)) { for (pri = self->tp_master->mr_primaries; pri; pri = pri->pri_next) if (pri->pri_updating) return 1; } else if (tport_is_primary(self)) { return self->tp_pri->pri_updating; } return 0;}/** Test if transport has been closed. * * @since New in @VERSION_1_12_4 */inline int tport_is_closed(tport_t const *self){ return self->tp_closed;}/** Test if transport has been shut down. * * @since New in @VERSION_1_12_4 */inline int tport_is_shutdown(tport_t const *self){ return self->tp_closed || self->tp_send_close || self->tp_recv_close;}/** Test if transport is bound */su_inline int tport_is_bound(tport_t const *self){ return self->tp_protoname != NULL;}/** Test if transport connection has been established. @NEW_1_12_5. */int tport_is_connected(tport_t const *self){ return self->tp_is_connected;}/** Test if transport can be used to send message. @NEW_1_12_7. */int tport_is_clear_to_send(tport_t const *self){ return tport_is_master(self) || tport_is_primary(self) || (tport_is_secondary(self) && tport_is_registered(self) && self->tp_reusable && !self->tp_closed && !self->tp_send_close);}/** Return true if transport has message in send queue. @NEW_1_12_7. */int tport_has_queued(tport_t const *self){ return self && self->tp_queue && self->tp_queue[self->tp_qhead];}/** MTU for transport */su_inline unsigned tport_mtu(tport_t const *self){ return self->tp_params->tpp_mtu;}su_inlineint tport_has_sigcomp(tport_t const *self){ return self->tp_name->tpn_comp != NULL;}/** Set IP TOS for socket */void tport_set_tos(su_socket_t socket, su_addrinfo_t *ai, int tos){ if (tos >= 0 && ai->ai_family == AF_INET && setsockopt(socket, IPPROTO_IP, IP_TOS, (const void*)&tos, sizeof(tos)) < 0) { SU_DEBUG_3(("tport: setsockopt(IP_TOS): %s\n", su_strerror(su_errno()))); }}static tport_t *tport_connect(tport_primary_t *pri, su_addrinfo_t *ai, tp_name_t const *tpn);static int bind6only_check(tport_master_t *mr);staticint tport_server_addrinfo(tport_master_t *mr, char const *canon, int family, char const *host, char const *service, char const *protocol, char const * const transports[], su_addrinfo_t **res);static int tport_get_local_addrinfo(tport_master_t *mr, char const *port, su_addrinfo_t const *hints, su_addrinfo_t **return_ai);int tport_getaddrinfo(char const *node, char const *service, su_addrinfo_t const *hints, su_addrinfo_t **res);static void tport_freeaddrinfo(su_addrinfo_t *ai);staticint tport_addrinfo_copy(su_addrinfo_t *dst, void *addr, socklen_t addrlen, su_addrinfo_t const *src);static int tport_bind_client(tport_master_t *self, tp_name_t const *tpn, char const * const transports[], enum tport_via public, tagi_t *tags), tport_bind_server(tport_master_t *, tp_name_t const *tpn, char const * const transports[], enum tport_via public, tagi_t *tags), tport_setname(tport_t *, char const *, su_addrinfo_t const *, char const *), tport_wakeup_pri(su_root_magic_t *m, su_wait_t *w, tport_t *self), tport_wakeup(su_root_magic_t *m, su_wait_t *w, tport_t *self), tport_base_wakeup(tport_t *self, int events), tport_connected(su_root_magic_t *m, su_wait_t *w, tport_t *self), tport_resolve(tport_t *self, msg_t *msg, tp_name_t const *tpn), tport_send_error(tport_t *, msg_t *, tp_name_t const *, char const *who), tport_send_fatal(tport_t *, msg_t *, tp_name_t const *, char const *who), tport_queue(tport_t *self, msg_t *msg), tport_queue_rest(tport_t *self, msg_t *msg, msg_iovec_t iov[], size_t iovused), tport_pending_error(tport_t *self, su_sockaddr_t const *dst, int error), tport_pending_errmsg(tport_t *self, msg_t *msg, int error);static ssize_t tport_vsend(tport_t *self, msg_t *msg, tp_name_t const *tpn, msg_iovec_t iov[], size_t iovused, struct sigcomp_compartment *cc);tport_t *tport_by_addrinfo(tport_primary_t const *pri, su_addrinfo_t const *ai, tp_name_t const *tpn);void tport_peer_address(tport_t *self, msg_t *msg);static void tport_parse(tport_t *self, int complete, su_time_t now);static tport_primary_t *tport_alloc_primary(tport_master_t *mr, tport_vtable_t const *vtable, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t const *tags, char const **return_culprit);static tport_primary_t *tport_listen(tport_master_t *mr, tport_vtable_t const *vtable, tp_name_t tpn[1], su_addrinfo_t *ai, tagi_t *tags);static void tport_zap_primary(tport_primary_t *);static char *localipname(int pf, char *buf, size_t bufsiz);static int getprotohints(su_addrinfo_t *hints, char const *proto, int flags);/* Stack class used when transports are being destroyed */staticvoid tport_destroy_recv(tp_stack_t *stack, tport_t *tp, msg_t *msg, tp_magic_t *magic, su_time_t received){ msg_destroy(msg);}staticvoid tport_destroy_error(tp_stack_t *stack, tport_t *tp, int errcode, char const *remote){}staticmsg_t *tport_destroy_alloc(tp_stack_t *stack, int flags, char const data[], usize_t len, tport_t const *tp, tp_client_t *tpc){ return NULL;}/** Name for "any" transport. @internal */static char const tpn_any[] = "*";/** Create the master transport. * * Master transport object is used to bind the protocol using transport with * actual transport objects corresponding to TCP, UDP, etc. * * @sa tport_tbind() * * @TAGS * TPTAG_LOG(), TPTAG_DUMP(), tags used with tport_set_params(), especially * TPTAG_QUEUESIZE(). */tport_t *tport_tcreate(tp_stack_t *stack, tp_stack_class_t const *tpac, su_root_t *root, tag_type_t tag, tag_value_t value, ...){ tport_master_t *mr; tp_name_t *tpn; tport_params_t *tpp; ta_list ta; if (!stack || !tpac || !root) { su_seterrno(EINVAL); return NULL; } mr = su_home_clone(NULL, sizeof *mr); if (!mr) return NULL; SU_DEBUG_7(("%s(): %p\n", "tport_create", (void *)mr)); mr->mr_stack = stack; mr->mr_tpac = tpac; mr->mr_root = root; mr->mr_master->tp_master = mr; mr->mr_master->tp_params = tpp = mr->mr_params;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -