]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/jserver/osrf_chat.c
Move the xmlSAXHandler out of the header and into the
[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 "osrf_chat.h"
17 #include <string.h>
18 #include <stdio.h>
19 #include <time.h>
20
21 static void osrfChatStartStream( void* blob );
22 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
23 static void osrfChatEndElement( void* blob, const xmlChar* name );
24 static void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
25 static void osrfChatParseError( void* blob, const char* msg, ... );
26
27 static xmlSAXHandler osrfChatSaxHandlerStruct = {
28    NULL,                                                /* internalSubset */
29    NULL,                                                /* isStandalone */
30    NULL,                                                /* hasInternalSubset */
31    NULL,                                                /* hasExternalSubset */
32    NULL,                                                /* resolveEntity */
33    NULL,                                                /* getEntity */
34    NULL,                                                /* entityDecl */
35    NULL,                                                /* notationDecl */
36    NULL,                                                /* attributeDecl */
37    NULL,                                                /* elementDecl */
38    NULL,                                                /* unparsedEntityDecl */
39    NULL,                                                /* setDocumentLocator */
40    osrfChatStartStream,                 /* startDocument */
41    NULL,                                                /* endDocument */
42    osrfChatStartElement,                /* startElement */
43    osrfChatEndElement,                  /* endElement */
44    NULL,                                                /* reference */
45    osrfChatHandleCharacter,             /* characters */
46    NULL,                                                /* ignorableWhitespace */
47    NULL,                                                /* processingInstruction */
48    NULL,                                                /* comment */
49    osrfChatParseError,                  /* xmlParserWarning */
50    osrfChatParseError,                  /* xmlParserError */
51    NULL,                                                /* xmlParserFatalError : unused */
52    NULL,                                                /* getParameterEntity */
53    NULL,                                                /* cdataBlock; */
54    NULL,                                                /* externalSubset; */
55    1,
56    NULL,
57    NULL,                                                /* startElementNs */
58    NULL,                                                /* endElementNs */
59    NULL                                                 /* xmlStructuredErrorFunc */
60 };
61
62 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;
63
64 #ifndef HOST_NAME_MAX
65 #define HOST_NAME_MAX 256
66 #endif
67
68 static int osrfChatXMLErrorOcurred = 0;
69
70 /* This is used by code in osrfChatPushData, but that code is
71    currently commented out.  Uncomment the next line if needed. */
72 //static int osrfChatClientSentDisconnect = 0;
73
74 /* shorter version of strcmp */
75 static int eq(const char* a, const char* b) { return (a && b && !strcmp(a,b)); }
76 //#define eq(a,b) ((a && b && !strcmp(a,b)) ? 1 : 0)
77
78 /* gnarly debug function */
79 static void chatdbg( osrfChatServer* server ) {
80
81         if(!server) return;
82         return; /* heavy logging, should only be used in heavy debug mode */
83
84         growing_buffer* buf = buffer_init(256);
85
86         buffer_add(buf, "---------------------------------------------------------------------\n");
87
88         buffer_fadd(buf, 
89                 "ChopChop Debug:\n"
90                 "Connections:           %lu\n"
91                 "Named nodes in hash:   %lu\n"
92                 "Domain:                %s\n"
93                 "Port:                  %d\n"
94                 "S2S Port:              %d\n"
95                 "-------------------------------------------------------\n",
96                 osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
97                 server->domain, server->port, server->s2sport );
98
99         osrfListIterator* itr = osrfNewListIterator(server->nodeList);
100         osrfChatNode* node;
101
102         while( (node = osrfListIteratorNext(itr)) ) {
103
104                 buffer_fadd( buf, 
105                         "sockid:    %d\n"
106                         "Remote:    %s\n"
107                         "State:     %d\n"
108                         "XMLState:  %d\n"
109                         "In Parse:  %d\n"
110                         "to:        %s\n"
111                         "Resource:  %s\n"
112                         "Username:  %s\n"
113                         "Domain:    %s\n"
114                         "Authkey:   %s\n"
115                         "type:          %d\n"
116                         "-------------------------------------------------------\n",
117                         node->sockid, node->remote, node->state, node->xmlstate, node->inparse,
118                         node->to, node->resource, node->username, node->domain, node->authkey, node->type );
119         }
120
121         osrfLogDebug( OSRF_LOG_MARK, "DEBUG:\n%s", buf->buf );
122         buffer_free(buf);
123         osrfListIteratorFree(itr);
124 }
125
126 osrfChatServer* osrfNewChatServer( char* domain, char* secret, int s2sport ) {
127         if(!(domain && secret)) return NULL;
128
129         osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
130
131         server->nodeHash        = osrfNewHash();
132         server->nodeList        = osrfNewList();
133         server->deadNodes = osrfNewList();
134         server->nodeList->freeItem = &osrfChatNodeFree;
135         server->domain          = strdup(domain);
136         server->secret      = strdup(secret);
137         server->s2sport = s2sport;
138         server->port        = 0;
139
140         // Build socket manager
141         server->mgr = safe_malloc(sizeof(socket_manager));
142         server->mgr->data_received = &osrfChatHandleData;
143         server->mgr->socket = NULL;
144         server->mgr->blob = server;
145         server->mgr->on_socket_closed = &osrfChatSocketClosed;
146
147         return server;
148 }
149
150 void osrfChatCleanupClients( osrfChatServer* server ) {
151         if(!server) return;
152         osrfListFree(server->deadNodes);
153         server->deadNodes = osrfNewList();
154 }
155
156
157
158 osrfChatNode* osrfNewChatNode( int sockid, char* domain ) {
159         if(sockid < 1 || !domain) return NULL;
160         osrfChatNode* node      = safe_malloc(sizeof(osrfChatNode));
161         node->sockid            = 0;
162         node->remote            = NULL;
163         node->state                             = OSRF_CHAT_STATE_NONE;
164         node->xmlstate          = 0;
165         node->inparse           = 0;
166         node->msgs                              = NULL; /* only s2s nodes cache messages */
167         node->parserCtx         = xmlCreatePushParserCtxt(osrfChatSaxHandler, node, "", 0, NULL);
168         node->msgDoc                    = xmlNewDoc(BAD_CAST "1.0");
169         node->domain = strdup(domain);
170         xmlKeepBlanksDefault(0);
171         node->authkey                   = NULL;
172         node->username                  = NULL;
173         node->resource                  = NULL;
174         node->to                                        = NULL;
175         node->type = 0;
176         node->parent            = NULL;
177         return node;
178 }
179
180
181 osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote ) {
182         if(!(domain && remote)) return NULL;
183         osrfChatNode* n = osrfNewChatNode( 1, domain );
184         n->state                = OSRF_CHAT_STATE_S2S_CHALLENGE;
185         n->sockid       = -1;
186         n->remote       = strdup(remote);
187         n->msgs         = osrfNewList();
188         n->msgs->freeItem = &osrfChatS2SMessageFree;
189         n->type = 1;
190         return n;
191 }
192
193 void osrfChatS2SMessageFree(void* n) { free(n); }
194
195 void osrfChatNodeFree( void* node ) {
196         if(!node) return;
197         osrfChatNode* n = (osrfChatNode*) node;
198
199         /* we can't free messages that are mid-parse because the
200                 we can't free the parser context */
201         if(n->inparse) {
202                 n->inparse = 0;
203                 osrfListPush(n->parent->deadNodes, n);
204                 return;
205         }
206
207         free(n->remote);
208         free(n->to);
209         free(n->username);
210         free(n->resource);
211         free(n->domain);
212         free(n->authkey);
213
214         osrfListFree(n->msgs);
215
216         if(n->parserCtx) {
217                 xmlFreeDoc(n->parserCtx->myDoc);
218                 xmlFreeParserCtxt(n->parserCtx);
219         }
220
221         xmlFreeDoc(n->msgDoc);
222         free(n);
223 }
224
225
226
227 int osrfChatServerConnect( osrfChatServer* cs,  int port, int s2sport, char* listenAddr ) {
228         if(!(cs && port && listenAddr)) return -1;
229         cs->port = port;
230         cs->s2sport = s2sport;
231         if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
232                 return -1;
233         if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
234                 return -1;
235         return 0;
236 }
237
238
239 int osrfChatServerWait( osrfChatServer* server ) {
240         if(!server) return -1;
241         while(1) {
242                 if(socket_wait_all(server->mgr, -1) < 0)
243                         osrfLogWarning( OSRF_LOG_MARK,  "jserver_wait(): socket_wait_all() returned error");
244         }
245         return -1;
246 }
247
248
249 void osrfChatServerFree(osrfChatServer* server ) {
250         if(!server) return;
251         osrfHashFree(server->nodeHash);
252         osrfListFree(server->nodeList);
253         osrfListFree(server->deadNodes);
254         socket_manager_free(server->mgr);
255         free(server->domain);
256         free(server->secret);
257
258         free(server);
259 }
260
261
262 void osrfChatHandleData( void* cs, 
263         socket_manager* mgr, int sockid, char* data, int parent_id ) {
264
265         if(!(cs && mgr && sockid && data)) return;
266
267         osrfChatServer* server = (osrfChatServer*) cs;
268
269         osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
270
271         if(node)
272                 osrfLogDebug( OSRF_LOG_MARK, "Found node for sockid %d with state %d", sockid, node->state);
273
274         if(!node) {
275                 osrfLogDebug( OSRF_LOG_MARK, "Adding new connection for sockid %d", sockid );
276                 node = osrfChatAddNode( server, sockid );
277         }
278
279         if(node) {
280                 if( (osrfChatPushData( server, node, data ) == -1) ) {
281                         osrfLogError( OSRF_LOG_MARK, 
282                                         "Node at socket %d with remote address %s and destination %s, "
283                                         "received bad XML [%s], disconnecting...", sockid, node->remote, node->to, data );
284                         osrfChatSendRaw(  node, OSRF_CHAT_PARSE_ERROR );
285                         osrfChatRemoveNode( server, node );
286                 }
287         }
288
289         osrfChatCleanupClients(server); /* clean up old dead clients */
290 }
291
292
293 void osrfChatSocketClosed( void* blob, int sockid ) {
294         if(!blob) return;
295         osrfChatServer* server = (osrfChatServer*) blob;
296         osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
297         osrfChatRemoveNode( server, node );
298 }
299
300 osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid ) {
301         if(!(server && sockid)) return NULL;
302         osrfChatNode* node = osrfNewChatNode(sockid, server->domain);
303         node->parent = server;
304         node->sockid = sockid;
305         osrfListSet( server->nodeList, node, sockid );
306         return node;
307 }
308
309 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
310         if(!(server && node)) return;
311         socket_disconnect(server->mgr, node->sockid);
312         if(node->remote) 
313                 osrfHashRemove( server->nodeHash, node->remote );
314         osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
315 }
316
317 int osrfChatSendRaw( osrfChatNode* node, char* msgXML ) {
318         if(!(node && msgXML)) return -1;
319         /* wait at most 3 second for this client to take our data */
320         return socket_send_timeout( node->sockid, msgXML, 3000000 ); 
321 }
322
323 void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
324         if(!(server && node)) return;
325         osrfChatSendRaw( node, "</stream:stream>");
326         osrfChatRemoveNode( server, node );
327 }
328
329
330 int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML ) {
331         if(!(cs && node && toAddr && msgXML)) return -1;
332
333         int l = strlen(toAddr);
334         char dombuf[l];
335         memset(dombuf, 0, sizeof(dombuf));
336         jid_get_domain( toAddr, dombuf, l );    
337
338         if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
339
340                 osrfLogInfo( OSRF_LOG_MARK, "Sending message on local connection\nfrom: %s\nto: %s", fromAddr, toAddr );
341                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
342                 if(tonode) {
343
344                         /* if we can't send to the recipient (recipient is gone or too busy, 
345                          * we drop the recipient and inform the sender that the recipient
346                          * is no more */
347                         if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
348
349                                 osrfChatRemoveNode( cs, tonode );
350                                 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
351
352                                 osrfLogError( OSRF_LOG_MARK, "Node failed to function. "
353                                                 "Responding to caller with error: %s", toAddr);
354
355
356                                 if( osrfChatSendRaw( node, xml ) < 0 ) {
357                                         osrfLogError(OSRF_LOG_MARK, "Sending node is now gone..removing");
358                                         osrfChatRemoveNode( cs, node );
359                                 }
360                                 free(xml);
361                         }
362
363                 } else {
364
365                         /* send an error message saying we don't have this connection */
366                         osrfLogInfo( OSRF_LOG_MARK, "We have no connection for %s", toAddr);
367                         char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
368                         if( osrfChatSendRaw( node, xml ) < 0 ) 
369                                 osrfChatRemoveNode( cs, node );
370                         free(xml);
371                 }
372
373         } else {
374
375                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
376                 if(tonode) {
377                         if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
378                                 osrfLogDebug( OSRF_LOG_MARK, "Routing message to server %s", dombuf);
379
380                                 if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
381                                         osrfLogError( OSRF_LOG_MARK, "Node failed to function: %s", toAddr);
382                                         char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
383                                         if( osrfChatSendRaw( node, xml ) < 0 ) 
384                                                 osrfChatRemoveNode( cs, node );
385                                         free(xml);
386                                         osrfChatRemoveNode( cs, tonode );
387                                 }
388
389                         } else {
390                                 osrfLogInfo( OSRF_LOG_MARK, "Received s2s message and we're still trying to connect...caching");
391                                 osrfListPush( tonode->msgs, strdup(msgXML) );
392                         }
393
394                 } else {
395
396                         if( osrfChatInitS2S( cs, dombuf, toAddr, msgXML ) != 0 ) {
397                                 osrfLogWarning( OSRF_LOG_MARK, "We are unable to connect to remote server %s for recipient %s", dombuf, toAddr);
398                                 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
399                                 osrfChatSendRaw( node, xml );
400                                 free(xml);
401                         }
402                 }
403         }
404
405         return 0;
406 }
407
408
409 /*
410 void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode ) {
411         if(!(toAddr && msgXML)) return;
412         osrfChatS2SMessage* msg = safe_malloc(sizeof(osrfChatS2SMessage));
413         msg->toAddr = strdup(toAddr);
414         msg->msgXML = strdup(msgXML);
415         osrfLogInfo( OSRF_LOG_MARK, "Pushing client message onto s2s queue waiting for connect... ");
416         osrfListPush( snode->msgs, msgXML );
417 }
418 */
419
420
421 int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML ) {
422         if(!(cs && remote && toAddr && msgXML)) return -1;
423
424         osrfLogInfo( OSRF_LOG_MARK, "Initing server2server connection to domain %s", remote );
425         osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
426         snode->parent = cs;
427
428         /* try to connect to the remote site */
429         snode->sockid = socket_open_tcp_client(cs->mgr, cs->s2sport, remote);
430         if(snode->sockid < 1) {
431                 osrfLogWarning( OSRF_LOG_MARK, "Unable to connect to remote server at %s", remote );
432                 osrfChatNodeFree( snode );
433                 return -1;
434         }
435
436         /* store the message we were supposed to deliver until we're fully connected */
437         //osrfChatCacheS2SMessage( toAddr, msgXML, snode );
438         osrfListPush( snode->msgs, strdup(msgXML) );
439         osrfHashSet(cs->nodeHash, snode, remote );
440         osrfListSet(cs->nodeList, snode, snode->sockid );
441
442         /* send the initial s2s request */
443         osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
444
445         osrfLogDebug( OSRF_LOG_MARK, "Added new s2s node...");
446         chatdbg(cs);
447
448         return 0;
449 }
450
451
452 /* commence SAX handling code */
453
454 int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
455         if(!(node && data)) return -1;
456
457         chatdbg(server);
458
459         osrfLogDebug( OSRF_LOG_MARK, "pushing data into xml parser for node %d with state %d:\n%s", 
460                                                  node->sockid, node->state, data);
461         node->inparse = 1;
462         xmlParseChunk(node->parserCtx, data, strlen(data), 0);
463         node->inparse = 0;
464
465         if(osrfChatXMLErrorOcurred) {
466                 osrfChatXMLErrorOcurred = 0;
467                 return -1;
468         }
469
470         /* we can't do cleanup of the XML handlers while in the middle of a 
471                 data push, so set flags in the data push and doe the cleanup here */
472         /*
473         if(osrfChatClientSentDisconnect) {
474                 osrfChatClientSentDisconnect  = 0;
475                 osrfChatNodeFinish( server, node );
476         }
477         */
478
479         return 0;
480 }
481
482
483 static void osrfChatStartStream( void* blob ) {
484         osrfLogDebug( OSRF_LOG_MARK, "Starting new client stream...");
485 }
486
487
488 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
489         if(!(blob && name)) return;
490         osrfChatNode* node = (osrfChatNode*) blob;
491
492         int status = -1;
493         char* nm = (char*) name;
494
495         osrfLogDebug( OSRF_LOG_MARK, "Starting element %s with namespace %s and node state %d", 
496                                                  nm, xmlSaxAttr(atts, "xmlns"), node->state );
497
498         switch( node->state ) {
499
500                 case OSRF_CHAT_STATE_NONE:
501                         status = osrfChatHandleNewConnection( node, nm, atts );
502                         osrfLogDebug( OSRF_LOG_MARK, "After NewConnection we have state %d", node->state);
503                         break;
504
505                 case OSRF_CHAT_STATE_CONNECTING:
506                         status = osrfChatHandleConnecting( node, nm, atts );
507                         break;
508
509                 case OSRF_CHAT_STATE_CONNECTED:
510                         status = osrfChatHandleConnected( node, nm, atts );
511                         break;
512
513                 case OSRF_CHAT_STATE_S2S_CHALLENGE:      
514                         status = osrfChatHandleS2SChallenge( node, nm, atts );
515                         break;
516
517                 case OSRF_CHAT_STATE_S2S_RESPONSE: /* server waiting for client response to challenge */
518                         if(eq(nm, "db:result")) {
519                                 char* remote = xmlSaxAttr(atts, "from");
520                                 if(remote) {
521                                         if( node->remote) free( node->remote );
522                                         node->remote = strdup(remote); /* copy off the client's id */
523                                 }
524                                 status = 0;
525                                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
526                         } else status = -1; 
527                         break;
528
529                 case OSRF_CHAT_STATE_S2S_VERIFY:        /* client : waiting for server verify message */
530                         if(eq(nm, "db:verify")) {
531                                 char* id = xmlSaxAttr( atts, "id" );
532                                 if(id) {
533                                         char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE, 
534                                                         node->remote, node->domain, id );
535                                         osrfChatSendRaw( node, xml );
536                                         free(xml);
537                                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
538                                         status = 0;
539                                 }
540                         }
541                         break;
542
543                 case OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE:       /* server waiting for client verify response */
544                 case OSRF_CHAT_STATE_S2S_VERIFY_FINAL: /* client waitig for final verify */
545                         status = osrfChatHandleS2SConnected( node, nm, atts );
546                         break;
547
548         }
549
550         if(status != 0) 
551                 osrfChatParseError( node, "We don't know how to handle the XML data received" );
552 }
553
554 #define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) osrfLogDebug( OSRF_LOG_MARK, z);
555
556
557
558 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
559         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
560
561         int status = -1;
562
563         if(eq(name,"db:verify")) { /* server receives verify from client */
564                 char* xml = va_list_to_string(OSRF_CHAT_S2S_VERIFY_FINAL, node->domain, node->remote ); 
565                 osrfChatSendRaw(node, xml );
566                 free(xml);
567                 status = 0;
568         }
569
570         if(eq(name, "db:result")) {
571                 /* send all the messages that we have queued for this server */
572                 node->state = OSRF_CHAT_STATE_CONNECTED;
573                 osrfListIterator* itr = osrfNewListIterator(node->msgs);
574
575                 char* xml;
576                 while( (xml = (char*) osrfListIteratorNext(itr)) ) {
577                         xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
578                         if(doc) {
579                                 char* from = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "from");
580                                 char* to = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "to");
581                                 osrfChatSend( node->parent, node, to, from, xml );
582                                 osrfLogDebug( OSRF_LOG_MARK, "Sending cached message from %s to %s", from, to);
583                                 xmlFree(to); xmlFree(from);
584                                 xmlFreeDoc(doc);
585                         }
586                 }
587
588                 osrfListIteratorFree(itr);
589                 osrfListFree(node->msgs);
590                 node->msgs = NULL;
591                 status = 0;
592         }
593
594         if(status == 0) {
595                 osrfLogInfo( OSRF_LOG_MARK, "Successfully made S2S connection to %s", node->remote );
596                 node->state = OSRF_CHAT_STATE_CONNECTED;
597                 node->xmlstate = 0;
598         }
599
600         return status;
601 }
602
603
604 /** check the namespace of the stream message to see if it's a server or client connection */
605 int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts ) {
606         CHAT_CHECK_VARS(node, name, "osrfChatHandleNewConnection()");
607
608         if(!eq(name, "stream:stream")) return -1;
609
610         if( node->authkey ) free( node->authkey );
611         node->authkey = osrfChatMkAuthKey();
612         char* ns = xmlSaxAttr(atts, "xmlns");
613         if(!ns) return -1;
614
615         if(eq(ns, "jabber:client")) { /* client connection */
616
617                 char* domain = xmlSaxAttr( atts, "to" );
618                 if(!domain) return -1; 
619         
620                 if(!eq(domain, node->domain)) {
621                         osrfLogWarning( OSRF_LOG_MARK, 
622                                 "Client attempting to connect to invalid domain %s. Our domain is %s", domain, node->domain);
623                         return -1;
624                 }
625         
626                 char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
627                 node->state = OSRF_CHAT_STATE_CONNECTING;
628
629                 osrfLogDebug( OSRF_LOG_MARK, "Server node %d setting state to OSRF_CHAT_STATE_CONNECTING[%d]",
630                                                          node->sockid, node->state );
631         
632                 osrfLogDebug( OSRF_LOG_MARK, "Server responding to connect message with\n%s\n", buf );
633                 osrfChatSendRaw( node, buf );
634                 free(buf);
635                 return 0;
636         }
637
638         /* server to server init */
639         if(eq(ns, "jabber:server")) { /* client connection */
640                 osrfLogInfo( OSRF_LOG_MARK, "We received a new server 2 server connection, generating auth key...");
641                 char* xml = va_list_to_string( OSRF_CHAT_S2S_CHALLENGE, node->authkey );
642                 osrfChatSendRaw( node, xml );
643                 free(xml);
644                 node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
645                 node->type = 1;
646                 return 0;
647         }
648
649         return -1;
650 }
651
652
653
654 char* osrfChatMkAuthKey() {
655         char hostname[HOST_NAME_MAX + 1] = "";
656         gethostname(hostname, sizeof(hostname) );
657         hostname[HOST_NAME_MAX] = '\0';
658         char keybuf[112];
659         snprintf(keybuf, sizeof(keybuf), "%d%ld%s", (int) time(NULL), (long) getpid(), hostname);
660         return strdup(shahash(keybuf));
661 }
662
663 int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts ) {
664         CHAT_CHECK_VARS(node, name, "osrfChatHandleConnecting()");
665         osrfLogDebug( OSRF_LOG_MARK, "Handling connect node %s", name );
666
667         if(eq(name, "iq")) node->xmlstate |= OSRF_CHAT_STATE_INIQ;
668         else if(eq(name,"username")) node->xmlstate |= OSRF_CHAT_STATE_INUSERNAME;
669         else if(eq(name,"resource")) node->xmlstate |= OSRF_CHAT_STATE_INRESOURCE;
670         return 0;
671 }
672
673 int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
674         CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
675
676         if(eq(name,"message")) {
677
678                 /* drop the old message and start with a new one */
679                 xmlNodePtr root = xmlNewNode(NULL, BAD_CAST name);
680                 xmlAddAttrs(root, atts);
681                 xmlNodePtr oldRoot = xmlDocSetRootElement(node->msgDoc, root);
682                 free(node->to);
683
684                 char* to = xmlSaxAttr(atts, "to");
685                 if(!to) to = "";
686
687                 node->to = strdup(to);
688                 if(oldRoot) xmlFreeNode(oldRoot);
689                 node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
690
691         } else {
692
693                 /* all non "message" nodes are simply added to the message */
694                 xmlNodePtr nodep = xmlNewNode(NULL, BAD_CAST name);
695                 xmlAddAttrs(nodep, atts);
696                 xmlAddChild(xmlDocGetRootElement(node->msgDoc), nodep);
697         }
698
699         return 0;
700 }
701
702 /* takes s2s secret, hashdomain, and the s2s auth token */
703 static char* osrfChatGenerateS2SKey( char* secret, char* hashdomain, char* authtoken ) {
704         if(!(secret && hashdomain && authtoken)) return NULL;
705         osrfLogInfo( OSRF_LOG_MARK, "Generating s2s key with auth token: %s", authtoken );
706         char* a = shahash(secret);
707         osrfLogDebug( OSRF_LOG_MARK, "S2S secret hash: %s", a);
708         char* b = va_list_to_string("%s%s", a, hashdomain);
709         char* c = shahash(b);
710         osrfLogDebug( OSRF_LOG_MARK, "S2S intermediate hash: %s", c);
711         char* d = va_list_to_string("%s%s", c, authtoken);
712         char* e = strdup(shahash(d));
713         free(b); free(d); 
714         return e;
715 }
716
717 int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts ) {
718         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
719
720 /* here we respond to the stream challenge */
721         if(eq(name, "stream:stream")) {
722                 char* id = xmlSaxAttr(atts, "id");
723                 if(id) {
724                         /* we use our domain in the s2s challenge hash */
725                         char* d = osrfChatGenerateS2SKey(node->parent->secret, node->domain, id );
726                         char* e = va_list_to_string(OSRF_CHAT_S2S_RESPONSE, node->remote, node->domain, d );
727                         osrfLogInfo( OSRF_LOG_MARK, "Answering s2s challenge with key:  %s", e );
728                         osrfChatSendRaw( node, e );
729                         free(d); free(e);
730                         node->state = OSRF_CHAT_STATE_S2S_VERIFY;
731                         return 0;
732                 }
733         }
734
735         return -1;
736 }
737
738 /*
739 int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts ) {
740         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
741
742         if(eq(name, "db:result")) {
743                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
744                 return 0;
745         }
746
747         return -1;
748 }
749 */
750
751
752
753 static void osrfChatEndElement( void* blob, const xmlChar* name ) {
754         if(!(blob && name)) return;
755         osrfChatNode* node = (osrfChatNode*) blob;
756
757         char* nm = (char*) name;
758
759         if(eq(nm,"stream:stream")) {
760                 osrfChatNodeFinish( node->parent, node );
761                 return;
762         }
763
764         if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
765                 if(eq(nm, "message")) {
766
767                         xmlNodePtr msg = xmlDocGetRootElement(node->msgDoc);
768                         if(msg && node->type == 0)
769                                 xmlSetProp(msg, BAD_CAST "from", BAD_CAST node->remote );
770                         char* string = xmlDocToString(node->msgDoc, 0 );
771
772                         char* from = (char*) xmlGetProp(msg, BAD_CAST "from");
773                         osrfLogDebug( OSRF_LOG_MARK,  "Routing message to %s\n%s\n", node->to, from, string );
774                         osrfChatSend( node->parent, node, node->to, from, string ); 
775                         xmlFree(from);
776                         free(string);
777                 }
778         }
779
780         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
781                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
782
783                         if(eq(nm, "iq")) {
784                                 node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
785                                 if( node->remote ) free( node->remote );
786                                 node->remote = va_list_to_string( 
787                                                 "%s@%s/%s", node->username, node->domain, node->resource );
788
789                                 osrfLogInfo( OSRF_LOG_MARK, "%s successfully logged in", node->remote );
790
791                                 osrfLogDebug( OSRF_LOG_MARK, "Setting remote address to %s", node->remote );
792                                 osrfChatSendRaw( node, OSRF_CHAT_LOGIN_OK );
793                                 if(osrfHashGet( node->parent->nodeHash, node->remote ) ) {
794                                         osrfLogWarning( OSRF_LOG_MARK, "New node replaces existing node for remote id %s", node->remote);
795                                         osrfHashRemove(node->parent->nodeHash, node->remote);
796                                 }
797                                 osrfHashSet( node->parent->nodeHash, node, node->remote );
798                                 node->state = OSRF_CHAT_STATE_CONNECTED;
799                         }
800                 }
801         }
802 }
803
804
805 static void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
806         if(!(blob && ch && len)) return;
807         osrfChatNode* node = (osrfChatNode*) blob;
808
809         /*
810         osrfLogDebug( OSRF_LOG_MARK, "Char Handler: state %d, xmlstate %d, chardata %s", 
811                         node->state, node->xmlstate, (char*) ch );
812         */
813
814         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
815                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
816
817                         if( node->xmlstate & OSRF_CHAT_STATE_INUSERNAME ) {
818                                 free(node->username);
819                                 node->username = strndup((char*) ch, len);
820                                 node->xmlstate &= ~OSRF_CHAT_STATE_INUSERNAME;
821                         }
822
823                         if( node->xmlstate & OSRF_CHAT_STATE_INRESOURCE ) {
824                                 free(node->resource);
825                                 node->resource = strndup((char*) ch, len);
826                                 node->xmlstate &= ~OSRF_CHAT_STATE_INRESOURCE;
827                         }
828                 }
829
830                 return;
831         } 
832         
833         if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
834                 xmlNodePtr last = xmlGetLastChild(xmlDocGetRootElement(node->msgDoc));
835                 xmlNodePtr txt = xmlNewTextLen(ch, len);
836                 xmlAddChild(last, txt);
837                 return;
838         }
839
840         if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
841                         (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
842
843                 char* key = strndup((char*) ch, len);
844                 osrfLogDebug( OSRF_LOG_MARK, "Got s2s key from %s : %s", node->remote, key );
845                 char* e = osrfChatGenerateS2SKey(node->parent->secret, node->remote, node->authkey );
846                 osrfLogInfo( OSRF_LOG_MARK, "\nReceived s2s key from server: %s\nKey should be: %s", key, e );
847
848                 if(eq(key, e)) {
849                         char* msg = va_list_to_string(OSRF_CHAT_S2S_VERIFY_REQUEST,  
850                                         node->authkey, node->domain, node->remote, e );
851                         osrfChatSendRaw(node, msg );
852                         free(msg);
853                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
854                         node->xmlstate = 0;
855
856                 } else {
857                         osrfLogWarning( OSRF_LOG_MARK, "Server2Server keys do not match!");
858                 }
859
860                 free( e );
861                 free( key );
862
863                 /* do the hash dance again */
864         }
865 }
866
867
868 static void osrfChatParseError( void* blob, const char* msg, ... ) {
869
870         osrfChatXMLErrorOcurred = 1;
871 }
872
873
874
875