|
@@ -30,18 +30,6 @@
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
*
|
|
|
- * ***************************************************
|
|
|
- * IMPORTANT NOTE
|
|
|
- *
|
|
|
- * All UACs but t_uac_dlg are being deprecated now
|
|
|
- * and will be removed from future versions of TM
|
|
|
- * module. Eliminate all dependancies on them asap.
|
|
|
- * For backwards compatibility (NOT RECOMMENDED)
|
|
|
- * turn off DEPRECATE_OLD_STUFF in defs.h. Similarly,
|
|
|
- * there is a new FIFO UAC.
|
|
|
- *
|
|
|
- * ****************************************************
|
|
|
- *
|
|
|
* History:
|
|
|
* --------
|
|
|
* 2003-01-23 t_uac_dlg now uses get_out_socket (jiri)
|
|
@@ -54,816 +42,260 @@
|
|
|
* 2003-03-01 kr set through a function now (jiri)
|
|
|
* 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
|
|
|
* 2003-04-02 port_no_str does not contain a leading ':' anymore (andrei)
|
|
|
- * 2003-04-15 t_uac_dlg now uses get_send_socket(get_out_socket doesn't
|
|
|
- * work for tcp) (andrei)
|
|
|
- *
|
|
|
*/
|
|
|
|
|
|
-
|
|
|
-#include "../../comp_defs.h"
|
|
|
-#include "defs.h"
|
|
|
-
|
|
|
-
|
|
|
-#include <stdlib.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <unistd.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include <errno.h>
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/stat.h>
|
|
|
-#include <fcntl.h>
|
|
|
-#include <signal.h>
|
|
|
-#include <limits.h>
|
|
|
#include <string.h>
|
|
|
-#include "../../parser/parse_from.h"
|
|
|
-#include "../../parser/msg_parser.h"
|
|
|
+#include "../../mem/shm_mem.h"
|
|
|
#include "../../dprint.h"
|
|
|
-#include "../../ut.h"
|
|
|
-#include "../../hash_func.h"
|
|
|
-#include "../../md5utils.h"
|
|
|
-#include "../../mem/mem.h"
|
|
|
-#include "../../fifo_server.h"
|
|
|
-#include "../../error.h"
|
|
|
-#include "../../pt.h"
|
|
|
+#include "../../globals.h"
|
|
|
+#include "../../md5.h"
|
|
|
#include "../../crc.h"
|
|
|
-#include "t_funcs.h"
|
|
|
-#include "config.h"
|
|
|
-#include "sip_msg.h"
|
|
|
+#include "../../ip_addr.h"
|
|
|
#include "ut.h"
|
|
|
+#include "h_table.h"
|
|
|
+#include "t_hooks.h"
|
|
|
+#include "t_funcs.h"
|
|
|
#include "t_msgbuilder.h"
|
|
|
+#include "callid.h"
|
|
|
#include "uac.h"
|
|
|
|
|
|
-/* header fields which are explicitely processed and are not copied
|
|
|
- * from FIFO line-by-line
|
|
|
- */
|
|
|
-#define skip_hf(_hf) (((_hf)->type==HDR_FROM) || ((_hf)->type==HDR_TO) \
|
|
|
- || ((_hf)->type==HDR_CALLID) || ((_hf)->type==HDR_CSEQ))
|
|
|
-
|
|
|
-/* Call-ID has the following form: <callid_nr>-<pid>@<ip>
|
|
|
- * callid_nr is initialized as a random number and continually
|
|
|
- * increases; -<pid>@<ip> is kept in callid_suffix
|
|
|
- */
|
|
|
-
|
|
|
-#define CALLID_SUFFIX_LEN (1 /* - */ + 5 /* pid */ \
|
|
|
- + 42 /* embedded v4inv6 address can be looong '128.' */ \
|
|
|
- + 2 /* parenthessis [] */ + 1 /* ZT 0 */ \
|
|
|
- + 16 /* one never knows ;-) */ )
|
|
|
-#define CALLID_NR_LEN 20
|
|
|
-
|
|
|
-/* the character which separates random from constant part */
|
|
|
-#define CID_SEP '-'
|
|
|
-
|
|
|
-/* length of FROM tags */
|
|
|
-#define FROM_TAG_LEN (MD5_LEN +1 /* - */ + CRC16_LEN)
|
|
|
-
|
|
|
-struct str_list {
|
|
|
- str s;
|
|
|
- struct str_list *next;
|
|
|
-};
|
|
|
|
|
|
-static unsigned long callid_nr;
|
|
|
-static char *callid_suffix;
|
|
|
-static int callid_suffix_len;
|
|
|
-static int rand_len; /* number of chars to display max rand */
|
|
|
-static char callid[CALLID_NR_LEN+CALLID_SUFFIX_LEN];
|
|
|
+#define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
|
|
|
|
|
|
-static char from_tag[ FROM_TAG_LEN+1 ];
|
|
|
+static char from_tag[FROM_TAG_LEN + 1];
|
|
|
|
|
|
+char* uac_from = "sip:[email protected]"; /* Module parameter */
|
|
|
|
|
|
|
|
|
-int uac_init() {
|
|
|
-
|
|
|
- int i;
|
|
|
- unsigned long uli;
|
|
|
- int rand_len_bits;
|
|
|
- int rand_cnt; /* number of rands() to be long enough */
|
|
|
- int rand_bits; /* length of rands() in bits */
|
|
|
+/*
|
|
|
+ * Initialize UAC
|
|
|
+ */
|
|
|
+int uac_init(void)
|
|
|
+{
|
|
|
str src[3];
|
|
|
|
|
|
- if (RAND_MAX<TABLE_ENTRIES) {
|
|
|
+ if (RAND_MAX < TABLE_ENTRIES) {
|
|
|
LOG(L_WARN, "Warning: uac does not spread "
|
|
|
- "accross the whole hash table\n");
|
|
|
- }
|
|
|
-
|
|
|
- /* calculate the initial call-id */
|
|
|
-
|
|
|
- /* how many bits and chars do we need to display the
|
|
|
- * whole ULONG number */
|
|
|
- for (rand_len_bits=0,uli=ULONG_MAX;uli;
|
|
|
- uli>>=1, rand_len_bits++ );
|
|
|
- rand_len=rand_len_bits/4;
|
|
|
- if (rand_len>CALLID_NR_LEN) {
|
|
|
- LOG(L_ERR, "ERROR: Too small callid buffer\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
-
|
|
|
- /* how long are the rand()s ? */
|
|
|
- for (rand_bits=0,i=RAND_MAX;i;i>>=1,rand_bits++);
|
|
|
- /* how many rands() fit in the ULONG ? */
|
|
|
- rand_cnt=rand_len_bits / rand_bits;
|
|
|
-
|
|
|
- /* now fill in the callid with as many random
|
|
|
- * numbers as you can + 1 */
|
|
|
- callid_nr=rand(); /* this is the + 1 */
|
|
|
- while(rand_cnt) {
|
|
|
- rand_cnt--;
|
|
|
- callid_nr<<=rand_bits;
|
|
|
- callid_nr|=rand();
|
|
|
+ "accross the whole hash table\n");
|
|
|
}
|
|
|
- callid_suffix=callid+rand_len;
|
|
|
- DBG("CALLID initialization: %lx (len=%d)\n",
|
|
|
- callid_nr, rand_len );
|
|
|
- DBG("CALLID0=%0*lx\n", rand_len, callid_nr );
|
|
|
-
|
|
|
|
|
|
/* calculate the initial From tag */
|
|
|
-
|
|
|
- src[0].s="Long live SER server";
|
|
|
- src[0].len=strlen(src[0].s);
|
|
|
- src[1].s=sock_info[bind_idx].address_str.s;
|
|
|
- src[1].len=strlen(src[1].s);
|
|
|
- src[2].s=sock_info[bind_idx].port_no_str.s;
|
|
|
- src[2].len=strlen(src[2].s);
|
|
|
-
|
|
|
- MDStringArray( from_tag, src, 3 );
|
|
|
- from_tag[MD5_LEN]=CID_SEP;
|
|
|
-
|
|
|
+ src[0].s = "Long live SER server";
|
|
|
+ src[0].len = strlen(src[0].s);
|
|
|
+ src[1].s = sock_info[bind_idx].address_str.s;
|
|
|
+ src[1].len = strlen(src[1].s);
|
|
|
+ src[2].s = sock_info[bind_idx].port_no_str.s;
|
|
|
+ src[2].len = strlen(src[2].s);
|
|
|
+
|
|
|
+ MDStringArray(from_tag, src, 3);
|
|
|
+ from_tag[MD5_LEN] = '-';
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
-int uac_child_init( int rank )
|
|
|
+/*
|
|
|
+ * Generate a From tag
|
|
|
+ */
|
|
|
+void generate_fromtag(str* tag, str* callid)
|
|
|
{
|
|
|
- callid_suffix_len=snprintf(callid_suffix,CALLID_SUFFIX_LEN,
|
|
|
- "%c%d@%.*s", CID_SEP, my_pid(),
|
|
|
- sock_info[bind_idx].address_str.len,
|
|
|
- sock_info[bind_idx].address_str.s );
|
|
|
- if (callid_suffix_len==-1 || callid_suffix_len>=CALLID_SUFFIX_LEN) {
|
|
|
- LOG(L_ERR, "ERROR: uac_child_init: buffer too small\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- DBG("DEBUG: callid_suffix: %s\n", callid_suffix );
|
|
|
- return 1;
|
|
|
+ /* calculate from tag from callid */
|
|
|
+ crcitt_string_array(&from_tag[MD5_LEN + 1], callid, 1);
|
|
|
+ tag->s = from_tag;
|
|
|
+ tag->len = FROM_TAG_LEN;
|
|
|
}
|
|
|
|
|
|
-static struct socket_info *uri2sock( str *uri, union sockaddr_union *to_su,
|
|
|
- int proto )
|
|
|
-{
|
|
|
- struct proxy_l *proxy;
|
|
|
- struct socket_info* send_sock;
|
|
|
|
|
|
- proxy = uri2proxy(uri, proto);
|
|
|
- if (proxy == 0) {
|
|
|
- ser_error = E_BAD_ADDRESS;
|
|
|
- LOG(L_ERR, "ERROR: uri2sock: Can't create a dst proxy\n");
|
|
|
- return 0;
|
|
|
+/*
|
|
|
+ * Check value of parameters
|
|
|
+ */
|
|
|
+static inline int check_params(str* method, str* to, str* from, dlg_t** dialog)
|
|
|
+{
|
|
|
+ if (!method || !to || !from || !dialog) {
|
|
|
+ LOG(L_ERR, "check_params(): Invalid parameter value\n");
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- hostent2su(to_su, &proxy->host, proxy->addr_idx,
|
|
|
- (proxy->port) ? proxy->port : SIP_PORT);
|
|
|
- send_sock=get_send_socket(to_su, proxy->proto);
|
|
|
- if (send_sock == 0) {
|
|
|
- LOG(L_ERR, "ERROR: uri2sock: no corresponding socket for af %d,"
|
|
|
- "proto %d\n", to_su->s.sa_family , proto);
|
|
|
- ser_error = E_NO_SOCKET;
|
|
|
+ if (!method->s || !method->len) {
|
|
|
+ LOG(L_ERR, "check_params(): Invalid request method\n");
|
|
|
+ return -2;
|
|
|
}
|
|
|
|
|
|
+ if (!to->s || !to->len) {
|
|
|
+ LOG(L_ERR, "check_params(): Invalid request method\n");
|
|
|
+ return -4;
|
|
|
+ }
|
|
|
|
|
|
- free_proxy(proxy);
|
|
|
- pkg_free(proxy);
|
|
|
- return send_sock;
|
|
|
+ if (!from->s || !from->len) {
|
|
|
+ LOG(L_ERR, "check_params(): Invalid request method\n");
|
|
|
+ return -5;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
-
|
|
|
|
|
|
|
|
|
/*
|
|
|
- * Send a request within a dialog
|
|
|
- *
|
|
|
- * Some parameters are required, some are optional (i.e., ephemeral,
|
|
|
- * default or empty values are created if 0 is passed as parameter). The
|
|
|
- * optional parameters are typically used to set some header fields
|
|
|
- * to dialog-related values (as opposed to having them set to
|
|
|
- * ephemeral values).
|
|
|
- *
|
|
|
- * Required:
|
|
|
- * - msg .. specifies type of message, such as "OPTIONS"
|
|
|
- * - ruri .. specifies request URI;
|
|
|
- * - from .. value of From header field (if it already includes from tag,
|
|
|
- * the fromtag parameter MUST point to en empty string; if
|
|
|
- * fromtag is 0, an ephemeral tag is always appended)
|
|
|
- * - to ... value of To header field (if it already includes to tag in it,
|
|
|
- * or you do not wish to set a to-tag the totag parameter MUST be 0)
|
|
|
- *
|
|
|
- * Optional:
|
|
|
- * - dst transport destination (expressed as URI) -- if present,
|
|
|
- * request is physically forwarded to address indicated in it,
|
|
|
- * overriding the transport address in ruri; useful for use with
|
|
|
- * outbound proxies or loose routers (that is where the first
|
|
|
- * element of route set comes in)
|
|
|
- * - fromtag from HF tag -- dialog-less applications do not to set it (==0),
|
|
|
- * in which case an ephemeral value is created; if fromtag present,
|
|
|
- * its appended to the From header field; it may be also present
|
|
|
- * and point to an empty string -- that only makes sense if
|
|
|
- * application includes the tag in From and does not care to
|
|
|
- * separate the tag from the rest of header field
|
|
|
- * - totag To HF tag; if 0, no to-tag is appended (unless it is already
|
|
|
- * part of to)
|
|
|
- * - cid .. callid; if 0, ephemeral value is created; transactions
|
|
|
- * within a dialog need to set this value to dialog's callid
|
|
|
- * - cseq .. CSeq; if 0, default value (DEFAULT_CSEQ) is used; transactions
|
|
|
- * within a dialog need to set this value to current local cseq,
|
|
|
- * which grows continously with transactions sent
|
|
|
- * - headers .. block of header fields that will be included in the
|
|
|
- * message. It MAY NOT include header fields already described
|
|
|
- * in other parameters (From, to, cid, cseq) or created
|
|
|
- * automatically (Content_length) otherwise the parameter
|
|
|
- * would appear multiple times. It MUST include all additional
|
|
|
- * header fields required for a given SIP message, like Content-Type
|
|
|
- * for any messages including a body or Contact for INVITEs.
|
|
|
- * - body .. if present, body and Content-Length is appended to the
|
|
|
- * SIP message; Content-Type then needs to be present inside
|
|
|
- * 'headers' parameter
|
|
|
- * - cb .. callback to be called when transaction completes; if none
|
|
|
- * present, no callback will be called
|
|
|
- * - cbp .. callback parameter -- value stored in transaction context
|
|
|
- *
|
|
|
- *
|
|
|
+ * Send a request using data from the dialog structure
|
|
|
*/
|
|
|
-int t_uac_dlg(str* msg, /* Type of the message - MESSAGE, OPTIONS etc. */
|
|
|
- str* dst, /* Real destination (can be different than R-URI) */
|
|
|
- int proto,
|
|
|
- str* ruri, /* Request-URI */
|
|
|
- str* to, /* To - w/o tag*/
|
|
|
- str* from, /* From - w/o tag*/
|
|
|
- str* totag, /* To tag */
|
|
|
- str* fromtag, /* From tag */
|
|
|
- int* cseq, /* Variable holding CSeq */
|
|
|
- str* cid, /* Call-ID */
|
|
|
- str* headers, /* Optional headers including CRLF */
|
|
|
- str* body, /* Message body */
|
|
|
- transaction_cb completion_cb, /* Callback parameter */
|
|
|
- void* cbp /* Callback pointer */
|
|
|
- )
|
|
|
+int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp)
|
|
|
{
|
|
|
-
|
|
|
- int r, branch, ret;
|
|
|
- unsigned int req_len;
|
|
|
- char *buf;
|
|
|
- struct cell *new_cell;
|
|
|
struct socket_info* send_sock;
|
|
|
- struct retr_buf *request;
|
|
|
- str callid_s, ftag, tmp;
|
|
|
union sockaddr_union to_su;
|
|
|
+ struct cell *new_cell;
|
|
|
+ struct retr_buf *request;
|
|
|
+ char* buf;
|
|
|
+ int buf_len;
|
|
|
|
|
|
- /* make -Wall shut up */
|
|
|
- ret=0;
|
|
|
-
|
|
|
- /* check for invalid parameter */
|
|
|
- if (!msg || !msg->s
|
|
|
- || !ruri || !ruri->s
|
|
|
- || !from || !from->s
|
|
|
- || !to || !to->s ) {
|
|
|
- LOG(L_ERR, "ERROR: t_uac_dlg: invalid parameters\n");
|
|
|
- ser_error = ret = E_INVALID_PARAMS;
|
|
|
-#ifdef XL_DEBUG
|
|
|
- abort();
|
|
|
-#endif
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
- send_sock=uri2sock( dst? dst: ruri, &to_su, proto );
|
|
|
- if (send_sock==0) {
|
|
|
- LOG(L_ERR, "ERROR: t_uac_dlg: no socket found\n");
|
|
|
- goto error00;
|
|
|
- }
|
|
|
-
|
|
|
- branch=0;
|
|
|
- /* No Call-ID given, calculate it */
|
|
|
- if (cid == 0) {
|
|
|
- callid_nr++;
|
|
|
- r = snprintf(callid, rand_len + 1, "%0*lx", rand_len, callid_nr);
|
|
|
- if (r == -1 || r>=rand_len+1) {
|
|
|
- LOG(L_CRIT, "BUG: SORRY, callid calculation failed\n");
|
|
|
- goto error00;
|
|
|
- }
|
|
|
-
|
|
|
- /* fix the ZT 0 */
|
|
|
- callid[rand_len] = CID_SEP;
|
|
|
- callid_s.s = callid;
|
|
|
- callid_s.len = rand_len + callid_suffix_len;
|
|
|
- }
|
|
|
+ send_sock = uri2sock(dialog->hooks.next_hop, &to_su, PROTO_NONE);
|
|
|
+ if (!send_sock) {
|
|
|
+ LOG(L_ERR, "t_uac: no socket found\n");
|
|
|
+ goto error2;
|
|
|
+ }
|
|
|
|
|
|
new_cell = build_cell(0);
|
|
|
if (!new_cell) {
|
|
|
- ret = E_OUT_OF_MEM;
|
|
|
- LOG(L_ERR, "ERROR: t_uac: short of cell shmem\n");
|
|
|
- goto error00;
|
|
|
+ LOG(L_ERR, "t_uac: short of cell shmem\n");
|
|
|
+ goto error2;
|
|
|
}
|
|
|
|
|
|
- new_cell->completion_cb = completion_cb;
|
|
|
+ new_cell->completion_cb = cb;
|
|
|
new_cell->cbp = cbp;
|
|
|
-
|
|
|
- /* cbp is installed -- tell error handling bellow not to free it */
|
|
|
+
|
|
|
+ /* cbp is installed -- tell error handling bellow not to free it */
|
|
|
cbp = 0;
|
|
|
|
|
|
- new_cell->is_invite = msg->len == INVITE_LEN && memcmp(msg->s, INVITE, INVITE_LEN) == 0;
|
|
|
- new_cell->local= 1 ;
|
|
|
+ new_cell->is_invite = method->len == INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN) == 0;
|
|
|
+ new_cell->local= 1;
|
|
|
set_kr(REQ_FWDED);
|
|
|
-
|
|
|
- request = &new_cell->uac[branch].request;
|
|
|
+
|
|
|
+ request = &new_cell->uac[0].request;
|
|
|
request->dst.to = to_su;
|
|
|
request->dst.send_sock = send_sock;
|
|
|
request->dst.proto = send_sock->proto;
|
|
|
request->dst.proto_reserved1 = 0;
|
|
|
|
|
|
- /* need to put in table to calculate label which is needed for printing */
|
|
|
+ /* need to put in table to calculate label which is needed for printing */
|
|
|
LOCK_HASH(new_cell->hash_index);
|
|
|
insert_into_hash_table_unsafe(new_cell);
|
|
|
UNLOCK_HASH(new_cell->hash_index);
|
|
|
|
|
|
- if (fromtag == 0) {
|
|
|
- /* calculate from tag from callid */
|
|
|
- crcitt_string_array(&from_tag[MD5_LEN + 1], (cid) ? (cid) : (&callid_s), 1);
|
|
|
- ftag.s = from_tag;
|
|
|
- ftag.len = FROM_TAG_LEN;
|
|
|
- }
|
|
|
-
|
|
|
- buf = build_uac_request_dlg(msg,
|
|
|
- ruri,
|
|
|
- to,
|
|
|
- from,
|
|
|
- totag,
|
|
|
- (fromtag) ? (fromtag) : (&ftag),
|
|
|
- (cseq) ? (*cseq) : DEFAULT_CSEQ,
|
|
|
- (cid) ? (cid) : (&callid_s),
|
|
|
- headers,
|
|
|
- body,
|
|
|
- branch,
|
|
|
- new_cell,
|
|
|
- &req_len,
|
|
|
- send_sock);
|
|
|
+ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len, send_sock);
|
|
|
if (!buf) {
|
|
|
- ret = E_OUT_OF_MEM;
|
|
|
- LOG(L_ERR, "ERROR: t_uac: short of req shmem\n");
|
|
|
- goto error01;
|
|
|
+ LOG(L_ERR, "t_uac: Error while building message\n");
|
|
|
+ goto error1;
|
|
|
}
|
|
|
+
|
|
|
new_cell->method.s = buf;
|
|
|
- new_cell->method.len = msg->len;
|
|
|
+ new_cell->method.len = method->len;
|
|
|
|
|
|
request->buffer = buf;
|
|
|
- request->buffer_len = req_len;
|
|
|
+ request->buffer_len = buf_len;
|
|
|
new_cell->nr_of_outgoings++;
|
|
|
-
|
|
|
-/*
|
|
|
- proxy->tx++;
|
|
|
- proxy->tx_bytes += req_len;
|
|
|
-*/
|
|
|
-
|
|
|
+
|
|
|
if (SEND_BUFFER(request) == -1) {
|
|
|
- if (dst) {
|
|
|
- tmp = *dst;
|
|
|
- } else {
|
|
|
- tmp = *ruri;
|
|
|
- }
|
|
|
- LOG(L_ERR, "ERROR: t_uac: UAC sending to \'%.*s\' failed\n", tmp.len, tmp.s);
|
|
|
-/*
|
|
|
- proxy->errors++;
|
|
|
- proxy->ok = 0;
|
|
|
-*/
|
|
|
+ LOG(L_ERR, "t_uac: Attempt to send to '%.*s' failed\n",
|
|
|
+ dialog->hooks.next_hop->len,
|
|
|
+ dialog->hooks.next_hop->s
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
start_retr(request);
|
|
|
-
|
|
|
- /* success */
|
|
|
return 1;
|
|
|
|
|
|
-error01:
|
|
|
+ error1:
|
|
|
LOCK_HASH(new_cell->hash_index);
|
|
|
remove_from_hash_table_unsafe(new_cell);
|
|
|
UNLOCK_HASH(new_cell->hash_index);
|
|
|
free_cell(new_cell);
|
|
|
|
|
|
-error00:
|
|
|
-/*
|
|
|
- free_proxy(proxy);
|
|
|
- pkg_free(proxy);
|
|
|
-*/
|
|
|
-
|
|
|
-done:
|
|
|
- /* if we did not install cbp, release it now */
|
|
|
+ error2:
|
|
|
+ /* if we did not install cbp, release it now */
|
|
|
if (cbp) shm_free(cbp);
|
|
|
- return ser_error = ret;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void fifo_callback( struct cell *t, struct sip_msg *reply,
|
|
|
- int code, void *param)
|
|
|
+/*
|
|
|
+ * Send a message within a dialog
|
|
|
+ */
|
|
|
+int req_within(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb completion_cb, void* cbp)
|
|
|
{
|
|
|
-
|
|
|
- char *filename;
|
|
|
- str text;
|
|
|
-
|
|
|
- DBG("DEBUG: fifo UAC completed with status %d\n", code);
|
|
|
- if (!t->cbp) {
|
|
|
- LOG(L_INFO, "INFO: fifo UAC completed with status %d\n", code);
|
|
|
- return;
|
|
|
+ if (!method || !dialog) {
|
|
|
+ LOG(L_ERR, "req_within: Invalid parameter value\n");
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
- filename=(char *)(t->cbp);
|
|
|
- if (reply==FAKED_REPLY) {
|
|
|
- get_reply_status(&text,reply,code);
|
|
|
- if (text.s==0) {
|
|
|
- LOG(L_ERR, "ERROR: fifo_callback: get_reply_status failed\n");
|
|
|
- fifo_reply(filename, "500 fifo_callback: get_reply_status failed\n");
|
|
|
- return;
|
|
|
- }
|
|
|
- fifo_reply(filename, "%.*s\n", text.len, text.s );
|
|
|
- pkg_free(text.s);
|
|
|
- } else {
|
|
|
- text.s=reply->first_line.u.reply.status.s;
|
|
|
- text.len=reply->len-(reply->first_line.u.reply.status.s-reply->buf);
|
|
|
- fifo_reply(filename, "%.*s", text.len, text.s );
|
|
|
+ if (dialog->state != DLG_CONFIRMED) {
|
|
|
+ LOG(L_ERR, "req_within: Dialog is not confirmed yet\n");
|
|
|
+ goto err;
|
|
|
}
|
|
|
- DBG("DEBUG: fifo_callback sucesssfuly completed\n");
|
|
|
-}
|
|
|
|
|
|
-static struct str_list *new_str(char *s, int len, struct str_list **last, int *total)
|
|
|
-{
|
|
|
- struct str_list *new;
|
|
|
- new=pkg_malloc(sizeof(struct str_list));
|
|
|
- if (!new) {
|
|
|
- LOG(L_ERR, "ERROR: get_hfblock: not enough mem\n");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- new->s.s=s;
|
|
|
- new->s.len=len;
|
|
|
- new->next=0;
|
|
|
+ if ((method->len == 3) && (!memcmp("ACK", method->s, 3))) goto send;
|
|
|
+ if ((method->len == 6) && (!memcmp("CANCEL", method->s, 6))) goto send;
|
|
|
+ dialog->loc_seq.value++; /* Increment CSeq */
|
|
|
+ send:
|
|
|
+ return t_uac(method, headers, body, dialog, completion_cb, cbp);
|
|
|
|
|
|
- (*last)->next=new;
|
|
|
- *last=new;
|
|
|
- *total+=len;
|
|
|
-
|
|
|
- return new;
|
|
|
+ err:
|
|
|
+ if (cbp) shm_free(cbp);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto)
|
|
|
-{
|
|
|
- struct str_list sl, *last, *new, *i, *foo;
|
|
|
- int hf_avail, frag_len, total_len;
|
|
|
- char *begin, *needle, *dst, *ret, *d;
|
|
|
- str *sock_name, *portname;
|
|
|
- union sockaddr_union to_su;
|
|
|
- struct socket_info* send_sock;
|
|
|
-
|
|
|
- ret=0; /* pesimist: assume failure */
|
|
|
- total_len=0;
|
|
|
- last=&sl;
|
|
|
- last->next=0;
|
|
|
- portname=sock_name=0;
|
|
|
-
|
|
|
- for (; hf; hf=hf->next) {
|
|
|
- if (skip_hf(hf)) continue;
|
|
|
-
|
|
|
- begin=needle=hf->name.s;
|
|
|
- hf_avail=hf->len;
|
|
|
-
|
|
|
- /* substitution loop */
|
|
|
- while(hf_avail) {
|
|
|
- d=memchr(needle, SUBST_CHAR, hf_avail);
|
|
|
- if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
|
|
|
- new=new_str(begin, hf_avail, &last, &total_len);
|
|
|
- if (!new) goto error;
|
|
|
- break;
|
|
|
- } else {
|
|
|
- frag_len=d-begin;
|
|
|
- d++; /* d not at the second substitution char */
|
|
|
- switch(*d) {
|
|
|
- case SUBST_CHAR: /* double SUBST_CHAR: IP */
|
|
|
- /* string before substitute */
|
|
|
- new=new_str(begin, frag_len, &last, &total_len);
|
|
|
- if (!new) goto error;
|
|
|
- /* substitute */
|
|
|
- if (!sock_name) {
|
|
|
- send_sock=uri2sock( uri, &to_su, proto );
|
|
|
- if (!send_sock) {
|
|
|
- LOG(L_ERR, "ERROR: get_hf_block: send_sock failed\n");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- sock_name=&send_sock->address_str;
|
|
|
- portname=&send_sock->port_no_str;
|
|
|
- }
|
|
|
- new=new_str(sock_name->s, sock_name->len,
|
|
|
- &last, &total_len );
|
|
|
- if (!new) goto error;
|
|
|
- /* inefficient - FIXME --andrei*/
|
|
|
- new=new_str(":", 1, &last, &total_len);
|
|
|
- if (!new) goto error;
|
|
|
- new=new_str(portname->s, portname->len,
|
|
|
- &last, &total_len );
|
|
|
- if (!new) goto error;
|
|
|
- /* keep going ... */
|
|
|
- begin=needle=d+1;hf_avail-=frag_len+2;
|
|
|
- continue;
|
|
|
- default:
|
|
|
- /* no valid substitution char -- keep going */
|
|
|
- hf_avail-=frag_len+1;
|
|
|
- needle=d;
|
|
|
- }
|
|
|
- } /* possible substitute */
|
|
|
- } /* substitution loop */
|
|
|
- /* proceed to next header */
|
|
|
- /* new=new_str(CRLF, CRLF_LEN, &last, &total_len );
|
|
|
- if (!new) goto error; */
|
|
|
- DBG("DEBUG: get_hf_block: one more hf processed\n");
|
|
|
- } /* header loop */
|
|
|
-
|
|
|
-
|
|
|
- /* construct a single header block now */
|
|
|
- ret=pkg_malloc(total_len);
|
|
|
- if (!ret) {
|
|
|
- LOG(L_ERR, "ERROR: get_hf_block no pkg mem for hf block\n");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- i=sl.next;
|
|
|
- dst=ret;
|
|
|
- while(i) {
|
|
|
- foo=i;
|
|
|
- i=i->next;
|
|
|
- memcpy(dst, foo->s.s, foo->s.len);
|
|
|
- dst+=foo->s.len;
|
|
|
- pkg_free(foo);
|
|
|
- }
|
|
|
- *l=total_len;
|
|
|
- return ret;
|
|
|
-
|
|
|
-error:
|
|
|
- i=sl.next;
|
|
|
- while(i) {
|
|
|
- foo=i;
|
|
|
- i=i->next;
|
|
|
- pkg_free(foo);
|
|
|
- }
|
|
|
- *l=0;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void fifo_uac_error(char *reply_fifo, int code, char *msg)
|
|
|
+/*
|
|
|
+ * Send an initial request that will start a dialog
|
|
|
+ */
|
|
|
+int req_outside(str* method, str* to, str* from, str* headers, str* body, dlg_t** dialog, transaction_cb cb, void* cbp)
|
|
|
{
|
|
|
- LOG(L_ERR, "ERROR: fifo_uac: %s\n", msg );
|
|
|
- fifo_reply(reply_fifo, "%d fifo_uac: %s", code, msg);
|
|
|
-}
|
|
|
+ str callid, fromtag;
|
|
|
|
|
|
-/* syntax:
|
|
|
-
|
|
|
- :t_uac_dlg:[file] EOL
|
|
|
- method EOL
|
|
|
- r-uri EOL
|
|
|
- dst EOL // ("." if no outbound server used)
|
|
|
- // must be used with dialogs/lr
|
|
|
- <EOL separated HFs>+ // From and To must be present at least;
|
|
|
- // dialog-apps must include tag in From
|
|
|
- // (an ephemeral is appended otherwise)
|
|
|
- // and supply CSeq/CallId
|
|
|
- .[EOL]
|
|
|
- [body]
|
|
|
- .EOL
|
|
|
-
|
|
|
-
|
|
|
- there is also the possibility to have server placed its
|
|
|
- hostname:portnumber in header fields -- just put double
|
|
|
- exclamation mark in any of the optional header fields
|
|
|
- (i.e., any but From/To/CallID,CSeq), they will be
|
|
|
- substituted hn:pn
|
|
|
-
|
|
|
-Example:
|
|
|
-
|
|
|
-sc fifo t_uac_dlg MESSAGE sip:[email protected] \
|
|
|
- . \ # no outbound proxy
|
|
|
- 'From:[email protected];tagd=123' \ # no to-tag -> ephemeral
|
|
|
- 'To:[email protected]' \
|
|
|
- 'Foo: sip:user@!! ' \ # expansion here
|
|
|
- 'CSEQ: 11 MESSAGE ' \
|
|
|
- . \ # EoH
|
|
|
- . # empty body
|
|
|
----
|
|
|
-U 192.168.2.16:5060 -> 192.168.2.1:5060
|
|
|
-MESSAGE sip:[email protected] SIP/2.0..
|
|
|
-Via: SIP/2.0/UDP 192.168.2.16;branch=z9hG4bK760c.922ea6a1.0..
|
|
|
-To: [email protected]..
|
|
|
-From: [email protected];tagd=123;tag=5405e669bc2980663aed2624dc31396f-fa77..
|
|
|
-CSeq: 11 MESSAGE..
|
|
|
-Call-ID: [email protected]..
|
|
|
-Content-Length: 0..
|
|
|
-User-Agent: Sip EXpress router (0.8.11pre4-tcp1-locking (i386/linux))..
|
|
|
-Foo: sip:[email protected]:5060..
|
|
|
-..
|
|
|
-
|
|
|
-
|
|
|
-*/
|
|
|
-
|
|
|
-int fifo_uac_dlg( FILE *stream, char *response_file )
|
|
|
-{
|
|
|
- char method_buf[MAX_METHOD];
|
|
|
- char ruri_buf[MAX_URI_SIZE];
|
|
|
- char outbound_buf[MAX_URI_SIZE];
|
|
|
- char header_buf[MAX_HEADER];
|
|
|
- char body_buf[MAX_BODY];
|
|
|
- str method, ruri, outbound, header, body;
|
|
|
- str hfb; /* header field block */
|
|
|
- struct sip_uri parsed_ruri, parsed_outbound;
|
|
|
- str dummy_empty;
|
|
|
- int fromtag;
|
|
|
- int cseq;
|
|
|
- struct cseq_body *parsed_cseq;
|
|
|
- int i;
|
|
|
- char c;
|
|
|
- struct to_body *parsed_from;
|
|
|
-
|
|
|
-
|
|
|
- char *shmem_file;
|
|
|
- int fn_len;
|
|
|
- int ret;
|
|
|
- int sip_error;
|
|
|
- char err_buf[MAX_REASON_LEN];
|
|
|
- int err_ret;
|
|
|
- struct sip_msg faked_msg;
|
|
|
-
|
|
|
-
|
|
|
- if (!read_line(method_buf, MAX_METHOD, stream,&method.len)
|
|
|
- ||method.len==0) {
|
|
|
- /* line breaking must have failed -- consume the rest
|
|
|
- and proceed to a new request
|
|
|
- */
|
|
|
- fifo_uac_error(response_file, 400, "method expected");
|
|
|
- return 1;
|
|
|
- }
|
|
|
- method.s=method_buf;
|
|
|
- DBG("DEBUG: fifo_uac: method: %.*s\n", method.len, method.s );
|
|
|
+ if (check_params(method, to, from, dialog) < 0) goto err;
|
|
|
+
|
|
|
+ generate_callid(&callid);
|
|
|
+ generate_fromtag(&fromtag, &callid);
|
|
|
|
|
|
- if (!read_line(ruri_buf, MAX_URI_SIZE, stream, &ruri.len)
|
|
|
- || ruri.len==0) {
|
|
|
- fifo_uac_error(response_file, 400, "ruri expected");
|
|
|
- return 1;
|
|
|
- }
|
|
|
- if (parse_uri(ruri_buf, ruri.len, &parsed_ruri) < 0 ) {
|
|
|
- fifo_uac_error(response_file, 400, "ruri invalid\n");
|
|
|
- return 1;
|
|
|
+ if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
|
|
|
+ LOG(L_ERR, "req_outside(): Error while creating new dialog\n");
|
|
|
+ goto err;
|
|
|
}
|
|
|
- ruri.s=ruri_buf;
|
|
|
- DBG("DEBUG: fifo_uac: ruri: %.*s\n", ruri.len, ruri.s);
|
|
|
|
|
|
- if (!read_line(outbound_buf, MAX_URI_SIZE, stream, &outbound.len)
|
|
|
- ||outbound.len==0) {
|
|
|
- fifo_uac_error(response_file, 400, "outbound address expected\n");
|
|
|
- return 1;
|
|
|
- }
|
|
|
- if (outbound.len==1 && outbound_buf[0]=='.' ) {
|
|
|
- DBG("DEBUG: fifo_uac: outbound empty\n");
|
|
|
- outbound.s=0; outbound.len=0;
|
|
|
- } else if (parse_uri(outbound_buf, outbound.len,
|
|
|
- &parsed_outbound) < 0 ) {
|
|
|
- fifo_uac_error(response_file, 400, "outbound uri invalid\n");
|
|
|
- return 1;
|
|
|
- } else {
|
|
|
- outbound.s=outbound_buf;
|
|
|
- DBG("DEBUG: fifo_uac: dst: %.*s\n", outbound.len, outbound.s);
|
|
|
- }
|
|
|
+ return t_uac(method, headers, body, *dialog, cb, cbp);
|
|
|
|
|
|
+ err:
|
|
|
+ if (cbp) shm_free(cbp);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
|
|
|
- /* now read and parse header fields */
|
|
|
- if (!read_line_set(header_buf, MAX_HEADER, stream, &header.len)
|
|
|
- || header.len==0 ) {
|
|
|
- fifo_uac_error(response_file, 400, "HFs expected");
|
|
|
- return 1;
|
|
|
- }
|
|
|
- header.s=header_buf;
|
|
|
- DBG("DEBUG: fifo_uac: header: %.*s\n", header.len, header.s );
|
|
|
- /* use SIP parser to look at what is in the FIFO request */
|
|
|
- memset(&faked_msg, 0, sizeof(struct sip_msg));
|
|
|
- faked_msg.len=header.len;
|
|
|
- faked_msg.buf=faked_msg.unparsed=header_buf;
|
|
|
- if (parse_headers(&faked_msg, HDR_EOH, 0)==-1 ) {
|
|
|
- DBG("DEBUG: fifo_uac: parse_headers failed\n");
|
|
|
- fifo_uac_error(response_file, 400, "HFs unparseable");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- DBG("DEBUG: fifo_uac: parse_headers succeeded\n");
|
|
|
|
|
|
- /* and eventually body */
|
|
|
- if (!read_body(body_buf, MAX_BODY, stream, &body.len)) {
|
|
|
- fifo_uac_error(response_file, 400, "body expected");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- body.s=body_buf;
|
|
|
- DBG("DEBUG: fifo_uac: body: %.*s\n", body.len, body.s );
|
|
|
+/*
|
|
|
+ * Send a transactional request, no dialogs involved
|
|
|
+ */
|
|
|
+int request(str* m, str* ruri, str* to, str* from, str* h, str* b, transaction_cb c, void* cp)
|
|
|
+{
|
|
|
+ str callid, fromtag;
|
|
|
+ dlg_t* dialog;
|
|
|
+ int res;
|
|
|
|
|
|
+ if (check_params(m, to, from, &dialog) < 0) goto err;
|
|
|
|
|
|
- /* at this moment, we collected all the things we got, let's
|
|
|
- * verify user has not forgotten something */
|
|
|
- if (body.len && !faked_msg.content_type) {
|
|
|
- fifo_uac_error(response_file, 400, "Content_type missing");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- if (body.len && faked_msg.content_length) {
|
|
|
- fifo_uac_error(response_file, 400, "Content_length disallowed");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- if (!faked_msg.to) {
|
|
|
- fifo_uac_error(response_file, 400, "To missing");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- if (!faked_msg.from) {
|
|
|
- fifo_uac_error(response_file, 400, "From missing");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- /* we also need to know if there is from-tag and add it otherwise */
|
|
|
- if (parse_from_header(&faked_msg)<0) {
|
|
|
- fifo_uac_error(response_file, 400, "Error in From");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- parsed_from=(struct to_body*)faked_msg.from->parsed;
|
|
|
- fromtag=parsed_from->tag_value.s &&
|
|
|
- parsed_from->tag_value.len;
|
|
|
- cseq=0;
|
|
|
- if (faked_msg.cseq && (parsed_cseq=get_cseq(&faked_msg))) {
|
|
|
- for (i=0; i<parsed_cseq->number.len; i++ ) {
|
|
|
- c=parsed_cseq->number.s[i];
|
|
|
- if (c>='0' && c<'9' ) cseq=cseq*10+c-'0';
|
|
|
- else {
|
|
|
- fifo_uac_error(response_file, 400, "non-nummerical CSeq");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- }
|
|
|
- if (parsed_cseq->method.len!=method.len
|
|
|
- || memcmp(parsed_cseq->method.s, method.s, method.len)!=0) {
|
|
|
- fifo_uac_error(response_file, 400, "CSeq method mismatch");
|
|
|
- goto error;
|
|
|
- }
|
|
|
- }
|
|
|
+ generate_callid(&callid);
|
|
|
+ generate_fromtag(&fromtag, &callid);
|
|
|
|
|
|
- hfb.s=get_hfblock(outbound.len ? &outbound : &ruri,
|
|
|
- faked_msg.headers, &hfb.len, PROTO_UDP);
|
|
|
- if (!hfb.s) {
|
|
|
- fifo_uac_error(response_file, 500, "no mem for hf block");
|
|
|
- goto error;
|
|
|
+ if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
|
|
|
+ LOG(L_ERR, "req_outside(): Error while creating temorary dialog\n");
|
|
|
+ goto err;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- DBG("DEBUG: fifo_uac: EoL -- proceeding to transaction creation\n");
|
|
|
- /* we got it all, initiate transaction now! */
|
|
|
- if (response_file) {
|
|
|
- fn_len=strlen(response_file)+1;
|
|
|
- shmem_file=shm_malloc(fn_len);
|
|
|
- if (shmem_file==0) {
|
|
|
- fifo_uac_error(response_file, 500, "no shmem");
|
|
|
- goto error01;
|
|
|
- }
|
|
|
- memcpy(shmem_file, response_file, fn_len );
|
|
|
- } else {
|
|
|
- shmem_file=0;
|
|
|
- }
|
|
|
- /* HACK: there is yet a shortcoming -- if t_uac fails, callback
|
|
|
- will not be triggered and no feedback will be printed
|
|
|
- to shmem_file
|
|
|
- */
|
|
|
- dummy_empty.s=0; dummy_empty.len=0;
|
|
|
- ret=t_uac_dlg( &method,
|
|
|
- outbound.len ? &outbound: 0,
|
|
|
- PROTO_UDP,
|
|
|
- &ruri,
|
|
|
- &faked_msg.to->body, /* possibly w/to-tag in it */
|
|
|
- &faked_msg.from->body,
|
|
|
- &dummy_empty, /* if present, to-tag passed in to */
|
|
|
- fromtag ? /* if fromtag present, ... */
|
|
|
- &dummy_empty: /* ... pass it in from ... */
|
|
|
- 0, /* use ephemeral otherwise */
|
|
|
- cseq ? &cseq : 0,
|
|
|
- faked_msg.callid ?
|
|
|
- &faked_msg.callid->body:
|
|
|
- 0,
|
|
|
- &hfb, /* headers -- TBD */
|
|
|
- &body,
|
|
|
- fifo_callback, shmem_file );
|
|
|
-
|
|
|
-
|
|
|
- if (ret<=0) {
|
|
|
- err_ret=err2reason_phrase(ret, &sip_error, err_buf,
|
|
|
- sizeof(err_buf), "FIFO/UAC" ) ;
|
|
|
- if (err_ret > 0 )
|
|
|
- {
|
|
|
-
|
|
|
- fifo_uac_error(response_file, sip_error, err_buf);
|
|
|
- } else {
|
|
|
- fifo_uac_error(response_file, 500, "FIFO/UAC error" );
|
|
|
- }
|
|
|
+ if (ruri) {
|
|
|
+ dialog->rem_target.s = ruri->s;
|
|
|
+ dialog->rem_target.len = ruri->len;
|
|
|
+ dialog->hooks.request_uri = &dialog->rem_target;
|
|
|
}
|
|
|
|
|
|
-error01:
|
|
|
- pkg_free(hfb.s);
|
|
|
+ res = t_uac(m, h, b, dialog, c, cp);
|
|
|
+ free_dlg(dialog);
|
|
|
+ return res;
|
|
|
|
|
|
-error:
|
|
|
- /* free_sip_msg(&faked_msg); */
|
|
|
- if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
|
|
|
- return 1;
|
|
|
+ err:
|
|
|
+ if (cp) shm_free(cp);
|
|
|
+ return -1;
|
|
|
}
|