2 Copyright (C) 2005 Georgia Public Library Service
3 Bill Erickson <billserickson@gmail.com>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
21 #include "opensrf/utils.h"
22 #include "opensrf/osrf_hash.h"
23 #include "opensrf/osrf_list.h"
24 #include "opensrf/log.h"
25 #include "opensrf/xml_utils.h"
26 #include "opensrf/socket_bundle.h"
27 #include "opensrf/sha.h"
28 #include "opensrf/transport_message.h"
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libxml/globals.h>
34 #include <libxml/xmlerror.h>
36 #include "osrf_chat.h"
38 /* client to server XML */
39 #define OSRF_CHAT_START_STREAM "<?xml version='1.0'?><stream:stream "\
40 "xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' "\
41 "from='%s' version='1.0' id='%s'>"
43 #define OSRF_CHAT_PARSE_ERROR "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
44 "version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'>"\
45 "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>" \
46 "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax " \
47 "error</text></stream:error></stream:stream>"
49 #define OSRF_CHAT_LOGIN_OK "<iq xmlns='jabber:client' id='0123456789' type='result'/>"
51 #define OSRF_CHAT_NO_RECIPIENT "<message xmlns='jabber:client' type='error' from='%s' to='%s'>"\
52 "<error type='cancel' code='404'><item-not-found " \
53 "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"\
54 "</error><body>NOT ADDING BODY</body></message>"
56 /* ---------------------------------------------------------------------------------- */
57 /* server to server XML */
59 // client to server init
60 #define OSRF_CHAT_S2S_INIT "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
61 "xmlns='jabber:server' xmlns:db='jabber:server:dialback'>"
63 // server to client challenge
64 #define OSRF_CHAT_S2S_CHALLENGE "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
65 "xmlns='jabber:server' id='%s' xmlns:db='jabber:server:dialback'>"
67 // client to server challenge response
68 #define OSRF_CHAT_S2S_RESPONSE "<db:result xmlns:db='jabber:server:dialback' to='%s' from='%s'>%s</db:result>"
70 // server to client verify
71 #define OSRF_CHAT_S2S_VERIFY_REQUEST \
72 "<db:verify xmlns:db='jabber:server:dialback' id='%s' from='%s' to='%s'>%s</db:verify>"
74 // client to server verify response
75 #define OSRF_CHAT_S2S_VERIFY_RESPONSE \
76 "<db:verify xmlns:db='jabber:server:dialback' type='valid' to='%s' from='%s' id='%s'/>"
78 //server to client final verification
79 #define OSRF_CHAT_S2S_VERIFY_FINAL \
80 "<db:result xmlns:db='jabber:server:dialback' type='valid' from='%s' to ='%s'/>"
83 #define OSRF_CHAT_STATE_NONE 0 /* blank node */
84 #define OSRF_CHAT_STATE_CONNECTING 1 /* we have received the opening stream */
85 #define OSRF_CHAT_STATE_CONNECTED 2 /* we have sent the OK/result message */
88 #define OSRF_CHAT_STATE_S2S_CHALLENGE 4 /* client : waiting for the challenge */
89 #define OSRF_CHAT_STATE_S2S_RESPONSE 5 /* server : waiting for the challenge response */
90 #define OSRF_CHAT_STATE_S2S_VERIFY 6 /* client : waiting for verify message */
91 #define OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE 7 /* server : waiting for verify response */
92 #define OSRF_CHAT_STATE_S2S_VERIFY_FINAL 8 /* client : waiting for final verify response */
94 /* xml parser states */
95 #define OSRF_CHAT_STATE_INMESSAGE 1
96 #define OSRF_CHAT_STATE_INIQ 2
97 #define OSRF_CHAT_STATE_INUSERNAME 4
98 #define OSRF_CHAT_STATE_INRESOURCE 8
99 #define OSRF_CHAT_STATE_INS2SRESULT 16
100 #define OSRF_CHAT_STATE_INS2SVERIFY 32
102 struct osrfChatNodeStruct {
104 int sockid; /* our socket id */
105 int type; /* 0 for client, 1 for server */
107 /* for clients this is the full JID of the client that connected to this server.
108 for servers it's the domain (network id) of the server we're connected to */
111 int state; /* for the various stages of connectivity and parsing */
112 int xmlstate; /* what part of the message are we currently parsing */
113 int inparse; /* true if we are currently parsing a chunk of XML. If so, we can't free the node.
114 we have to cache it and free it later */
116 char* to; /* The JID where the current message is being routed */
118 char* domain; /* the domain, resource, and username of our connecting entity. */
119 char* resource; /* for s2s nodes, resource and username will be empty . */
122 char* authkey; /* when doing any auth negotiation, this is the auth seed hash */
123 osrfList* msgs; /* if we're a server node we may have a pool of messages
124 waiting to be delivered */
126 xmlParserCtxtPtr parserCtx;
128 osrfChatServer* parent;
132 struct __osrfChatS2SMessageStruct {
136 typedef struct __osrfChatS2SMessageStruct osrfChatS2SMessage;
139 struct osrfChatServerStruct {
140 osrfHash* nodeHash; /* sometimes we need hash (remote id) lookup,
141 sometimes we need socket id lookup */
143 osrfList* deadNodes; /* collection of nodes to free when we get a chance */
145 char* secret; /* shared S2S secret */
146 char* domain; /* the domain this server hosts */
151 //static void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode );
153 static osrfChatNode* osrfNewChatS2SNode( const char* domain, const char* remote );
154 static osrfChatNode* osrfNewChatNode( int sockid, const char* domain );
155 static void osrfChatNodeFree( void* node );
157 static void osrfChatHandleData( void* cs,
158 socket_manager* mgr, int sockid, char* data, int parent_id );
160 /* removes dead nodes that have been cached due to mid-parse removals */
161 static void osrfChatCleanupClients( osrfChatServer* server );
163 static osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid );
164 static void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node );
166 /** pushes new data into the nodes parser */
167 static int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data );
169 static void osrfChatSocketClosed( void* blob, int sockid );
172 Sends msgXML to the client with remote 'toAddr'. If we have no connection
173 to 'toAddr' and the domain for 'toAddr' is different from our hosted domain
174 we attempt to send the message to the domain found in 'toAddr'.
176 static int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, const char* toAddr,
177 const char* fromAddr, const char* msgXML );
178 static int osrfChatSendRaw( osrfChatNode* node, const char* xml );
180 static void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node );
182 /* initializes the negotiation of a server to server connection */
183 static int osrfChatInitS2S( osrfChatServer* cs, const char* remote, const char* toAddr,
184 const char* msgXML );
186 static int osrfChatHandleNewConnection( osrfChatNode* node, const char* name,
187 const xmlChar** atts );
188 static int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts );
189 static int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts );
190 static int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name,
191 const xmlChar** atts );
192 //static int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name,
193 // const xmlChar** atts );
195 static int osrfChatHandleS2SConnected( osrfChatNode* node, const char* nm, const xmlChar**atts );
197 static void osrfChatS2SMessageFree(void* n);
199 /* generates a random sha1 hex key */
200 static char* osrfChatMkAuthKey();
202 static void osrfChatStartStream( void* blob );
203 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
204 static void osrfChatEndElement( void* blob, const xmlChar* name );
205 static void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
206 static void osrfChatParseError( void* blob, const char* msg, ... );
208 static xmlSAXHandler osrfChatSaxHandlerStruct = {
209 NULL, /* internalSubset */
210 NULL, /* isStandalone */
211 NULL, /* hasInternalSubset */
212 NULL, /* hasExternalSubset */
213 NULL, /* resolveEntity */
214 NULL, /* getEntity */
215 NULL, /* entityDecl */
216 NULL, /* notationDecl */
217 NULL, /* attributeDecl */
218 NULL, /* elementDecl */
219 NULL, /* unparsedEntityDecl */
220 NULL, /* setDocumentLocator */
221 osrfChatStartStream, /* startDocument */
222 NULL, /* endDocument */
223 osrfChatStartElement, /* startElement */
224 osrfChatEndElement, /* endElement */
225 NULL, /* reference */
226 osrfChatHandleCharacter, /* characters */
227 NULL, /* ignorableWhitespace */
228 NULL, /* processingInstruction */
230 osrfChatParseError, /* xmlParserWarning */
231 osrfChatParseError, /* xmlParserError */
232 NULL, /* xmlParserFatalError : unused */
233 NULL, /* getParameterEntity */
234 NULL, /* cdataBlock; */
235 NULL, /* externalSubset; */
238 NULL, /* startElementNs */
239 NULL, /* endElementNs */
240 NULL /* xmlStructuredErrorFunc */
243 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;
245 #ifndef HOST_NAME_MAX
246 #define HOST_NAME_MAX 256
249 static int osrfChatXMLErrorOcurred = 0;
251 /* This is used by code in osrfChatPushData, but that code is
252 currently commented out. Uncomment the next line if needed. */
253 //static int osrfChatClientSentDisconnect = 0;
255 /* shorter version of strcmp */
256 static int eq(const char* a, const char* b) {
257 return (a && b && !strcmp(a,b));
259 //#define eq(a,b) ((a && b && !strcmp(a,b)) ? 1 : 0)
261 /* gnarly debug function */
262 static void chatdbg( osrfChatServer* server ) {
265 return; /* heavy logging, should only be used in heavy debug mode */
267 growing_buffer* buf = buffer_init(256);
269 buffer_add(buf, "---------------------------------------------------------------------\n");
274 "Named nodes in hash: %lu\n"
278 "-------------------------------------------------------\n",
279 osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
280 server->domain, server->port, server->s2sport );
282 osrfListIterator* itr = osrfNewListIterator(server->nodeList);
285 while( (node = osrfListIteratorNext(itr)) ) {
299 "-------------------------------------------------------\n",
300 node->sockid, node->remote, node->state, node->xmlstate, node->inparse,
301 node->to, node->resource, node->username, node->domain, node->authkey, node->type );
304 osrfLogDebug( OSRF_LOG_MARK, "DEBUG:\n%s", buf->buf );
306 osrfListIteratorFree(itr);
309 osrfChatServer* osrfNewChatServer( const char* domain, const char* secret, int s2sport ) {
310 if(!(domain && secret)) return NULL;
312 osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
314 server->nodeHash = osrfNewHash();
315 server->nodeList = osrfNewList();
316 server->deadNodes = osrfNewList();
317 server->nodeList->freeItem = &osrfChatNodeFree;
318 server->domain = strdup(domain);
319 server->secret = strdup(secret);
320 server->s2sport = s2sport;
323 // Build socket manager
324 server->mgr = safe_malloc(sizeof(socket_manager));
325 server->mgr->data_received = &osrfChatHandleData;
326 server->mgr->socket = NULL;
327 server->mgr->blob = server;
328 server->mgr->on_socket_closed = &osrfChatSocketClosed;
333 static void osrfChatCleanupClients( osrfChatServer* server ) {
335 osrfListFree(server->deadNodes);
336 server->deadNodes = osrfNewList();
341 static osrfChatNode* osrfNewChatNode( int sockid, const char* domain ) {
342 if(sockid < 1 || !domain) return NULL;
343 osrfChatNode* node = safe_malloc(sizeof(osrfChatNode));
346 node->state = OSRF_CHAT_STATE_NONE;
349 node->msgs = NULL; /* only s2s nodes cache messages */
350 node->parserCtx = xmlCreatePushParserCtxt(osrfChatSaxHandler, node, "", 0, NULL);
351 node->msgDoc = xmlNewDoc(BAD_CAST "1.0");
352 node->domain = strdup(domain);
353 xmlKeepBlanksDefault(0);
354 node->authkey = NULL;
355 node->username = NULL;
356 node->resource = NULL;
364 static osrfChatNode* osrfNewChatS2SNode( const char* domain, const char* remote ) {
365 if(!(domain && remote)) return NULL;
366 osrfChatNode* n = osrfNewChatNode( 1, domain );
367 n->state = OSRF_CHAT_STATE_S2S_CHALLENGE;
369 n->remote = strdup(remote);
370 n->msgs = osrfNewList();
371 n->msgs->freeItem = &osrfChatS2SMessageFree;
376 void osrfChatS2SMessageFree(void* n) {
380 static void osrfChatNodeFree( void* node ) {
382 osrfChatNode* n = (osrfChatNode*) node;
384 /* we can't free messages that are mid-parse because the
385 we can't free the parser context */
388 osrfListPush(n->parent->deadNodes, n);
399 osrfListFree(n->msgs);
402 xmlFreeDoc(n->parserCtx->myDoc);
403 xmlFreeParserCtxt(n->parserCtx);
406 xmlFreeDoc(n->msgDoc);
412 int osrfChatServerConnect( osrfChatServer* cs, int port, int s2sport, char* listenAddr ) {
413 if(!(cs && port && listenAddr)) return -1;
415 cs->s2sport = s2sport;
416 if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
418 if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
424 int osrfChatServerWait( osrfChatServer* server ) {
425 if(!server) return -1;
427 if(socket_wait_all(server->mgr, -1) < 0)
428 osrfLogWarning( OSRF_LOG_MARK, "jserver_wait(): socket_wait_all() returned error");
434 void osrfChatServerFree(osrfChatServer* server ) {
436 osrfHashFree(server->nodeHash);
437 osrfListFree(server->nodeList);
438 osrfListFree(server->deadNodes);
439 socket_manager_free(server->mgr);
440 free(server->domain);
441 free(server->secret);
447 static void osrfChatHandleData( void* cs,
448 socket_manager* mgr, int sockid, char* data, int parent_id ) {
450 if(!(cs && mgr && sockid && data)) return;
452 osrfChatServer* server = (osrfChatServer*) cs;
454 osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
457 osrfLogDebug( OSRF_LOG_MARK, "Found node for sockid %d with state %d",
458 sockid, node->state );
461 osrfLogDebug( OSRF_LOG_MARK, "Adding new connection for sockid %d", sockid );
462 node = osrfChatAddNode( server, sockid );
466 if( (osrfChatPushData( server, node, data ) == -1) ) {
467 osrfLogError( OSRF_LOG_MARK,
468 "Node at socket %d with remote address %s and destination %s, "
469 "received bad XML [%s], disconnecting...",
470 sockid, node->remote, node->to, data );
471 osrfChatSendRaw( node, OSRF_CHAT_PARSE_ERROR );
472 osrfChatRemoveNode( server, node );
476 osrfChatCleanupClients(server); /* clean up old dead clients */
480 static void osrfChatSocketClosed( void* blob, int sockid ) {
482 osrfChatServer* server = (osrfChatServer*) blob;
483 osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
484 osrfChatRemoveNode( server, node );
487 static osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid ) {
488 if(!(server && sockid)) return NULL;
489 osrfChatNode* node = osrfNewChatNode(sockid, server->domain);
490 node->parent = server;
491 node->sockid = sockid;
492 osrfListSet( server->nodeList, node, sockid );
496 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
497 if(!(server && node)) return;
498 socket_disconnect(server->mgr, node->sockid);
500 osrfHashRemove( server->nodeHash, node->remote );
501 osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
504 static int osrfChatSendRaw( osrfChatNode* node, const char* msgXML ) {
505 if(!(node && msgXML)) return -1;
506 /* wait at most 3 second for this client to take our data */
507 return socket_send_timeout( node->sockid, msgXML, 3000000 );
510 static void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
511 if(!(server && node)) return;
512 osrfChatSendRaw( node, "</stream:stream>");
513 osrfChatRemoveNode( server, node );
517 static int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, const char* toAddr,
518 const char* fromAddr, const char* msgXML ) {
519 if(!(cs && node && toAddr && msgXML)) return -1;
521 int l = strlen(toAddr);
523 memset(dombuf, 0, sizeof(dombuf));
524 jid_get_domain( toAddr, dombuf, l );
526 if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
528 osrfLogInfo( OSRF_LOG_MARK, "Sending message on local connection\nfrom: %s\nto: %s",
530 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
533 /* if we can't send to the recipient (recipient is gone or too busy,
534 * we drop the recipient and inform the sender that the recipient
536 if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
538 osrfChatRemoveNode( cs, tonode );
539 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
541 osrfLogError( OSRF_LOG_MARK, "Node failed to function. "
542 "Responding to caller with error: %s", toAddr);
544 if( osrfChatSendRaw( node, xml ) < 0 ) {
545 osrfLogError(OSRF_LOG_MARK, "Sending node is now gone..removing");
546 osrfChatRemoveNode( cs, node );
553 /* send an error message saying we don't have this connection */
554 osrfLogInfo( OSRF_LOG_MARK, "We have no connection for %s", toAddr);
555 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
556 if( osrfChatSendRaw( node, xml ) < 0 )
557 osrfChatRemoveNode( cs, node );
563 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
565 if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
566 osrfLogDebug( OSRF_LOG_MARK, "Routing message to server %s", dombuf);
568 if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
569 osrfLogError( OSRF_LOG_MARK, "Node failed to function: %s", toAddr);
570 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
571 if( osrfChatSendRaw( node, xml ) < 0 )
572 osrfChatRemoveNode( cs, node );
574 osrfChatRemoveNode( cs, tonode );
578 osrfLogInfo( OSRF_LOG_MARK,
579 "Received s2s message and we're still trying to connect...caching");
580 osrfListPush( tonode->msgs, strdup(msgXML) );
585 if( osrfChatInitS2S( cs, dombuf, toAddr, msgXML ) != 0 ) {
586 osrfLogWarning( OSRF_LOG_MARK,
587 "We are unable to connect to remote server %s for recipient %s",
589 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
590 osrfChatSendRaw( node, xml );
601 static void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode ) {
602 if(!(toAddr && msgXML)) return;
603 osrfChatS2SMessage* msg = safe_malloc(sizeof(osrfChatS2SMessage));
604 msg->toAddr = strdup(toAddr);
605 msg->msgXML = strdup(msgXML);
606 osrfLogInfo( OSRF_LOG_MARK, "Pushing client message onto s2s queue waiting for connect... ");
607 osrfListPush( snode->msgs, msgXML );
612 static int osrfChatInitS2S( osrfChatServer* cs, const char* remote, const char* toAddr,
613 const char* msgXML ) {
614 if(!(cs && remote && toAddr && msgXML)) return -1;
616 osrfLogInfo( OSRF_LOG_MARK, "Initing server2server connection to domain %s", remote );
617 osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
620 /* try to connect to the remote site */
621 snode->sockid = socket_open_tcp_client(cs->mgr, cs->s2sport, remote);
622 if(snode->sockid < 1) {
623 osrfLogWarning( OSRF_LOG_MARK, "Unable to connect to remote server at %s", remote );
624 osrfChatNodeFree( snode );
628 /* store the message we were supposed to deliver until we're fully connected */
629 //osrfChatCacheS2SMessage( toAddr, msgXML, snode );
630 osrfListPush( snode->msgs, strdup(msgXML) );
631 osrfHashSet(cs->nodeHash, snode, remote );
632 osrfListSet(cs->nodeList, snode, snode->sockid );
634 /* send the initial s2s request */
635 osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
637 osrfLogDebug( OSRF_LOG_MARK, "Added new s2s node...");
644 /* commence SAX handling code */
646 static int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
647 if(!(node && data)) return -1;
651 osrfLogDebug( OSRF_LOG_MARK, "pushing data into xml parser for node %d with state %d:\n%s",
652 node->sockid, node->state, data);
654 xmlParseChunk(node->parserCtx, data, strlen(data), 0);
657 if(osrfChatXMLErrorOcurred) {
658 osrfChatXMLErrorOcurred = 0;
662 /* we can't do cleanup of the XML handlers while in the middle of a
663 data push, so set flags in the data push and do the cleanup here */
665 if(osrfChatClientSentDisconnect) {
666 osrfChatClientSentDisconnect = 0;
667 osrfChatNodeFinish( server, node );
675 static void osrfChatStartStream( void* blob ) {
676 osrfLogDebug( OSRF_LOG_MARK, "Starting new client stream...");
680 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
681 if(!(blob && name)) return;
682 osrfChatNode* node = (osrfChatNode*) blob;
685 char* nm = (char*) name;
687 osrfLogDebug( OSRF_LOG_MARK, "Starting element %s with namespace %s and node state %d",
688 nm, xmlSaxAttr(atts, "xmlns"), node->state );
690 switch( node->state ) {
692 case OSRF_CHAT_STATE_NONE:
693 status = osrfChatHandleNewConnection( node, nm, atts );
694 osrfLogDebug( OSRF_LOG_MARK, "After NewConnection we have state %d", node->state);
697 case OSRF_CHAT_STATE_CONNECTING:
698 status = osrfChatHandleConnecting( node, nm, atts );
701 case OSRF_CHAT_STATE_CONNECTED:
702 status = osrfChatHandleConnected( node, nm, atts );
705 case OSRF_CHAT_STATE_S2S_CHALLENGE:
706 status = osrfChatHandleS2SChallenge( node, nm, atts );
709 case OSRF_CHAT_STATE_S2S_RESPONSE: /* server waiting for client response to challenge */
710 if(eq(nm, "db:result")) {
711 const char* remote = xmlSaxAttr(atts, "from");
713 if( node->remote) free( node->remote );
714 node->remote = strdup(remote); /* copy off the client's id */
717 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
722 case OSRF_CHAT_STATE_S2S_VERIFY: /* client : waiting for server verify message */
723 if(eq(nm, "db:verify")) {
724 const char* id = xmlSaxAttr( atts, "id" );
726 char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE,
727 node->remote, node->domain, id );
728 osrfChatSendRaw( node, xml );
730 node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
736 case OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE: /* server waiting for client verify response */
737 case OSRF_CHAT_STATE_S2S_VERIFY_FINAL: /* client waitig for final verify */
738 status = osrfChatHandleS2SConnected( node, nm, atts );
744 osrfChatParseError( node, "We don't know how to handle the XML data received" );
747 #define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) osrfLogDebug( OSRF_LOG_MARK, z);
751 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
752 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
756 if(eq(name,"db:verify")) { /* server receives verify from client */
757 char* xml = va_list_to_string(OSRF_CHAT_S2S_VERIFY_FINAL, node->domain, node->remote );
758 osrfChatSendRaw(node, xml );
763 if(eq(name, "db:result")) {
764 /* send all the messages that we have queued for this server */
765 node->state = OSRF_CHAT_STATE_CONNECTED;
766 osrfListIterator* itr = osrfNewListIterator(node->msgs);
769 while( (xml = (char*) osrfListIteratorNext(itr)) ) {
770 xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
772 char* from = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "from");
773 char* to = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "to");
774 osrfChatSend( node->parent, node, to, from, xml );
775 osrfLogDebug( OSRF_LOG_MARK, "Sending cached message from %s to %s", from, to);
776 xmlFree(to); xmlFree(from);
781 osrfListIteratorFree(itr);
782 osrfListFree(node->msgs);
788 osrfLogInfo( OSRF_LOG_MARK, "Successfully made S2S connection to %s", node->remote );
789 node->state = OSRF_CHAT_STATE_CONNECTED;
797 /** check the namespace of the stream message to see if it's a server or client connection */
798 static int osrfChatHandleNewConnection( osrfChatNode* node, const char* name,
799 const xmlChar** atts ) {
800 CHAT_CHECK_VARS(node, name, "osrfChatHandleNewConnection()");
802 if(!eq(name, "stream:stream"))
805 if( node->authkey ) free( node->authkey );
806 node->authkey = osrfChatMkAuthKey();
807 const char* ns = xmlSaxAttr(atts, "xmlns");
811 if(eq(ns, "jabber:client")) { /* client connection */
813 const char* domain = xmlSaxAttr( atts, "to" );
817 if(!eq(domain, node->domain)) {
818 osrfLogWarning( OSRF_LOG_MARK,
819 "Client attempting to connect to invalid domain %s. Our domain is %s",
820 domain, node->domain);
824 char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
825 node->state = OSRF_CHAT_STATE_CONNECTING;
827 osrfLogDebug( OSRF_LOG_MARK,
828 "Server node %d setting state to OSRF_CHAT_STATE_CONNECTING[%d]",
829 node->sockid, node->state );
831 osrfLogDebug( OSRF_LOG_MARK, "Server responding to connect message with\n%s\n", buf );
832 osrfChatSendRaw( node, buf );
837 /* server to server init */
838 if(eq(ns, "jabber:server")) { /* client connection */
839 osrfLogInfo( OSRF_LOG_MARK,
840 "We received a new server 2 server connection, generating auth key...");
841 char* xml = va_list_to_string( OSRF_CHAT_S2S_CHALLENGE, node->authkey );
842 osrfChatSendRaw( node, xml );
844 node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
854 char* osrfChatMkAuthKey() {
855 char hostname[HOST_NAME_MAX + 1] = "";
856 gethostname(hostname, sizeof(hostname) );
857 hostname[HOST_NAME_MAX] = '\0';
859 snprintf(keybuf, sizeof(keybuf), "%d%ld%s", (int) time(NULL), (long) getpid(), hostname);
860 return strdup(shahash(keybuf));
863 static int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts ) {
864 CHAT_CHECK_VARS(node, name, "osrfChatHandleConnecting()");
865 osrfLogDebug( OSRF_LOG_MARK, "Handling connect node %s", name );
868 node->xmlstate |= OSRF_CHAT_STATE_INIQ;
869 else if(eq(name,"username"))
870 node->xmlstate |= OSRF_CHAT_STATE_INUSERNAME;
871 else if(eq(name,"resource"))
872 node->xmlstate |= OSRF_CHAT_STATE_INRESOURCE;
876 static int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
877 CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
879 if(eq(name,"message")) {
881 /* drop the old message and start with a new one */
882 xmlNodePtr root = xmlNewNode(NULL, BAD_CAST name);
883 xmlAddAttrs(root, atts);
884 xmlNodePtr oldRoot = xmlDocSetRootElement(node->msgDoc, root);
887 const char* to = xmlSaxAttr(atts, "to");
891 node->to = strdup(to);
893 xmlFreeNode(oldRoot);
894 node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
898 /* all non "message" nodes are simply added to the message */
899 xmlNodePtr nodep = xmlNewNode(NULL, BAD_CAST name);
900 xmlAddAttrs(nodep, atts);
901 xmlAddChild(xmlDocGetRootElement(node->msgDoc), nodep);
907 /* takes s2s secret, hashdomain, and the s2s auth token */
908 static char* osrfChatGenerateS2SKey(
909 const char* secret, const char* hashdomain, const char* authtoken ) {
910 if(!(secret && hashdomain && authtoken)) return NULL;
911 osrfLogInfo( OSRF_LOG_MARK, "Generating s2s key with auth token: %s", authtoken );
912 char* a = shahash(secret);
913 osrfLogDebug( OSRF_LOG_MARK, "S2S secret hash: %s", a);
914 char* b = va_list_to_string("%s%s", a, hashdomain);
915 char* c = shahash(b);
916 osrfLogDebug( OSRF_LOG_MARK, "S2S intermediate hash: %s", c);
917 char* d = va_list_to_string("%s%s", c, authtoken);
918 char* e = strdup(shahash(d));
923 static int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name,
924 const xmlChar** atts ) {
925 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
927 /* here we respond to the stream challenge */
928 if(eq(name, "stream:stream")) {
929 const char* id = xmlSaxAttr(atts, "id");
931 /* we use our domain in the s2s challenge hash */
932 char* d = osrfChatGenerateS2SKey(node->parent->secret, node->domain, id );
933 char* e = va_list_to_string(OSRF_CHAT_S2S_RESPONSE, node->remote, node->domain, d );
934 osrfLogInfo( OSRF_LOG_MARK, "Answering s2s challenge with key: %s", e );
935 osrfChatSendRaw( node, e );
937 node->state = OSRF_CHAT_STATE_S2S_VERIFY;
946 static int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name,
947 const xmlChar** atts ) {
948 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
950 if(eq(name, "db:result")) {
951 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
961 static void osrfChatEndElement( void* blob, const xmlChar* name ) {
962 if(!(blob && name)) return;
963 osrfChatNode* node = (osrfChatNode*) blob;
965 char* nm = (char*) name;
967 if(eq(nm,"stream:stream")) {
968 osrfChatNodeFinish( node->parent, node );
972 if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
973 if(eq(nm, "message")) {
975 xmlNodePtr msg = xmlDocGetRootElement(node->msgDoc);
976 if(msg && node->type == 0)
977 xmlSetProp(msg, BAD_CAST "from", BAD_CAST node->remote );
978 char* string = xmlDocToString(node->msgDoc, 0 );
980 char* from = (char*) xmlGetProp(msg, BAD_CAST "from");
981 osrfLogDebug( OSRF_LOG_MARK, "Routing message to %s\n%s\n", node->to, from, string );
982 osrfChatSend( node->parent, node, node->to, from, string );
988 if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
989 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
992 node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
994 free( node->remote );
995 node->remote = va_list_to_string(
996 "%s@%s/%s", node->username, node->domain, node->resource );
998 osrfLogInfo( OSRF_LOG_MARK, "%s successfully logged in", node->remote );
1000 osrfLogDebug( OSRF_LOG_MARK, "Setting remote address to %s", node->remote );
1001 osrfChatSendRaw( node, OSRF_CHAT_LOGIN_OK );
1002 if(osrfHashGet( node->parent->nodeHash, node->remote ) ) {
1003 osrfLogWarning( OSRF_LOG_MARK,
1004 "New node replaces existing node for remote id %s", node->remote);
1005 osrfHashRemove(node->parent->nodeHash, node->remote);
1007 osrfHashSet( node->parent->nodeHash, node, node->remote );
1008 node->state = OSRF_CHAT_STATE_CONNECTED;
1015 static void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
1016 if(!(blob && ch && len)) return;
1017 osrfChatNode* node = (osrfChatNode*) blob;
1020 osrfLogDebug( OSRF_LOG_MARK, "Char Handler: state %d, xmlstate %d, chardata %s",
1021 node->state, node->xmlstate, (char*) ch );
1024 if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
1025 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
1027 if( node->xmlstate & OSRF_CHAT_STATE_INUSERNAME ) {
1028 free(node->username);
1029 node->username = strndup((char*) ch, len);
1030 node->xmlstate &= ~OSRF_CHAT_STATE_INUSERNAME;
1033 if( node->xmlstate & OSRF_CHAT_STATE_INRESOURCE ) {
1034 free(node->resource);
1035 node->resource = strndup((char*) ch, len);
1036 node->xmlstate &= ~OSRF_CHAT_STATE_INRESOURCE;
1043 if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
1044 xmlNodePtr last = xmlGetLastChild(xmlDocGetRootElement(node->msgDoc));
1045 xmlNodePtr txt = xmlNewTextLen(ch, len);
1046 xmlAddChild(last, txt);
1050 if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
1051 (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
1053 char* key = strndup((char*) ch, len);
1054 osrfLogDebug( OSRF_LOG_MARK, "Got s2s key from %s : %s", node->remote, key );
1055 char* e = osrfChatGenerateS2SKey(node->parent->secret, node->remote, node->authkey );
1056 osrfLogInfo( OSRF_LOG_MARK,
1057 "\nReceived s2s key from server: %s\nKey should be: %s", key, e );
1060 char* msg = va_list_to_string(OSRF_CHAT_S2S_VERIFY_REQUEST,
1061 node->authkey, node->domain, node->remote, e );
1062 osrfChatSendRaw(node, msg );
1064 node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
1068 osrfLogWarning( OSRF_LOG_MARK, "Server2Server keys do not match!");
1074 /* do the hash dance again */
1079 static void osrfChatParseError( void* blob, const char* msg, ... ) {
1081 osrfChatXMLErrorOcurred = 1;