xmpp.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
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 
00109 #include <stdio.h>
00110 #include <stdlib.h>
00111 #include <errno.h>
00112 #include <string.h>
00113 
00114 #include "../../sr_module.h"
00115 #include "../../mem/mem.h"
00116 #include "../../data_lump_rpl.h"
00117 #include "../../parser/msg_parser.h"
00118 #include "../../parser/parse_content.h"
00119 #include "../../parser/parse_from.h"
00120 #include "../../parser/parse_param.h"
00121 #include "../../modules/tm/tm_load.h"
00122 #include "../../cfg/cfg_struct.h"
00123 
00124 #include "xode.h"
00125 #include "xmpp.h"
00126 #include "network.h"
00127 #include "xmpp_api.h"
00128 
00129 #include <arpa/inet.h>
00130 
00131 /* XXX hack */
00132 #define DB_KEY  "this-be-a-random-key"
00133 
00134 MODULE_VERSION
00135 
00136 struct tm_binds tmb;
00137 
00138 static int  mod_init(void);
00139 static int  child_init(int rank);
00140 static void xmpp_process(int rank);
00141 static int  cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar);
00142 
00143 int xmpp_gwmap_param(modparam_t type, void *val);
00144 
00145 static int pipe_fds[2] = {-1,-1};
00146 
00147 /*
00148  * Configuration
00149  */
00150 char *backend = "component";
00151 char *domain_sep_str = NULL;
00152 char domain_separator = '*';
00153 char *gateway_domain = "sip2xmpp.example.net";
00154 char *xmpp_domain = "xmpp2sip.example.net";
00155 char *xmpp_host = "xmpp.example.com";
00156 int xmpp_port = 0;
00157 char *xmpp_password = "secret";
00158 str outbound_proxy= {0, 0};
00159 
00160 param_t *_xmpp_gwmap_list = NULL;
00161 
00162 #define DEFAULT_COMPONENT_PORT 5347
00163 #define DEFAULT_SERVER_PORT 5269
00164 
00165 static proc_export_t procs[] = {
00166         {"XMPP receiver",  0,  0, xmpp_process, 1 },
00167         {0,0,0,0,0}
00168 };
00169 
00170 
00171 /*
00172  * Exported functions
00173  */
00174 static cmd_export_t cmds[] = {
00175         {"xmpp_send_message", (cmd_function)cmd_send_message, 0, 0, 0, REQUEST_ROUTE},
00176         {"bind_xmpp",         (cmd_function)bind_xmpp,        0, 0, 0, 0},
00177         {0, 0, 0, 0, 0, 0}
00178 };
00179 
00180 /*
00181  * Exported parameters
00182  */
00183 static param_export_t params[] = {
00184         { "backend",                    STR_PARAM, &backend },
00185         { "domain_separator",   STR_PARAM, &domain_sep_str },
00186         { "gateway_domain",             STR_PARAM, &gateway_domain },
00187         { "xmpp_domain",                STR_PARAM, &xmpp_domain },
00188         { "xmpp_host",                  STR_PARAM, &xmpp_host },
00189         { "xmpp_port",                  INT_PARAM, &xmpp_port },
00190         { "xmpp_password",              STR_PARAM, &xmpp_password },
00191         { "outbound_proxy",             STR_PARAM, &outbound_proxy.s},
00192         { "gwmap",              STR_PARAM|USE_FUNC_PARAM, (void*)xmpp_gwmap_param},
00193         {0, 0, 0}
00194 };
00195 
00196 /*
00197  * Module description
00198  */
00199 struct module_exports exports = {
00200         "xmpp",          /* Module name */
00201         DEFAULT_DLFLAGS, /* dlopen flags */
00202         cmds,            /* Exported functions */
00203         params,          /* Exported parameters */
00204         0,               /* exported statistics */
00205         0,               /* exported MI functions */
00206         0,               /* exported pseudo-variables */
00207         procs,           /* extra processes */
00208         mod_init,        /* Initialization function */
00209         0,               /* Response function */
00210         0,               /* Destroy function */
00211         child_init,      /* Child init function */
00212 };
00213 
00214 /*
00215  * initialize module
00216  */
00217 static int mod_init(void) {
00218 
00219         if (load_tm_api(&tmb)) {
00220                 LM_ERR("failed to load tm API\n");
00221                 return -1;
00222         }
00223         
00224         if (strcmp(backend, "component") && strcmp(backend, "server")) {
00225                 LM_ERR("invalid backend '%s'\n", backend);
00226                 return -1;
00227         }
00228 
00229         if (!xmpp_port) {
00230                 if (!strcmp(backend, "component"))
00231                         xmpp_port = DEFAULT_COMPONENT_PORT;
00232                 else if (!strcmp(backend, "server"))
00233                         xmpp_port = DEFAULT_SERVER_PORT;
00234         }
00235 
00236         /* fix up the domain separator -- we only need 1 char */
00237         if (domain_sep_str && *domain_sep_str)
00238                 domain_separator = *domain_sep_str;
00239 
00240         if(outbound_proxy.s)
00241                 outbound_proxy.len= strlen(outbound_proxy.s);
00242 
00243         if(init_xmpp_cb_list()<0){
00244                 LM_ERR("failed to init callback list\n");
00245                 return -1;
00246         }
00247 
00248         if (pipe(pipe_fds) < 0) {
00249                 LM_ERR("pipe() failed\n");
00250                 return -1;
00251         }
00252 
00253         /* add space for one extra process */
00254         register_procs(1);
00255         /* add child to update local config framework structures */
00256         cfg_register_child(1);
00257 
00258         return 0;
00259 }
00260 
00264 static int child_init(int rank)
00265 {
00266         int pid;
00267 
00268         if (rank==PROC_MAIN) {
00269                 pid=fork_process(PROC_NOCHLDINIT, "XMPP Manager", 1);
00270                 if (pid<0)
00271                         return -1; /* error */
00272                 if(pid==0){
00273                         /* child */
00274                         /* initialize the config framework */
00275                         if (cfg_child_init())
00276                                 return -1;
00277 
00278                         xmpp_process(1);
00279                 }
00280         }
00281 
00282         return 0;
00283 }
00284 
00285 
00286 static void xmpp_process(int rank)
00287 {
00288         /* if this blasted server had a decent I/O loop, we'd
00289          * just add our socket to it and connect().
00290          */
00291         close(pipe_fds[1]);
00292 
00293         LM_DBG("started child connection process\n");
00294         if (!strcmp(backend, "component"))
00295                 xmpp_component_child_process(pipe_fds[0]);
00296         else if (!strcmp(backend, "server"))
00297                 xmpp_server_child_process(pipe_fds[0]);
00298 }
00299 
00300 
00301 /*********************************************************************************/
00302 
00308 int xmpp_send_sip_msg(char *from, char *to, char *msg)
00309 {
00310         str msg_type = { "MESSAGE", 7 };
00311         str hdr, fromstr, tostr, msgstr;
00312         char buf[512];
00313         uac_req_t uac_r;
00314         
00315         hdr.s = buf;
00316         hdr.len = snprintf(buf, sizeof(buf),
00317                         "Content-type: text/plain" CRLF "Contact: %s" CRLF, from);
00318 
00319         fromstr.s = from;
00320         fromstr.len = strlen(from);
00321         tostr.s = to;
00322         tostr.len = strlen(to);
00323         msgstr.s = msg;
00324         msgstr.len = strlen(msg);
00325 
00326         set_uac_req(&uac_r, &msg_type, &hdr, &msgstr, 0, 0, 0, 0);
00327         return tmb.t_request(
00328                         &uac_r,
00329                         0,                                                      
00330                         &tostr,                                                 
00331                         &fromstr,                                               
00332                         (outbound_proxy.s)?&outbound_proxy:NULL/* Outbound proxy*/
00333                         );
00334 }
00335 
00336 
00337 /*********************************************************************************/
00338 
00339 static char *shm_strdup(str *src)
00340 {
00341         char *res;
00342 
00343         if (!src || !src->s)
00344                 return NULL;
00345         if (!(res = (char *) shm_malloc(src->len + 1)))
00346                 return NULL;
00347         strncpy(res, src->s, src->len);
00348         res[src->len] = 0;
00349         return res;
00350 }
00351 
00352 void xmpp_free_pipe_cmd(struct xmpp_pipe_cmd *cmd)
00353 {
00354         if (cmd->from)
00355                 shm_free(cmd->from);
00356         if (cmd->to)
00357                 shm_free(cmd->to);
00358         if (cmd->body)
00359                 shm_free(cmd->body);
00360         if (cmd->id)
00361                 shm_free(cmd->id);
00362         shm_free(cmd);
00363 }
00364 
00365 static int xmpp_send_pipe_cmd(enum xmpp_pipe_cmd_type type, str *from, str *to, 
00366                 str *body, str *id)
00367 {
00368         struct xmpp_pipe_cmd *cmd;
00369         
00371         cmd = (struct xmpp_pipe_cmd *) shm_malloc(sizeof(struct xmpp_pipe_cmd));
00372         memset(cmd, 0, sizeof(struct xmpp_pipe_cmd));
00373 
00374         cmd->type = type;
00375         cmd->from = shm_strdup(from);
00376         cmd->to = shm_strdup(to);
00377         cmd->body = shm_strdup(body);
00378         cmd->id = shm_strdup(id);
00379 
00380         if (write(pipe_fds[1], &cmd, sizeof(cmd)) != sizeof(cmd)) {
00381                 LM_ERR("failed to write to command pipe: %s\n", strerror(errno));
00382                 xmpp_free_pipe_cmd(cmd);
00383                 return -1;
00384         }
00385         return 0;
00386 }
00387 
00388 static int cmd_send_message(struct sip_msg* msg, char* _foo, char* _bar)
00389 {
00390         str body, from_uri, dst, tagid;
00391         int mime;
00392 
00393         LM_DBG("cmd_send_message\n");
00394         
00395         /* extract body */
00396         if (!(body.s = get_body(msg))) {
00397                 LM_ERR("failed to extract body\n");
00398                 return -1;
00399         }
00400         if (!msg->content_length) {
00401                 LM_ERR("no content-length found\n");
00402                 return -1;
00403         }
00404         body.len = get_content_length(msg);
00405         if ((mime = parse_content_type_hdr(msg)) < 1) {
00406                 LM_ERR("failed parse content-type\n");
00407                 return -1;
00408         }
00409         if (mime != (TYPE_TEXT << 16) + SUBTYPE_PLAIN 
00410                         && mime != (TYPE_MESSAGE << 16) + SUBTYPE_CPIM) {
00411                 LM_ERR("invalid content-type 0x%x\n", mime);
00412                 return -1;
00413         }
00414 
00415         /* extract sender */
00416         if (parse_headers(msg, HDR_TO_F | HDR_FROM_F, 0) == -1 || !msg->to
00417                         || !msg->from) {
00418                 LM_ERR("no To/From headers\n");
00419                 return -1;
00420         }
00421         if (parse_from_header(msg) < 0 || !msg->from->parsed) {
00422                 LM_ERR("failed to parse From header\n");
00423                 return -1;
00424         }
00425         from_uri = ((struct to_body *) msg->from->parsed)->uri;
00426         tagid = ((struct to_body *) msg->from->parsed)->tag_value;
00427         LM_DBG("message from <%.*s>\n", from_uri.len, from_uri.s);
00428 
00429         /* extract recipient */
00430         dst.len = 0;
00431         if (msg->new_uri.len > 0) {
00432                 LM_DBG("using new URI as destination\n");
00433                 dst = msg->new_uri;
00434         } else if (msg->first_line.u.request.uri.s 
00435                         && msg->first_line.u.request.uri.len > 0) {
00436                 LM_DBG("using R-URI as destination\n");
00437                 dst = msg->first_line.u.request.uri;
00438         } else if (msg->to->parsed) {
00439                 LM_DBG("using TO-URI as destination\n");
00440                 dst = ((struct to_body *) msg->to->parsed)->uri;
00441         } else {
00442                 LM_ERR("failed to find a valid destination\n");
00443                 return -1;
00444         }
00445         
00446         if (!xmpp_send_pipe_cmd(XMPP_PIPE_SEND_MESSAGE, &from_uri, &dst, &body,
00447                                 &tagid))
00448                 return 1;
00449         return -1;
00450 }
00451 
00452 
00456 int xmpp_send_xpacket(str *from, str *to, str *msg, str *id)
00457 {
00458         if(from==NULL || to==NULL || msg==NULL || id==NULL)
00459                 return -1;
00460         return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PACKET, from, to, msg, id);
00461 }
00462 
00466 int xmpp_send_xmessage(str *from, str *to, str *msg, str *id)
00467 {
00468         if(from==NULL || to==NULL || msg==NULL || id==NULL)
00469                 return -1;
00470         return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_MESSAGE, from, to, msg, id);
00471 }
00472 
00476 int xmpp_send_xsubscribe(str *from, str *to, str *msg, str *id)
00477 {
00478         if(from==NULL || to==NULL || msg==NULL || id==NULL)
00479                 return -1;
00480         return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PSUBSCRIBE, from, to, msg, id);
00481 }
00482 
00486 int xmpp_send_xnotify(str *from, str *to, str *msg, str *id)
00487 {
00488         if(from==NULL || to==NULL || msg==NULL || id==NULL)
00489                 return -1;
00490         return xmpp_send_pipe_cmd(XMPP_PIPE_SEND_PNOTIFY, from, to, msg, id);
00491 }
00492 
00496 int xmpp_gwmap_param(modparam_t type, void *val)
00497 {
00498         str inv;
00499         param_hooks_t phooks;
00500         param_t *params = NULL;
00501         param_t *it = NULL;
00502 
00503         if(val==NULL)
00504                 return -1;
00505         inv.s = (char*)val;
00506         inv.len = strlen(inv.s);
00507         if(inv.len<=0)
00508                 return -1;
00509 
00510         if(inv.s[inv.len-1]==';')
00511                 inv.len--;
00512         if (parse_params(&inv, CLASS_ANY, &phooks, &params)<0)
00513         {
00514                 LM_ERR("failed parsing params value\n");
00515                 return -1;
00516         }
00517         if(_xmpp_gwmap_list==NULL)
00518         {
00519                 _xmpp_gwmap_list = params;
00520         } else {
00521                 it = _xmpp_gwmap_list;
00522                 while(it->next) it = it->next;
00523                 it->next = params;
00524         }
00525         return 0;
00526 }