xmpp_component.c

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

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