jabberd2  2.2.17
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; line: %d, column: %d", errstring, XML_GetCurrentLineNumber(s->expat), XML_GetCurrentColumnNumber(s->expat));
46  _sx_gen_error(sxe, SX_ERR_XML_PARSE, "XML parse error", errstring);
47  _sx_event(s, event_ERROR, (void *) &sxe);
48 
50  _sx_close(s);
51 
52  _sx_buffer_free(buf);
53 
54  return;
55  }
56 
57  /* !!! is this the right thing to do? we should probably set
58  * s->fail and let the code further down handle it. */
59  _sx_buffer_free(buf);
60 
61  return;
62  }
63 
64  /* check if the stanza size limit is exceeded (it wasn't reset by parser) */
65  if(s->rbytesmax && s->rbytes > s->rbytesmax) {
66  /* parse error */
67  _sx_debug(ZONE, "maximum stanza size (%d) exceeded by reading %d bytes", s->rbytesmax, s->rbytes);
68 
69  errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));
70 
71  _sx_gen_error(sxe, SX_ERR_XML_PARSE, "stream read error", "Maximum stanza size exceeded");
72  _sx_event(s, event_ERROR, (void *) &sxe);
73 
75  _sx_close(s);
76 
77  _sx_buffer_free(buf);
78 
79  return;
80  }
81 
82  /* done with the buffer */
83  _sx_buffer_free(buf);
84 
85  /* process completed nads */
86  if(s->state >= state_STREAM)
87  while((nad = jqueue_pull(s->rnadq)) != NULL) {
88  int plugin_error;
89 #ifdef SX_DEBUG
90  char *out; int len;
91  nad_print(nad, 0, &out, &len);
92  _sx_debug(ZONE, "completed nad: %.*s", len, out);
93 #endif
94 
95  /* check for errors */
96  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) {
97 
98  errstring = NULL;
99 
100  /* get text error description if available - XMPP 4.7.2 */
101  if((ns = nad_find_scoped_namespace(nad, uri_STREAM_ERR, NULL)) >= 0)
102  if((elem = nad_find_elem(nad, 0, ns, "text", 1)) >= 0)
103  if(NAD_CDATA_L(nad, elem) > 0) {
104  errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
105  sprintf(errstring, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
106  }
107 
108  /* if not available, look for legacy error text as in <stream:error>description</stream:error> */
109  if (errstring == NULL && NAD_CDATA_L(nad, 0) > 0) {
110  errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, 0) + 1));
111  sprintf(errstring, "%.*s", NAD_CDATA_L(nad, 0), NAD_CDATA(nad, 0));
112  }
113 
114  /* if not available, log the whole packet for debugging */
115  if (errstring == NULL) {
116  char *xml;
117  int xlen;
118 
119  nad_print(nad, 0, &xml, &xlen);
120  errstring = (char *) malloc(sizeof(char) * (xlen + 1));
121  sprintf(errstring, "%.*s", xlen, xml);
122  }
123 
124  if(s->state < state_CLOSING) {
125  _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", errstring);
126  _sx_event(s, event_ERROR, (void *) &sxe);
128  }
129 
130  if(errstring != NULL) free(errstring);
131 
132  nad_free(nad);
133 
134  break;
135  }
136 
137  /* run it by the plugins */
138  if(_sx_chain_nad_read(s, nad) == 0)
139  return;
140 
141  /* now let the plugins process the completed nad */
142  plugin_error = 0;
143  if(s->env != NULL)
144  for(i = 0; i < s->env->nplugins; i++)
145  if(s->env->plugins[i]->process != NULL) {
146  int plugin_ret;
147  plugin_ret = (s->env->plugins[i]->process)(s, s->env->plugins[i], nad);
148  if(plugin_ret == 0) {
149  plugin_error ++;
150  break;
151  }
152  }
153 
154  /* hand it to the app */
155  if ((plugin_error == 0) && (s->state < state_CLOSING))
156  _sx_event(s, event_PACKET, (void *) nad);
157  }
158 
159  /* something went wrong, bail */
160  if(s->fail) {
161  _sx_close(s);
162 
163  return;
164  }
165 
166  /* stream was closed */
167  if(s->depth < 0 && s->state < state_CLOSING) {
168  /* close the stream if necessary */
169  if(s->state >= state_STREAM_SENT) {
170  jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
171  s->want_write = 1;
172  }
173 
175 
176  return;
177  }
178 }
179 
182  sx_buf_t in, out;
183  int read, ret;
184 
185  assert((int) (s != NULL));
186 
187  /* do we care? */
188  if(!s->want_read && s->state < state_CLOSING)
189  return 0; /* no more thanks */
190 
191  _sx_debug(ZONE, "%d ready for reading", s->tag);
192 
193  /* new buffer */
194  in = _sx_buffer_new(NULL, 1024, NULL, NULL);
195 
196  /* get them to read stuff */
197  read = _sx_event(s, event_READ, (void *) in);
198 
199  /* bail if something went wrong */
200  if(read < 0) {
201  _sx_buffer_free(in);
202  s->want_read = 0;
203  s->want_write = 0;
204  return 0;
205  }
206 
207  if(read == 0) {
208  /* nothing to read
209  * should never happen because we did get a read event,
210  * thus there is something to read, or error handled
211  * via (read < 0) block before (errors return -1) */
212  _sx_debug(ZONE, "decoded 0 bytes read data - this should not happen");
213  _sx_buffer_free(in);
214 
215  } else {
216  _sx_debug(ZONE, "passed %d read bytes", in->len);
217 
218  /* make a copy for processing */
219  out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
220 
221  /* run it by the plugins */
222  ret = _sx_chain_io_read(s, out);
223  if(ret <= 0) {
224  if(ret < 0) {
225  /* permanent failure, its all over */
226  /* !!! shut down */
227  s->want_read = s->want_write = 0;
228  }
229 
230  _sx_buffer_free(in);
231  _sx_buffer_free(out);
232 
233  /* done */
234  if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
235  return s->want_read;
236  }
237 
238  _sx_buffer_free(in);
239 
240  _sx_debug(ZONE, "decoded read data (%d bytes): %.*s", out->len, out->len, out->data);
241 
242  /* into the parser with you */
243  _sx_process_read(s, out);
244  }
245 
246  /* if we've written everything, and we're closed, then inform the app it can kill us */
247  if(s->want_write == 0 && s->state == state_CLOSING) {
249  _sx_event(s, event_CLOSED, NULL);
250  return 0;
251  }
252 
253  if(s->state == state_CLOSED)
254  return 0;
255 
256  if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
257  return s->want_read;
258 }
259 
262  sx_buf_t in, out;
263  int ret;
264 
265  assert(s != NULL);
266 
267  if (s->wbufpending != NULL) {
268  /* there's already a pending buffer ready to write */
269  return 0;
270  }
271 
272  /* get the first buffer off the queue */
273  in = jqueue_pull(s->wbufq);
274  if(in == NULL) {
275  /* if there was a write event, and something is interested,
276  we still have to tell the plugins */
277  in = _sx_buffer_new(NULL, 0, NULL, NULL);
278  }
279 
280  /* if there's more to write, we want to make sure we get it */
281  s->want_write = jqueue_size(s->wbufq);
282 
283  /* make a copy for processing */
284  out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
285 
286  _sx_debug(ZONE, "encoding %d bytes for writing: %.*s", in->len, in->len, in->data);
287 
288  /* run it by the plugins */
289  ret = _sx_chain_io_write(s, out);
290  if(ret <= 0) {
291  /* TODO/!!!: Are we leaking the 'out' buffer here? How about the 'in' buffer? */
292  if(ret == -1) {
293  /* temporary failure, push it back on the queue */
294  jqueue_push(s->wbufq, in, (s->wbufq->front != NULL) ? s->wbufq->front->priority : 0);
295  s->want_write = 1;
296  } else if(ret == -2) {
297  /* permanent failure, its all over */
298  /* !!! shut down */
299  s->want_read = s->want_write = 0;
300  return -1;
301  }
302 
303  /* done */
304  return 0;
305  }
306 
307  _sx_buffer_free(in);
308 
309  if (out->len == 0)
310  /* if there's nothing to write, then we're done */
311  _sx_buffer_free(out);
312  else
313  s->wbufpending = out;
314 
315  return 0;
316 }
317 
319  sx_buf_t out;
320  int ret, written;
321 
322  assert((int) (s != NULL));
323 
324  /* do we care? */
325  if(!s->want_write && s->state < state_CLOSING)
326  return 0; /* no more thanks */
327 
328  _sx_debug(ZONE, "%d ready for writing", s->tag);
329 
330  ret = _sx_get_pending_write(s);
331  if (ret < 0) {
332  /* fatal error */
333  _sx_debug(ZONE, "fatal error after attempt to write on fd %d", s->tag);
334  /* permanent error so inform the app it can kill us */
335  sx_kill(s);
336  return 0;
337  }
338 
339  /* if there's nothing to write, then we're done */
340  if(s->wbufpending == NULL) {
341  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
342  return s->want_write;
343  }
344 
345  out = s->wbufpending;
346  s->wbufpending = NULL;
347 
348  /* get the callback to do the write */
349  _sx_debug(ZONE, "handing app %d bytes to write", out->len);
350  written = _sx_event(s, event_WRITE, (void *) out);
351 
352  if(written < 0) {
353  /* bail if something went wrong */
354  _sx_buffer_free(out);
355  s->want_read = 0;
356  s->want_write = 0;
357  return 0;
358  } else if(written < out->len) {
359  /* if not fully written, this buffer is still pending */
360  out->len -= written;
361  out->data += written;
362  s->wbufpending = out;
363  s->want_write ++;
364  } else {
365  /* notify */
366  if(out->notify != NULL)
367  (out->notify)(s, out->notify_arg);
368 
369  /* done with this */
370  _sx_buffer_free(out);
371  }
372 
373  /* if we've written everything, and we're closed, then inform the app it can kill us */
374  if(s->want_write == 0 && s->state == state_CLOSING) {
376  _sx_event(s, event_CLOSED, NULL);
377  return 0;
378  }
379 
380  if(s->state == state_CLOSED)
381  return 0;
382 
383  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
384  return s->want_write;
385 }
386 
388 int _sx_nad_write(sx_t s, nad_t nad, int elem) {
389  char *out;
390  int len;
391 
392  /* silently drop it if we're closing or closed */
393  if(s->state >= state_CLOSING) {
394  log_debug(ZONE, "stream closed, dropping outgoing packet");
395  nad_free(nad);
396  return 1;
397  }
398 
399  /* run it through the plugins */
400  if(_sx_chain_nad_write(s, nad, elem) == 0)
401  return 1;
402 
403  /* serialise it */
404  nad_print(nad, elem, &out, &len);
405 
406  _sx_debug(ZONE, "queueing for write: %.*s", len, out);
407 
408  /* ready to go */
409  jqueue_push(s->wbufq, _sx_buffer_new(out, len, NULL, NULL), 0);
410 
411  nad_free(nad);
412 
413  /* things to write */
414  s->want_write = 1;
415 
416  return 0;
417 }
418 
420 void sx_nad_write_elem(sx_t s, nad_t nad, int elem) {
421  assert((int) (s != NULL));
422  assert((int) (nad != NULL));
423 
424  if(_sx_nad_write(s, nad, elem) == 1)
425  return;
426 
427  /* things to write */
428  s->want_write = 1;
429  _sx_event(s, event_WANT_WRITE, NULL);
430 
431  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
432 }
433 
435 int _sx_raw_write(sx_t s, char *buf, int len) {
436  /* siltently drop it if we're closing or closed */
437  if(s->state >= state_CLOSING) {
438  log_debug(ZONE, "stream closed, dropping outgoing raw data");
439  return 1;
440  }
441 
442  _sx_debug(ZONE, "queuing for write: %.*s", len, buf);
443 
444  /* ready to go */
445  jqueue_push(s->wbufq, _sx_buffer_new(buf, len, NULL, NULL), 0);
446 
447  /* things to write */
448  s->want_write = 1;
449 
450  return 0;
451 }
452 
454 void sx_raw_write(sx_t s, char *buf, int len) {
455  assert((int) (s != NULL));
456  assert((int) (buf != NULL));
457  assert(len);
458 
459  if(_sx_raw_write(s, buf, len) == 1)
460  return;
461 
462  /* things to write */
463  s->want_write = 1;
464  _sx_event(s, event_WANT_WRITE, NULL);
465 
466  if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
467 }
468 
470 void _sx_close(sx_t s) {
471  /* close the stream if necessary */
472  if(s->state >= state_STREAM_SENT) {
473  jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
474  s->want_write = 1;
475  }
476 
478 }
479 
480 void sx_close(sx_t s) {
481  assert((int) (s != NULL));
482 
483  if(s->state >= state_CLOSING)
484  return;
485 
486  if(s->state >= state_STREAM_SENT && s->state < state_CLOSING) {
487  _sx_close(s);
488  _sx_event(s, event_WANT_WRITE, NULL);
489  } else {
491  _sx_event(s, event_CLOSED, NULL);
492  }
493 }
494 
495 void sx_kill(sx_t s) {
496  assert((int) (s != NULL));
497 
499  _sx_event(s, event_CLOSED, NULL);
500 }