jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2007 Tomasz Sterna 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; version 2 of the License. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00017 */ 00018 00023 #include "sx.h" 00024 00025 static void _sx_compress_notify_compress(sx_t s, void *arg) { 00026 00027 _sx_debug(ZONE, "preparing for compress"); 00028 00029 _sx_reset(s); 00030 00031 /* start listening */ 00032 sx_server_init(s, s->flags | SX_COMPRESS_WRAPPER); 00033 } 00034 00035 static int _sx_compress_process(sx_t s, sx_plugin_t p, nad_t nad) { 00036 int flags; 00037 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; 00038 sx_error_t sxe; 00039 00040 /* not interested if we're a server and we never offered it */ 00041 if(s->type == type_SERVER && !(s->flags & SX_COMPRESS_OFFER)) 00042 return 1; 00043 00044 /* only want compress packets */ 00045 if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != sizeof(uri_COMPRESS)-1 || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_COMPRESS, sizeof(uri_COMPRESS)-1) != 0) 00046 return 1; 00047 00048 /* compress from client */ 00049 if(s->type == type_SERVER) { 00050 if(NAD_ENAME_L(nad, 0) == 8 && strncmp(NAD_ENAME(nad, 0), "compress", 8) == 0) { 00051 nad_free(nad); 00052 00053 /* can't go on if we've been here before */ 00054 if(s->compressed) { 00055 _sx_debug(ZONE, "compress requested on already compressed channel, dropping packet"); 00056 return 0; 00057 } 00058 00059 _sx_debug(ZONE, "compress requested, setting up"); 00060 00061 /* go ahead */ 00062 jqueue_push(s->wbufq, _sx_buffer_new("<compressed xmlns='" uri_COMPRESS "'/>", sizeof(uri_COMPRESS)-1 + 22, _sx_compress_notify_compress, NULL), 0); 00063 s->want_write = 1; 00064 00065 /* handled the packet */ 00066 return 0; 00067 } 00068 } 00069 00070 else if(s->type == type_CLIENT) { 00071 /* kick off the handshake */ 00072 if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "compressed", 7) == 0) { 00073 nad_free(nad); 00074 00075 /* save interesting bits */ 00076 flags = s->flags; 00077 00078 if(s->ns != NULL) ns = strdup(s->ns); 00079 00080 if(s->req_to != NULL) to = strdup(s->req_to); 00081 if(s->req_from != NULL) from = strdup(s->req_from); 00082 if(s->req_version != NULL) version = strdup(s->req_version); 00083 00084 /* reset state */ 00085 _sx_reset(s); 00086 00087 _sx_debug(ZONE, "server ready for compression, starting"); 00088 00089 /* second time round */ 00090 sx_client_init(s, flags | SX_COMPRESS_WRAPPER, ns, to, from, version); 00091 00092 /* free bits */ 00093 if(ns != NULL) free(ns); 00094 if(to != NULL) free(to); 00095 if(from != NULL) free(from); 00096 if(version != NULL) free(version); 00097 00098 return 0; 00099 } 00100 00101 /* busted server */ 00102 if(NAD_ENAME_L(nad, 0) == 7 && strncmp(NAD_ENAME(nad, 0), "failure", 7) == 0) { 00103 nad_free(nad); 00104 00105 _sx_debug(ZONE, "server can't handle compression, business as usual"); 00106 00107 _sx_gen_error(sxe, SX_ERR_COMPRESS_FAILURE, "compress failure", "Server was unable to establish compression"); 00108 _sx_event(s, event_ERROR, (void *) &sxe); 00109 00110 return 0; 00111 } 00112 } 00113 00114 _sx_debug(ZONE, "unknown compress namespace element '%.*s', dropping packet", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); 00115 nad_free(nad); 00116 return 0; 00117 } 00118 00119 static void _sx_compress_features(sx_t s, sx_plugin_t p, nad_t nad) { 00120 int ns; 00121 00122 /* if the session is already compressed, or the app told us not to, 00123 * or STARTTLS is required and stream is not encrypted yet, then we don't offer anything */ 00124 if(s->compressed || !(s->flags & SX_COMPRESS_OFFER) || ((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0)) 00125 return; 00126 00127 _sx_debug(ZONE, "offering compression"); 00128 00129 ns = nad_add_namespace(nad, uri_COMPRESS_FEATURE, NULL); 00130 nad_append_elem(nad, ns, "compression", 1); 00131 nad_append_elem(nad, ns, "method", 2); 00132 nad_append_cdata(nad, "zlib", 4, 3); 00133 } 00134 00135 static int _sx_compress_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { 00136 _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; 00137 int ret; 00138 sx_error_t sxe; 00139 00140 /* only bothering if they asked for wrappermode */ 00141 if(!(s->flags & SX_COMPRESS_WRAPPER) || !s->compressed) 00142 return 1; 00143 00144 _sx_debug(ZONE, "in _sx_compress_wio"); 00145 00146 /* move the data into the zlib write buffer */ 00147 if(buf->len > 0) { 00148 _sx_debug(ZONE, "loading %d bytes into zlib write buffer", buf->len); 00149 00150 _sx_buffer_alloc_margin(sc->wbuf, 0, buf->len); 00151 memcpy(sc->wbuf->data + sc->wbuf->len, buf->data, buf->len); 00152 sc->wbuf->len += buf->len; 00153 00154 _sx_buffer_clear(buf); 00155 } 00156 00157 /* compress the data */ 00158 if(sc->wbuf->len > 0) { 00159 sc->wstrm.avail_in = sc->wbuf->len; 00160 sc->wstrm.next_in = sc->wbuf->data; 00161 /* deflate() on write buffer until there is data to compress */ 00162 do { 00163 /* make place for deflated data */ 00164 _sx_buffer_alloc_margin(buf, 0, sc->wbuf->len + SX_COMPRESS_CHUNK); 00165 00166 sc->wstrm.avail_out = sc->wbuf->len + SX_COMPRESS_CHUNK; 00167 sc->wstrm.next_out = buf->data + buf->len; 00168 00169 ret = deflate(&(sc->wstrm), Z_SYNC_FLUSH); 00170 assert(ret != Z_STREAM_ERROR); 00171 00172 buf->len += sc->wbuf->len + SX_COMPRESS_CHUNK - sc->wstrm.avail_out; 00173 00174 } while (sc->wstrm.avail_out == 0); 00175 00176 if(ret != Z_OK || sc->wstrm.avail_in != 0) { 00177 /* throw an error */ 00178 _sx_gen_error(sxe, SX_ERR_COMPRESS, "compression error", "Error during compression"); 00179 _sx_event(s, event_ERROR, (void *) &sxe); 00180 00181 sx_error(s, stream_err_INTERNAL_SERVER_ERROR, "Error during compression"); 00182 sx_close(s); 00183 00184 return -2; /* fatal */ 00185 } 00186 00187 sc->wbuf->len = sc->wstrm.avail_in; 00188 sc->wbuf->data = sc->wstrm.next_in; 00189 } 00190 00191 _sx_debug(ZONE, "passing %d bytes from zlib write buffer", buf->len); 00192 00193 return 1; 00194 } 00195 00196 static int _sx_compress_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { 00197 _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; 00198 int ret; 00199 sx_error_t sxe; 00200 00201 /* only bothering if they asked for wrappermode */ 00202 if(!(s->flags & SX_COMPRESS_WRAPPER) || !s->compressed) 00203 return 1; 00204 00205 _sx_debug(ZONE, "in _sx_compress_rio"); 00206 00207 /* move the data into the zlib read buffer */ 00208 if(buf->len > 0) { 00209 _sx_debug(ZONE, "loading %d bytes into zlib read buffer", buf->len); 00210 00211 _sx_buffer_alloc_margin(sc->rbuf, 0, buf->len); 00212 memcpy(sc->rbuf->data + sc->rbuf->len, buf->data, buf->len); 00213 sc->rbuf->len += buf->len; 00214 00215 _sx_buffer_clear(buf); 00216 } 00217 00218 /* decompress the data */ 00219 if(sc->rbuf->len > 0) { 00220 sc->rstrm.avail_in = sc->rbuf->len; 00221 sc->rstrm.next_in = sc->rbuf->data; 00222 /* run inflate() on read buffer while able to fill the output buffer */ 00223 do { 00224 /* make place for inflated data */ 00225 _sx_buffer_alloc_margin(buf, 0, SX_COMPRESS_CHUNK); 00226 00227 sc->rstrm.avail_out = SX_COMPRESS_CHUNK; 00228 sc->rstrm.next_out = buf->data + buf->len; 00229 00230 ret = inflate(&(sc->rstrm), Z_SYNC_FLUSH); 00231 assert(ret != Z_STREAM_ERROR); 00232 switch (ret) { 00233 case Z_NEED_DICT: 00234 case Z_DATA_ERROR: 00235 case Z_MEM_ERROR: 00236 /* throw an error */ 00237 _sx_gen_error(sxe, SX_ERR_COMPRESS, "compression error", "Error during decompression"); 00238 _sx_event(s, event_ERROR, (void *) &sxe); 00239 00240 sx_error(s, stream_err_INVALID_XML, "Error during decompression"); 00241 sx_close(s); 00242 00243 return -2; 00244 } 00245 00246 buf->len += SX_COMPRESS_CHUNK - sc->rstrm.avail_out; 00247 00248 } while (sc->rstrm.avail_out == 0); 00249 00250 sc->rbuf->len = sc->rstrm.avail_in; 00251 sc->rbuf->data = sc->rstrm.next_in; 00252 } 00253 00254 _sx_debug(ZONE, "passing %d bytes from zlib read buffer", buf->len); 00255 00256 /* flag if we want to read */ 00257 if(sc->rbuf->len > 0) 00258 s->want_read = 1; 00259 00260 if(buf->len == 0) 00261 return 0; 00262 00263 return 1; 00264 } 00265 00266 static void _sx_compress_new(sx_t s, sx_plugin_t p) { 00267 _sx_compress_conn_t sc; 00268 00269 /* only bothering if they asked for wrappermode */ 00270 if(!(s->flags & SX_COMPRESS_WRAPPER) || s->compressed) 00271 return; 00272 00273 _sx_debug(ZONE, "preparing for compressed connect for %d", s->tag); 00274 00275 sc = (_sx_compress_conn_t) calloc(1, sizeof(struct _sx_compress_conn_st)); 00276 00277 /* initialize streams */ 00278 sc->rstrm.zalloc = Z_NULL; 00279 sc->rstrm.zfree = Z_NULL; 00280 sc->rstrm.opaque = Z_NULL; 00281 sc->rstrm.avail_in = 0; 00282 sc->rstrm.next_in = Z_NULL; 00283 inflateInit(&(sc->rstrm)); 00284 00285 sc->wstrm.zalloc = Z_NULL; 00286 sc->wstrm.zfree = Z_NULL; 00287 sc->wstrm.opaque = Z_NULL; 00288 deflateInit(&(sc->wstrm), Z_DEFAULT_COMPRESSION); 00289 00290 /* read and write buffers */ 00291 sc->rbuf = _sx_buffer_new(NULL, 0, NULL, NULL); 00292 sc->wbuf = _sx_buffer_new(NULL, 0, NULL, NULL); 00293 00294 s->plugin_data[p->index] = (void *) sc; 00295 00296 /* bring the plugin online */ 00297 _sx_chain_io_plugin(s, p); 00298 00299 /* mark stream compressed */ 00300 s->compressed = 1; 00301 } 00302 00304 static void _sx_compress_free(sx_t s, sx_plugin_t p) { 00305 _sx_compress_conn_t sc = (_sx_compress_conn_t) s->plugin_data[p->index]; 00306 00307 if(sc == NULL) 00308 return; 00309 00310 log_debug(ZONE, "cleaning up compression state"); 00311 00312 if(s->type == type_NONE) { 00313 free(sc); 00314 return; 00315 } 00316 00317 /* end streams */ 00318 inflateEnd(&(sc->rstrm)); 00319 deflateEnd(&(sc->wstrm)); 00320 00321 /* free buffers */ 00322 _sx_buffer_free(sc->rbuf); 00323 _sx_buffer_free(sc->wbuf); 00324 00325 free(sc); 00326 00327 s->plugin_data[p->index] = NULL; 00328 } 00329 00331 int sx_compress_init(sx_env_t env, sx_plugin_t p, va_list args) { 00332 00333 _sx_debug(ZONE, "initialising compression plugin"); 00334 00335 p->client = _sx_compress_new; 00336 p->server = _sx_compress_new; 00337 p->rio = _sx_compress_rio; 00338 p->wio = _sx_compress_wio; 00339 p->features = _sx_compress_features; 00340 p->process = _sx_compress_process; 00341 p->free = _sx_compress_free; 00342 00343 return 0; 00344 } 00345 00346 int sx_compress_client_compress(sx_plugin_t p, sx_t s, char *pemfile) { 00347 assert((int) (p != NULL)); 00348 assert((int) (s != NULL)); 00349 00350 /* sanity */ 00351 if(s->type != type_CLIENT || s->state != state_STREAM) { 00352 _sx_debug(ZONE, "wrong conn type or state for client compress"); 00353 return 1; 00354 } 00355 00356 /* check if we're already compressed */ 00357 if((s->flags & SX_COMPRESS_WRAPPER) || s->compressed) { 00358 _sx_debug(ZONE, "channel already compressed"); 00359 return 1; 00360 } 00361 00362 _sx_debug(ZONE, "initiating compress sequence"); 00363 00364 /* go */ 00365 jqueue_push(s->wbufq, _sx_buffer_new("<compress xmlns='" uri_COMPRESS "'><method>zlib</method></compress>", sizeof(uri_COMPRESS)-1 + 51, NULL, NULL), 0); 00366 s->want_write = 1; 00367 _sx_event(s, event_WANT_WRITE, NULL); 00368 00369 return 0; 00370 }