]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/jserver/osrf_chat.c
Bump libopensrf version-info revision and age
[OpenSRF.git] / src / jserver / osrf_chat.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service
3 Bill Erickson <billserickson@gmail.com>
4
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.
9
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.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18 #include <time.h>
19
20 /* opensrf headers */
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"
29
30 /* libxml2 headers */
31 #include <libxml/parser.h>
32 #include <libxml/tree.h>
33 #include <libxml/globals.h>
34 #include <libxml/xmlerror.h>
35
36 #include "osrf_chat.h"
37
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'>"
42
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>"
48
49 #define OSRF_CHAT_LOGIN_OK "<iq xmlns='jabber:client' id='0123456789' type='result'/>"
50
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>"
55
56 /* ---------------------------------------------------------------------------------- */
57 /* server to server XML */
58
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'>"
62
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'>"
66
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>"
69
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>"
73
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'/>"
77
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'/>"
81
82 /* c2s states */
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 */
86
87 /* s2s states */
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 */
93
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
101
102 struct osrfChatNodeStruct {
103
104         int sockid;         /* our socket id */
105         int type;           /* 0 for client, 1 for server */
106
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 */
109         char* remote;
110
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 */
115
116         char* to;           /* The JID where the current message is being routed */
117
118         char* domain;       /* the domain, resource, and username of our connecting entity. */
119         char* resource;     /* for s2s nodes, resource and username will be empty . */
120         char* username;
121
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 */
125
126         xmlParserCtxtPtr parserCtx;
127         xmlDocPtr msgDoc;
128         osrfChatServer* parent;
129 };
130
131 /*
132 struct __osrfChatS2SMessageStruct {
133         char* toAddr;
134         char* msgXML;
135 };
136 typedef struct __osrfChatS2SMessageStruct osrfChatS2SMessage;
137 */
138
139 struct osrfChatServerStruct {
140         osrfHash* nodeHash; /* sometimes we need hash (remote id) lookup,
141                                sometimes we need socket id lookup */
142         osrfList* nodeList;
143         osrfList* deadNodes;    /* collection of nodes to free when we get a chance */
144         socket_manager* mgr;
145         char* secret;           /* shared S2S secret */
146         char* domain;           /* the domain this server hosts */
147         int s2sport;
148         int port;
149 };
150
151 //static void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode );
152
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 );
156
157 static void osrfChatHandleData( void* cs,
158                 socket_manager* mgr, int sockid, char* data, int parent_id );
159
160 /* removes dead nodes that have been cached due to mid-parse removals */
161 static void osrfChatCleanupClients( osrfChatServer* server );
162
163 static osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid );
164 static void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node );
165
166 /** pushes new data into the nodes parser */
167 static int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data );
168
169 static void osrfChatSocketClosed( void* blob, int sockid );
170
171 /**
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'.
175 */
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 );
179
180 static void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node );
181
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 );
185
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 );
194
195 static int osrfChatHandleS2SConnected( osrfChatNode* node, const char* nm, const xmlChar**atts );
196
197 static void osrfChatS2SMessageFree(void* n);
198
199 /* generates a random sha1 hex key */
200 static char* osrfChatMkAuthKey();
201
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, ... );
207
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 */
229         NULL,                       /* comment */
230         osrfChatParseError,         /* xmlParserWarning */
231         osrfChatParseError,         /* xmlParserError */
232         NULL,                       /* xmlParserFatalError : unused */
233         NULL,                       /* getParameterEntity */
234         NULL,                       /* cdataBlock; */
235         NULL,                       /* externalSubset; */
236         1,
237         NULL,
238         NULL,                       /* startElementNs */
239         NULL,                       /* endElementNs */
240         NULL                        /* xmlStructuredErrorFunc */
241 };
242
243 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;
244
245 #ifndef HOST_NAME_MAX
246 #define HOST_NAME_MAX 256
247 #endif
248
249 static int osrfChatXMLErrorOcurred = 0;
250
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;
254
255 /* shorter version of strcmp */
256 static int eq(const char* a, const char* b) {
257         return (a && b && !strcmp(a,b));
258 }
259 //#define eq(a,b) ((a && b && !strcmp(a,b)) ? 1 : 0)
260
261 /* gnarly debug function */
262 static void chatdbg( osrfChatServer* server ) {
263
264         if(!server) return;
265         return; /* heavy logging, should only be used in heavy debug mode */
266
267         growing_buffer* buf = buffer_init(256);
268
269         buffer_add(buf, "---------------------------------------------------------------------\n");
270
271         buffer_fadd(buf,
272                 "ChopChop Debug:\n"
273                 "Connections:           %lu\n"
274                 "Named nodes in hash:   %lu\n"
275                 "Domain:                %s\n"
276                 "Port:                  %d\n"
277                 "S2S Port:              %d\n"
278                 "-------------------------------------------------------\n",
279                 osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
280                 server->domain, server->port, server->s2sport );
281
282         osrfListIterator* itr = osrfNewListIterator(server->nodeList);
283         osrfChatNode* node;
284
285         while( (node = osrfListIteratorNext(itr)) ) {
286
287                 buffer_fadd( buf,
288                         "sockid:    %d\n"
289                         "Remote:    %s\n"
290                         "State:     %d\n"
291                         "XMLState:  %d\n"
292                         "In Parse:  %d\n"
293                         "to:        %s\n"
294                         "Resource:  %s\n"
295                         "Username:  %s\n"
296                         "Domain:    %s\n"
297                         "Authkey:   %s\n"
298                         "type:      %d\n"
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 );
302         }
303
304         osrfLogDebug( OSRF_LOG_MARK, "DEBUG:\n%s", buf->buf );
305         buffer_free(buf);
306         osrfListIteratorFree(itr);
307 }
308
309 osrfChatServer* osrfNewChatServer( const char* domain, const char* secret, int s2sport ) {
310         if(!(domain && secret)) return NULL;
311
312         osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
313
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;
321         server->port        = 0;
322
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;
329
330         return server;
331 }
332
333 static void osrfChatCleanupClients( osrfChatServer* server ) {
334         if(!server) return;
335         osrfListFree(server->deadNodes);
336         server->deadNodes = osrfNewList();
337 }
338
339
340
341 static osrfChatNode* osrfNewChatNode( int sockid, const char* domain ) {
342         if(sockid < 1 || !domain) return NULL;
343         osrfChatNode* node      = safe_malloc(sizeof(osrfChatNode));
344         node->sockid            = 0;
345         node->remote            = NULL;
346         node->state             = OSRF_CHAT_STATE_NONE;
347         node->xmlstate          = 0;
348         node->inparse           = 0;
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;
357         node->to                = NULL;
358         node->type = 0;
359         node->parent            = NULL;
360         return node;
361 }
362
363
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;
368         n->sockid   = -1;
369         n->remote   = strdup(remote);
370         n->msgs     = osrfNewList();
371         n->msgs->freeItem = &osrfChatS2SMessageFree;
372         n->type     = 1;
373         return n;
374 }
375
376 void osrfChatS2SMessageFree(void* n) {
377          free(n);
378 }
379
380 static void osrfChatNodeFree( void* node ) {
381         if(!node) return;
382         osrfChatNode* n = (osrfChatNode*) node;
383
384         /* we can't free messages that are mid-parse because the
385                 we can't free the parser context */
386         if(n->inparse) {
387                 n->inparse = 0;
388                 osrfListPush(n->parent->deadNodes, n);
389                 return;
390         }
391
392         free(n->remote);
393         free(n->to);
394         free(n->username);
395         free(n->resource);
396         free(n->domain);
397         free(n->authkey);
398
399         osrfListFree(n->msgs);
400
401         if(n->parserCtx) {
402                 xmlFreeDoc(n->parserCtx->myDoc);
403                 xmlFreeParserCtxt(n->parserCtx);
404         }
405
406         xmlFreeDoc(n->msgDoc);
407         free(n);
408 }
409
410
411
412 int osrfChatServerConnect( osrfChatServer* cs, int port, int s2sport, char* listenAddr ) {
413         if(!(cs && port && listenAddr)) return -1;
414         cs->port = port;
415         cs->s2sport = s2sport;
416         if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
417                 return -1;
418         if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
419                 return -1;
420         return 0;
421 }
422
423
424 int osrfChatServerWait( osrfChatServer* server ) {
425         if(!server) return -1;
426         while(1) {
427                 if(socket_wait_all(server->mgr, -1) < 0)
428                         osrfLogWarning( OSRF_LOG_MARK,  "jserver_wait(): socket_wait_all() returned error");
429         }
430         return -1;
431 }
432
433
434 void osrfChatServerFree(osrfChatServer* server ) {
435         if(!server) return;
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);
442
443         free(server);
444 }
445
446
447 static void osrfChatHandleData( void* cs,
448         socket_manager* mgr, int sockid, char* data, int parent_id ) {
449
450         if(!(cs && mgr && sockid && data)) return;
451
452         osrfChatServer* server = (osrfChatServer*) cs;
453
454         osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
455
456         if(node)
457                 osrfLogDebug( OSRF_LOG_MARK, "Found node for sockid %d with state %d",
458                                 sockid, node->state );
459
460         if(!node) {
461                 osrfLogDebug( OSRF_LOG_MARK, "Adding new connection for sockid %d", sockid );
462                 node = osrfChatAddNode( server, sockid );
463         }
464
465         if(node) {
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 );
473                 }
474         }
475
476         osrfChatCleanupClients(server); /* clean up old dead clients */
477 }
478
479
480 static void osrfChatSocketClosed( void* blob, int sockid ) {
481         if(!blob) return;
482         osrfChatServer* server = (osrfChatServer*) blob;
483         osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
484         osrfChatRemoveNode( server, node );
485 }
486
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 );
493         return node;
494 }
495
496 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
497         if(!(server && node)) return;
498         socket_disconnect(server->mgr, node->sockid);
499         if(node->remote)
500                 osrfHashRemove( server->nodeHash, node->remote );
501         osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
502 }
503
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 );
508 }
509
510 static void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
511         if(!(server && node)) return;
512         osrfChatSendRaw( node, "</stream:stream>");
513         osrfChatRemoveNode( server, node );
514 }
515
516
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;
520
521         int l = strlen(toAddr);
522         char dombuf[l];
523         memset(dombuf, 0, sizeof(dombuf));
524         jid_get_domain( toAddr, dombuf, l );
525
526         if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
527
528                 osrfLogInfo( OSRF_LOG_MARK, "Sending message on local connection\nfrom: %s\nto: %s",
529                                 fromAddr, toAddr );
530                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
531                 if(tonode) {
532
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
535                          * is no more */
536                         if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
537
538                                 osrfChatRemoveNode( cs, tonode );
539                                 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
540
541                                 osrfLogError( OSRF_LOG_MARK, "Node failed to function. "
542                                                 "Responding to caller with error: %s", toAddr);
543
544                                 if( osrfChatSendRaw( node, xml ) < 0 ) {
545                                         osrfLogError(OSRF_LOG_MARK, "Sending node is now gone..removing");
546                                         osrfChatRemoveNode( cs, node );
547                                 }
548                                 free(xml);
549                         }
550
551                 } else {
552
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 );
558                         free(xml);
559                 }
560
561         } else {
562
563                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
564                 if(tonode) {
565                         if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
566                                 osrfLogDebug( OSRF_LOG_MARK, "Routing message to server %s", dombuf);
567
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 );
573                                         free(xml);
574                                         osrfChatRemoveNode( cs, tonode );
575                                 }
576
577                         } else {
578                                 osrfLogInfo( OSRF_LOG_MARK,
579                                                 "Received s2s message and we're still trying to connect...caching");
580                                 osrfListPush( tonode->msgs, strdup(msgXML) );
581                         }
582
583                 } else {
584
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",
588                                                 dombuf, toAddr);
589                                 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
590                                 osrfChatSendRaw( node, xml );
591                                 free(xml);
592                         }
593                 }
594         }
595
596         return 0;
597 }
598
599
600 /*
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 );
608 }
609 */
610
611
612 static int osrfChatInitS2S( osrfChatServer* cs, const char* remote, const char* toAddr,
613                 const char* msgXML ) {
614         if(!(cs && remote && toAddr && msgXML)) return -1;
615
616         osrfLogInfo( OSRF_LOG_MARK, "Initing server2server connection to domain %s", remote );
617         osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
618         snode->parent = cs;
619
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 );
625                 return -1;
626         }
627
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 );
633
634         /* send the initial s2s request */
635         osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
636
637         osrfLogDebug( OSRF_LOG_MARK, "Added new s2s node...");
638         chatdbg(cs);
639
640         return 0;
641 }
642
643
644 /* commence SAX handling code */
645
646 static int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
647         if(!(node && data)) return -1;
648
649         chatdbg(server);
650
651         osrfLogDebug( OSRF_LOG_MARK, "pushing data into xml parser for node %d with state %d:\n%s",
652                         node->sockid, node->state, data);
653         node->inparse = 1;
654         xmlParseChunk(node->parserCtx, data, strlen(data), 0);
655         node->inparse = 0;
656
657         if(osrfChatXMLErrorOcurred) {
658                 osrfChatXMLErrorOcurred = 0;
659                 return -1;
660         }
661
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 */
664         /*
665         if(osrfChatClientSentDisconnect) {
666                 osrfChatClientSentDisconnect  = 0;
667                 osrfChatNodeFinish( server, node );
668         }
669         */
670
671         return 0;
672 }
673
674
675 static void osrfChatStartStream( void* blob ) {
676         osrfLogDebug( OSRF_LOG_MARK, "Starting new client stream...");
677 }
678
679
680 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
681         if(!(blob && name)) return;
682         osrfChatNode* node = (osrfChatNode*) blob;
683
684         int status = -1;
685         char* nm = (char*) name;
686
687         osrfLogDebug( OSRF_LOG_MARK, "Starting element %s with namespace %s and node state %d",
688                                                  nm, xmlSaxAttr(atts, "xmlns"), node->state );
689
690         switch( node->state ) {
691
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);
695                         break;
696
697                 case OSRF_CHAT_STATE_CONNECTING:
698                         status = osrfChatHandleConnecting( node, nm, atts );
699                         break;
700
701                 case OSRF_CHAT_STATE_CONNECTED:
702                         status = osrfChatHandleConnected( node, nm, atts );
703                         break;
704
705                 case OSRF_CHAT_STATE_S2S_CHALLENGE:
706                         status = osrfChatHandleS2SChallenge( node, nm, atts );
707                         break;
708
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");
712                                 if(remote) {
713                                         if( node->remote) free( node->remote );
714                                         node->remote = strdup(remote); /* copy off the client's id */
715                                 }
716                                 status = 0;
717                                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
718                         } else
719                                 status = -1;
720                         break;
721
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" );
725                                 if(id) {
726                                         char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE,
727                                                         node->remote, node->domain, id );
728                                         osrfChatSendRaw( node, xml );
729                                         free(xml);
730                                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
731                                         status = 0;
732                                 }
733                         }
734                         break;
735
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 );
739                         break;
740
741         }
742
743         if(status != 0)
744                 osrfChatParseError( node, "We don't know how to handle the XML data received" );
745 }
746
747 #define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) osrfLogDebug( OSRF_LOG_MARK, z);
748
749
750
751 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
752         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
753
754         int status = -1;
755
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 );
759                 free(xml);
760                 status = 0;
761         }
762
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);
767
768                 const char* xml;
769                 while( (xml = (char*) osrfListIteratorNext(itr)) ) {
770                         xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
771                         if(doc) {
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);
777                                 xmlFreeDoc(doc);
778                         }
779                 }
780
781                 osrfListIteratorFree(itr);
782                 osrfListFree(node->msgs);
783                 node->msgs = NULL;
784                 status = 0;
785         }
786
787         if(status == 0) {
788                 osrfLogInfo( OSRF_LOG_MARK, "Successfully made S2S connection to %s", node->remote );
789                 node->state = OSRF_CHAT_STATE_CONNECTED;
790                 node->xmlstate = 0;
791         }
792
793         return status;
794 }
795
796
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()");
801
802         if(!eq(name, "stream:stream"))
803                 return -1;
804
805         if( node->authkey ) free( node->authkey );
806         node->authkey = osrfChatMkAuthKey();
807         const char* ns = xmlSaxAttr(atts, "xmlns");
808         if(!ns)
809                 return -1;
810
811         if(eq(ns, "jabber:client")) { /* client connection */
812
813                 const char* domain = xmlSaxAttr( atts, "to" );
814                 if(!domain)
815                         return -1;
816
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);
821                         return -1;
822                 }
823
824                 char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
825                 node->state = OSRF_CHAT_STATE_CONNECTING;
826
827                 osrfLogDebug( OSRF_LOG_MARK,
828                                 "Server node %d setting state to OSRF_CHAT_STATE_CONNECTING[%d]",
829                                 node->sockid, node->state );
830
831                 osrfLogDebug( OSRF_LOG_MARK, "Server responding to connect message with\n%s\n", buf );
832                 osrfChatSendRaw( node, buf );
833                 free(buf);
834                 return 0;
835         }
836
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 );
843                 free(xml);
844                 node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
845                 node->type = 1;
846                 return 0;
847         }
848
849         return -1;
850 }
851
852
853
854 char* osrfChatMkAuthKey() {
855         char hostname[HOST_NAME_MAX + 1] = "";
856         gethostname(hostname, sizeof(hostname) );
857         hostname[HOST_NAME_MAX] = '\0';
858         char keybuf[112];
859         snprintf(keybuf, sizeof(keybuf), "%d%ld%s", (int) time(NULL), (long) getpid(), hostname);
860         return strdup(shahash(keybuf));
861 }
862
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 );
866
867         if(eq(name, "iq"))
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;
873         return 0;
874 }
875
876 static int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
877         CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
878
879         if(eq(name,"message")) {
880
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);
885                 free(node->to);
886
887                 const char* to = xmlSaxAttr(atts, "to");
888                 if(!to)
889                         to = "";
890
891                 node->to = strdup(to);
892                 if(oldRoot)
893                         xmlFreeNode(oldRoot);
894                 node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
895
896         } else {
897
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);
902         }
903
904         return 0;
905 }
906
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));
919         free(b); free(d);
920         return e;
921 }
922
923 static int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name,
924                 const xmlChar** atts ) {
925         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
926
927 /* here we respond to the stream challenge */
928         if(eq(name, "stream:stream")) {
929                 const char* id = xmlSaxAttr(atts, "id");
930                 if(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 );
936                         free(d); free(e);
937                         node->state = OSRF_CHAT_STATE_S2S_VERIFY;
938                         return 0;
939                 }
940         }
941
942         return -1;
943 }
944
945 /*
946 static int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name,
947                 const xmlChar** atts ) {
948         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
949
950         if(eq(name, "db:result")) {
951                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
952                 return 0;
953         }
954
955         return -1;
956 }
957 */
958
959
960
961 static void osrfChatEndElement( void* blob, const xmlChar* name ) {
962         if(!(blob && name)) return;
963         osrfChatNode* node = (osrfChatNode*) blob;
964
965         char* nm = (char*) name;
966
967         if(eq(nm,"stream:stream")) {
968                 osrfChatNodeFinish( node->parent, node );
969                 return;
970         }
971
972         if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
973                 if(eq(nm, "message")) {
974
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 );
979
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 );
983                         xmlFree(from);
984                         free(string);
985                 }
986         }
987
988         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
989                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
990
991                         if(eq(nm, "iq")) {
992                                 node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
993                                 if( node->remote )
994                                         free( node->remote );
995                                 node->remote = va_list_to_string(
996                                                 "%s@%s/%s", node->username, node->domain, node->resource );
997
998                                 osrfLogInfo( OSRF_LOG_MARK, "%s successfully logged in", node->remote );
999
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);
1006                                 }
1007                                 osrfHashSet( node->parent->nodeHash, node, node->remote );
1008                                 node->state = OSRF_CHAT_STATE_CONNECTED;
1009                         }
1010                 }
1011         }
1012 }
1013
1014
1015 static void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
1016         if(!(blob && ch && len)) return;
1017         osrfChatNode* node = (osrfChatNode*) blob;
1018
1019         /*
1020         osrfLogDebug( OSRF_LOG_MARK, "Char Handler: state %d, xmlstate %d, chardata %s",
1021                         node->state, node->xmlstate, (char*) ch );
1022         */
1023
1024         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
1025                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
1026
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;
1031                         }
1032
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;
1037                         }
1038                 }
1039
1040                 return;
1041         }
1042
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);
1047                 return;
1048         }
1049
1050         if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
1051                         (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
1052
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 );
1058
1059                 if(eq(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 );
1063                         free(msg);
1064                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
1065                         node->xmlstate = 0;
1066
1067                 } else {
1068                         osrfLogWarning( OSRF_LOG_MARK, "Server2Server keys do not match!");
1069                 }
1070
1071                 free( e );
1072                 free( key );
1073
1074                 /* do the hash dance again */
1075         }
1076 }
1077
1078
1079 static void osrfChatParseError( void* blob, const char* msg, ... ) {
1080
1081         osrfChatXMLErrorOcurred = 1;
1082 }