jabberd2  2.2.16
sx/io.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "sx.h"
00022 
00024 void _sx_process_read(sx_t s, sx_buf_t buf) {
00025     sx_error_t sxe;
00026     nad_t nad;
00027     char *errstring;
00028     int i;
00029     int ns, elem;
00030 
00031     /* Note that buf->len can validly be 0 here, if we got data from
00032        the socket but the plugin didn't return anything to us (e.g. a
00033        SSL packet was split across a tcp segment boundary) */
00034 
00035     /* count bytes read */
00036     s->rbytes += buf->len;
00037 
00038     /* parse it */
00039     if(XML_Parse(s->expat, buf->data, buf->len, 0) == 0) {
00040         /* only report error we haven't already */
00041         if(!s->fail) {
00042             /* parse error */
00043             errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));
00044 
00045             _sx_debug(ZONE, "XML parse error: %s; line: %d, column: %d", errstring, XML_GetCurrentLineNumber(s->expat), XML_GetCurrentColumnNumber(s->expat));
00046             _sx_gen_error(sxe, SX_ERR_XML_PARSE, "XML parse error", errstring);
00047             _sx_event(s, event_ERROR, (void *) &sxe);
00048 
00049             _sx_error(s, stream_err_XML_NOT_WELL_FORMED, errstring);
00050             _sx_close(s);
00051 
00052             _sx_buffer_free(buf);
00053 
00054             return;
00055         }
00056 
00057         /* !!! is this the right thing to do? we should probably set
00058          *     s->fail and let the code further down handle it. */
00059         _sx_buffer_free(buf);
00060 
00061         return;
00062     }
00063 
00064     /* check if the stanza size limit is exceeded (it wasn't reset by parser) */
00065     if(s->rbytesmax && s->rbytes > s->rbytesmax) {
00066         /* parse error */
00067         _sx_debug(ZONE, "maximum stanza size (%d) exceeded by reading %d bytes", s->rbytesmax, s->rbytes);
00068 
00069         errstring = (char *) XML_ErrorString(XML_GetErrorCode(s->expat));
00070 
00071         _sx_gen_error(sxe, SX_ERR_XML_PARSE, "stream read error", "Maximum stanza size exceeded");
00072         _sx_event(s, event_ERROR, (void *) &sxe);
00073 
00074         _sx_error(s, stream_err_POLICY_VIOLATION, errstring);
00075         _sx_close(s);
00076 
00077         _sx_buffer_free(buf);
00078 
00079         return;
00080     }
00081 
00082     /* done with the buffer */
00083     _sx_buffer_free(buf);
00084 
00085     /* process completed nads */
00086     if(s->state >= state_STREAM)
00087         while((nad = jqueue_pull(s->rnadq)) != NULL) {
00088             int plugin_error;
00089 #ifdef SX_DEBUG
00090             char *out; int len;
00091             nad_print(nad, 0, &out, &len);
00092             _sx_debug(ZONE, "completed nad: %.*s", len, out);
00093 #endif
00094 
00095             /* check for errors */
00096             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) {
00097 
00098                 errstring = NULL;
00099 
00100                 /* get text error description if available - XMPP 4.7.2 */
00101                 if((ns = nad_find_scoped_namespace(nad, uri_STREAM_ERR, NULL)) >= 0) 
00102                     if((elem = nad_find_elem(nad, 0, ns, "text", 1)) >= 0)
00103                         if(NAD_CDATA_L(nad, elem) > 0) {
00104                             errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, elem) + 1));
00105                             sprintf(errstring, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
00106                         }
00107 
00108                 /* if not available, look for legacy error text as in <stream:error>description</stream:error> */
00109                 if (errstring == NULL && NAD_CDATA_L(nad, 0) > 0) {
00110                     errstring = (char *) malloc(sizeof(char) * (NAD_CDATA_L(nad, 0) + 1));
00111                     sprintf(errstring, "%.*s", NAD_CDATA_L(nad, 0), NAD_CDATA(nad, 0));
00112                 }
00113 
00114                 /* if not available, log the whole packet for debugging */
00115                 if (errstring == NULL) {
00116                     char *xml;
00117                     int xlen;
00118 
00119                     nad_print(nad, 0, &xml, &xlen);
00120                     errstring = (char *) malloc(sizeof(char) * (xlen + 1));
00121                     sprintf(errstring, "%.*s", xlen, xml);
00122                 }
00123 
00124                 if(s->state < state_CLOSING) {
00125                     _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", errstring);
00126                     _sx_event(s, event_ERROR, (void *) &sxe);
00127                     _sx_state(s, state_CLOSING);
00128                 }
00129 
00130                 if(errstring != NULL) free(errstring);
00131 
00132                 nad_free(nad);
00133 
00134                 break;
00135             }
00136 
00137             /* run it by the plugins */
00138             if(_sx_chain_nad_read(s, nad) == 0)
00139                 return;
00140 
00141             /* now let the plugins process the completed nad */
00142             plugin_error = 0;
00143             if(s->env != NULL)
00144                 for(i = 0; i < s->env->nplugins; i++)
00145                     if(s->env->plugins[i]->process != NULL) {
00146                         int plugin_ret;
00147                         plugin_ret = (s->env->plugins[i]->process)(s, s->env->plugins[i], nad);
00148                         if(plugin_ret == 0) {
00149                             plugin_error ++;
00150                             break;
00151                         }
00152                     }
00153 
00154             /* hand it to the app */
00155             if ((plugin_error == 0) && (s->state < state_CLOSING))
00156                 _sx_event(s, event_PACKET, (void *) nad);
00157         }
00158 
00159     /* something went wrong, bail */
00160     if(s->fail) {
00161         _sx_close(s);
00162 
00163         return;
00164     }
00165 
00166     /* stream was closed */
00167     if(s->depth < 0 && s->state < state_CLOSING) {
00168         /* close the stream if necessary */
00169         if(s->state >= state_STREAM_SENT) {
00170             jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
00171             s->want_write = 1;
00172         }
00173 
00174         _sx_state(s, state_CLOSING);
00175 
00176         return;
00177     }
00178 }
00179 
00181 int sx_can_read(sx_t s) {
00182     sx_buf_t in, out;
00183     int read, ret;
00184 
00185     assert((int) (s != NULL));
00186 
00187     /* do we care? */
00188     if(!s->want_read && s->state < state_CLOSING)
00189         return 0;           /* no more thanks */
00190 
00191     _sx_debug(ZONE, "%d ready for reading", s->tag);
00192 
00193     /* new buffer */
00194     in = _sx_buffer_new(NULL, 1024, NULL, NULL);
00195 
00196     /* get them to read stuff */
00197     read = _sx_event(s, event_READ, (void *) in);
00198 
00199     /* bail if something went wrong */
00200     if(read < 0) {
00201         _sx_buffer_free(in);
00202         s->want_read = 0;
00203         s->want_write = 0;
00204         return 0;
00205     }
00206 
00207     if(read == 0) {
00208         /* nothing to read
00209          * should never happen because we did get a read event,
00210          * thus there is something to read, or error handled
00211          * via (read < 0) block before (errors return -1) */
00212         _sx_debug(ZONE, "decoded 0 bytes read data - this should not happen");
00213         _sx_buffer_free(in);
00214 
00215     } else {
00216         _sx_debug(ZONE, "passed %d read bytes", in->len);
00217 
00218         /* make a copy for processing */
00219         out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
00220 
00221         /* run it by the plugins */
00222         ret = _sx_chain_io_read(s, out);
00223         if(ret <= 0) {
00224             if(ret < 0) {
00225                 /* permanent failure, its all over */
00226                 /* !!! shut down */
00227                 s->want_read = s->want_write = 0;
00228             }
00229 
00230             _sx_buffer_free(in);
00231             _sx_buffer_free(out);
00232 
00233             /* done */
00234             if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
00235             return s->want_read;
00236         }
00237 
00238         _sx_buffer_free(in);
00239 
00240         _sx_debug(ZONE, "decoded read data (%d bytes): %.*s", out->len, out->len, out->data);
00241 
00242         /* into the parser with you */
00243         _sx_process_read(s, out);
00244     }
00245 
00246     /* if we've written everything, and we're closed, then inform the app it can kill us */
00247     if(s->want_write == 0 && s->state == state_CLOSING) {
00248         _sx_state(s, state_CLOSED);
00249         _sx_event(s, event_CLOSED, NULL);
00250         return 0;
00251     }
00252 
00253     if(s->state == state_CLOSED)
00254         return 0;
00255 
00256     if(s->want_write) _sx_event(s, event_WANT_WRITE, NULL);
00257     return s->want_read;
00258 }
00259 
00261 static int _sx_get_pending_write(sx_t s) {
00262     sx_buf_t in, out;
00263     int ret;
00264 
00265     assert(s != NULL);
00266 
00267     if (s->wbufpending != NULL) {
00268     /* there's already a pending buffer ready to write */
00269     return 0;
00270     }
00271 
00272     /* get the first buffer off the queue */
00273     in = jqueue_pull(s->wbufq);
00274     if(in == NULL) {
00275         /* if there was a write event, and something is interested,
00276        we still have to tell the plugins */
00277         in = _sx_buffer_new(NULL, 0, NULL, NULL);
00278     }
00279 
00280     /* if there's more to write, we want to make sure we get it */
00281     s->want_write = jqueue_size(s->wbufq);
00282 
00283     /* make a copy for processing */
00284     out = _sx_buffer_new(in->data, in->len, in->notify, in->notify_arg);
00285 
00286     _sx_debug(ZONE, "encoding %d bytes for writing: %.*s", in->len, in->len, in->data);
00287 
00288     /* run it by the plugins */
00289     ret = _sx_chain_io_write(s, out);
00290     if(ret <= 0) {
00291     /* TODO/!!!: Are we leaking the 'out' buffer here? How about the 'in' buffer? */
00292         if(ret == -1) {
00293             /* temporary failure, push it back on the queue */
00294             jqueue_push(s->wbufq, in, (s->wbufq->front != NULL) ? s->wbufq->front->priority : 0);
00295             s->want_write = 1;
00296         } else if(ret == -2) {
00297             /* permanent failure, its all over */
00298             /* !!! shut down */
00299             s->want_read = s->want_write = 0;
00300             return -1;
00301         }
00302 
00303         /* done */
00304         return 0;
00305     }
00306 
00307     _sx_buffer_free(in);
00308 
00309     if (out->len == 0)
00310     /* if there's nothing to write, then we're done */
00311         _sx_buffer_free(out);
00312     else
00313         s->wbufpending = out;
00314 
00315     return 0;
00316 }
00317 
00318 int sx_can_write(sx_t s) {
00319     sx_buf_t out;
00320     int ret, written;
00321 
00322     assert((int) (s != NULL));
00323 
00324     /* do we care? */
00325     if(!s->want_write && s->state < state_CLOSING)
00326         return 0;           /* no more thanks */
00327 
00328     _sx_debug(ZONE, "%d ready for writing", s->tag);
00329 
00330     ret = _sx_get_pending_write(s);
00331     if (ret < 0) {
00332         /* fatal error */
00333         _sx_debug(ZONE, "fatal error after attempt to write on fd %d", s->tag);
00334         /* permanent error so inform the app it can kill us */
00335         sx_kill(s);
00336         return 0;
00337     }
00338 
00339     /* if there's nothing to write, then we're done */
00340     if(s->wbufpending == NULL) {
00341         if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
00342         return s->want_write;
00343     }
00344 
00345     out = s->wbufpending;
00346     s->wbufpending = NULL;
00347 
00348     /* get the callback to do the write */
00349     _sx_debug(ZONE, "handing app %d bytes to write", out->len);
00350     written = _sx_event(s, event_WRITE, (void *) out);
00351 
00352     if(written < 0) {
00353         /* bail if something went wrong */
00354         _sx_buffer_free(out);
00355         s->want_read = 0;
00356         s->want_write = 0;
00357         return 0;
00358     } else if(written < out->len) {
00359         /* if not fully written, this buffer is still pending */
00360         out->len -= written;
00361         out->data += written;
00362         s->wbufpending = out;
00363         s->want_write ++;
00364     } else {
00365         /* notify */
00366         if(out->notify != NULL)
00367             (out->notify)(s, out->notify_arg);
00368 
00369         /* done with this */
00370         _sx_buffer_free(out);
00371     }
00372 
00373     /* if we've written everything, and we're closed, then inform the app it can kill us */
00374     if(s->want_write == 0 && s->state == state_CLOSING) {
00375         _sx_state(s, state_CLOSED);
00376         _sx_event(s, event_CLOSED, NULL);
00377         return 0;
00378     }
00379 
00380     if(s->state == state_CLOSED)
00381         return 0;
00382 
00383     if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
00384     return s->want_write;
00385 }
00386 
00388 int _sx_nad_write(sx_t s, nad_t nad, int elem) {
00389     char *out;
00390     int len;
00391 
00392     /* silently drop it if we're closing or closed */
00393     if(s->state >= state_CLOSING) {
00394         log_debug(ZONE, "stream closed, dropping outgoing packet");
00395         nad_free(nad);
00396         return 1;
00397     }
00398 
00399     /* run it through the plugins */
00400     if(_sx_chain_nad_write(s, nad, elem) == 0)
00401         return 1;
00402 
00403     /* serialise it */
00404     nad_print(nad, elem, &out, &len);
00405 
00406     _sx_debug(ZONE, "queueing for write: %.*s", len, out);
00407 
00408     /* ready to go */
00409     jqueue_push(s->wbufq, _sx_buffer_new(out, len, NULL, NULL), 0);
00410 
00411     nad_free(nad);
00412 
00413     /* things to write */
00414     s->want_write = 1;
00415 
00416     return 0;
00417 }
00418 
00420 void sx_nad_write_elem(sx_t s, nad_t nad, int elem) {
00421     assert((int) (s != NULL));
00422     assert((int) (nad != NULL));
00423 
00424     if(_sx_nad_write(s, nad, elem) == 1)
00425         return;
00426 
00427     /* things to write */
00428     s->want_write = 1;
00429     _sx_event(s, event_WANT_WRITE, NULL);
00430 
00431     if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
00432 }
00433 
00435 int _sx_raw_write(sx_t s, char *buf, int len) {
00436     /* siltently drop it if we're closing or closed */
00437     if(s->state >= state_CLOSING) {
00438         log_debug(ZONE, "stream closed, dropping outgoing raw data");
00439         return 1;
00440     }
00441 
00442     _sx_debug(ZONE, "queuing for write: %.*s", len, buf);
00443 
00444     /* ready to go */
00445     jqueue_push(s->wbufq, _sx_buffer_new(buf, len, NULL, NULL), 0);
00446 
00447     /* things to write */
00448     s->want_write = 1;
00449 
00450     return 0;
00451 }
00452 
00454 void sx_raw_write(sx_t s, char *buf, int len) {
00455     assert((int) (s != NULL));
00456     assert((int) (buf != NULL));
00457     assert(len);
00458 
00459     if(_sx_raw_write(s, buf, len) == 1)
00460         return;
00461 
00462     /* things to write */
00463     s->want_write = 1;
00464     _sx_event(s, event_WANT_WRITE, NULL);
00465 
00466     if(s->want_read) _sx_event(s, event_WANT_READ, NULL);
00467 }
00468 
00470 void _sx_close(sx_t s) {
00471     /* close the stream if necessary */
00472     if(s->state >= state_STREAM_SENT) {
00473         jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
00474         s->want_write = 1;
00475     }
00476 
00477     _sx_state(s, state_CLOSING);
00478 }
00479 
00480 void sx_close(sx_t s) {
00481     assert((int) (s != NULL));
00482 
00483     if(s->state >= state_CLOSING)
00484         return;
00485 
00486     if(s->state >= state_STREAM_SENT && s->state < state_CLOSING) {
00487         _sx_close(s);
00488         _sx_event(s, event_WANT_WRITE, NULL);
00489     } else {
00490         _sx_state(s, state_CLOSED);
00491         _sx_event(s, event_CLOSED, NULL);
00492     }
00493 }
00494 
00495 void sx_kill(sx_t s) {
00496     assert((int) (s != NULL));
00497 
00498     _sx_state(s, state_CLOSED);
00499     _sx_event(s, event_CLOSED, NULL);
00500 }