00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 #include <stdio.h>
00089 #include <stdlib.h>
00090 #include <errno.h>
00091 #include <string.h>
00092
00093 #include "../../sr_module.h"
00094 #include "../../cfg/cfg_struct.h"
00095
00096 #include "xmpp.h"
00097 #include "xmpp_api.h"
00098 #include "network.h"
00099 #include "xode.h"
00100
00101 #include <arpa/inet.h>
00102
00103
00104 #define DB_KEY "this-be-a-random-key"
00105
00106 #define CONN_DEAD 0
00107 #define CONN_INBOUND 1
00108 #define CONN_OUTBOUND 2
00109
00110 struct xmpp_private_data {
00111 int fd;
00112 int listen_fd;
00113 int in_fd;
00114 int running;
00115 };
00116
00117 struct xmpp_connection {
00118 struct xmpp_connection *next;
00119
00120 char *domain;
00121 int type;
00122 int fd;
00123 char *stream_id;
00124 xode_pool pool;
00125 xode_stream stream;
00126 xode todo;
00127 };
00128
00129 static char local_secret[64] = { 0, };
00130
00131 static void in_stream_node_callback(int type, xode node, void *arg);
00132 static void out_stream_node_callback(int type, xode node, void *arg);
00133
00134 static struct xmpp_connection *conn_list = NULL;
00135
00136 static struct xmpp_connection *conn_new(int type, int fd, char *domain)
00137 {
00138 struct xmpp_connection *conn = NULL;
00139
00140 conn = malloc(sizeof(struct xmpp_connection));
00141
00142 if(conn==NULL)
00143 {
00144 LM_ERR("out of memory\n");
00145 return NULL;
00146 }
00147
00148 memset(conn, 0, sizeof(struct xmpp_connection));
00149 conn->domain = domain ? strdup(domain) : NULL;
00150 conn->type = type;
00151 conn->fd = fd;
00152 conn->todo = xode_new_tag("todo");
00153
00154 conn->pool = xode_pool_new();
00155 conn->stream = xode_stream_new(conn->pool,
00156 (type==CONN_INBOUND)?in_stream_node_callback:out_stream_node_callback,
00157 conn);
00158
00159 conn->next = conn_list;
00160 conn_list = conn;
00161 return conn;
00162 }
00163
00164 static void conn_free(struct xmpp_connection *conn)
00165 {
00166 struct xmpp_connection **last_p, *link;
00167
00168 last_p = &conn_list;
00169 for (link = conn_list; link; link = link->next) {
00170 if (link == conn) {
00171 *last_p = link->next;
00172 break;
00173 }
00174 last_p = &link->next;
00175 }
00176
00177 if (conn->todo)
00178 xode_free(conn->todo);
00179 xode_pool_free(conn->pool);
00180 if (conn->fd != -1)
00181 close(conn->fd);
00182 if (conn->stream_id)
00183 free(conn->stream_id);
00184 if (conn->domain)
00185 free(conn->domain);
00186 free(conn);
00187 }
00188
00189 static struct xmpp_connection *conn_find_domain(char *domain, int type)
00190 {
00191 struct xmpp_connection *conn;
00192
00193 for (conn = conn_list; conn; conn = conn->next)
00194 if (conn->domain && !strcasecmp(conn->domain, domain)
00195 && conn->type == type)
00196 return conn;
00197 return NULL;
00198 }
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 static int xode_send(int fd, xode x)
00215 {
00216 char *str = xode_to_str(x);
00217 int len = strlen(str);
00218
00219 LM_DBG("xode_send->%d [%s]\n", fd, str);
00220
00221 if (net_send(fd, str, len) != len) {
00222 LM_ERR("send() failed: %s\n", strerror(errno));
00223 return -1;
00224 }
00225 return len;
00226 }
00227
00228 static int xode_send_domain(char *domain, xode x)
00229 {
00230 struct xmpp_connection *conn;
00231
00232 if ((conn = conn_find_domain(domain, CONN_OUTBOUND))) {
00233 xode_send(conn->fd, x);
00234 xode_free(x);
00235 } else {
00236 if((conn = conn_new(CONN_OUTBOUND, -1, domain))==0)
00237 return -1;
00238 xode_insert_node(conn->todo, x);
00239 }
00240 return 1;
00241 }
00242
00243 static void out_stream_node_callback(int type, xode node, void *arg)
00244 {
00245 struct xmpp_connection *conn = (struct xmpp_connection *) arg;
00246 struct xmpp_connection *in_conn = NULL;
00247 char *tag;
00248 xode x;
00249
00250 LM_DBG("outstream callback: %d: %s\n", type,
00251 node?xode_get_name(node):"n/a");
00252
00253 if (conn->domain)
00254 in_conn = conn_find_domain(conn->domain, CONN_INBOUND);
00255
00256 switch (type) {
00257 case XODE_STREAM_ROOT:
00258 x = xode_new_tag("db:result");
00259 xode_put_attrib(x, "xmlns:db", "jabber:server:dialback");
00260 xode_put_attrib(x, "from", xmpp_domain);
00261 xode_put_attrib(x, "to", conn->domain);
00262
00263 xode_insert_cdata(x, db_key(local_secret, conn->domain,
00264 xode_get_attrib(node, "id")), -1);
00265 xode_send(conn->fd, x);
00266 xode_free(x);
00267
00268 break;
00269 case XODE_STREAM_NODE:
00270 tag = xode_get_name(node);
00271
00272 if (!strcmp(tag, "db:verify")) {
00273 char *from = xode_get_attrib(node, "from");
00274 char *to = xode_get_attrib(node, "to");
00275 char *id = xode_get_attrib(node, "id");
00276 char *type = xode_get_attrib(node, "type");
00277
00278
00279 if (!strcmp(type, "valid") || !strcmp(type, "invalid")) {
00280
00281 x = xode_new_tag("db:result");
00282 xode_put_attrib(x, "xmlns:db", "jabber:server:dialback");
00283 xode_put_attrib(x, "from", to);
00284 xode_put_attrib(x, "to", from);
00285 xode_put_attrib(x, "id", id);
00286 xode_put_attrib(x, "type", type);
00287 if (in_conn)
00288 xode_send(in_conn->fd, x);
00289 else
00290 LM_ERR("need to send reply to domain '%s', but no inbound"
00291 " connection found\n", from);
00292 xode_free(x);
00293 }
00294 } else if (!strcmp(tag, "db:result")) {
00295 char *type = xode_get_attrib(node, "type");
00296
00297 if (type && !strcmp(type, "valid")) {
00298
00299
00300 for (x = xode_get_firstchild(conn->todo); x;
00301 x = xode_get_nextsibling(x)) {
00302 LM_DBG("sending todo tag '%s'\n", xode_get_name(x));
00303 xode_send(conn->fd, x);
00304 }
00305 xode_free(conn->todo);
00306 conn->todo = NULL;
00307 }
00308 }
00309 break;
00310 case XODE_STREAM_ERROR:
00311 LM_ERR("outstream error\n");
00312
00313 case XODE_STREAM_CLOSE:
00314 conn->type = CONN_DEAD;
00315 break;
00316 }
00317 xode_free(node);
00318 }
00319
00320 static void in_stream_node_callback(int type, xode node, void *arg)
00321 {
00322 struct xmpp_connection *conn = (struct xmpp_connection *) arg;
00323 char *tag;
00324 xode x;
00325
00326 LM_DBG("instream callback: %d: %s\n",
00327 type, node ? xode_get_name(node) : "n/a");
00328 switch (type) {
00329 case XODE_STREAM_ROOT:
00330 conn->stream_id = strdup(random_secret());
00331 net_printf(conn->fd,
00332 "<?xml version='1.0'?>"
00333 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' version='1.0'"
00334 " xmlns:db='jabber:server:dialback' id='%s' from='%s'>", conn->stream_id, xmpp_domain);
00335 net_printf(conn->fd,"<stream:features xmlns:stream='http://etherx.jabber.org/streams'/>");
00336 break;
00337 case XODE_STREAM_NODE:
00338 tag = xode_get_name(node);
00339
00340 if (!strcmp(tag, "db:result")) {
00341 char *from = xode_get_attrib(node, "from");
00342 char *to = xode_get_attrib(node, "to");
00343
00344 char *type = xode_get_attrib(node, "type");
00345 char *cdata = xode_get_data(node);
00346
00347 if (!type) {
00348 if (conn->domain) {
00349 LM_DBG("connection %d has old domain '%s'\n",conn->fd,
00350 conn->domain);
00351 free(conn->domain);
00352 }
00353 conn->domain = strdup(from);
00354 LM_DBG("connection %d set domain '%s'\n",
00355 conn->fd, conn->domain);
00356
00357
00358 x = xode_new_tag("db:verify");
00359 xode_put_attrib(x, "xmlns:db", "jabber:server:dialback");
00360 xode_put_attrib(x, "from", to);
00361 xode_put_attrib(x, "to", from);
00362
00363 xode_put_attrib(x, "id", conn->stream_id);
00364 xode_insert_cdata(x, cdata, -1);
00365 xode_send_domain(from, x);
00366 }
00367 } else if (!strcmp(tag, "db:verify")) {
00368 char *from = xode_get_attrib(node, "from");
00369 char *to = xode_get_attrib(node, "to");
00370 char *id = xode_get_attrib(node, "id");
00371 char *type = xode_get_attrib(node, "type");
00372 char *cdata = xode_get_data(node);
00373
00374 if (!type) {
00375
00376 x = xode_new_tag("db:verify");
00377 xode_put_attrib(x, "xmlns:db", "jabber:server:dialback");
00378 xode_put_attrib(x, "from", to);
00379 xode_put_attrib(x, "to", from);
00380 xode_put_attrib(x, "id", id);
00381
00382 if (cdata && !strcmp(cdata, db_key(local_secret, from, id))) {
00383 xode_put_attrib(x, "type", "valid");
00384 } else {
00385 xode_put_attrib(x, "type", "invalid");
00386 }
00387 xode_send(conn->fd, x);
00388 xode_free(x);
00389 }
00390 } else if (!strcmp(tag, "message")) {
00391 char *from = xode_get_attrib(node, "from");
00392 char *to = xode_get_attrib(node, "to");
00393 char *type = xode_get_attrib(node, "type");
00394 xode body = xode_get_tag(node, "body");
00395 char *msg;
00396
00397 if (!type)
00398 type = "chat";
00399 if (!strcmp(type, "error")) {
00400 LM_DBG("received message error stanza\n");
00401 goto out;
00402 }
00403
00404 if (!from || !to || !body) {
00405 LM_DBG("invalid <message/> attributes\n");
00406 goto out;
00407 }
00408
00409 if (!(msg = xode_get_data(body)))
00410 msg = "";
00411 xmpp_send_sip_msg(
00412 encode_uri_xmpp_sip(from),
00413 decode_uri_xmpp_sip(to),
00414 msg);
00415 } else if (!strcmp(tag, "presence")) {
00416
00417 }
00418 break;
00419
00420 break;
00421 case XODE_STREAM_ERROR:
00422 LM_ERR("instream error\n");
00423
00424 case XODE_STREAM_CLOSE:
00425 conn->type = CONN_DEAD;
00426 break;
00427 }
00428 out:
00429 xode_free(node);
00430 }
00431
00432 static void do_send_message_server(struct xmpp_pipe_cmd *cmd)
00433 {
00434 char *domain;
00435 xode x;
00436
00437 LM_DBG("rom=[%s] to=[%s] body=[%s]\n", cmd->from,cmd->to, cmd->body);
00438
00439 x = xode_new_tag("message");
00440 xode_put_attrib(x, "xmlns", "jabber:client");
00441 xode_put_attrib(x, "id", cmd->id);
00442 xode_put_attrib(x, "from", encode_uri_sip_xmpp(cmd->from));
00443 xode_put_attrib(x, "to", decode_uri_sip_xmpp(cmd->to));
00444 xode_put_attrib(x, "type", "chat");
00445 xode_insert_cdata(xode_insert_tag(x, "body"), cmd->body, -1);
00446
00447 domain = extract_domain(decode_uri_sip_xmpp(cmd->to));
00448 xode_send_domain(domain, x);
00449 }
00450
00451 int xmpp_server_child_process(int data_pipe)
00452 {
00453 int rv;
00454 int listen_fd;
00455 fd_set fdset;
00456 struct xmpp_connection *conn;
00457
00458 snprintf(local_secret, sizeof(local_secret), "%s", random_secret());
00459
00460 while ((listen_fd = net_listen(xmpp_domain, xmpp_port)) < 0) {
00461
00462 sleep(3);
00463 }
00464
00465 while (1) {
00466 FD_ZERO(&fdset);
00467 FD_SET(data_pipe, &fdset);
00468 FD_SET(listen_fd, &fdset);
00469
00470
00471 for (conn = conn_list; conn; ) {
00472 struct xmpp_connection *next = conn->next;
00473
00474 if (conn->type == CONN_DEAD)
00475 conn_free(conn);
00476 conn = next;
00477 }
00478
00479 for (conn = conn_list; conn; conn = conn->next) {
00480
00481 if (conn->type == CONN_OUTBOUND && conn->fd == -1) {
00482 if ((conn->fd = net_connect(conn->domain, xmpp_port)) >= 0)
00483 {
00484 net_printf(conn->fd,
00485 "<?xml version='1.0'?>"
00486 "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:server' version='1.0' "
00487 "xmlns:db='jabber:server:dialback' to='%s' from='%s'>",
00488 conn->domain, xmpp_domain);
00489 net_printf(conn->fd,
00490 "<stream:features xmlns:stream='http://etherx.jabber.org/streams'/>");
00491 } else {
00492 conn->type = CONN_DEAD;
00493 }
00494 }
00495
00496 if (conn->fd != -1)
00497 FD_SET(conn->fd, &fdset);
00498 }
00499
00500 rv = select(FD_SETSIZE, &fdset, NULL, NULL, NULL);
00501
00502
00503 cfg_update();
00504
00505 if (rv < 0) {
00506 LM_ERR("select() failed: %s\n", strerror(errno));
00507 } else if (!rv) {
00508
00509 } else {
00510 for (conn = conn_list; conn; conn = conn->next) {
00511 if (conn->fd != -1 && FD_ISSET(conn->fd, &fdset)) {
00512 char *buf = net_read_static(conn->fd);
00513 if (!buf) {
00514 conn->type = CONN_DEAD;
00515 } else {
00516 LM_DBG("stream (fd %d, domain '%s') read\n[%s]\n",
00517 conn->fd, conn->domain, buf);
00518 xode_stream_eat(conn->stream, buf, strlen(buf));
00519 }
00520 }
00521 }
00522
00523 if (FD_ISSET(listen_fd, &fdset)) {
00524 struct sockaddr_in sin;
00525 unsigned int len = sizeof(sin);
00526 int fd;
00527
00528 if ((fd = accept(listen_fd,(struct sockaddr*)&sin, &len))<0) {
00529 LM_ERR("accept() failed: %s\n", strerror(errno));
00530 } else {
00531 LM_DBG("accept()ed connection from %s:%d\n",
00532 inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
00533 conn_new(CONN_INBOUND, fd, NULL);
00534 }
00535 }
00536
00537 if (FD_ISSET(data_pipe, &fdset)) {
00538 struct xmpp_pipe_cmd *cmd;
00539
00540 if (read(data_pipe, &cmd, sizeof(cmd)) != sizeof(cmd)) {
00541 LM_ERR("failed to read from command pipe: %s\n",
00542 strerror(errno));
00543 } else {
00544 LM_DBG("got pipe cmd %d\n", cmd->type);
00545 switch (cmd->type) {
00546 case XMPP_PIPE_SEND_MESSAGE:
00547 do_send_message_server(cmd);
00548 break;
00549 case XMPP_PIPE_SEND_PACKET:
00550 case XMPP_PIPE_SEND_PSUBSCRIBE:
00551 case XMPP_PIPE_SEND_PNOTIFY:
00552 break;
00553 }
00554 xmpp_free_pipe_cmd(cmd);
00555 }
00556 }
00557 }
00558 }
00559 return 0;
00560 }
00561