jabberd2  2.3.4
server.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 static void _sx_server_notify_header(sx_t s, void *arg) {
24  int i, ns, len;
25  nad_t nad;
26  const char *c;
27  sx_buf_t buf;
28 
29  _sx_debug(ZONE, "stream established");
30 
31  /* get the plugins to setup */
32  if(s->env != NULL)
33  for(i = 0; i < s->env->nplugins; i++)
34  if(s->env->plugins[i]->stream != NULL)
35  (s->env->plugins[i]->stream)(s, s->env->plugins[i]);
36 
37  /* bump us to stream if a plugin didn't do it already */
38  if(s->state < state_STREAM) {
40  _sx_event(s, event_STREAM, NULL);
41  }
42 
43  /* next, build the features */
44  if(s->req_version != NULL && strcmp(s->req_version, "1.0") == 0) {
45  _sx_debug(ZONE, "building features nad");
46 
47  nad = nad_new();
48 
49  ns = nad_add_namespace(nad, uri_STREAMS, "stream");
50  nad_append_elem(nad, ns, "features", 0);
51 
52  /* get the plugins to populate it */
53  if(s->env != NULL)
54  for(i = 0; i < s->env->nplugins; i++)
55  if(s->env->plugins[i]->features != NULL)
56  (s->env->plugins[i]->features)(s, s->env->plugins[i], nad);
57 
58  /* new buffer for the nad */
59  nad_print(nad, 0, &c, &len);
60  buf = _sx_buffer_new(c, len, NULL, NULL);
61  nad_free(nad);
62 
63  /* send this off too */
64  /* !!! should this go via wnad/rnad? */
65  jqueue_push(s->wbufq, buf, 0);
66  s->want_write = 1;
67  }
68 
69  /* if they sent packets before the stream was established, process the now */
70  if(jqueue_size(s->rnadq) > 0 && (s->state == state_STREAM || s->state == state_OPEN)) {
71  _sx_debug(ZONE, "processing packets sent before stream, naughty them");
72  _sx_process_read(s, _sx_buffer_new(c, 0, NULL, NULL));
73  }
74 }
75 
76 static void _sx_server_element_start(void *arg, const char *name, const char **atts) {
77  sx_t s = (sx_t) arg;
78  int tflag = 0, fflag = 0, vflag = 0, len, i, r;
79  const char **attr;
80  char *c, id[41];
81  sx_buf_t buf;
82  sx_error_t sxe;
83 
84  if(s->fail) return;
85 
86  /* check element and namespace */
87  if (s->flags & SX_WEBSOCKET_WRAPPER) {
88  i = strlen(uri_XFRAMING) + 5;
89  r = strlen(name) < i || strncmp(name, uri_XFRAMING "|open", i) != 0 || (name[i] != '\0' && name[i] != '|');
90  } else {
91  i = strlen(uri_STREAMS) + 7;
92  r = strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|');
93  }
94  if (r) {
95  /* throw an error */
96  _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream open");
97  _sx_event(s, event_ERROR, (void *) &sxe);
99  s->fail = 1;
100  return;
101  }
102 
103 
104  /* pull interesting things out of the header */
105  attr = atts;
106  while(attr[0] != NULL) {
107  if(!tflag && strcmp(attr[0], "to") == 0) {
108  if(s->req_to != NULL) free((void*)s->req_to);
109  s->req_to = strdup(attr[1]);
110  tflag = 1;
111  }
112 
113  if(!fflag && strcmp(attr[0], "from") == 0) {
114  s->req_from = strdup(attr[1]);
115  fflag = 1;
116  }
117 
118  if(!vflag && strcmp(attr[0], "version") == 0) {
119  s->req_version = strdup(attr[1]);
120  vflag = 1;
121  }
122 
123  attr += 2;
124  }
125 
126  _sx_debug(ZONE, "stream request: to %s from %s version %s", s->req_to, s->req_from, s->req_version);
127 
128  /* check version */
129  if(s->req_version != NULL && strcmp(s->req_version, "1.0") != 0) {
130  /* throw an error */
131  _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Unsupported version");
132  _sx_event(s, event_ERROR, (void *) &sxe);
134  s->fail = 1;
135  return;
136  }
137 
138  /* !!! get the app to verify this stuff? */
139 
140  /* bump */
142 
143  /* response attributes */
144  if(s->req_to != NULL) s->res_from = strdup(s->req_to);
145  if(s->req_from != NULL) s->res_to = strdup(s->req_from);
146 
147  /* Only send 1.0 version if client has indicated a stream version - c/f XMPP 4.4.1 para 4 */
148  if(s->req_version != NULL) s->res_version = strdup("1.0");
149 
150  /* stream id */
151  for(i = 0; i < 40; i++) {
152  r = (int) (36.0 * rand() / RAND_MAX);
153  id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87);
154  }
155  id[40] = '\0';
156 
157  s->id = strdup(id);
158 
159  _sx_debug(ZONE, "stream id is %s", id);
160 
161  /* build the response */
162  if (s->flags & SX_WEBSOCKET_WRAPPER) {
163  len = 55;
164  } else {
165  len = strlen(uri_STREAMS) + 99;
166  }
167 
168  if(s->ns != NULL) len += 9 + strlen(s->ns);
169  if(s->res_to != NULL) len += 6 + strlen(s->res_to);
170  if(s->res_from != NULL) len += 8 + strlen(s->res_from);
171  if(s->res_version != NULL) len += 11 + strlen(s->res_version);
172 
173  buf = _sx_buffer_new(NULL, len, _sx_server_notify_header, NULL);
174 
175  c = buf->data;
176  if (s->flags & SX_WEBSOCKET_WRAPPER) {
177  strcpy(c, "<open");
178  } else {
179  strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'");
180  }
181 
182  if(s->ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", s->ns); }
183  if(s->res_to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", s->res_to); }
184  if(s->res_from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", s->res_from); }
185  if(s->res_version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", s->res_version); }
186 
187  c = strchr(c, '\0'); sprintf(c, " id='%s'", id);
188  if (s->flags & SX_WEBSOCKET_WRAPPER) {
189  c = strchr(c, '\0'); strcpy(c, " />");
190  } else {
191  c = strchr(c, '\0'); strcpy(c, ">");
192  }
193  assert(buf->len == strlen(buf->data) + 1); /* post-facto overrun detection */
194  buf->len --;
195 
196  /* plugins can mess with the header too */
197  if(s->env != NULL)
198  for(i = 0; i < s->env->nplugins; i++)
199  if(s->env->plugins[i]->header != NULL)
200  (s->env->plugins[i]->header)(s, s->env->plugins[i], buf);
201 
202  _sx_debug(ZONE, "prepared stream response: %.*s", buf->len, buf->data);
203 
204  /* off it goes */
205  jqueue_push(s->wbufq, buf, 0);
206 
207  s->depth++;
208 
209  /* we're alive */
210  XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end);
211  XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata);
212  XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start);
213 
214  /* we have stuff to write */
215  s->want_write = 1;
216 }
217 
218 static void _sx_server_element_end(void *arg, const char *name) {
219  sx_t s = (sx_t) arg;
220 
221  if(s->fail) return;
222 
223  s->depth--;
224 }
225 
227 static void _sx_server_ns_start(void *arg, const char *prefix, const char *uri) {
228  sx_t s = (sx_t) arg;
229 
230  /* only want the default namespace */
231  if(prefix != NULL)
232  return;
233 
234  /* sanity; MSXML-based clients have been known to send xmlns='' from time to time */
235  if(uri == NULL)
236  return;
237 
238  /* sanity check (should never happen if expat is doing its job) */
239  if(s->ns != NULL)
240  return;
241 
242  s->ns = strdup(uri);
243 
244  /* done */
245  XML_SetStartNamespaceDeclHandler(s->expat, NULL);
246 }
247 
248 void sx_server_init(sx_t s, unsigned int flags) {
249  int i;
250 
251  assert((int) (s != NULL));
252 
253  /* can't do anything if we're alive already */
254  if(s->state != state_NONE)
255  return;
256 
257  s->type = type_SERVER;
258  s->flags = flags;
259 
260  _sx_debug(ZONE, "doing server init for sx %d %s", s->tag, _sx_flags(s));
261 
262  /* plugin */
263  if(s->env != NULL)
264  for(i = 0; i < s->env->nplugins; i++)
265  if(s->env->plugins[i]->server != NULL)
266  (s->env->plugins[i]->server)(s, s->env->plugins[i]);
267 
268  /* we want to read */
269  XML_SetElementHandler(s->expat, (void *) _sx_server_element_start, (void *) _sx_server_element_end);
270  XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_server_ns_start);
271 
272  _sx_debug(ZONE, "waiting for stream header");
273 
274  s->want_read = 1;
275  _sx_event(s, event_WANT_READ, NULL);
276 }
Definition: nad.h:93
nad_t nad_new(void)
create a new nad
Definition: nad.c:125
Definition: sx.h:113
static void _sx_server_element_start(void *arg, const char *name, const char **atts)
Definition: server.c:76
_sx_state_t state
Definition: sx.h:315
#define _sx_event(s, e, data)
Definition: sx.h:391
void(* server)(sx_t s, sx_plugin_t p)
Definition: sx.h:356
unsigned int flags
Definition: sx.h:275
static void _sx_server_element_end(void *arg, const char *name)
Definition: server.c:218
const char * req_to
Definition: sx.h:281
jqueue_t wbufq
Definition: sx.h:300
Definition: sx.h:70
#define stream_err_UNSUPPORTED_VERSION
Definition: sx.h:146
Definition: sx.h:65
int jqueue_size(jqueue_t q)
Definition: jqueue.c:126
void(* features)(sx_t s, sx_plugin_t p, nad_t nad)
Definition: sx.h:369
error info for event_ERROR
Definition: sx.h:99
int tag
Definition: sx.h:257
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:734
static void _sx_server_ns_start(void *arg, const char *prefix, const char *uri)
catch the application namespace so we can get the response right
Definition: server.c:227
sx_env_t env
Definition: sx.h:254
void sx_server_init(sx_t s, unsigned int flags)
Definition: server.c:248
#define SX_ERR_STREAM
Definition: sx.h:94
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:667
const char * ns
Definition: sx.h:278
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
holds the state for a single stream
Definition: sx.h:252
int depth
Definition: sx.h:319
char * data
Definition: sx.h:114
void _sx_element_end(void *arg, const char *name)
Definition: callback.c:108
sx_plugin_t * plugins
Definition: sx.h:379
void jqueue_push(jqueue_t q, void *data, int priority)
Definition: jqueue.c:44
int fail
Definition: sx.h:320
jqueue_t rnadq
Definition: sx.h:302
void(* stream)(sx_t s, sx_plugin_t p)
Definition: sx.h:367
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:220
const char * res_from
Definition: sx.h:287
const char * res_to
Definition: sx.h:286
void _sx_process_read(sx_t s, sx_buf_t buf)
handler for read data
Definition: io.c:24
#define SX_WEBSOCKET_WRAPPER
Definition: plugins.h:34
#define _sx_debug
Definition: sx.h:404
#define uri_STREAMS
Definition: uri.h:34
_sx_type_t type
Definition: sx.h:272
const char * req_version
Definition: sx.h:283
const char * res_version
Definition: sx.h:288
void _sx_namespace_start(void *arg, const char *prefix, const char *uri)
Definition: callback.c:142
void _sx_cdata(void *arg, const char *str, int len)
Definition: callback.c:129
const char * req_from
Definition: sx.h:282
Definition: sx.h:83
unsigned int len
Definition: sx.h:115
struct _sx_st * sx_t
Definition: sx.h:51
void _sx_error(sx_t s, int err, const char *text)
send an error
Definition: error.c:53
void _sx_element_start(void *arg, const char *name, const char **atts)
primary expat callbacks
Definition: callback.c:24
#define stream_err_BAD_FORMAT
Definition: sx.h:124
#define _sx_gen_error(e, c, g, s)
helper macro to populate this struct
Definition: sx.h:106
#define ZONE
Definition: mio_impl.h:76
int want_read
Definition: sx.h:305
#define _sx_state(s, st)
Definition: sx.h:405
XML_Parser expat
Definition: sx.h:318
static void _sx_server_notify_header(sx_t s, void *arg)
Definition: server.c:23
#define uri_XFRAMING
Definition: uri.h:44
Definition: sx.h:74
int nplugins
Definition: sx.h:380
int want_write
Definition: sx.h:305
const char * id
Definition: sx.h:291
void nad_print(nad_t nad, int elem, const char **xml, int *len)
create a string representation of the given element (and children), point references to it ...
Definition: nad.c:1164
void(* header)(sx_t s, sx_plugin_t p, sx_buf_t buf)
Definition: sx.h:366
char * _sx_flags(sx_t s)
show sx flags as string - for logging
Definition: sx.c:349