Newer
Older
unsigned int sipoptions; /*!< Supported SIP options */
struct ast_flags flags[2]; /*!< SIP_ flags */
Russell Bryant
committed
/*! Mailboxes that this peer cares about */
AST_LIST_HEAD_NOLOCK(, sip_mailbox) mailboxes;
int maxcallbitrate; /*!< Maximum Bitrate for a video call */
int expire; /*!< When to expire this peer registration */
int capability; /*!< Codec capability */
int rtptimeout; /*!< RTP timeout */
int rtpholdtimeout; /*!< RTP Hold Timeout */
int rtpkeepalive; /*!< Send RTP packets for keepalive */
ast_group_t callgroup; /*!< Call group */
ast_group_t pickupgroup; /*!< Pickup group */
struct sip_proxy *outboundproxy; /*!< Outbound proxy for this peer */
struct ast_dnsmgr_entry *dnsmgr;/*!< DNS refresh manager for peer */
struct sockaddr_in addr; /*!< IP address of peer */
struct sip_pvt *call; /*!< Call pointer */
int pokeexpire; /*!< When to expire poke (qualify= checking) */
int lastms; /*!< How long last response took (in ms), or -1 for no response */
int maxms; /*!< Max ms we will accept for the host to be up, 0 to not monitor */
Russell Bryant
committed
int qualifyfreq; /*!< Qualification: How often to check for the host to be up */
struct timeval ps; /*!< Time for sending SIP OPTION in sip_pke_peer() */
struct sockaddr_in defaddr; /*!< Default IP address, used until registration */
struct ast_ha *ha; /*!< Access control list */
struct ast_ha *contactha; /*!< Restrict what IPs are allowed in the Contact header (for registration) */
struct ast_variable *chanvars; /*!< Variables to set for channel created by user */
Kevin P. Fleming
committed
struct sip_pvt *mwipvt; /*!< Subscription for MWI */
Russell Bryant
committed
struct sip_st_cfg stimer; /*!< SIP Session-Timers */
int timer_t1; /*!< The maximum T1 value for the peer */
int timer_b; /*!< The maximum timer B (transaction timeouts) */
Mark Michelson
committed
int deprecated_username; /*!< If it's a realtime peer, are they using the deprecated "username" instead of "defaultuser" */
Olle Johansson
committed
/*XXX Seems like we suddenly have two flags with the same content. Why? To be continued... */
enum sip_peer_type type; /*!< Distinguish between "user" and "peer" types. This is used solely for CLI and manager commands */
Mark Michelson
committed
unsigned int disallowed_methods;
/*!
* \brief Registrations with other SIP proxies
*
* Created by sip_register(), the entry is linked in the 'regl' list,
* and never deleted (other than at 'sip reload' or module unload times).
* The entry always has a pending timeout, either waiting for an ACK to
* the REGISTER message (in which case we have to retransmit the request),
* or waiting for the next REGISTER message to be sent (either the initial one,
* or once the previously completed registration one expires).
* The registration can be in one of many states, though at the moment
* the handling is a bit mixed.
*/
Mark Spencer
committed
ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1);
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(callid); /*!< Global Call-ID */
AST_STRING_FIELD(realm); /*!< Authorization realm */
AST_STRING_FIELD(nonce); /*!< Authorization nonce */
AST_STRING_FIELD(opaque); /*!< Opaque nonsense */
AST_STRING_FIELD(qop); /*!< Quality of Protection, since SIP wasn't complicated enough yet. */
AST_STRING_FIELD(authdomain); /*!< Authorization domain */
AST_STRING_FIELD(regdomain); /*!< Registration domain */
AST_STRING_FIELD(username); /*!< Who we are registering as */
AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */
AST_STRING_FIELD(hostname); /*!< Domain or host we register to */
AST_STRING_FIELD(secret); /*!< Password in clear text */
AST_STRING_FIELD(md5secret); /*!< Password in md5 */
Olle Johansson
committed
AST_STRING_FIELD(callback); /*!< Contact extension */
AST_STRING_FIELD(random);
AST_STRING_FIELD(peername); /*!< Peer registering to */
enum sip_transport transport; /*!< Transport for this registration UDP, TCP or TLS */
int portno; /*!< Optional port override */
int expire; /*!< Sched ID of expiration */
int configured_expiry; /*!< Configured value to use for the Expires header */
int expiry; /*!< Negotiated value used for the Expires header */
int regattempts; /*!< Number of attempts (since the last success) */
int timeout; /*!< sched id of sip_reg_timeout */
int refresh; /*!< How often to refresh */
Olle Johansson
committed
struct sip_pvt *call; /*!< create a sip_pvt structure for each outbound "registration dialog" in progress */
enum sipregistrystate regstate; /*!< Registration state (see above) */
Tilghman Lesher
committed
struct timeval regtime; /*!< Last successful registration time */
int callid_valid; /*!< 0 means we haven't chosen callid for this registry yet. */
unsigned int ocseq; /*!< Sequence number we got to for REGISTERs for this registry */
Jeff Peeler
committed
struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for register */
struct sockaddr_in us; /*!< Who the server thinks we are */
int noncecount; /*!< Nonce-count */
char lastmsg[256]; /*!< Last Message sent/received */
/*! \brief Definition of a thread that handles a socket */
struct sip_threadinfo {
int stop;
pthread_t threadid;
Russell Bryant
committed
struct ast_tcptls_session_instance *tcptls_session;
enum sip_transport type; /*!< We keep a copy of the type here so we can display it in the connection list */
AST_LIST_ENTRY(sip_threadinfo) list;
};
/*! \brief Definition of an MWI subscription to another server */
struct sip_subscription_mwi {
ASTOBJ_COMPONENTS_FULL(struct sip_subscription_mwi,1,1);
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(username); /*!< Who we are sending the subscription as */
AST_STRING_FIELD(authuser); /*!< Who we *authenticate* as */
AST_STRING_FIELD(hostname); /*!< Domain or host we subscribe to */
AST_STRING_FIELD(secret); /*!< Password in clear text */
AST_STRING_FIELD(mailbox); /*!< Mailbox store to put MWI into */
);
enum sip_transport transport; /*!< Transport to use */
int portno; /*!< Optional port override */
int resub; /*!< Sched ID of resubscription */
unsigned int subscribed:1; /*!< Whether we are currently subscribed or not */
struct sip_pvt *call; /*!< Outbound subscription dialog */
struct ast_dnsmgr_entry *dnsmgr; /*!< DNS refresh manager for subscription */
struct sockaddr_in us; /*!< Who the server thinks we are */
};
/* --- Hash tables of various objects --------*/
#ifdef LOW_MEMORY
static int hash_peer_size = 17;
static int hash_dialog_size = 17;
static int hash_user_size = 17;
#else
static int hash_peer_size = 563; /*!< Size of peer hash table, prime number preferred! */
static int hash_dialog_size = 563;
static int hash_user_size = 563;
#endif
/*! \brief The thread list of TCP threads */
static AST_LIST_HEAD_STATIC(threadl, sip_threadinfo);
/*! \brief The peer list: Users, Peers and Friends */
static struct ao2_container *peers;
static struct ao2_container *peers_by_ip;
/*! \brief The register list: Other SIP proxies we register with and place calls to */
static struct ast_register_list {
Mark Spencer
committed
ASTOBJ_CONTAINER_COMPONENTS(struct sip_registry);
/*! \brief The MWI subscription list */
static struct ast_subscription_mwi_list {
ASTOBJ_CONTAINER_COMPONENTS(struct sip_subscription_mwi);
} submwil;
* \note The only member of the peer used here is the name field
*/
static int peer_hash_cb(const void *obj, const int flags)
{
const struct sip_peer *peer = obj;
return ast_str_case_hash(peer->name);
}
/*!
* \note The only member of the peer used here is the name field
*/
static int peer_cmp_cb(void *obj, void *arg, int flags)
{
struct sip_peer *peer = obj, *peer2 = arg;
return !strcasecmp(peer->name, peer2->name) ? CMP_MATCH | CMP_STOP : 0;
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
}
/*!
* \note the peer's addr struct provides to fields combined to make a key: the sin_addr.s_addr and sin_port fields.
*/
static int peer_iphash_cb(const void *obj, const int flags)
{
const struct sip_peer *peer = obj;
int ret1 = peer->addr.sin_addr.s_addr;
if (ret1 < 0)
ret1 = -ret1;
if (ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT)) {
return ret1;
} else {
return ret1 + peer->addr.sin_port;
}
}
/*!
* \note the peer's addr struct provides to fields combined to make a key: the sin_addr.s_addr and sin_port fields.
*/
static int peer_ipcmp_cb(void *obj, void *arg, int flags)
{
struct sip_peer *peer = obj, *peer2 = arg;
if (peer->addr.sin_addr.s_addr != peer2->addr.sin_addr.s_addr)
return 0;
if (!ast_test_flag(&peer->flags[0], SIP_INSECURE_PORT) && !ast_test_flag(&peer2->flags[0], SIP_INSECURE_PORT)) {
if (peer->addr.sin_port == peer2->addr.sin_port)
return CMP_MATCH | CMP_STOP;
else
return 0;
}
return CMP_MATCH | CMP_STOP;
}
/*!
* \note The only member of the dialog used here callid string
*/
static int dialog_hash_cb(const void *obj, const int flags)
{
const struct sip_pvt *pvt = obj;
return ast_str_case_hash(pvt->callid);
}
/*!
* \note The only member of the dialog used here callid string
*/
static int dialog_cmp_cb(void *obj, void *arg, int flags)
{
struct sip_pvt *pvt = obj, *pvt2 = arg;
return !strcasecmp(pvt->callid, pvt2->callid) ? CMP_MATCH | CMP_STOP : 0;
}
Kevin P. Fleming
committed
static int temp_pvt_init(void *);
Russell Bryant
committed
static void temp_pvt_cleanup(void *);
/*! \brief A per-thread temporary pvt structure */
Kevin P. Fleming
committed
AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
static void ts_ast_rtp_destroy(void *);
AST_THREADSTORAGE_CUSTOM(ts_audio_rtp, NULL, ts_ast_rtp_destroy);
AST_THREADSTORAGE_CUSTOM(ts_video_rtp, NULL, ts_ast_rtp_destroy);
AST_THREADSTORAGE_CUSTOM(ts_text_rtp, NULL, ts_ast_rtp_destroy);
/*! \brief Authentication list for realm authentication
* \todo Move the sip_auth list to AST_LIST */
static struct sip_auth *authl = NULL;
/* --- Sockets and networking --------------*/
Olle Johansson
committed
/*! \brief Main socket for UDP SIP communication.
*
* sipsock is shared between the SIP manager thread (which handles reload
Olle Johansson
committed
* requests), the udp io handler (sipsock_read()) and the user routines that
* issue udp writes (using __sip_xmit()).
* The socket is -1 only when opening fails (this is a permanent condition),
* or when we are handling a reload() that changes its address (this is
* a transient situation during which we might have a harmless race, see
* below). Because the conditions for the race to be possible are extremely
* rare, we don't want to pay the cost of locking on every I/O.
* Rather, we remember that when the race may occur, communication is
* bound to fail anyways, so we just live with this event and let
* the protocol handle this above us.
*/
static int sipsock = -1;
static struct sockaddr_in bindaddr; /*!< UDP: The address we bind to */
/*! \brief our (internal) default address/port to put in SIP/SDP messages
* internip is initialized picking a suitable address from one of the
* interfaces, and the same port number we bind to. It is used as the
* default address/port in SIP messages, and as the default address
* (but not port) in SDP messages.
*/
static struct sockaddr_in internip;
/*! \brief our external IP address/port for SIP sessions.
* externip.sin_addr is only set when we know we might be behind
* a NAT, and this is done using a variety of (mutually exclusive)
* ways from the config file:
*
* + with "externip = host[:port]" we specify the address/port explicitly.
* The address is looked up only once when (re)loading the config file;
*
* + with "externhost = host[:port]" we do a similar thing, but the
* hostname is stored in externhost, and the hostname->IP mapping
* is refreshed every 'externrefresh' seconds;
*
* + with "stunaddr = host[:port]" we run queries every externrefresh seconds
* to the specified server, and store the result in externip.
*
* Other variables (externhost, externexpire, externrefresh) are used
* to support the above functions.
*/
static struct sockaddr_in externip; /*!< External IP address if we are behind NAT */
static char externhost[MAXHOSTNAMELEN]; /*!< External host name */
static time_t externexpire; /*!< Expiration counter for re-resolving external host name in dynamic DNS */
Mark Spencer
committed
static int externrefresh = 10;
static struct sockaddr_in stunaddr; /*!< stun server address */
/*! \brief List of local networks
* We store "localnet" addresses from the config file into an access list,
* marked as 'DENY', so the call to ast_apply_ha() will return
* AST_SENSE_DENY for 'local' addresses, and AST_SENSE_ALLOW for 'non local'
* (i.e. presumably public) addresses.
*/
static struct ast_ha *localaddr; /*!< List of local networks, on the same side of NAT as this Asterisk */
static int ourport_tcp; /*!< The port used for TCP connections */
static int ourport_tls; /*!< The port used for TCP/TLS connections */
static struct sockaddr_in debugaddr;
static struct ast_config *notify_types; /*!< The list of manual NOTIFY types we know how to send */
/*! some list management macros. */
#define UNLINK(element, head, prev) do { \
if (prev) \
(prev)->next = (element)->next; \
else \
(head) = (element)->next; \
} while (0)
enum t38_action_flag {
SDP_T38_NONE = 0, /*!< Do not modify T38 information at all */
SDP_T38_INITIATE, /*!< Remote side has requested T38 with us */
SDP_T38_ACCEPT, /*!< Remote side accepted our T38 request */
};
Olle Johansson
committed
/*---------------------------- Forward declarations of functions in chan_sip.c */
/* Note: This is added to help splitting up chan_sip.c into several files
in coming releases. */
Olle Johansson
committed
/*--- PBX interface functions */
static struct ast_channel *sip_request_call(const char *type, int format, const struct ast_channel *requestor, void *data, int *cause);
Olle Johansson
committed
static int sip_devicestate(void *data);
static int sip_sendtext(struct ast_channel *ast, const char *text);
static int sip_call(struct ast_channel *ast, char *dest, int timeout);
static int sip_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen);
Olle Johansson
committed
static int sip_hangup(struct ast_channel *ast);
static int sip_answer(struct ast_channel *ast);
static struct ast_frame *sip_read(struct ast_channel *ast);
static int sip_write(struct ast_channel *ast, struct ast_frame *frame);
static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
static int sip_transfer(struct ast_channel *ast, const char *dest);
static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
static int sip_senddigit_begin(struct ast_channel *ast, char digit);
static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen);
Joshua Colp
committed
static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
static const char *sip_get_callid(struct ast_channel *chan);
static int handle_request_do(struct sip_request *req, struct sockaddr_in *sin);
static int sip_standard_port(enum sip_transport type, int port);
static int sip_prepare_socket(struct sip_pvt *p);
Brett Bryant
committed
static int sip_parse_host(char *line, int lineno, char **hostname, int *portnum, enum sip_transport *transport);
Olle Johansson
committed
/*--- Transmitting responses and requests */
static int sipsock_read(int *id, int fd, short events, void *ignore);
static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len);
static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod);
static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static int retrans_pkt(const void *data);
static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg);
static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req);
static int transmit_response_with_date(struct sip_pvt *p, const char *msg, const struct sip_request *req);
Mark Michelson
committed
static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp, int rpid);
static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable);
static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int seqno, enum xmittype reliable, int newbranch);
static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init);
Russell Bryant
committed
static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int oldsdp);
static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
static int transmit_info_with_vidupdate(struct sip_pvt *p);
Mark Spencer
committed
static int transmit_message_with_text(struct sip_pvt *p, const char *text);
static int transmit_refer(struct sip_pvt *p, const char *dest);
static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, const char *vmexten);
static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate);
Joshua Colp
committed
static int transmit_notify_custom(struct sip_pvt *p, struct ast_variable *vars);
static int transmit_register(struct sip_registry *r, int sipmethod, const char *auth, const char *authheader);
Olle Johansson
committed
static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno);
static void copy_request(struct sip_request *dst, const struct sip_request *src);
static void receive_message(struct sip_pvt *p, struct sip_request *req);
Mark Michelson
committed
static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward);
static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *event, int cache_only);
Olle Johansson
committed
/*--- Dialog management */
static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *sin,
int useglobal_nat, const int intended_method, struct sip_request *req);
static int __sip_autodestruct(const void *data);
Olle Johansson
committed
static void sip_scheddestroy(struct sip_pvt *p, int ms);
static int sip_cancel_destroy(struct sip_pvt *p);
static struct sip_pvt *sip_destroy(struct sip_pvt *p);
static void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglist);
static void *registry_unref(struct sip_registry *reg, char *tag);
static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist);
static int __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
Olle Johansson
committed
static void __sip_pretend_ack(struct sip_pvt *p);
Olle Johansson
committed
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
static int auto_congest(const void *arg);
Olle Johansson
committed
static int update_call_counter(struct sip_pvt *fup, int event);
static int hangup_sip2cause(int cause);
static const char *hangup_cause2sip(int cause);
static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method);
static void free_old_route(struct sip_route *route);
static void list_route(struct sip_route *route);
static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards);
static enum check_auth_result register_verify(struct sip_pvt *p, struct sockaddr_in *sin,
struct sip_request *req, const char *uri);
static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
static void check_pendings(struct sip_pvt *p);
static void *sip_park_thread(void *stuff);
static int sip_park(struct ast_channel *chan1, struct ast_channel *chan2, struct sip_request *req, int seqno);
static int sip_sipredirect(struct sip_pvt *p, const char *dest);
Olle Johansson
committed
/*--- Codec handling / SDP */
static void try_suggested_sip_codec(struct sip_pvt *p);
static const char* get_sdp_iterate(int* start, struct sip_request *req, const char *name);
static const char *get_sdp(struct sip_request *req, const char *name);
static int find_sdp(struct sip_request *req);
static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action);
Kevin P. Fleming
committed
static void add_codec_to_sdp(const struct sip_pvt *p, int codec,
struct ast_str **m_buf, struct ast_str **a_buf,
int debug, int *min_packet_size);
Kevin P. Fleming
committed
static void add_noncodec_to_sdp(const struct sip_pvt *p, int format,
struct ast_str **m_buf, struct ast_str **a_buf,
Olle Johansson
committed
int debug);
static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int oldsdp, int add_audio, int add_t38);
static void do_setnat(struct sip_pvt *p);
static void stop_media_flows(struct sip_pvt *p);
Olle Johansson
committed
/*--- Authentication stuff */
static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len);
static int build_reply_digest(struct sip_pvt *p, int method, char *digest, int digest_len);
static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *req, const char *username,
const char *secret, const char *md5secret, int sipmethod,
const char *uri, enum xmittype reliable, int ignore);
static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
int sipmethod, const char *uri, enum xmittype reliable,
struct sockaddr_in *sin, struct sip_peer **authpeer);
static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, const char *uri, enum xmittype reliable, struct sockaddr_in *sin);
Olle Johansson
committed
/*--- Domain handling */
static int check_sip_domain(const char *domain, char *context, size_t len); /* Check if domain is one of our local domains */
static int add_sip_domain(const char *domain, const enum domain_mode mode, const char *context);
static void clear_sip_domains(void);
Olle Johansson
committed
/*--- SIP realm authentication */
static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno);
static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */
static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
Olle Johansson
committed
/*--- Misc functions */
static void check_rtp_timeout(struct sip_pvt *dialog, time_t t);
Olle Johansson
committed
static int sip_do_reload(enum channelreloadreason reason);
static int reload_config(enum channelreloadreason reason);
static int expire_register(const void *data);
static void *do_monitor(void *data);
Olle Johansson
committed
static int restart_monitor(void);
Tilghman Lesher
committed
static void peer_mailboxes_to_str(struct ast_str **mailbox_str, struct sip_peer *peer);
Olle Johansson
committed
static struct ast_variable *copy_vars(struct ast_variable *src);
/* static int sip_addrcmp(char *name, struct sockaddr_in *sin); Support for peer matching */
static int sip_refer_allocate(struct sip_pvt *p);
static void ast_quiet_chan(struct ast_channel *chan);
static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
Olle Johansson
committed
Tilghman Lesher
committed
/*!
* \brief generic function for determining if a correct transport is being
* used to contact a peer
*
* this is done as a macro so that the "tmpl" var can be passed either a
* sip_request or a sip_peer
*/
#define check_request_transport(peer, tmpl) ({ \
int ret = 0; \
if (peer->socket.type == tmpl->socket.type) \
; \
else if (!(peer->transports & tmpl->socket.type)) {\
ast_log(LOG_ERROR, \
"'%s' is not a valid transport for '%s'. we only use '%s'! ending call.\n", \
get_transport(tmpl->socket.type), peer->name, get_transport_list(peer->transports) \
Tilghman Lesher
committed
); \
ret = 1; \
} else if (peer->socket.type & SIP_TRANSPORT_TLS) { \
ast_log(LOG_WARNING, \
"peer '%s' HAS NOT USED (OR SWITCHED TO) TLS in favor of '%s' (but this was allowed in sip.conf)!\n", \
peer->name, get_transport(tmpl->socket.type) \
); \
} else { \
ast_debug(1, \
"peer '%s' has contacted us over %s even though we prefer %s.\n", \
peer->name, get_transport(tmpl->socket.type), get_transport(peer->socket.type) \
); \
}\
(ret); \
})
/*--- Device monitoring and Device/extension state/event handling */
static int cb_extensionstate(char *context, char* exten, int state, void *data);
static int sip_devicestate(void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
static void sip_poke_all_peers(void);
static void sip_peer_hold(struct sip_pvt *p, int hold);
static void mwi_event_cb(const struct ast_event *, void *);
/*--- Applications, functions, CLI and manager command helpers */
Olle Johansson
committed
static const char *sip_nat_mode(const struct sip_pvt *p);
static char *sip_show_inuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Russell Bryant
committed
static char *transfermode2str(enum transfermodes mode) attribute_const;
static int peer_status(struct sip_peer *peer, char *status, int statuslen);
static char *sip_show_sched(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char * _sip_show_peers(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_show_peers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static void print_group(int fd, ast_group_t group, int crlf);
Russell Bryant
committed
static const char *dtmfmode2str(int mode) attribute_const;
static int str2dtmfmode(const char *str) attribute_unused;
static const char *insecure2str(int mode) attribute_const;
static void cleanup_stale_contexts(char *new, char *old);
static void print_codec_to_cli(int fd, struct ast_codec_pref *pref);
static const char *domain_mode_to_text(const enum domain_mode mode);
static char *sip_show_domains(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_show_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *_sip_qualify_peer(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[]);
static char *sip_qualify_peer(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_unregister(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_mwi(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Russell Bryant
committed
static const char *subscription_type2str(enum subscriptiontype subtype) attribute_pure;
static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
static char *complete_sip_peer(const char *word, int state, int flags2);
static char *complete_sip_registered_peer(const char *word, int state, int flags2);
Joshua Colp
committed
static char *complete_sip_show_history(const char *line, const char *word, int pos, int state);
static char *complete_sip_show_peer(const char *line, const char *word, int pos, int state);
static char *complete_sip_unregister(const char *line, const char *word, int pos, int state);
static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Olle Johansson
committed
static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_do_debug_ip(int fd, const char *arg);
static char *sip_do_debug_peer(int fd, const char *arg);
static char *sip_do_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Joshua Colp
committed
static char *sip_cli_notify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static char *sip_set_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static int sip_dtmfmode(struct ast_channel *chan, const char *data);
static int sip_addheader(struct ast_channel *chan, const char *data);
static int sip_do_reload(enum channelreloadreason reason);
static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
static int acf_channel_read(struct ast_channel *chan, const char *funcname, char *preparse, char *buf, size_t buflen);
Olle Johansson
committed
/*--- Debugging
Functions for enabling debug per IP or fully, or enabling history logging for
a SIP dialog
*/
static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to debuglog at end of dialog, before destroying data */
Olle Johansson
committed
static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
static inline int sip_debug_test_pvt(struct sip_pvt *p);
/*! \brief Append to SIP dialog history
\return Always returns 0 */
#define append_history(p, event, fmt , args... ) append_history_full(p, "%-15s " fmt, event, ## args)
Olle Johansson
committed
static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
static void sip_dump_history(struct sip_pvt *dialog);
Olle Johansson
committed
/*--- Device object handling */
Russell Bryant
committed
static struct sip_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int realtime);
Olle Johansson
committed
static int update_call_counter(struct sip_pvt *fup, int event);
static void sip_destroy_peer(struct sip_peer *peer);
static void sip_destroy_peer_fn(void *peer);
Olle Johansson
committed
static void set_peer_defaults(struct sip_peer *peer);
static struct sip_peer *temp_peer(const char *name);
static void register_peer_exten(struct sip_peer *peer, int onoff);
static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int forcenamematch, int devstate_only);
static int sip_poke_peer_s(const void *data);
static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req);
static void reg_source_db(struct sip_peer *peer);
static void destroy_association(struct sip_peer *peer);
static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno);
static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v);
static void set_socket_transport(struct sip_socket *socket, int transport);
Olle Johansson
committed
/* Realtime device support */
static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, const char *useragent, int expirey, int deprecated_username, int lastms);
static void update_peer(struct sip_peer *p, int expire);
static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername);
static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin, int devstate_only);
static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
Olle Johansson
committed
/*--- Internal UA client handling (outbound registrations) */
static void ast_sip_ouraddrfor(struct in_addr *them, struct sockaddr_in *us, struct sip_pvt *p);
Olle Johansson
committed
static void sip_registry_destroy(struct sip_registry *reg);
static int sip_register(const char *value, int lineno);
static const char *regstate2str(enum sipregistrystate regstate) attribute_const;
static int sip_reregister(const void *data);
static int __sip_do_register(struct sip_registry *r);
static int sip_reg_timeout(const void *data);
static void sip_send_all_registers(void);
static int sip_reinvite_retry(const void *data);
Olle Johansson
committed
/*--- Parsing SIP requests and responses */
static void append_date(struct sip_request *req); /* Append date to SIP packet */
static int determine_firstline_parts(struct sip_request *req);
Kevin P. Fleming
committed
static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype);
static const char *gettag(const struct sip_request *req, const char *header, char *tagbuf, int tagbufsize);
static int find_sip_method(const char *msg);
static unsigned int parse_sip_options(struct sip_pvt *pvt, const char *supported);
static unsigned int parse_allowed_methods(struct sip_request *req);
static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_request *req);
static int parse_request(struct sip_request *req);
static const char *get_header(const struct sip_request *req, const char *name);
static const char *referstatus2str(enum referstatus rstatus) attribute_pure;
Olle Johansson
committed
static int method_match(enum sipmethod id, const char *name);
static void parse_copy(struct sip_request *dst, const struct sip_request *src);
Olle Johansson
committed
static char *get_in_brackets(char *tmp);
static const char *find_alias(const char *name, const char *_default);
static const char *__get_header(const struct sip_request *req, const char *name, int *start);
static int lws2sws(char *msgbuf, int len);
static void extract_uri(struct sip_pvt *p, struct sip_request *req);
Olle Johansson
committed
static char *remove_uri_parameters(char *uri);
static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_pvt *pvt);
static void check_via(struct sip_pvt *p, struct sip_request *req);
static char *get_calleridname(const char *input, char *output, size_t outputsize);
Mark Michelson
committed
static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, char **number, int *reason);
static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
static int get_msg_text(char *buf, int len, struct sip_request *req, int addnewline);
Olle Johansson
committed
static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
Mark Michelson
committed
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward);
Matthew Nicholson
committed
static int get_domain(const char *str, char *domain, int len);
static void get_realm(struct sip_pvt *p, const struct sip_request *req);
Olle Johansson
committed
/*-- TCP connection handling ---*/
Russell Bryant
committed
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session);
static void *sip_tcp_worker_fn(void *);
Olle Johansson
committed
/*--- Constructing requests and responses */
static void initialize_initreq(struct sip_pvt *p, struct sip_request *req);
static int init_req(struct sip_request *req, int sipmethod, const char *recip);
static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch);
static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod);
static int init_resp(struct sip_request *resp, const char *msg);
static inline int resp_needs_contact(const char *msg, enum sipmethod method);
static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg, const struct sip_request *req);
Olle Johansson
committed
static const struct sockaddr_in *sip_real_dst(const struct sip_pvt *p);
static void build_via(struct sip_pvt *p);
static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
Tilghman Lesher
committed
static int create_addr(struct sip_pvt *dialog, const char *opeer, struct sockaddr_in *sin, int newdialog);
Olle Johansson
committed
static char *generate_random_string(char *buf, size_t size);
static void build_callid_pvt(struct sip_pvt *pvt);
static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
static void make_our_tag(char *tagbuf, size_t len);
static int add_header(struct sip_request *req, const char *var, const char *value);
static int add_header_contentLength(struct sip_request *req, int len);
static int add_line(struct sip_request *req, const char *line);
static int add_text(struct sip_request *req, const char *text);
static int add_digit(struct sip_request *req, char digit, unsigned int duration, int mode);
Mark Michelson
committed
static int add_rpid(struct sip_request *req, struct sip_pvt *p);
Olle Johansson
committed
static int add_vidupdate(struct sip_request *req);
static void add_route(struct sip_request *req, struct sip_route *route);
static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
Olle Johansson
committed
static void set_destination(struct sip_pvt *p, char *uri);
static void append_date(struct sip_request *req);
static void build_contact(struct sip_pvt *p);
/*------Request handling functions */
static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int *recount, int *nounlock);
static int handle_request_update(struct sip_pvt *p, struct sip_request *req);
static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin, int *recount, const char *e, int *nounlock);
static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, int *nounlock);
static int handle_request_bye(struct sip_pvt *p, struct sip_request *req);
static int handle_request_register(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, const char *e);
static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req);
static int handle_request_message(struct sip_pvt *p, struct sip_request *req);
static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e);
static void handle_request_info(struct sip_pvt *p, struct sip_request *req);
static int handle_request_options(struct sip_pvt *p, struct sip_request *req);
static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct sockaddr_in *sin);
static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin, int seqno, const char *e);
static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno);
/*------Response handling functions */
static void handle_response_invite(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno);
/*------ T38 Support --------- */
static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
Joshua Colp
committed
static void change_t38_state(struct sip_pvt *p, int state);
Russell Bryant
committed
/*------ Session-Timers functions --------- */
static void proc_422_rsp(struct sip_pvt *p, struct sip_request *rsp);
static int proc_session_timer(const void *vp);
static void stop_session_timer(struct sip_pvt *p);
static void start_session_timer(struct sip_pvt *p);
static void restart_session_timer(struct sip_pvt *p);
static const char *strefresher2str(enum st_refresher r);
static int parse_session_expires(const char *p_hdrval, int *const p_interval, enum st_refresher *const p_ref);
static int parse_minse(const char *p_hdrval, int *const p_interval);
static int st_get_se(struct sip_pvt *, int max);
static enum st_refresher st_get_refresher(struct sip_pvt *);
static enum st_mode st_get_mode(struct sip_pvt *);
static struct sip_st_dlg* sip_st_alloc(struct sip_pvt *const p);
/*------- RTP Glue functions -------- */
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *instance, struct ast_rtp_instance *vinstance, struct ast_rtp_instance *tinstance, int codecs, int nat_active);
/*!--- SIP MWI Subscription support */
static int sip_subscribe_mwi(const char *value, int lineno);
static void sip_subscribe_mwi_destroy(struct sip_subscription_mwi *mwi);
static void sip_send_all_mwi_subscriptions(void);
static int sip_subscribe_mwi_do(const void *data);
static int __sip_subscribe_mwi_do(struct sip_subscription_mwi *mwi);
Russell Bryant
committed
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
.description = "Session Initiation Protocol (SIP)",
.capabilities = AST_FORMAT_AUDIO_MASK, /* all audio formats */
Russell Bryant
committed
.properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
.requester = sip_request_call, /* called with chan unlocked */
.devicestate = sip_devicestate, /* called with chan unlocked (not chan-specific) */
.call = sip_call, /* called with chan locked */
.hangup = sip_hangup, /* called with chan locked */
.answer = sip_answer, /* called with chan locked */
.read = sip_read, /* called with chan locked */
.write = sip_write, /* called with chan locked */
.write_video = sip_write, /* called with chan locked */
.write_text = sip_write,
.indicate = sip_indicate, /* called with chan locked */
.transfer = sip_transfer, /* called with chan locked */
.fixup = sip_fixup, /* called with chan locked */
.send_digit_begin = sip_senddigit_begin, /* called with chan unlocked */
.send_digit_end = sip_senddigit_end,
.bridge = ast_rtp_instance_bridge, /* XXX chan unlocked ? */
.early_bridge = ast_rtp_instance_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
.func_channel_read = acf_channel_read,
.setoption = sip_setoption,
Joshua Colp
committed
.queryoption = sip_queryoption,
.get_pvt_uniqueid = sip_get_callid,
};
/*! \brief This version of the sip channel tech has no send_digit_begin
* callback so that the core knows that the channel does not want
* DTMF BEGIN frames.
* The struct is initialized just before registering the channel driver,
* and is for use with channels using SIP INFO DTMF.
*/
static struct ast_channel_tech sip_tech_info;
/*! \brief Working TLS connection configuration */
static struct ast_tls_config sip_tls_cfg;
/*! \brief Default TLS connection configuration */
static struct ast_tls_config default_tls_cfg;
/*! \brief The TCP server definition */
static struct ast_tcptls_session_args sip_tcp_desc = {
.accept_fd = -1,
.master = AST_PTHREADT_NULL,
.tls_cfg = NULL,
.poll_timeout = -1,
.name = "SIP TCP server",
.accept_fn = ast_tcptls_server_root,
.worker_fn = sip_tcp_worker_fn,
};
/*! \brief The TCP/TLS server definition */
static struct ast_tcptls_session_args sip_tls_desc = {
.accept_fd = -1,
.master = AST_PTHREADT_NULL,
.tls_cfg = &sip_tls_cfg,
.poll_timeout = -1,
.name = "SIP TLS server",
.accept_fn = ast_tcptls_server_root,
.worker_fn = sip_tcp_worker_fn,
};
/* wrapper macro to tell whether t points to one of the sip_tech descriptors */
#define IS_SIP_TECH(t) ((t) == &sip_tech || (t) == &sip_tech_info)
/*! \brief map from an integer value to a string.
* If no match is found, return errorstring
*/
static const char *map_x_s(const struct _map_x_s *table, int x, const char *errorstring)
{
const struct _map_x_s *cur;
for (cur = table; cur->s; cur++)
if (cur->x == x)
return cur->s;
return errorstring;
}
/*! \brief map from a string to an integer value, case insensitive.
* If no match is found, return errorvalue.
*/
static int map_s_x(const struct _map_x_s *table, const char *s, int errorvalue)
{
const struct _map_x_s *cur;
for (cur = table; cur->s; cur++)
if (!strcasecmp(cur->s, s))
return cur->x;
return errorvalue;
}
Olle Johansson
committed
/*!
* duplicate a list of channel variables, \return the copy.
*/
static struct ast_variable *copy_vars(struct ast_variable *src)
{
struct ast_variable *res = NULL, *tmp, *v = NULL;
for (v = src ; v ; v = v->next) {
if ((tmp = ast_variable_new(v->name, v->value, v->file))) {
tmp->next = res;
res = tmp;
}
}
return res;
}
/*! \brief SIP TCP connection handler */
static void *sip_tcp_worker_fn(void *data)
{
Russell Bryant
committed
struct ast_tcptls_session_instance *tcptls_session = data;
Russell Bryant
committed
return _sip_tcp_helper_thread(NULL, tcptls_session);
/*! \brief SIP TCP thread management function
This function reads from the socket, parses the packet into a request
*/
Russell Bryant
committed
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session)
{
int res, cl;
struct sip_request req = { 0, } , reqcpy = { 0, };
struct sip_threadinfo *me;
Brett Bryant
committed
char buf[1024] = "";
me = ast_calloc(1, sizeof(*me));
if (!me)
goto cleanup2;
me->threadid = pthread_self();
Russell Bryant
committed
me->tcptls_session = tcptls_session;
if (tcptls_session->ssl)
me->type = SIP_TRANSPORT_TLS;
else
me->type = SIP_TRANSPORT_TCP;
Russell Bryant
committed
ast_debug(2, "Starting thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
AST_LIST_LOCK(&threadl);
AST_LIST_INSERT_TAIL(&threadl, me, list);
AST_LIST_UNLOCK(&threadl);
if (!(req.data = ast_str_create(SIP_MIN_PACKET)))
goto cleanup;
if (!(reqcpy.data = ast_str_create(SIP_MIN_PACKET)))
goto cleanup;
Kevin P. Fleming
committed
struct ast_str *str_save;
str_save = req.data;
memset(&req, 0, sizeof(req));
req.data = str_save;
ast_str_reset(req.data);
Kevin P. Fleming
committed
str_save = reqcpy.data;
memset(&reqcpy, 0, sizeof(reqcpy));
reqcpy.data = str_save;
ast_str_reset(reqcpy.data);
Russell Bryant
committed
memset(buf, 0, sizeof(buf));
Russell Bryant
committed
if (tcptls_session->ssl) {
set_socket_transport(&req.socket, SIP_TRANSPORT_TLS);
req.socket.port = htons(ourport_tls);
} else {
set_socket_transport(&req.socket, SIP_TRANSPORT_TCP);
req.socket.port = htons(ourport_tcp);
}
Russell Bryant
committed
res = ast_wait_for_input(tcptls_session->fd, -1);
Russell Bryant
committed
ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
goto cleanup;
}
/* Read in headers one line at a time */
while (req.len < 4 || strncmp(REQ_OFFSET_TO_STR(&req, len - 4), "\r\n\r\n", 4)) {
Russell Bryant
committed
ast_mutex_lock(&tcptls_session->lock);
if (!fgets(buf, sizeof(buf), tcptls_session->f)) {
ast_mutex_unlock(&tcptls_session->lock);
Russell Bryant
committed
ast_mutex_unlock(&tcptls_session->lock);
if (me->stop)
goto cleanup;
Tilghman Lesher
committed
ast_str_append(&req.data, 0, "%s", buf);
req.len = req.data->used;
copy_request(&reqcpy, &req);
parse_request(&reqcpy);
/* In order to know how much to read, we need the content-length header */
if (sscanf(get_header(&reqcpy, "Content-Length"), "%30d", &cl)) {
Russell Bryant
committed
ast_mutex_lock(&tcptls_session->lock);
if (!fread(buf, (cl < sizeof(buf)) ? cl : sizeof(buf), 1, tcptls_session->f)) {
ast_mutex_unlock(&tcptls_session->lock);
Brett Bryant
committed
}
Russell Bryant
committed
ast_mutex_unlock(&tcptls_session->lock);
if (me->stop)
goto cleanup;
cl -= strlen(buf);
Tilghman Lesher
committed
ast_str_append(&req.data, 0, "%s", buf);
req.len = req.data->used;
/*! \todo XXX If there's no Content-Length or if the content-length and what
we receive is not the same - we should generate an error */
Russell Bryant
committed
req.socket.tcptls_session = tcptls_session;
handle_request_do(&req, &tcptls_session->remote_address);
}
cleanup:
AST_LIST_LOCK(&threadl);
AST_LIST_REMOVE(&threadl, me, list);
AST_LIST_UNLOCK(&threadl);
ast_free(me);
cleanup2:
Russell Bryant
committed
fclose(tcptls_session->f);
tcptls_session->f = NULL;
tcptls_session->fd = -1;
if (reqcpy.data) {
ast_free(reqcpy.data);
if (req.data) {
ast_free(req.data);
req.data = NULL;
}
Russell Bryant
committed
ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
Russell Bryant
committed
ao2_ref(tcptls_session, -1);
tcptls_session = NULL;
return NULL;
}
/*!
* helper functions to unreference various types of objects.
* By handling them this way, we don't have to declare the
* destructor on each call, which removes the chance of errors.
*/
static void *unref_peer(struct sip_peer *peer, char *tag)
ao2_t_ref(peer, -1, tag);
return NULL;
static struct sip_peer *ref_peer(struct sip_peer *peer, char *tag)
{
return peer;
}
/*! \brief maintain proper refcounts for a sip_pvt's outboundproxy