jabberd2
2.2.16
|
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 }