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