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