jabberd2  2.3.4
io.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sx.h"
22 
25  sx_error_t sxe;
26  nad_t nad;
27  char *errstring;
28  int i;
29  int ns, elem;
30 
31  /* Note that buf->len can validly be 0 here, if we got data from
32  the socket but the plugin didn't return anything to us (e.g. a
33  SSL packet was split across a tcp segment boundary) */
34 
35  /* count bytes read */
36  s->rbytes += buf->len;
37 
38  /* parse it */
39  if(XML_Parse(s->expat, buf->data, buf->len, 0) == 0) {
40  /* only report error we haven't already */
41  if(!s->fail) {
42  /* parse error */
43  errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));
44 
45  _sx_debug(ZONE, "XML parse error: %s, character %d: %.*s",
46  errstring, XML_GetCurrentByteIndex(s->expat) - s->rbytes_total, buf->len, buf->data);
47  _sx_gen_error(sxe, SX_ERR_XML_PARSE, "XML parse error", errstring);
48  _sx_event(s, event_ERROR, (void *) &sxe);
49 
51  _sx_close(s);
52 
53  _sx_buffer_free(buf);
54 
55  return;
56  }
57 
58  /* !!! is this the right thing to do? we should probably set
59  * s->fail and let the code further down handle it. */
60  _sx_buffer_free(buf);
61 
62  return;
63  }
64 
65  /* check if the stanza size limit is exceeded (it wasn't reset by parser) */
66  if(s->rbytesmax && s->rbytes > s->rbytesmax) {
67  /* parse error */
68  _sx_debug(ZONE, "maximum stanza size (%d) exceeded by reading %d bytes", s->rbytesmax, s->rbytes);
69 
70  errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));
71 
72  _sx_gen_error(sxe, SX_ERR_XML_PARSE, "stream read error", "Maximum stanza size exceeded");
73  _sx_event(s, event_ERROR, (void *) &sxe);
74 
76  _sx_close(s);
77 
78  _sx_buffer_free(buf);
79 
80  return;
81  }
82 
83  /* count bytes processed */
84  s->rbytes_total += buf->len;
85 
86  /* done with the buffer */
87  _sx_buffer_free(buf);
88 
89  /* process completed nads */
90  if(s->state >= state_STREAM)
91  while((nad = jqueue_pull(s->rnadq)) != NULL) {
92  int plugin_error;
93 #ifdef SX_DEBUG
94  const char *out; int len;
95  nad_print(nad, 0, &out, &len);
96  _sx_debug(ZONE, "completed nad: %.*s", len, out);
97 #endif
98 
99  /* check for errors */
100  if(NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_STREAMS) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_STREAMS, strlen(uri_STREAMS)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "error", 5) == 0) {
101 
102  errstring = NULL;
103 
104  /* get text error description if available - XMPP 4.7.2 */
105  if((ns = nad_find_scoped_namespace(nad, uri_STREAM_ERR, NULL)) >= 0)
106  if((elem = nad_find_elem(nad, 0, ns, "text", 1)) >= 0)
107  if(NAD_CDATA_L(nad, elem) > 0) {
108  errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
109  sprintf(errstring, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
110  }
111 
112  /* if not available, look for legacy error text as in <stream:error>description</stream:error> */
113  if (errstring == NULL && NAD_CDATA_L(nad, 0) > 0) {
114  errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, 0) + 1));
115  sprintf(errstring, "%.*s", NAD_CDATA_L(nad, 0), NAD_CDATA(nad, 0));
116  }
117 
118  /* if not available, log the whole packet for debugging */
119  if (errstring == NULL) {
120  const char *xml;
121  int xlen;
122 
123  nad_print(nad, 0, &xml, &xlen);
124  errstring = (char *) malloc(sizeof(char) * (xlen + 1));
125  sprintf(errstring, "%.*s", xlen, xml);
126  }
127 
128  if(s->state < state_CLOSING) {
129  _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", errstring);
130  _sx_event(s, event_ERROR, (void *) &sxe);
132  }
133 
134  if(errstring != NULL) free(errstring);
135 
136  nad_free(nad);
137 
138  break;
139  }
140 
141  /* check for close */
142  if ((s->flags & SX_WEBSOCKET_WRAPPER) && NAD_ENS(nad, 0) >= 0 && NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_XFRAMING) && strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_XFRAMING, strlen(uri_XFRAMING)) == 0 && NAD_ENAME_L(nad, 0) == 5 && strncmp(NAD_ENAME(nad, 0), "close", 5) == 0) {
143  _sx_debug(ZONE, "<close/> frame @ depth %d", s->depth);
144  s->fail = 1;
145  break;
146  }
147 
148  /* run it by the plugins */
149  if(_sx_chain_nad_read(s, nad) == 0)
150  return;
151 
152  /* now let the plugins process the completed nad */
153  plugin_error = 0;
154  if(s->env != NULL)
155  for(i = 0; i < s->env->nplugins; i++)
156  if(s->env->plugins[i]->process != NULL) {
157  int plugin_ret;
158  plugin_ret = (s->env->plugins[i]->process)(s, s->env->plugins[i], nad);
159  if(plugin_ret == 0) {
160  plugin_error ++;
161  break;
162  }
163  }
164 
165  /* hand it to the app */
166  if ((plugin_error == 0) && (s->state < state_CLOSING))
167  _sx_event(s, event_PACKET, (void *) nad);
168  }
169 
170  /* something went wrong, bail */
171  if(s->fail) {
172  _sx_close(s);
173 
174  return;
175  }
176 
177  /* stream was closed */
178  if(s->depth < 0 && s->state < state_CLOSING) {
179  /* close the stream if necessary */
180 
181  if(s->state >= state_STREAM_SENT) {
182  if (s->flags & SX_WEBSOCKET_WRAPPER)
183  jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0);
184  else
185  jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
186  s->want_write = 1;
187  }
188 
190 
191  return;
192  }
193 }
194 
197  sx_buf_t in, out;
198  int read, ret;
199 
200  assert((int) (s != NULL));
201 
202  /* do we care? */
203  if(!s->want_read && s->state < state_CLOSING)
204  return 0; /* no more thanks */
205 
206  _sx_debug(ZONE, "%d ready for reading", s->tag);
207 
208  /* new buffer */
209  in = _sx_buffer_new(NULL, 1024, NULL, NULL);
210 
211  /* get them to read stuff */
212  read = _sx_event(s, event_READ, (void *) in);
213 
214  /* bail if something went wrong */
215  if(read < 0) {
216  _sx_buffer_free(in);
217  s->want_read = 0;
218  s->want_write = 0;
219  return 0;
220  }
221 
222  if(read == 0) {
223  /* nothing to read
224  * should never happen because we did get a read event,
225  * thus there is something to read, or error handled
226  * via (read < 0) block before (errors return -1) */
227  _sx_debug(ZONE, "decoded 0 bytes read data - this should not happen");
228  _sx_buffer_free(in);
229 
230  } else {
231  _sx_debug(ZONE, "passed %d read bytes", in->len);
232 
233  /* make a copy for processing */
234  out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
235 
236  /* run it by the plugins */
237  ret = _sx_chain_io_read(s, out);
238  if(ret <= 0) {
239  if(ret < 0) {
240  /* permanent failure, its all over */
241  /* !!! shut down */
242  s->want_read = s->want_write = 0;
243  }
244 
245  _sx_buffer_free(in);
246  _sx_buffer_free(out);
247 
248  /* done */
249  if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
250  return s->want_read;
251  }
252 
253  _sx_buffer_free(in);
254 
255  _sx_debug(ZONE, "decoded read data (%d bytes): %.*s", out->len, out->len, out->data);
256 
257  /* into the parser with you */
258  _sx_process_read(s, out);
259  }
260 
261  /* if we've written everything, and we're closed, then inform the app it can kill us */
262  if(s->want_write == 0 && s->state == state_CLOSING) {
264  _sx_event(s, event_CLOSED, NULL);
265  return 0;
266  }
267 
268  if(s->state == state_CLOSED)
269  return 0;
270 
271  if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
272  return s->want_read;
273 }
274 
277  sx_buf_t in, out;
278  int ret;
279 
280  assert(s != NULL);
281 
282  if (s->wbufpending != NULL) {
283  /* there's already a pending buffer ready to write */
284  return 0;
285  }
286 
287  /* get the first buffer off the queue */
288  in = jqueue_pull(s->wbufq);
289  if(in == NULL) {
290  /* if there was a write event, and something is interested,
291  we still have to tell the plugins */
292  in = _sx_buffer_new(NULL, 0, NULL, NULL);
293  }
294 
295  /* if there's more to write, we want to make sure we get it */
296  s->want_write = jqueue_size(s->wbufq);
297 
298  /* make a copy for processing */
299  out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
300 
301  _sx_debug(ZONE, "encoding %d bytes for writing: %.*s", in->len, in->len, in->data);
302 
303  /* run it by the plugins */
304  ret = _sx_chain_io_write(s, out);
305  if(ret <= 0) {
306  /* TODO/!!!: Are we leaking the 'out' buffer here? How about the 'in' buffer? */
307  if(ret == -1) {
308  /* temporary failure, push it back on the queue */
309  jqueue_push(s->wbufq, in, (s->wbufq->front != NULL) ? s->wbufq->front->priority : 0);
310  s->want_write = 1;
311  } else if(ret == -2) {
312  /* permanent failure, its all over */
313  /* !!! shut down */
314  s->want_read = s->want_write = 0;
315  return -1;
316  }
317 
318  /* done */
319  return 0;
320  }
321 
322  _sx_buffer_free(in);
323 
324  if (out->len == 0)
325  /* if there's nothing to write, then we're done */
326  _sx_buffer_free(out);
327  else
328  s->wbufpending = out;
329 
330  return 0;
331 }
332 
334  sx_buf_t out;
335  int ret, written;
336 
337  assert((int) (s != NULL));
338 
339  /* do we care? */
340  if(!s->want_write && s->state < state_CLOSING)
341  return 0; /* no more thanks */
342 
343  _sx_debug(ZONE, "%d ready for writing", s->tag);
344 
345  ret = _sx_get_pending_write(s);
346  if (ret < 0) {
347  /* fatal error */
348  _sx_debug(ZONE, "fatal error after attempt to write on fd %d", s->tag);
349  /* permanent error so inform the app it can kill us */
350  sx_kill(s);
351  return 0;
352  }
353 
354  /* if there's nothing to write, then we're done */
355  if(s->wbufpending == NULL) {
356  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
357  return s->want_write;
358  }
359 
360  out = s->wbufpending;
361  s->wbufpending = NULL;
362 
363  /* get the callback to do the write */
364  _sx_debug(ZONE, "handing app %d bytes to write", out->len);
365  written = _sx_event(s, event_WRITE, (void *) out);
366 
367  if(written < 0) {
368  /* bail if something went wrong */
369  _sx_buffer_free(out);
370  s->want_read = 0;
371  s->want_write = 0;
372  return 0;
373  } else if(written < out->len) {
374  /* if not fully written, this buffer is still pending */
375  out->len -= written;
376  out->data += written;
377  s->wbufpending = out;
378  s->want_write ++;
379  } else {
380  /* notify */
381  if(out->notify != NULL)
382  (out->notify)(s, out->notify_arg);
383 
384  /* done with this */
385  _sx_buffer_free(out);
386  }
387 
388  /* if we've written everything, and we're closed, then inform the app it can kill us */
389  if(s->want_write == 0 && s->state == state_CLOSING) {
391  _sx_event(s, event_CLOSED, NULL);
392  return 0;
393  }
394 
395  if(s->state == state_CLOSED)
396  return 0;
397 
398  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
399  return s->want_write;
400 }
401 
403 int _sx_nad_write(sx_t s, nad_t nad, int elem) {
404  const char *out;
405  int len;
406 
407  /* silently drop it if we're closing or closed */
408  if(s->state >= state_CLOSING) {
409  log_debug(ZONE, "stream closed, dropping outgoing packet");
410  nad_free(nad);
411  return 1;
412  }
413 
414  /* run it through the plugins */
415  if(_sx_chain_nad_write(s, nad, elem) == 0)
416  return 1;
417 
418  /* serialise it */
419  nad_print(nad, elem, &out, &len);
420 
421  _sx_debug(ZONE, "queueing for write: %.*s", len, out);
422 
423  /* ready to go */
424  jqueue_push(s->wbufq, _sx_buffer_new(out, len, NULL, NULL), 0);
425 
426  nad_free(nad);
427 
428  /* things to write */
429  s->want_write = 1;
430 
431  return 0;
432 }
433 
435 void sx_nad_write_elem(sx_t s, nad_t nad, int elem) {
436  assert((int) (s != NULL));
437  assert((int) (nad != NULL));
438 
439  if(_sx_nad_write(s, nad, elem) == 1)
440  return;
441 
442  /* things to write */
443  s->want_write = 1;
444  _sx_event(s, event_WANT_WRITE, NULL);
445 
446  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
447 }
448 
450 int _sx_raw_write(sx_t s, const char *buf, int len) {
451  /* siltently drop it if we're closing or closed */
452  if(s->state >= state_CLOSING) {
453  log_debug(ZONE, "stream closed, dropping outgoing raw data");
454  return 1;
455  }
456 
457  _sx_debug(ZONE, "queuing for write: %.*s", len, buf);
458 
459  /* ready to go */
460  jqueue_push(s->wbufq, _sx_buffer_new(buf, len, NULL, NULL), 0);
461 
462  /* things to write */
463  s->want_write = 1;
464 
465  return 0;
466 }
467 
469 void sx_raw_write(sx_t s, const char *buf, int len) {
470  assert((int) (s != NULL));
471  assert((int) (buf != NULL));
472  assert(len);
473 
474  if(_sx_raw_write(s, buf, len) == 1)
475  return;
476 
477  /* things to write */
478  s->want_write = 1;
479  _sx_event(s, event_WANT_WRITE, NULL);
480 
481  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
482 }
483 
485 void _sx_close(sx_t s) {
486  /* close the stream if necessary */
487  if(s->state >= state_STREAM_SENT) {
488  if (s->flags & SX_WEBSOCKET_WRAPPER)
489  jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0);
490  else
491  jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
492  s->want_write = 1;
493  }
494 
496 }
497 
498 void sx_close(sx_t s) {
499  assert((int) (s != NULL));
500 
501  if(s->state >= state_CLOSING)
502  return;
503 
504  if(s->state >= state_STREAM_SENT && s->state < state_CLOSING) {
505  _sx_close(s);
506  _sx_event(s, event_WANT_WRITE, NULL);
507  } else {
509  _sx_event(s, event_CLOSED, NULL);
510  }
511 }
512 
513 void sx_kill(sx_t s) {
514  assert((int) (s != NULL));
515 
517  _sx_event(s, event_CLOSED, NULL);
518 }
int _sx_chain_nad_write(sx_t s, nad_t nad, int elem)
Definition: chain.c:103
int _sx_chain_io_write(sx_t s, sx_buf_t buf)
Definition: chain.c:75
int priority
Definition: util.h:317
Definition: nad.h:93
Definition: sx.h:113
_sx_state_t state
Definition: sx.h:315
#define _sx_event(s, e, data)
Definition: sx.h:391
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
unsigned int flags
Definition: sx.h:275
void sx_nad_write_elem(sx_t s, nad_t nad, int elem)
app version
Definition: io.c:435
Definition: sx.h:59
jqueue_t wbufq
Definition: sx.h:300
int _sx_raw_write(sx_t s, const char *buf, int len)
send raw data out
Definition: io.c:450
int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:204
Definition: sx.h:65
int jqueue_size(jqueue_t q)
Definition: jqueue.c:126
error info for event_ERROR
Definition: sx.h:99
int rbytesmax
Definition: sx.h:312
int tag
Definition: sx.h:257
int sx_can_write(sx_t s)
Definition: io.c:333
sx_env_t env
Definition: sx.h:254
void sx_raw_write(sx_t s, const char *buf, int len)
app version
Definition: io.c:469
#define NAD_ENAME(N, E)
Definition: nad.h:183
#define SX_ERR_STREAM
Definition: sx.h:94
_jqueue_node_t front
Definition: util.h:327
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
Definition: sx.h:60
sx_buf_t wbufpending
Definition: sx.h:301
int sx_can_read(sx_t s)
we can read
Definition: io.c:196
holds the state for a single stream
Definition: sx.h:252
int depth
Definition: sx.h:319
char * data
Definition: sx.h:114
int rbytes
Definition: sx.h:308
#define NAD_ENAME_L(N, E)
Definition: nad.h:184
sx_plugin_t * plugins
Definition: sx.h:379
void jqueue_push(jqueue_t q, void *data, int priority)
Definition: jqueue.c:44
#define NAD_NURI_L(N, NS)
Definition: nad.h:192
int fail
Definition: sx.h:320
jqueue_t rnadq
Definition: sx.h:302
void _sx_buffer_free(sx_buf_t buf)
utility: kill a buffer
Definition: sx.c:244
#define SX_ERR_XML_PARSE
Definition: sx.h:96
sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg)
utility: make a new buffer if len>0 but data is NULL, the buffer will contain that many bytes of garb...
Definition: sx.c:220
void sx_close(sx_t s)
Definition: io.c:498
#define log_debug(...)
Definition: log.h:65
void _sx_process_read(sx_t s, sx_buf_t buf)
handler for read data
Definition: io.c:24
#define SX_WEBSOCKET_WRAPPER
Definition: plugins.h:34
#define _sx_debug
Definition: sx.h:404
int rbytes_total
Definition: sx.h:309
#define uri_STREAMS
Definition: uri.h:34
_sx_notify_t notify
Definition: sx.h:119
#define stream_err_POLICY_VIOLATION
Definition: sx.h:137
void _sx_close(sx_t s)
close a stream
Definition: io.c:485
void * jqueue_pull(jqueue_t q)
Definition: jqueue.c:96
int _sx_chain_nad_read(sx_t s, nad_t nad)
Definition: chain.c:116
int _sx_chain_io_read(sx_t s, sx_buf_t buf)
Definition: chain.c:89
unsigned int len
Definition: sx.h:115
#define uri_STREAM_ERR
Definition: uri.h:50
void _sx_error(sx_t s, int err, const char *text)
send an error
Definition: error.c:53
#define stream_err_XML_NOT_WELL_FORMED
Definition: sx.h:147
#define NAD_CDATA(N, E)
Definition: nad.h:185
void sx_kill(sx_t s)
Definition: io.c:513
#define _sx_gen_error(e, c, g, s)
helper macro to populate this struct
Definition: sx.h:106
#define ZONE
Definition: mio_impl.h:76
int want_read
Definition: sx.h:305
#define _sx_state(s, st)
Definition: sx.h:405
XML_Parser expat
Definition: sx.h:318
#define NAD_NURI(N, NS)
Definition: nad.h:191
int(* process)(sx_t s, sx_plugin_t p, nad_t nad)
Definition: sx.h:372
#define uri_XFRAMING
Definition: uri.h:44
void * notify_arg
Definition: sx.h:120
static int _sx_get_pending_write(sx_t s)
we can write
Definition: io.c:276
int _sx_nad_write(sx_t s, nad_t nad, int elem)
send a new nad out
Definition: io.c:403
int nplugins
Definition: sx.h:380
int want_write
Definition: sx.h:305
void nad_print(nad_t nad, int elem, const char **xml, int *len)
create a string representation of the given element (and children), point references to it ...
Definition: nad.c:1164
#define NAD_ENS(N, E)
Definition: nad.h:196
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
find a namespace in scope
Definition: nad.c:290