jabberd2  2.2.17
sx.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 #include <time.h>
23 
24 sx_t sx_new(sx_env_t env, int tag, sx_callback_t cb, void *arg) {
25  sx_t s;
26  int i;
27 
28  assert((int) (cb != NULL));
29 
30  s = (sx_t) calloc(1, sizeof(struct _sx_st));
31 
32  s->env = env;
33  s->tag = tag;
34  s->cb = cb;
35  s->cb_arg = arg;
36 
37  s->expat = XML_ParserCreateNS(NULL, '|');
38  XML_SetReturnNSTriplet(s->expat, 1);
39  XML_SetUserData(s->expat, (void *) s);
40  /* Prevent the "billion laughs" attack against expat by disabling
41  * internal entity expansion. With 2.x, forcibly stop the parser
42  * if an entity is declared - this is safer and a more obvious
43  * failure mode. With older versions, simply prevent expenansion
44  * of such entities. */
45 #ifdef HAVE_XML_STOPPARSER
46  XML_SetEntityDeclHandler(s->expat, (void *) _sx_entity_declaration);
47 #else
48  XML_SetDefaultHandler(s->expat, NULL);
49 #endif
50 
51 #ifdef HAVE_XML_SETHASHSALT
52  XML_SetHashSalt(s->expat, clock());
53 #endif
54 
55  s->wbufq = jqueue_new();
56  s->rnadq = jqueue_new();
57 
58  if(env != NULL) {
59  s->plugin_data = (void **) calloc(1, sizeof(void *) * env->nplugins);
60 
61  for(i = 0; i < env->nplugins; i++)
62  if(env->plugins[i]->new != NULL)
63  (env->plugins[i]->new)(s, env->plugins[i]);
64  }
65 
66  _sx_debug(ZONE, "allocated new sx for %d", tag);
67 
68  return s;
69 }
70 
71 void sx_free(sx_t s) {
72  sx_buf_t buf;
73  nad_t nad;
74  int i;
75  _sx_chain_t scan, next;
76 
77  if (s == NULL)
78  return;
79 
80  /* we are not reentrant */
81  assert(!s->reentry);
82 
83  _sx_debug(ZONE, "freeing sx for %d", s->tag);
84 
85  if(s->ns != NULL) free(s->ns);
86 
87  if(s->req_to != NULL) free(s->req_to);
88  if(s->req_from != NULL) free(s->req_from);
89  if(s->req_version != NULL) free(s->req_version);
90 
91  if(s->res_to != NULL) free(s->res_to);
92  if(s->res_from != NULL) free(s->res_from);
93  if(s->res_version != NULL) free(s->res_version);
94 
95  if(s->id != NULL) free(s->id);
96 
97  while((buf = jqueue_pull(s->wbufq)) != NULL)
98  _sx_buffer_free(buf);
99  if (s->wbufpending != NULL)
101 
102  while((nad = jqueue_pull(s->rnadq)) != NULL)
103  nad_free(nad);
104 
105  jqueue_free(s->wbufq);
106  jqueue_free(s->rnadq);
107 
108  XML_ParserFree(s->expat);
109 
110  if(s->nad != NULL) nad_free(s->nad);
111 
112  if(s->auth_method != NULL) free(s->auth_method);
113  if(s->auth_id != NULL) free(s->auth_id);
114 
115  if(s->env != NULL) {
116  _sx_debug(ZONE, "freeing %d env plugins", s->env->nplugins);
117  for(i = 0; i < s->env->nplugins; i++)
118  if(s->env->plugins[i]->free != NULL)
119  (s->env->plugins[i]->free)(s, s->env->plugins[i]);
120 
121  scan = s->wio;
122  while(scan != NULL) {
123  next = scan->wnext;
124  free(scan);
125  scan = next;
126  }
127 
128  scan = s->wnad;
129  while(scan != NULL) {
130  next = scan->wnext;
131  free(scan);
132  scan = next;
133  }
134 
135  free(s->plugin_data);
136  }
137 
138  free(s);
139 }
140 
142 void sx_auth(sx_t s, const char *auth_method, const char *auth_id) {
143  assert((int) (s != NULL));
144 
145  _sx_debug(ZONE, "authenticating stream (method=%s; id=%s)", auth_method, auth_id);
146 
147  if(auth_method != NULL) s->auth_method = strdup(auth_method);
148  if(auth_id != NULL) s->auth_id = strdup(auth_id);
149 
150  _sx_state(s, state_OPEN);
151  _sx_event(s, event_OPEN, NULL);
152 }
153 
155 void _sx_reset(sx_t s) {
156  struct _sx_st temp;
157  sx_t new;
158 
159  _sx_debug(ZONE, "resetting stream state");
160 
161  /* we want to reset the contents of s, but we can't free s because
162  * the caller (and others) hold references. so, we make a new sx_t,
163  * copy the contents (only pointers), free it (which will free strings
164  * and queues), then make another new one, and copy the contents back
165  * into s */
166 
167  temp.env = s->env;
168  temp.tag = s->tag;
169  temp.cb = s->cb;
170  temp.cb_arg = s->cb_arg;
171 
172  temp.ip = s->ip;
173  temp.port = s->port;
174  temp.flags = s->flags;
175  temp.reentry = s->reentry;
176  temp.ssf = s->ssf;
177  temp.compressed = s->compressed;
178  temp.wio = s->wio;
179  temp.rio = s->rio;
180  temp.wnad = s->wnad;
181  temp.rnad = s->rnad;
182  temp.rbytesmax = s->rbytesmax;
183  temp.plugin_data = s->plugin_data;
184 
185  s->reentry = 0;
186 
187  s->env = NULL; /* we get rid of this, because we don't want plugin data to be freed */
188 
189  new = (sx_t) malloc(sizeof(struct _sx_st));
190  memcpy(new, s, sizeof(struct _sx_st));
191  sx_free(new);
192 
193  new = sx_new(NULL, temp.tag, temp.cb, temp.cb_arg);
194  memcpy(s, new, sizeof(struct _sx_st));
195  free(new);
196 
197  /* massaged expat into shape */
198  XML_SetUserData(s->expat, (void *) s);
199 
200  s->env = temp.env;
201  s->ip = temp.ip;
202  s->port = temp.port;
203  s->flags = temp.flags;
204  s->reentry = temp.reentry;
205  s->ssf = temp.ssf;
206  s->compressed = temp.compressed;
207  s->wio = temp.wio;
208  s->rio = temp.rio;
209  s->wnad = temp.wnad;
210  s->rnad = temp.rnad;
211  s->rbytesmax = temp.rbytesmax;
212  s->plugin_data = temp.plugin_data;
213 
214  s->has_reset = 1;
215 
216  _sx_debug(ZONE, "finished resetting stream state");
217 }
218 
223 sx_buf_t _sx_buffer_new(const char *data, int len, _sx_notify_t notify, void *notify_arg) {
224  sx_buf_t buf;
225 
226  buf = (sx_buf_t) calloc(1, sizeof(struct _sx_buf_st));
227 
228  if (len <= 0) {
229  buf->data = buf->heap = NULL;
230  buf->len = 0;
231  } else {
232  buf->data = buf->heap = (char *) malloc(sizeof(char) * len);
233  if(data != NULL)
234  memcpy(buf->data, data, len);
235  else
236  memset(buf->data, '$', len); /* catch uninitialized use */
237  buf->len = len;
238  }
239 
240  buf->notify = notify;
241  buf->notify_arg = notify_arg;
242 
243  return buf;
244 }
245 
248  if(buf->heap != NULL)
249  free(buf->heap);
250 
251  free(buf);
252 }
253 
256  if(buf->heap != NULL) {
257  free(buf->heap);
258  buf->heap = NULL;
259  }
260  buf->data = NULL;
261  buf->len = 0;
262 }
263 
265 void _sx_buffer_alloc_margin(sx_buf_t buf, int before, int after)
266 {
267  char *new_heap;
268 
269  assert( before >= 0 );
270  assert( after >= 0 );
271 
272  /* If there wasn't any data in the buf, we can just allocate space for the margins */
273  if (buf->data == NULL || buf->len == 0) {
274  if (buf->heap != NULL)
275  buf->heap = realloc(buf->heap, before+after);
276  else
277  buf->heap = malloc(before+after);
278  buf->data = buf->heap + before;
279  return;
280  }
281 
282  if (buf->heap != NULL) {
283  int old_leader = buf->data - buf->heap;
284  /* Hmmm, maybe we can just call realloc() ? */
285  if (old_leader >= before && old_leader <= (before * 4)) {
286  buf->heap = realloc(buf->heap, before + buf->len + after);
287  buf->data = buf->heap + old_leader;
288  return;
289  }
290  }
291 
292  /* Most general case --- allocate a new buffer, copy stuff over, free the old one. */
293  new_heap = malloc(before + buf->len + after);
294  memcpy(new_heap + before, buf->data, buf->len);
295  if (buf->heap != NULL)
296  free(buf->heap);
297  buf->heap = new_heap;
298  buf->data = new_heap + before;
299 }
300 
302 void _sx_buffer_set(sx_buf_t buf, char *newdata, int newlength, char *newheap)
303 {
304  if (newheap == NULL) {
305  buf->len = 0;
306  _sx_buffer_alloc_margin(buf, 0, newlength);
307  if (newlength > 0)
308  memcpy(buf->data, newdata, newlength);
309  buf->len = newlength;
310  return;
311  }
312 
313  _sx_buffer_clear(buf);
314  buf->data = newdata;
315  buf->len = newlength;
316  buf->heap = newheap;
317 }
318 
320 void __sx_debug(const char *file, int line, const char *msgfmt, ...) {
321  va_list ap;
322  char *pos, message[MAX_DEBUG];
323  int sz;
324 
325  /* insert the header */
326  snprintf(message, MAX_DEBUG, "sx (%s:%d) ", file, line);
327 
328  /* find the end and attach the rest of the msg */
329  for (pos = message; *pos != '\0'; pos++); /*empty statement */
330  sz = pos - message;
331  va_start(ap, msgfmt);
332  vsnprintf(pos, MAX_DEBUG - sz, msgfmt, ap);
333  va_end(ap);
334  fprintf(stderr,"%s", message);
335  fprintf(stderr, "\n");
336  fflush(stderr);
337 }
338 
339 int __sx_event(const char *file, int line, sx_t s, sx_event_t e, void *data) {
340  int ret;
341 
342  _sx_debug(file, line, "tag %d event %d data 0x%x", s->tag, e, data);
343 
344  s->reentry++;
345  ret = (s->cb)(s, e, data, s->cb_arg);
346  s->reentry--;
347 
348  return ret;
349 }