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 /* client to server XML */
37 #define OSRF_CHAT_START_STREAM "<?xml version='1.0'?><stream:stream "\
38 "xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' "\
39 "from='%s' version='1.0' id='%s'>"
41 #define OSRF_CHAT_PARSE_ERROR "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
42 "version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'>"\
43 "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>" \
44 "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax error</text></stream:error></stream:stream>"
46 #define OSRF_CHAT_LOGIN_OK "<iq xmlns='jabber:client' id='0123456789' type='result'/>"
48 #define OSRF_CHAT_NO_RECIPIENT "<message xmlns='jabber:client' type='error' from='%s' to='%s'>"\
49 "<error type='cancel' code='404'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"\
50 "</error><body>NOT ADDING BODY</body></message>"
52 /* ---------------------------------------------------------------------------------- */
53 /* server to server XML */
55 // client to server init
56 #define OSRF_CHAT_S2S_INIT "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
57 "xmlns='jabber:server' xmlns:db='jabber:server:dialback'>"
59 // server to client challenge
60 #define OSRF_CHAT_S2S_CHALLENGE "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
61 "xmlns='jabber:server' id='%s' xmlns:db='jabber:server:dialback'>"
63 // client to server challenge response
64 #define OSRF_CHAT_S2S_RESPONSE "<db:result xmlns:db='jabber:server:dialback' to='%s' from='%s'>%s</db:result>"
66 // server to client verify
67 #define OSRF_CHAT_S2S_VERIFY_REQUEST "<db:verify xmlns:db='jabber:server:dialback' id='%s' from='%s' to='%s'>%s</db:verify>"
69 // client to server verify response
70 #define OSRF_CHAT_S2S_VERIFY_RESPONSE "<db:verify xmlns:db='jabber:server:dialback' type='valid' to='%s' from='%s' id='%s'/>"
72 //server to client final verification
73 #define OSRF_CHAT_S2S_VERIFY_FINAL "<db:result xmlns:db='jabber:server:dialback' type='valid' from='%s' to ='%s'/>"
77 #define OSRF_CHAT_STATE_NONE 0 /* blank node */
78 #define OSRF_CHAT_STATE_CONNECTING 1 /* we have received the opening stream */
79 #define OSRF_CHAT_STATE_CONNECTED 2 /* we have sent the OK/result message */
82 #define OSRF_CHAT_STATE_S2S_CHALLENGE 4 /* client : waiting for the challenge */
83 #define OSRF_CHAT_STATE_S2S_RESPONSE 5 /* server : waiting for the challenge response */
84 #define OSRF_CHAT_STATE_S2S_VERIFY 6 /* client : waiting for verify message */
85 #define OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE 7 /* server : waiting for verify response */
86 #define OSRF_CHAT_STATE_S2S_VERIFY_FINAL 8 /* client : waiting for final verify response */
88 /* xml parser states */
89 #define OSRF_CHAT_STATE_INMESSAGE 1
90 #define OSRF_CHAT_STATE_INIQ 2
91 #define OSRF_CHAT_STATE_INUSERNAME 4
92 #define OSRF_CHAT_STATE_INRESOURCE 8
93 #define OSRF_CHAT_STATE_INS2SRESULT 16
94 #define OSRF_CHAT_STATE_INS2SVERIFY 32
97 struct __osrfChatNodeStruct {
99 int sockid; /* our socket id */
101 int type; /* 0 for client, 1 for server */
103 /* for clients this is the full JID of the client that connected to this server.
104 for servers it's the domain (network id) of the server we're connected to */
108 int state; /* for the various stages of connectivity and parsing */
109 int xmlstate; /* what part of the message are we currently parsing */
110 int inparse; /* true if we are currently parsing a chunk of XML. If so, we can't
111 free the node. we have to cache it and free it later */
113 char* to; /* The JID where the current message is being routed */
115 char* domain; /* the domain, resource, and username of our connecting entity. */
116 char* resource; /* for s2s nodes, resource and username will be empty . */
119 char* authkey; /* when doing any auth negotiation, this is the auth seed hash */
120 osrfList* msgs; /* if we're a server node we may have a pool of messages waiting to be delivered */
122 xmlParserCtxtPtr parserCtx;
124 struct __osrfChatServerStruct* parent;
127 typedef struct __osrfChatNodeStruct osrfChatNode;
130 struct __osrfChatS2SMessageStruct {
134 typedef struct __osrfChatS2SMessageStruct osrfChatS2SMessage;
137 struct __osrfChatServerStruct {
138 osrfHash* nodeHash; /* sometimes we need hash (remote id) lookup, sometimes we need socket id lookup */
140 osrfList* deadNodes; /* collection of nodes to free when we get a chance */
142 char* secret; /* shared S2S secret */
143 char* domain; /* the domain this server hosts */
148 typedef struct __osrfChatServerStruct osrfChatServer;
151 void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode );
153 osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote );
154 osrfChatNode* osrfNewChatNode( int sockid, char* domain );
155 void osrfChatNodeFree( void* node );
157 /* @param s2sSecret The Server to server secret. OK to leave NULL if no
158 server to server communication is expected
160 osrfChatServer* osrfNewChatServer( char* domain, char* s2sSecret, int s2sport );
162 int osrfChatServerConnect( osrfChatServer* cs, int port, int s2sport, char* listenAddr );
164 int osrfChatServerWait( osrfChatServer* server );
165 void osrfChatServerFree(osrfChatServer* cs);
167 void osrfChatHandleData( void* cs,
168 socket_manager* mgr, int sockid, char* data, int parent_id );
171 /* removes dead nodes that have been cached due to mid-parse removals */
172 void osrfChatCleanupClients( osrfChatServer* server );
175 osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid );
178 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node );
180 /** pushes new data into the nodes parser */
181 int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data );
184 void osrfChatSocketClosed( void* blob, int sockid );
187 Sends msgXML to the client with remote 'toAddr'. if we have no connection
188 to 'toAddr' and the domain for 'toAddr' is different than our hosted domain
189 we attempt to send the message to the domain found in 'toAddr'.
191 int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML );
193 int osrfChatSendRaw( osrfChatNode* node, char* xml );
196 void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node );
198 /* initializes the negotiation of a server to server connection */
199 int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML );
202 void osrfChatStartStream( void* blob );
203 void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
204 void osrfChatEndElement( void* blob, const xmlChar* name );
205 void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
206 void osrfChatParseError( void* blob, const char* msg, ... );
208 int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts );
209 int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts );
210 int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts );
211 int osrfChatHandleS2SInit( osrfChatNode* node, const char* name, const xmlChar** atts );
212 int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts );
213 int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts );
215 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* nm, const xmlChar**atts );
217 void osrfChatS2SMessageFree(void* n);
221 /* generates a random sha1 hex key */
222 char* osrfChatMkAuthKey();
224 static xmlSAXHandler osrfChatSaxHandlerStruct = {
225 NULL, /* internalSubset */
226 NULL, /* isStandalone */
227 NULL, /* hasInternalSubset */
228 NULL, /* hasExternalSubset */
229 NULL, /* resolveEntity */
230 NULL, /* getEntity */
231 NULL, /* entityDecl */
232 NULL, /* notationDecl */
233 NULL, /* attributeDecl */
234 NULL, /* elementDecl */
235 NULL, /* unparsedEntityDecl */
236 NULL, /* setDocumentLocator */
237 osrfChatStartStream, /* startDocument */
238 NULL, /* endDocument */
239 osrfChatStartElement, /* startElement */
240 osrfChatEndElement, /* endElement */
241 NULL, /* reference */
242 osrfChatHandleCharacter, /* characters */
243 NULL, /* ignorableWhitespace */
244 NULL, /* processingInstruction */
246 osrfChatParseError, /* xmlParserWarning */
247 osrfChatParseError, /* xmlParserError */
248 NULL, /* xmlParserFatalError : unused */
249 NULL, /* getParameterEntity */
250 NULL, /* cdataBlock; */
251 NULL, /* externalSubset; */
254 NULL, /* startElementNs */
255 NULL, /* endElementNs */
256 NULL /* xmlStructuredErrorFunc */
259 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;