xmpp.c

Go to the documentation of this file.
00001 /*
00002  * $Id: xmpp.c 5756 2009-03-23 13:06:16Z henningw $
00003  *
00004  * XMPP Module
00005  * This file is part of Kamailio, a free SIP server.
00006  *
00007  * Copyright (C) 2006 Voice Sistem S.R.L.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  * Author: Andreea Spirea
00024  *
00025  */
00026 
00027 /*! \defgroup xmpp XMPP: The SIP/Simple - XMPP integration core 
00028  *  This module implements gateway functionality between SIP and XMPP. 
00029  *
00030  *  This module in parts replace the older \ref jabber module.
00031  */
00032 
00033 /*! \file
00034  * \brief Kamailio XMPP module :: 
00035  *  \ingroup xmpp
00036  *
00037  * \page XMPProuting XMPP to SIP transport interface
00038  *
00039  * An inbound SIP URI:
00040  *   from sip:user1@domain1 to sip:user2*domain2@gateway_domain
00041  * is translated to an XMPP JID:
00042  *   from user1*domain1@xmpp_domain to user2@domain2
00043  *
00044  * An inbound XMPP JID (uri):
00045  *   from user1@domain1 to user2*domain2@xmpp_domain
00046  * is translated to a SIP URI:
00047  *   from sip:user1*domain1@gateway_domain to sip:user2@domain2
00048  *
00049  * Where '*' is the domain_separator, and gateway_domain and
00050  * xmpp_domain are defined below.
00051  *
00052  * 
00053  * 2-way dialback sequence with xmppd2:
00054  *
00055  *  Originating server (us)         Receiving server (them)      Authoritative server (us)
00056  *  -----------------------         -----------------------      -------------------------
00057  *           |                               |                               |
00058  *           |    establish connection       |                               |
00059  *           |------------------------------>|                               |
00060  *           |    send stream header         |                               |
00061  *           |------------------------------>|                               |
00062  *           |    send stream header         |                               |
00063  *           |<------------------------------|                               |
00064  *           |    send db:result request     |                               |
00065  *           |------------------------------>|                               |
00066  *                                           |    establish connection       |
00067  *                                           |------------------------------>|
00068  *                                           |    send stream header         |
00069  *                                           |------------------------------>|
00070  *                                           |    send stream header         |
00071  *                                           |<------------------------------|
00072  *                                           |    send db:result request     |
00073  *                                           |------------------------------>|
00074  *           |    send db:verify request     |
00075  *           |------------------------------>|
00076  *           |    send db:verify response    |
00077  *           |<------------------------------|
00078  *                                           |    send db:result response    |
00079  *                                           |------------------------------>|
00080  *                                           |    send db:verify request     |
00081  *                                           |<------------------------------|
00082  *                                           |    send db:verify response    |
00083  *                                           |------------------------------>|
00084  *           |    send db:result response    |
00085  *           |<------------------------------|
00086  *           :                               :                               :
00087  *           :                               :                               :
00088  *           |    outgoing <message/>        |                               :
00089  *           |------------------------------>|                               :
00090  *                                           |    incoming <message/>        |
00091  *                                           |------------------------------>|
00092  *
00093  * Note: Dialback is an old mechanism that is now replaced by TLS connections
00094  *     in "modern" XMPP servers. With TLS, dialback is not used.
00095  */
00096 
00097 #include <stdio.h>
00098 #include <stdlib.h>
00099 #include <errno.h>
00100 #include <string.h>
00101 
00102 #include "../../sr_module.h"
00103 #include "../../mem/mem.h"
00104 #include "../../data_lump_rpl.h"
00105 #include "../../parser/msg_parser.h"
00106 #include "../../parser/parse_content.h"
00107 #include "../../parser/parse_from.h"
00108 #include "../tm/tm_load.h"
00109 
00110 #include "xode.h"
00111 #include "xmpp.h"
00112 #include "network.h"
00113 #include "xmpp_api.h"
00114 
00115 #include <arpa/inet.h>
00116 
00117 /* XXX hack */
00118 #define DB_KEY "this-be-a-random-key"
00119 
00120 MODULE_VERSION
00121 
00122 struct tm_binds tmb;
00123 
00124 static int  mod_init(void);
00125 static void xmpp_process(int rank);
00126 static int  cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar);
00127 
00128 static int pipe_fds[2] = {-1,-1};
00129 
00130 /*
00131  * Configuration
00132  */
00133 char *backend = "component";
00134 char *domain_sep_str = NULL;
00135 char domain_separator = '*';
00136 char *gateway_domain = "sip2xmpp.example.net";
00137 char *xmpp_domain = "xmpp2sip.example.net";
00138 char *xmpp_host = "xmpp.example.com";
00139 int xmpp_port = 0;
00140 char *xmpp_password = "secret";
00141 str outbound_proxy= {0, 0};
00142 
00143 #define DEFAULT_COMPONENT_PORT 5347
00144 #define DEFAULT_SERVER_PORT 5269
00145 
00146 static proc_export_t procs[] = {
00147    {"XMPP receiver",  0,  0, xmpp_process, 1 },
00148    {0,0,0,0,0}
00149 };
00150 
00151 
00152 /*
00153  * Exported functions
00154  */
00155 static cmd_export_t cmds[] = {
00156    {"xmpp_send_message", (cmd_function)cmd_send_message, 0, 0, 0, REQUEST_ROUTE},
00157    {"bind_xmpp",         (cmd_function)bind_xmpp,        0, 0, 0, 0},
00158    {0, 0, 0, 0, 0, 0}
00159 };
00160 
00161 /*
00162  * Exported parameters
00163  */
00164 static param_export_t params[] = {
00165    { "backend",         STR_PARAM, &backend },
00166    { "domain_separator",   STR_PARAM, &domain_sep_str },
00167    { "gateway_domain",     STR_PARAM, &gateway_domain },
00168    { "xmpp_domain",     STR_PARAM, &xmpp_domain },
00169    { "xmpp_host",       STR_PARAM, &xmpp_host },
00170    { "xmpp_port",       INT_PARAM, &xmpp_port },
00171    { "xmpp_password",      STR_PARAM, &xmpp_password },
00172    { "outbound_proxy",     STR_PARAM, &outbound_proxy.s},
00173    {0, 0, 0}
00174 };
00175 
00176 /*
00177  * Module description
00178  */
00179 struct module_exports exports = {
00180    "xmpp",          /* Module name */
00181    DEFAULT_DLFLAGS, /* dlopen flags */
00182    cmds,            /* Exported functions */
00183    params,          /* Exported parameters */
00184    0,               /* exported statistics */
00185    0,               /* exported MI functions */
00186    0,               /* exported pseudo-variables */
00187    procs,           /* extra processes */
00188    mod_init,        /* Initialization function */
00189    0,               /* Response function */
00190    0,               /* Destroy function */
00191    0,               /* Child init function */
00192 };
00193 
00194 /*
00195  * initialize module
00196  */
00197 static int mod_init(void) {
00198 
00199    if (load_tm_api(&tmb)) {
00200       LM_ERR("failed to load tm API\n");
00201       return -1;
00202    }
00203    
00204    if (strcmp(backend, "component") && strcmp(backend, "server")) {
00205       LM_ERR("invalid backend '%s'\n", backend);
00206       return -1;
00207    }
00208 
00209    if (!xmpp_port) {
00210       if (!strcmp(backend, "component"))
00211          xmpp_port = DEFAULT_COMPONENT_PORT;
00212       else if (!strcmp(backend, "server"))
00213          xmpp_port = DEFAULT_SERVER_PORT;
00214    }
00215 
00216    /* fix up the domain separator -- we only need 1 char */
00217    if (domain_sep_str && *domain_sep_str)
00218       domain_separator = *domain_sep_str;
00219 
00220    if(outbound_proxy.s)
00221       outbound_proxy.len= strlen(outbound_proxy.s);
00222 
00223    if(init_xmpp_cb_list()<0){
00224       LM_ERR("failed to init callback list\n");
00225       return -1;
00226    }
00227 
00228    if (pipe(pipe_fds) < 0) {
00229       LM_ERR("pipe() failed\n");
00230       return -1;
00231    }
00232 
00233    return 0;
00234 }
00235 
00236 
00237 static void xmpp_process(int rank)
00238 {
00239    /* if this blasted server had a decent I/O loop, we'd
00240     * just add our socket to it and connect().
00241     */
00242    close(pipe_fds[1]);
00243 
00244    LM_DBG("started child connection process\n");
00245    if (!strcmp(backend, "component"))
00246       xmpp_component_child_process(pipe_fds[0]);
00247    else if (!strcmp(backend, "server"))
00248       xmpp_server_child_process(pipe_fds[0]);
00249 }
00250 
00251 
00252 /*********************************************************************************/
00253 
00254 /*! \brief Relay a MESSAGE to a SIP client 
00255    \todo This assumes that a message is text/plain, which is not always the case with
00256       XMPP messages. We should propably also set the character set, as all
00257       SIP clients doesn't assume utf8 for text/plain
00258 */
00259 int xmpp_send_sip_msg(char *from, char *to, char *msg)
00260 {
00261    str msg_type = { "MESSAGE", 7 };
00262    str hdr, fromstr, tostr, msgstr;
00263    char buf[512];
00264    
00265    hdr.s = buf;
00266    hdr.len = snprintf(buf, sizeof(buf),
00267          "Content-type: text/plain" CRLF "Contact: %s" CRLF, from);
00268 
00269    fromstr.s = from;
00270    fromstr.len = strlen(from);
00271    tostr.s = to;
00272    tostr.len = strlen(to);
00273    msgstr.s = msg;
00274    msgstr.len = strlen(msg);
00275 
00276    return tmb.t_request(
00277          &msg_type,                 /*!< Type of the message */
00278          0,                   /*!< Request-URI */
00279          &tostr,                    /*!< To */
00280          &fromstr,                  /*!< From */
00281          &hdr,                   /*!< Optional headers */
00282          &msgstr,                /*!< Message body */
00283    (outbound_proxy.s)?&outbound_proxy:NULL,/* Outbound proxy*/
00284          0,                      /*!< Callback function */
00285          0                       /*!< Callback parameter */
00286          );
00287 }
00288 
00289 
00290 /*********************************************************************************/
00291 
00292 static char *shm_strdup(str *src)
00293 {
00294    char *res;
00295 
00296    if (!src || !src->s)
00297       return NULL;
00298    if (!(res = (char *) shm_malloc(src->len + 1)))
00299       return NULL;
00300    strncpy(res, src->s, src->len);
00301    res[src->len] = 0;
00302    return res;
00303 }
00304 
00305 void xmpp_free_pipe_cmd(struct xmpp_pipe_cmd *cmd)
00306 {
00307    if (cmd->from)
00308       shm_free(cmd->from);
00309    if (cmd->to)
00310       shm_free(cmd->to);
00311    if (cmd->body)
00312       shm_free(cmd->body);
00313    if (cmd->id)
00314       shm_free(cmd->id);
00315    shm_free(cmd);
00316 }
00317 
00318 static int xmpp_send_pipe_cmd(enum xmpp_pipe_cmd_type type, str *from, str *to, 
00319       str *body, str *id)
00320 {
00321    struct xmpp_pipe_cmd *cmd;
00322    
00323    /*! \todo: make shm allocation for one big chunk to include all fields */
00324    cmd = (struct xmpp_pipe_cmd *) shm_malloc(sizeof(struct xmpp_pipe_cmd));
00325    memset(cmd, 0, sizeof(struct xmpp_pipe_cmd));
00326 
00327    cmd->type = type;
00328    cmd->from = shm_strdup(from);
00329    cmd->to = shm_strdup(to);
00330    cmd->body = shm_strdup(body);
00331    cmd->id = shm_strdup(id);
00332 
00333    if (write(pipe_fds[1], &cmd, sizeof(cmd)) != sizeof(cmd)) {
00334       LM_ERR("failed to write to command pipe: %s\n", strerror(errno));
00335       xmpp_free_pipe_cmd(cmd);
00336       return -1;
00337    }
00338    return 0;
00339 }
00340 
00341 static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar)
00342 {
00343    str body, from_uri, dst, tagid;
00344    int mime;
00345 
00346    LM_DBG("cmd_send_message\n");
00347    
00348    /* extract body */
00349    if (!(body.s = get_body(msg))) {
00350       LM_ERR("failed to extract body\n");
00351       return -1;
00352    }
00353    if (!msg->content_length) {
00354       LM_ERR("no content-length found\n");
00355       return -1;
00356    }
00357    body.len = get_content_length(msg);
00358    if ((mime = parse_content_type_hdr(msg)) < 1) {
00359       LM_ERR("failed parse content-type\n");
00360       return -1;
00361    }
00362    if (mime != (TYPE_TEXT << 16) + SUBTYPE_PLAIN 
00363          && mime != (TYPE_MESSAGE << 16) + SUBTYPE_CPIM) {
00364       LM_ERR("invalid content-type 0x%x\n", mime);
00365       return -1;
00366    }
00367 
00368    /* extract sender */
00369    if (parse_headers(msg, HDR_TO_F | HDR_FROM_F, 0) == -1 || !msg->to
00370          || !msg->from) {
00371       LM_ERR("no To/From headers\n");
00372       return -1;
00373    }
00374    if (parse_from_header(msg) < 0 || !msg->from->parsed) {
00375       LM_ERR("failed to parse From header\n");
00376       return -1;
00377    }
00378    from_uri = ((struct to_body *) msg->from->parsed)->uri;
00379    tagid = ((struct to_body *) msg->from->parsed)->tag_value;
00380    LM_DBG("message from <%.*s>\n", from_uri.len, from_uri.s);
00381 
00382    /* extract recipient */
00383    dst.len = 0;
00384    if (msg->new_uri.len > 0) {
00385       LM_DBG("using new URI as destination\n");
00386       dst = msg->new_uri;
00387    } else if (msg->first_line.u.request.uri.s 
00388          && msg->first_line.u.request.uri.len > 0) {
00389       LM_DBG("using R-URI as destination\n");
00390       dst = msg->first_line.u.request.uri;
00391    } else if (msg->to->parsed) {
00392       LM_DBG("using TO-URI as destination\n");
00393       dst = ((struct to_body *) msg->to->parsed)->uri;
00394    } else {
00395       LM_ERR("failed to find a valid destination\n");
00396       return -1;
00397    }
00398    
00399    if (!xmpp_send_pipe_cmd(XMPP_PIPE_SEND_MESSAGE, &from_uri, &dst, &body,
00400             &tagid))
00401       return 1;
00402    return -1;
00403 }
00404 
00405 
00406 /*!
00407  *
00408  */
00409 int xmpp_send_xpacket(str *from, str *to, str *msg, str *id)
00410 {
00411    if(from==NULL || to==NULL || msg==NULL || id==NULL)
00412       return -1;
00413    return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PACKET, from, to, msg, id);
00414 }
00415 
00416 /*!
00417  *
00418  */
00419 int xmpp_send_xmessage(str *from, str *to, str *msg, str *id)
00420 {
00421    if(from==NULL || to==NULL || msg==NULL || id==NULL)
00422       return -1;
00423    return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_MESSAGE, from, to, msg, id);
00424 }
00425 
00426 /*!
00427  *
00428  */
00429 int xmpp_send_xsubscribe(str *from, str *to, str *msg, str *id)
00430 {
00431    if(from==NULL || to==NULL || msg==NULL || id==NULL)
00432       return -1;
00433    return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PSUBSCRIBE, from, to, msg, id);
00434 }
00435 
00436 /*!
00437  *
00438  */
00439 int xmpp_send_xnotify(str *from, str *to, str *msg, str *id)
00440 {
00441    if(from==NULL || to==NULL || msg==NULL || id==NULL)
00442       return -1;
00443    return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PNOTIFY, from, to, msg, id);
00444 }
00445 

Generated on Fri May 25 00:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6