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/logging.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 8
94 #define OSRF_CHAT_STATE_INS2SVERIFY 8
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 */
121 osrfList* msgs; /* if we're a server node we may have a pool of messages waiting to be delivered */
123 xmlParserCtxtPtr parserCtx;
125 struct __osrfChatServerStruct* parent;
128 typedef struct __osrfChatNodeStruct osrfChatNode;
130 struct __osrfChatS2SMessageStruct {
134 typedef struct __osrfChatS2SMessageStruct osrfChatS2SMessage;
136 struct __osrfChatServerStruct {
137 osrfHash* nodeHash; /* sometimes we need hash (remote id) lookup, sometimes we need socket id lookup */
139 osrfList* deadNodes; /* collection of nodes to free when we get a chance */
141 char* secret; /* shared S2S secret */
142 char* domain; /* the domain this server hosts */
147 typedef struct __osrfChatServerStruct osrfChatServer;
150 void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode );
152 osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote );
153 osrfChatNode* osrfNewChatNode( int sockid, char* domain );
154 void osrfChatNodeFree( void* node );
156 /* @param s2sSecret The Server to server secret. OK to leave NULL if no
157 server to server communication is expected
159 osrfChatServer* osrfNewChatServer( char* domain, char* s2sSecret, int s2sport );
161 int osrfChatServerConnect( osrfChatServer* cs, int port, int s2sport, char* listenAddr );
163 int osrfChatServerWait( osrfChatServer* server );
164 void osrfChatServerFree(osrfChatServer* cs);
166 void osrfChatHandleData( void* cs,
167 socket_manager* mgr, int sockid, char* data, int parent_id );
170 /* removes dead nodes that have been cached due to mid-parse removals */
171 void osrfChatCleanupClients( osrfChatServer* server );
174 osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid );
177 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node );
179 /** pushes new data into the nodes parser */
180 int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data );
183 void osrfChatSocketClosed( void* blob, int sockid );
186 Sends msgXML to the client with remote 'toAddr'. if we have no connection
187 to 'toAddr' and the domain for 'toAddr' is different than our hosted domain
188 we attempt to send the message to the domain found in 'toAddr'.
190 int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML );
192 int osrfChatSendRaw( osrfChatNode* node, char* xml );
195 void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node );
197 /* initializes the negotiation of a server to server connection */
198 int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML );
201 void osrfChatStartStream( void* blob );
202 void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
203 void osrfChatEndElement( void* blob, const xmlChar* name );
204 void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
205 void osrfChatParseError( void* blob, const char* msg, ... );
207 int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts );
208 int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts );
209 int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts );
210 int osrfChatHandleS2SInit( osrfChatNode* node, const char* name, const xmlChar** atts );
211 int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts );
212 int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts );
214 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* nm, const xmlChar**atts );
216 void osrfChatS2SMessageFree(void* n);
220 /* generates a random sha1 hex key */
221 char* osrfChatMkAuthKey();
223 static xmlSAXHandler osrfChatSaxHandlerStruct = {
224 NULL, /* internalSubset */
225 NULL, /* isStandalone */
226 NULL, /* hasInternalSubset */
227 NULL, /* hasExternalSubset */
228 NULL, /* resolveEntity */
229 NULL, /* getEntity */
230 NULL, /* entityDecl */
231 NULL, /* notationDecl */
232 NULL, /* attributeDecl */
233 NULL, /* elementDecl */
234 NULL, /* unparsedEntityDecl */
235 NULL, /* setDocumentLocator */
236 osrfChatStartStream, /* startDocument */
237 NULL, /* endDocument */
238 osrfChatStartElement, /* startElement */
239 osrfChatEndElement, /* endElement */
240 NULL, /* reference */
241 osrfChatHandleCharacter, /* characters */
242 NULL, /* ignorableWhitespace */
243 NULL, /* processingInstruction */
245 osrfChatParseError, /* xmlParserWarning */
246 osrfChatParseError, /* xmlParserError */
247 NULL, /* xmlParserFatalError : unused */
248 NULL, /* getParameterEntity */
249 NULL, /* cdataBlock; */
250 NULL, /* externalSubset; */
253 NULL, /* startElementNs */
254 NULL, /* endElementNs */
255 NULL /* xmlStructuredErrorFunc */
258 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;