jabberd2  2.2.16
sx/sx.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 
00023 sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg) {
00024     sx_t s;
00025     int i;
00026 
00027     assert((int) (cb != NULL));
00028 
00029     s = (sx_t) calloc(1, sizeof(struct _sx_st));
00030 
00031     s->env = env;
00032     s->tag = tag;
00033     s->cb = cb;
00034     s->cb_arg = arg;
00035 
00036     s->expat = XML_ParserCreateNS(NULL, '|');
00037     XML_SetReturnNSTriplet(s->expat, 1);
00038     XML_SetUserData(s->expat, (void *) s);
00039     /* Prevent the "billion laughs" attack against expat by disabling
00040      * internal entity expansion.  With 2.x, forcibly stop the parser
00041      * if an entity is declared - this is safer and a more obvious
00042      * failure mode.  With older versions, simply prevent expenansion
00043      * of such entities. */
00044 #ifdef HAVE_XML_STOPPARSER
00045     XML_SetEntityDeclHandler(s->expat, (void *) _sx_entity_declaration);
00046 #else
00047     XML_SetDefaultHandler(s->expat, NULL);
00048 #endif
00049 
00050     s->wbufq = jqueue_new();
00051     s->rnadq = jqueue_new();
00052 
00053     if(env != NULL) {
00054         s->plugin_data = (void **) calloc(1, sizeof(void *) * env->nplugins);
00055 
00056         for(i = 0; i < env->nplugins; i++)
00057             if(env->plugins[i]->new != NULL)
00058                 (env->plugins[i]->new)(s, env->plugins[i]);
00059     }
00060 
00061     _sx_debug(ZONE, "allocated new sx for %d", tag);
00062 
00063     return s;
00064 }
00065 
00066 void sx_free(sx_t s) {
00067     sx_buf_t buf;
00068     nad_t nad;
00069     int i;
00070     _sx_chain_t scan, next;
00071 
00072     if (s == NULL)
00073         return;
00074 
00075     /* we are not reentrant */
00076     assert(!s->reentry);
00077 
00078     _sx_debug(ZONE, "freeing sx for %d", s->tag);
00079 
00080     if(s->ns != NULL) free(s->ns);
00081 
00082     if(s->req_to != NULL) free(s->req_to);
00083     if(s->req_from != NULL) free(s->req_from);
00084     if(s->req_version != NULL) free(s->req_version);
00085 
00086     if(s->res_to != NULL) free(s->res_to);
00087     if(s->res_from != NULL) free(s->res_from);
00088     if(s->res_version != NULL) free(s->res_version);
00089 
00090     if(s->id != NULL) free(s->id);
00091 
00092     while((buf = jqueue_pull(s->wbufq)) != NULL)
00093         _sx_buffer_free(buf);
00094     if (s->wbufpending != NULL)
00095         _sx_buffer_free(s->wbufpending);
00096 
00097     while((nad = jqueue_pull(s->rnadq)) != NULL)
00098         nad_free(nad);
00099 
00100     jqueue_free(s->wbufq);
00101     jqueue_free(s->rnadq);
00102 
00103     XML_ParserFree(s->expat);
00104 
00105     if(s->nad != NULL) nad_free(s->nad);
00106 
00107     if(s->auth_method != NULL) free(s->auth_method);
00108     if(s->auth_id != NULL) free(s->auth_id);
00109 
00110     if(s->env != NULL) {
00111         _sx_debug(ZONE, "freeing %d env plugins", s->env->nplugins);
00112         for(i = 0; i < s->env->nplugins; i++)
00113             if(s->env->plugins[i]->free != NULL)
00114                 (s->env->plugins[i]->free)(s, s->env->plugins[i]);
00115 
00116         scan = s->wio;
00117         while(scan != NULL) {
00118             next = scan->wnext;
00119             free(scan);
00120             scan = next;
00121         }
00122 
00123         scan = s->wnad;
00124         while(scan != NULL) {
00125             next = scan->wnext;
00126             free(scan);
00127             scan = next;
00128         }
00129 
00130         free(s->plugin_data);
00131     }
00132 
00133     free(s);
00134 }
00135 
00137 void sx_auth(sx_t s, const char *auth_method, const char *auth_id) {
00138     assert((int) (s != NULL));
00139 
00140     _sx_debug(ZONE, "authenticating stream (method=%s; id=%s)", auth_method, auth_id);
00141 
00142     if(auth_method != NULL) s->auth_method = strdup(auth_method);
00143     if(auth_id != NULL) s->auth_id = strdup(auth_id);
00144 
00145     _sx_state(s, state_OPEN);
00146     _sx_event(s, event_OPEN, NULL);
00147 }
00148 
00150 void _sx_reset(sx_t s) {
00151     struct _sx_st temp;
00152     sx_t new;
00153 
00154     _sx_debug(ZONE, "resetting stream state");
00155 
00156     /* we want to reset the contents of s, but we can't free s because
00157      * the caller (and others) hold references. so, we make a new sx_t,
00158      * copy the contents (only pointers), free it (which will free strings
00159      * and queues), then make another new one, and copy the contents back
00160      * into s */
00161 
00162     temp.env = s->env;
00163     temp.tag = s->tag;
00164     temp.cb = s->cb;
00165     temp.cb_arg = s->cb_arg;
00166 
00167     temp.ip = s->ip;
00168     temp.port = s->port;
00169     temp.flags = s->flags;
00170     temp.reentry = s->reentry;
00171     temp.ssf = s->ssf;
00172     temp.compressed = s->compressed;
00173     temp.wio = s->wio;
00174     temp.rio = s->rio;
00175     temp.wnad = s->wnad;
00176     temp.rnad = s->rnad;
00177     temp.rbytesmax = s->rbytesmax;
00178     temp.plugin_data = s->plugin_data;
00179 
00180     s->reentry = 0;
00181 
00182     s->env = NULL;  /* we get rid of this, because we don't want plugin data to be freed */
00183 
00184     new = (sx_t) malloc(sizeof(struct _sx_st));
00185     memcpy(new, s, sizeof(struct _sx_st));
00186     sx_free(new);
00187 
00188     new = sx_new(NULL, temp.tag, temp.cb, temp.cb_arg);
00189     memcpy(s, new, sizeof(struct _sx_st));
00190     free(new);
00191 
00192     /* massaged expat into shape */
00193     XML_SetUserData(s->expat, (void *) s);
00194 
00195     s->env = temp.env;
00196     s->ip = temp.ip;
00197     s->port = temp.port;
00198     s->flags = temp.flags;
00199     s->reentry = temp.reentry;
00200     s->ssf = temp.ssf;
00201     s->compressed = temp.compressed;
00202     s->wio = temp.wio;
00203     s->rio = temp.rio;
00204     s->wnad = temp.wnad;
00205     s->rnad = temp.rnad;
00206     s->rbytesmax = temp.rbytesmax;
00207     s->plugin_data = temp.plugin_data;
00208 
00209     s->has_reset = 1;
00210 
00211     _sx_debug(ZONE, "finished resetting stream state");
00212 }
00213 
00218 sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg) {
00219     sx_buf_t buf;
00220 
00221     buf = (sx_buf_t) calloc(1, sizeof(struct _sx_buf_st));
00222 
00223     if (len <= 0) {
00224         buf->data = buf->heap = NULL;
00225         buf->len = 0;
00226     } else {
00227         buf->data = buf->heap = (char *) malloc(sizeof(char) * len);
00228         if(data != NULL)
00229             memcpy(buf->data, data, len);
00230         else
00231             memset(buf->data, '$', len);  /* catch uninitialized use */
00232         buf->len = len;
00233     }
00234 
00235     buf->notify = notify;
00236     buf->notify_arg = notify_arg;
00237 
00238     return buf;
00239 }
00240 
00242 void _sx_buffer_free(sx_buf_t buf) {
00243     if(buf->heap != NULL)
00244         free(buf->heap);
00245 
00246     free(buf);
00247 }
00248 
00250 void _sx_buffer_clear(sx_buf_t buf) {
00251     if(buf->heap != NULL) {
00252         free(buf->heap);
00253         buf->heap = NULL;
00254     }
00255     buf->data = NULL;
00256     buf->len = 0;
00257 }
00258 
00260 void _sx_buffer_alloc_margin(sx_buf_t buf, int before, int after)
00261 {
00262     char *new_heap;
00263 
00264     assert( before >= 0 );
00265     assert( after >= 0 );
00266 
00267     /* If there wasn't any data in the buf, we can just allocate space for the margins */
00268     if (buf->data == NULL || buf->len == 0) {
00269         if (buf->heap != NULL)
00270             buf->heap = realloc(buf->heap, before+after);
00271         else
00272             buf->heap = malloc(before+after);
00273         buf->data = buf->heap + before;
00274         return;
00275     }
00276 
00277     if (buf->heap != NULL) {
00278         int old_leader = buf->data - buf->heap;
00279         /* Hmmm, maybe we can just call realloc() ? */
00280         if (old_leader >= before && old_leader <= (before * 4)) {
00281             buf->heap = realloc(buf->heap, before + buf->len + after);
00282             buf->data = buf->heap + old_leader;
00283             return;
00284         }
00285     }
00286 
00287     /* Most general case --- allocate a new buffer, copy stuff over, free the old one. */
00288     new_heap = malloc(before + buf->len + after);
00289     memcpy(new_heap + before, buf->data, buf->len);
00290     if (buf->heap != NULL)
00291         free(buf->heap);
00292     buf->heap = new_heap;
00293     buf->data = new_heap + before;
00294 }
00295 
00297 void _sx_buffer_set(sx_buf_t buf, char *newdata, int newlength, char *newheap)
00298 {
00299     if (newheap == NULL) {
00300         buf->len = 0;
00301         _sx_buffer_alloc_margin(buf, 0, newlength);
00302         if (newlength > 0)
00303             memcpy(buf->data, newdata, newlength);
00304         buf->len = newlength;
00305         return;
00306     }
00307 
00308     _sx_buffer_clear(buf);
00309     buf->data = newdata;
00310     buf->len = newlength;
00311     buf->heap = newheap;
00312 }
00313 
00315 void __sx_debug(const char *file, int line, const char *msgfmt, ...) {
00316     va_list ap;
00317     char *pos, message[MAX_DEBUG];
00318     int sz;
00319 
00320     /* insert the header */
00321     snprintf(message, MAX_DEBUG, "sx (%s:%d) ", file, line);
00322 
00323     /* find the end and attach the rest of the msg */
00324     for (pos = message; *pos != '\0'; pos++); /*empty statement */
00325     sz = pos - message;
00326     va_start(ap, msgfmt);
00327     vsnprintf(pos, MAX_DEBUG - sz, msgfmt, ap);
00328     va_end(ap);
00329     fprintf(stderr,"%s", message);
00330     fprintf(stderr, "\n");
00331     fflush(stderr);
00332 }
00333 
00334 int __sx_event(const char *file, int line, sx_t s, sx_event_t e, void *data) {
00335     int ret;
00336 
00337     _sx_debug(file, line, "tag %d event %d data 0x%x", s->tag, e, data);
00338 
00339     s->reentry++;
00340     ret = (s->cb)(s, e, data, s->cb_arg);
00341     s->reentry--;
00342 
00343     return ret;
00344 }