123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /*
- * $Id$
- *
- * XMPP Module
- * This file is part of Kamailio, a free SIP server.
- *
- * Copyright (C) 2006 Voice Sistem S.R.L.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Andreea Spirea
- *
- */
- /*! \file
- * \brief Kamailio XMPP :: XMPP Component interface support
- * \ingroup xmpp
- */
- /*
- * An inbound SIP message:
- * from sip:user1@domain1 to sip:user2*domain2@gateway_domain
- * is translated to an XMPP message:
- * from user1*domain1@xmpp_domain to user2@domain2
- *
- * An inbound XMPP message:
- * from user1@domain1 to user2*domain2@xmpp_domain
- * is translated to a SIP message:
- * from sip:user1*domain1@gateway_domain to sip:user2@domain2
- *
- * Where '*' is the domain_separator, and gateway_domain and
- * xmpp_domain are defined below.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include "../../sr_module.h"
- #include "../../cfg/cfg_struct.h"
- #include "xmpp.h"
- #include "xmpp_api.h"
- #include "network.h"
- #include "xode.h"
- struct xmpp_private_data {
- int fd; /* socket */
- int running;
- };
- static int xode_send(int fd, xode x)
- {
- char *str = xode_to_str(x);
- int len = strlen(str);
-
- LM_DBG("xode_send [%s]\n", str);
- if (net_send(fd, str, len) != len) {
- LM_ERR("send() error: %s\n", strerror(errno));
- return -1;
- }
- /* should str be freed?!?! */
- return len;
- }
- static void stream_node_callback(int type, xode node, void *arg)
- {
- struct xmpp_private_data *priv = (struct xmpp_private_data *) arg;
- char *id, *hash, *tag;
- char buf[4096];
- xode x;
- LM_DBG("stream callback: %d: %s\n", type, node ? xode_get_name(node) : "n/a");
- switch (type) {
- case XODE_STREAM_ROOT:
- id = xode_get_attrib(node, "id");
- snprintf(buf, sizeof(buf), "%s%s", id, xmpp_password);
- hash = shahash(buf);
-
- x = xode_new_tag("handshake");
- xode_insert_cdata(x, hash, -1);
- xode_send(priv->fd, x);
- xode_free(x);
- break;
- case XODE_STREAM_NODE:
- tag = xode_get_name(node);
- if (!strcmp(tag, "handshake")) {
- LM_DBG("handshake succeeded\n");
- } else if (!strcmp(tag, "message")) {
- LM_DBG("XMPP IM received\n");
- char *from = xode_get_attrib(node, "from");
- char *to = xode_get_attrib(node, "to");
- char *type = xode_get_attrib(node, "type");
- xode body = xode_get_tag(node, "body");
- char *msg;
-
- if (!type)
- type = "chat";
- if (!strcmp(type, "error")) {
- LM_DBG("received message error stanza\n");
- goto out;
- }
-
- if (!from || !to || !body) {
- LM_DBG("invalid <message/> attributes\n");
- goto out;
- }
- if (!(msg = xode_get_data(body)))
- msg = "";
- xmpp_send_sip_msg(
- encode_uri_xmpp_sip(from),
- decode_uri_xmpp_sip(to),
- msg);
- } else if (!strcmp(tag, "presence")) {
- /* call presence callbacks */
- LM_DBG("XMPP Presence received\n");
- run_xmpp_callbacks(XMPP_RCV_PRESENCE, xode_to_str(node));
- }else if (!strcmp(tag, "iq")) {
- /* call presence callbacks */
- LM_DBG("XMPP IQ received\n");
- run_xmpp_callbacks(XMPP_RCV_IQ, xode_to_str(node));
- }
- break;
- case XODE_STREAM_ERROR:
- LM_ERR("stream error\n");
- /* fall-through */
- case XODE_STREAM_CLOSE:
- priv->running = 0;
- break;
- }
- out:
- xode_free(node);
- }
- /*!
- *
- */
- static int do_send_message_component(struct xmpp_private_data *priv,
- struct xmpp_pipe_cmd *cmd)
- {
- xode x;
- LM_DBG("do_send_message_component from=[%s] to=[%s] body=[%s]\n",
- cmd->from, cmd->to, cmd->body);
- x = xode_new_tag("message");
- xode_put_attrib(x, "id", cmd->id); // XXX
- xode_put_attrib(x, "from", encode_uri_sip_xmpp(cmd->from));
- xode_put_attrib(x, "to", decode_uri_sip_xmpp(cmd->to));
- xode_put_attrib(x, "type", "chat");
- xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1);
-
- xode_send(priv->fd, x);
- xode_free(x);
- /* missing error handling here ?!?!*/
- return 0;
- }
- static int do_send_bulk_message_component(struct xmpp_private_data *priv,
- struct xmpp_pipe_cmd *cmd)
- {
- int len;
- LM_DBG("do_send_bulk_message_component from=[%s] to=[%s] body=[%s]\n",
- cmd->from, cmd->to, cmd->body);
- len = strlen(cmd->body);
- if (net_send(priv->fd, cmd->body, len) != len) {
- LM_ERR("do_send_bulk_message_component: %s\n",strerror(errno));
- return -1;
- }
- return 0;
- }
- int xmpp_component_child_process(int data_pipe)
- {
- int fd, maxfd, rv;
- fd_set fdset;
- xode_pool pool;
- xode_stream stream;
- struct xmpp_private_data priv;
- struct xmpp_pipe_cmd *cmd;
-
- while (1) {
- fd = net_connect(xmpp_host, xmpp_port);
- if (fd < 0) {
- sleep(3);
- continue;
- }
-
- priv.fd = fd;
- priv.running = 1;
-
- pool = xode_pool_new();
- stream = xode_stream_new(pool, stream_node_callback, &priv);
-
- net_printf(fd,
- "<?xml version='1.0'?>"
- "<stream:stream xmlns='jabber:component:accept' to='%s' "
- "version='1.0' xmlns:stream='http://etherx.jabber.org/streams'>",
- xmpp_domain);
-
- while (priv.running) {
- FD_ZERO(&fdset);
- FD_SET(data_pipe, &fdset);
- FD_SET(fd, &fdset);
- maxfd = fd > data_pipe ? fd : data_pipe;
- rv = select(maxfd + 1, &fdset, NULL, NULL, NULL);
-
- /* update the local config framework structures */
- cfg_update();
- if (rv < 0) {
- LM_ERR("select() failed: %s\n", strerror(errno));
- } else if (!rv) {
- /* timeout */
- } else if (FD_ISSET(fd, &fdset)) {
- char *buf = net_read_static(fd);
- if (!buf)
- /* connection closed */
- break;
- LM_DBG("server read\n[%s]\n", buf);
- xode_stream_eat(stream, buf, strlen(buf));
- } else if (FD_ISSET(data_pipe, &fdset)) {
- if (read(data_pipe, &cmd, sizeof(cmd)) != sizeof(cmd)) {
- LM_ERR("failed to read from command pipe: %s\n",
- strerror(errno));
- } else {
- LM_DBG("got pipe cmd %d\n", cmd->type);
- switch (cmd->type) {
- case XMPP_PIPE_SEND_MESSAGE:
- do_send_message_component(&priv, cmd);
- break;
- case XMPP_PIPE_SEND_PACKET:
- case XMPP_PIPE_SEND_PSUBSCRIBE:
- case XMPP_PIPE_SEND_PNOTIFY:
- do_send_bulk_message_component(&priv, cmd);
- break;
- }
- xmpp_free_pipe_cmd(cmd);
- }
- }
- }
-
- xode_pool_free(pool);
-
- close(fd);
- }
- return 0;
- }
|