xmpp_component.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  */
00031 /*
00032  * An inbound SIP message:
00033  *   from sip:user1@domain1 to sip:user2*domain2@gateway_domain
00034  * is translated to an XMPP message:
00035  *   from user1*domain1@xmpp_domain to user2@domain2
00036  *
00037  * An inbound XMPP message:
00038  *   from user1@domain1 to user2*domain2@xmpp_domain
00039  * is translated to a SIP message:
00040  *   from sip:user1*domain1@gateway_domain to sip:user2@domain2
00041  *
00042  * Where '*' is the domain_separator, and gateway_domain and
00043  * xmpp_domain are defined below.
00044  */
00045 
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <errno.h>
00049 #include <string.h>
00050 
00051 #include "../../sr_module.h"
00052 #include "../../cfg/cfg_struct.h"
00053 
00054 #include "xmpp.h"
00055 #include "xmpp_api.h"
00056 #include "network.h"
00057 #include "xode.h"
00058 
00059 struct xmpp_private_data {
00060         int fd;         /* socket */
00061         int running;
00062 };
00063 
00064 static int xode_send(int fd, xode x)
00065 {
00066         char *str = xode_to_str(x);
00067         int len = strlen(str);
00068         
00069         LM_DBG("xode_send [%s]\n", str);
00070 
00071         if (net_send(fd, str, len) != len) {
00072                 LM_ERR("send() error: %s\n", strerror(errno));
00073                 return -1;
00074         }
00075         /* should str be freed?!?! */
00076         return len;
00077 }
00078 
00079 static void stream_node_callback(int type, xode node, void *arg) 
00080 {
00081         struct xmpp_private_data *priv = (struct xmpp_private_data *) arg;
00082         char *id, *hash, *tag;
00083         char buf[4096];
00084         xode x;
00085 
00086         LM_DBG("stream callback: %d: %s\n", type, node ? xode_get_name(node) : "n/a");
00087         switch (type) {
00088         case XODE_STREAM_ROOT:
00089                 id = xode_get_attrib(node, "id");
00090                 snprintf(buf, sizeof(buf), "%s%s", id, xmpp_password);
00091                 hash = shahash(buf);
00092                 
00093                 x = xode_new_tag("handshake");
00094                 xode_insert_cdata(x, hash, -1);
00095                 xode_send(priv->fd, x);
00096                 xode_free(x);
00097                 break;
00098         case XODE_STREAM_NODE:
00099                 tag = xode_get_name(node);
00100                 if (!strcmp(tag, "handshake")) {
00101                         LM_DBG("handshake succeeded\n");
00102                 } else if (!strcmp(tag, "message")) {
00103                         LM_DBG("XMPP IM received\n");
00104                         char *from = xode_get_attrib(node, "from");
00105                         char *to = xode_get_attrib(node, "to");
00106                         char *type = xode_get_attrib(node, "type");
00107                         xode body = xode_get_tag(node, "body");
00108                         char *msg;
00109                         
00110                         if (!type)
00111                                 type = "chat";
00112                         if (!strcmp(type, "error")) {   
00113                                 LM_DBG("received message error stanza\n");
00114                                 goto out;
00115                         }
00116                         
00117                         if (!from || !to || !body) {
00118                                 LM_DBG("invalid <message/> attributes\n");
00119                                 goto out;
00120                         }
00121 
00122                         if (!(msg = xode_get_data(body)))
00123                                 msg = "";
00124                         xmpp_send_sip_msg(
00125                                 encode_uri_xmpp_sip(from),
00126                                 decode_uri_xmpp_sip(to),
00127                                 msg);
00128                 } else if (!strcmp(tag, "presence")) {
00129                         /* call presence callbacks */
00130                         LM_DBG("XMPP Presence received\n");
00131                         run_xmpp_callbacks(XMPP_RCV_PRESENCE, xode_to_str(node));
00132                 }else if (!strcmp(tag, "iq")) {
00133                         /* call presence callbacks */
00134                         LM_DBG("XMPP IQ received\n");
00135                         run_xmpp_callbacks(XMPP_RCV_IQ, xode_to_str(node));
00136                 }
00137                 break;
00138         case XODE_STREAM_ERROR:
00139                 LM_ERR("stream error\n");
00140                 /* fall-through */
00141         case XODE_STREAM_CLOSE:
00142                 priv->running = 0;
00143                 break;
00144         }
00145 out:
00146         xode_free(node);
00147 }
00148 
00152 static int do_send_message_component(struct xmpp_private_data *priv,
00153                 struct xmpp_pipe_cmd *cmd)
00154 {
00155         xode x;
00156 
00157         LM_DBG("do_send_message_component from=[%s] to=[%s] body=[%s]\n",
00158                         cmd->from, cmd->to, cmd->body);
00159 
00160         x = xode_new_tag("message");
00161         xode_put_attrib(x, "id", cmd->id); // XXX
00162         xode_put_attrib(x, "from", encode_uri_sip_xmpp(cmd->from));
00163         xode_put_attrib(x, "to", decode_uri_sip_xmpp(cmd->to));
00164         xode_put_attrib(x, "type", "chat");
00165         xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1);
00166                         
00167         xode_send(priv->fd, x);
00168         xode_free(x);
00169 
00170         /* missing error handling here ?!?!*/
00171         return 0;
00172 }
00173 
00174 static int do_send_bulk_message_component(struct xmpp_private_data *priv,
00175                 struct xmpp_pipe_cmd *cmd)
00176 {
00177         int len;
00178 
00179         LM_DBG("do_send_bulk_message_component from=[%s] to=[%s] body=[%s]\n",
00180                         cmd->from, cmd->to, cmd->body);
00181         len = strlen(cmd->body);
00182         if (net_send(priv->fd, cmd->body, len) != len) {
00183                 LM_ERR("do_send_bulk_message_component: %s\n",strerror(errno));
00184                 return -1;
00185         }
00186         return 0;
00187 }
00188 
00189 
00190 int xmpp_component_child_process(int data_pipe)
00191 {
00192         int fd, maxfd, rv;
00193         fd_set fdset;
00194         xode_pool pool;
00195         xode_stream stream;
00196         struct xmpp_private_data priv;
00197         struct xmpp_pipe_cmd *cmd;
00198         
00199         while (1) {
00200                 fd = net_connect(xmpp_host, xmpp_port);
00201                 if (fd < 0) {
00202                         sleep(3);
00203                         continue;
00204                 }
00205                 
00206                 priv.fd = fd;
00207                 priv.running = 1;
00208                 
00209                 pool = xode_pool_new();
00210                 stream = xode_stream_new(pool, stream_node_callback, &priv);
00211                 
00212                 net_printf(fd,
00213                         "<?xml version='1.0'?>"
00214                         "<stream:stream xmlns='jabber:component:accept' to='%s' "
00215                         "version='1.0' xmlns:stream='http://etherx.jabber.org/streams'>",
00216                         xmpp_domain);
00217                 
00218                 while (priv.running) {
00219                         FD_ZERO(&fdset);
00220                         FD_SET(data_pipe, &fdset);
00221                         FD_SET(fd, &fdset);
00222                         maxfd = fd > data_pipe ? fd : data_pipe;
00223                         rv = select(maxfd + 1, &fdset, NULL, NULL, NULL);
00224                         
00225                         /* update the local config framework structures */
00226                         cfg_update();
00227 
00228                         if (rv < 0) {
00229                                 LM_ERR("select() failed: %s\n", strerror(errno));
00230                         } else if (!rv) {
00231                                 /* timeout */
00232                         } else if (FD_ISSET(fd, &fdset)) {
00233                                 char *buf = net_read_static(fd);
00234 
00235                                 if (!buf)
00236                                         /* connection closed */
00237                                         break;
00238 
00239                                 LM_DBG("server read\n[%s]\n", buf);
00240                                 xode_stream_eat(stream, buf, strlen(buf));
00241                         } else if (FD_ISSET(data_pipe, &fdset)) {
00242                                 if (read(data_pipe, &cmd, sizeof(cmd)) != sizeof(cmd)) {
00243                                         LM_ERR("failed to read from command pipe: %s\n",
00244                                                         strerror(errno));
00245                                 } else {
00246                                         LM_DBG("got pipe cmd %d\n", cmd->type);
00247                                         switch (cmd->type) {
00248                                         case XMPP_PIPE_SEND_MESSAGE:
00249                                                 do_send_message_component(&priv, cmd);
00250                                                 break;
00251                                         case XMPP_PIPE_SEND_PACKET:
00252                                         case XMPP_PIPE_SEND_PSUBSCRIBE:
00253                                         case XMPP_PIPE_SEND_PNOTIFY:
00254                                                 do_send_bulk_message_component(&priv, cmd);
00255                                                 break;
00256                                         }
00257                                         xmpp_free_pipe_cmd(cmd);
00258                                 }
00259                         }
00260                 }
00261                 
00262                 xode_pool_free(pool);
00263                 
00264                 close(fd);
00265         }
00266         return 0;
00267 }
00268