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