]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/jserver/jserver-c.c
more install goodness, fixed random jserver bug
[OpenSRF.git] / src / jserver / jserver-c.c
1 #include "jserver-c.h"
2
3 /* ------------------------------------------------
4         some pre-packaged Jabber XML
5         ------------------------------------------------ */
6 static const char* xml_parse_error = "<stream:stream xmlns:stream='http://etherx.jabber.org/streams'" 
7         "version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'>"
8         "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
9         "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax error</text></stream:error></stream:stream>";
10
11 static const char* xml_login_ok = "<iq xmlns='jabber:client' id='asdfjkl' type='result'/>";
12
13
14 jserver* jserver_init() {
15         jserver* js                                     = safe_malloc(sizeof(jserver));
16         js->mgr                                         = safe_malloc(sizeof(socket_manager));
17         js->mgr->data_received  = &jserver_handle_request;
18         js->mgr->blob                           = js;
19         js->mgr->on_socket_closed       = &jserver_socket_closed;
20         js->client                                      = NULL;
21
22         return js;
23 }
24
25 void jserver_free(jserver* js) {
26         if(js == NULL) return;
27         jclient_node* node; 
28         while(js->client) {
29                 node = js->client->next;
30                 _jserver_remove_client_id(js, js->client->id);
31                 js->client = node;
32         }
33         socket_manager_free(js->mgr);
34         free(js);
35 }
36
37 void jserver_socket_closed(void* blob, int sock_id) {
38         jserver* js = (jserver*) blob;
39         if(js == NULL) return;
40         info_handler("Removing client %d - site closed socket",sock_id);
41         _jserver_remove_client_id(js, sock_id);
42 }
43
44 /* opens the inet and unix sockets that we're listening on */
45 int jserver_connect(jserver* js, int port, char* unix_path) {
46         if(js == NULL || js->mgr == NULL) return -1;
47         int status = 0;
48
49         if(port > 0) {
50                 status = socket_open_tcp_server(js->mgr, port);
51                 if(status == -1) return status;
52         }
53
54         if(unix_path != NULL) {
55                 status = socket_open_unix_server(js->mgr, unix_path);
56                 if(status == -1) return status;
57         }
58
59         return 0;
60 }
61
62 void _free_jclient_node(jclient_node* node) {
63         if(node == NULL) return;
64         free(node->addr);
65         jserver_session_free(node->session);
66         free(node);
67 }
68
69 /* allocates a new client node */
70 jclient_node* _new_jclient_node(int id) {
71         jclient_node* node = safe_malloc(sizeof(jclient_node));
72         node->id = id;
73         node->addr = NULL;
74         node->session = jserver_session_init();
75         node->session->blob = node;
76         node->session->on_msg_complete = &jserver_client_handle_msg; 
77         node->session->on_from_discovered = &jserver_client_from_found;
78         node->session->on_login_init = &jserver_client_login_init;
79         node->session->on_login_ok = &jserver_client_login_ok;
80         node->session->on_client_finish = &jserver_client_finish;
81         return node;
82 }
83
84 /* client has sent the end of it's session doc, we may now disconnect */
85 void jserver_client_finish(void* blob) {
86         jclient_node* node = (jclient_node*) blob;
87         if(node == NULL) return;
88         jserver_send_id(node->id, "</stream:stream>");
89         _jserver_remove_client(node->parent, node->addr);
90
91 }
92
93 void jserver_client_from_found(void* blob, char* from) {
94         jclient_node* node = (jclient_node*) blob;
95         if(node == NULL || from == NULL) return;
96
97         /* prevent duplicate login - kick off original */
98         _jserver_remove_client(node->parent, from);
99         info_handler("logged in: %s", from);
100         node->addr = strdup(from);
101 }
102
103 void jserver_client_login_init(void* blob, char* reply) {
104         debug_handler("here");
105         jclient_node* node = (jclient_node*) blob;
106         if(node == NULL || reply == NULL) return;
107         debug_handler("jserver handling login init");
108         jserver_send_id(node->id, reply);
109 }
110
111 void jserver_client_login_ok(void* blob) {
112         jclient_node* node = (jclient_node*) blob;
113         if(node == NULL) return;
114         info_handler("Client logging in ok => %d", node->id);
115         jserver_send_id(node->id, xml_login_ok);
116 }
117
118 void jserver_client_handle_msg( 
119         void* blob, char* xml, char* from, char* to ) {
120
121         jclient_node* node = (jclient_node*) blob;
122         if(node == NULL || xml == NULL || to == NULL) return;
123         int from_id = 0;
124
125         jclient_node* from_node = jserver_find_client(node->parent, from);
126         if(from_node)
127                 from_id = from_node->id;
128
129
130         debug_handler("Client %d received from %s message : %s", 
131                         node->id, from, xml );
132
133         jserver_send(node->parent, from_id, to, xml);
134 }
135
136 /* allocates a new client node and adds it to the set */
137 jclient_node* _jserver_add_client(jserver* js, int id) {
138         if(js == NULL) return NULL;
139         jclient_node* node = _new_jclient_node(id);
140         node->next = js->client;
141         js->client = node;
142         node->parent = js;
143         return node;
144 }
145
146
147 /* removes and frees a client node */
148 void _jserver_remove_client(jserver* js, char* addr) {
149         if(js == NULL || js->client == NULL || addr == NULL) return;
150
151         jclient_node* node = js->client;
152
153         if(node->addr && !strcmp(node->addr,addr)) {
154                 js->client = node->next;
155                 debug_handler("Removing the first jserver client");
156                 socket_disconnect(js->mgr, node->id);
157                 _free_jclient_node(node);
158                 return;
159         }
160
161         debug_handler("Searching for jclient to remove");
162         jclient_node* tail_node = node;
163         node = node->next;
164
165         while(node) {
166                 if(node->addr && !strcmp(node->addr,addr)) {
167                         tail_node->next = node->next;
168                         debug_handler("Removing a jserver client");
169                         socket_disconnect(js->mgr, node->id);
170                         _free_jclient_node(node);
171                         return;
172                 }
173                 tail_node = node;
174                 node = node->next;
175         }
176 }
177
178
179 /* removes and frees a client node */
180 void _jserver_remove_client_id(jserver* js, int id) {
181         if(js == NULL || js->client == NULL) return;
182
183         jclient_node* node = js->client;
184
185         debug_handler("Searching for jclient to remove with id %d", id);
186         debug_handler("First node in list has id %d", node->id );
187
188         if(node->id == id) {
189                 js->client = node->next;
190                 debug_handler("Removing the first jserver client");
191                 socket_disconnect(js->mgr, node->id);
192                 _free_jclient_node(node);
193                 return;
194         }
195
196         jclient_node* tail_node = node;
197         node = node->next;
198
199         while(node) {
200                 debug_handler("Checking node %d to remove", node->id);
201                 if(node->id == id) {
202                         tail_node->next = node->next;
203                         debug_handler("Removing a jserver client");
204                         socket_disconnect(js->mgr, node->id);
205                         _free_jclient_node(node);
206                         return;
207                 }
208                 tail_node = node;
209                 node = node->next;
210         }
211 }
212
213 /* finds a client node by addr */
214 jclient_node* jserver_find_client(jserver* js, char* addr) {
215         if(js == NULL || addr == NULL) return NULL;
216         jclient_node* node = js->client;
217         while(node) {
218                 if(node->addr && !strcmp(node->addr, addr)) 
219                         return node;
220                 node = node->next;
221         }
222         return NULL;
223 }
224
225 jclient_node* jserver_find_client_id(jserver* js, int id) {
226         if(js == NULL) return NULL;
227         jclient_node* node = js->client;
228         while(node) {
229                 if(node->id == id) 
230                         return node;
231                 node = node->next;
232         }
233         return NULL;
234 }
235
236 /* sends msg to client at 'to_addr' */
237 int jserver_send(jserver* js, int from_id, char* to_addr, const char* msg_xml) {
238         debug_handler("sending message to %s : %s", to_addr, msg_xml);
239         if(to_addr == NULL || msg_xml == NULL) return -1;
240
241         jclient_node* node = jserver_find_client(js, to_addr);
242
243         if(node == NULL) {
244                 info_handler("message to non-existent client %s", to_addr);
245                 if(from_id > 0) {
246                         jclient_node* from = jserver_find_client_id(js, from_id);
247
248                         if(from) {
249                                 info_handler("replying with error...");
250                                 char buf[2048];
251                                 memset(buf, 0, 2048);
252                                 snprintf(buf, 2047, "<message xmlns='jabber:client' type='error' from='%s' "
253                                         "to='%s'><error type='cancel' code='404'><item-not-found "
254                                         "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>"
255                                         "<body>NOT ADDING BODY</body></message>", to_addr, from->addr );
256                                 jserver_send_id(from_id, buf);
257                         }
258                 }
259                 return -1;
260         }
261
262         return jserver_send_id(node->id, msg_xml);
263 }
264
265 int jserver_send_id(int client_id, const char* msg_xml) {
266         if(msg_xml == NULL || client_id < 1) return -1;
267         return socket_send(client_id, msg_xml );
268 }
269
270 /* waits for any incoming data */
271 int jserver_wait(jserver* js) {
272         if(js == NULL) return -1;
273         while(1) {
274                 if(socket_wait_all(js->mgr, -1) < 0)
275                         warning_handler(
276                                 "jserver_wait(): socket_wait_all() returned error");
277
278         }
279 }
280
281
282 int _jserver_push_client_data(jclient_node* node, char* data) {
283         if(node == NULL || data == NULL) return -1;
284         return jserver_session_push_data( node->session, data);
285 }
286
287 void jserver_handle_request(void* js_blob, 
288         socket_manager* mgr, int sock_id, char* data, int parent_id ) {
289
290         jserver* js = (jserver*) js_blob;
291
292         debug_handler("jsever received data from socket %d (parent %d)", sock_id, parent_id );
293
294         jclient_node* node = jserver_find_client_id(js, sock_id);
295         if(!node) {
296                 debug_handler("We have a new client connection, adding to list");
297                 node = _jserver_add_client(js, sock_id);
298         }
299
300         if(_jserver_push_client_data(node, data) == -1) {
301                 warning_handler("Client sent bad data, disconnecting...");
302                 jserver_send_id(node->id, xml_parse_error);
303                 _jserver_remove_client(js, node->addr);         
304
305         } else {
306                 debug_handler("Client data successfully parsed");
307         }
308
309 }
310
311
312
313