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 static void _sx_server_notify_header(sx_t s, void *arg) { 00024 int i, ns, len; 00025 nad_t nad; 00026 char *c; 00027 sx_buf_t buf; 00028 00029 _sx_debug(ZONE, "stream established"); 00030 00031 /* get the plugins to setup */ 00032 if(s->env != NULL) 00033 for(i = 0; i < s->env->nplugins; i++) 00034 if(s->env->plugins[i]->stream != NULL) 00035 (s->env->plugins[i]->stream)(s, s->env->plugins[i]); 00036 00037 /* bump us to stream if a plugin didn't do it already */ 00038 if(s->state < state_STREAM) { 00039 _sx_state(s, state_STREAM); 00040 _sx_event(s, event_STREAM, NULL); 00041 } 00042 00043 /* next, build the features */ 00044 if(s->req_version != NULL && strcmp(s->req_version, "1.0") == 0) { 00045 _sx_debug(ZONE, "building features nad"); 00046 00047 nad = nad_new(); 00048 00049 ns = nad_add_namespace(nad, uri_STREAMS, "stream"); 00050 nad_append_elem(nad, ns, "features", 0); 00051 00052 /* get the plugins to populate it */ 00053 if(s->env != NULL) 00054 for(i = 0; i < s->env->nplugins; i++) 00055 if(s->env->plugins[i]->features != NULL) 00056 (s->env->plugins[i]->features)(s, s->env->plugins[i], nad); 00057 00058 /* new buffer for the nad */ 00059 nad_print(nad, 0, &c, &len); 00060 buf = _sx_buffer_new(c, len, NULL, NULL); 00061 nad_free(nad); 00062 00063 /* send this off too */ 00064 /* !!! should this go via wnad/rnad? */ 00065 jqueue_push(s->wbufq, buf, 0); 00066 s->want_write = 1; 00067 } 00068 00069 /* if they sent packets before the stream was established, process the now */ 00070 if(jqueue_size(s->rnadq) > 0 && (s->state == state_STREAM || s->state == state_OPEN)) { 00071 _sx_debug(ZONE, "processing packets sent before stream, naughty them"); 00072 _sx_process_read(s, _sx_buffer_new(c, 0, NULL, NULL)); 00073 } 00074 } 00075 00076 static void _sx_server_element_start(void *arg, const char *name, const char **atts) { 00077 sx_t s = (sx_t) arg; 00078 int tflag = 0, fflag = 0, vflag = 0, len, i, r; 00079 const char **attr; 00080 char *c, id[41]; 00081 sx_buf_t buf; 00082 sx_error_t sxe; 00083 00084 if(s->fail) return; 00085 00086 /* check element and namespace */ 00087 i = strlen(uri_STREAMS) + 7; 00088 if(strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|')) { 00089 /* throw an error */ 00090 _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream start"); 00091 _sx_event(s, event_ERROR, (void *) &sxe); 00092 _sx_error(s, stream_err_BAD_FORMAT, NULL); 00093 s->fail = 1; 00094 return; 00095 } 00096 00097 /* pull interesting things out of the header */ 00098 attr = atts; 00099 while(attr[0] != NULL) { 00100 if(!tflag && strcmp(attr[0], "to") == 0) { 00101 if(s->req_to != NULL) free(s->req_to); 00102 s->req_to = strdup(attr[1]); 00103 tflag = 1; 00104 } 00105 00106 if(!fflag && strcmp(attr[0], "from") == 0) { 00107 s->req_from = strdup(attr[1]); 00108 fflag = 1; 00109 } 00110 00111 if(!vflag && strcmp(attr[0], "version") == 0) { 00112 s->req_version = strdup(attr[1]); 00113 vflag = 1; 00114 } 00115 00116 attr += 2; 00117 } 00118 00119 _sx_debug(ZONE, "stream request: to %s from %s version %s", s->req_to, s->req_from, s->req_version); 00120 00121 /* check version */ 00122 if(s->req_version != NULL && strcmp(s->req_version, "1.0") != 0) { 00123 /* throw an error */ 00124 _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Unsupported version"); 00125 _sx_event(s, event_ERROR, (void *) &sxe); 00126 _sx_error(s, stream_err_UNSUPPORTED_VERSION, NULL); 00127 s->fail = 1; 00128 return; 00129 } 00130 00131 /* !!! get the app to verify this stuff? */ 00132 00133 /* bump */ 00134 _sx_state(s, state_STREAM_RECEIVED); 00135 00136 /* response attributes */ 00137 if(s->req_to != NULL) s->res_from = strdup(s->req_to); 00138 if(s->req_from != NULL) s->res_to = strdup(s->req_from); 00139 00140 /* Only send 1.0 version if client has indicated a stream version - c/f XMPP 4.4.1 para 4 */ 00141 if(s->req_version != NULL) s->res_version = strdup("1.0"); 00142 00143 /* stream id */ 00144 for(i = 0; i < 40; i++) { 00145 r = (int) (36.0 * rand() / RAND_MAX); 00146 id[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87); 00147 } 00148 id[40] = '\0'; 00149 00150 s->id = strdup(id); 00151 00152 _sx_debug(ZONE, "stream id is %s", id); 00153 00154 /* build the response */ 00155 len = strlen(uri_STREAMS) + 99; 00156 00157 if(s->ns != NULL) len += 9 + strlen(s->ns); 00158 if(s->res_to != NULL) len += 6 + strlen(s->res_to); 00159 if(s->res_from != NULL) len += 8 + strlen(s->res_from); 00160 if(s->res_version != NULL) len += 11 + strlen(s->res_version); 00161 00162 buf = _sx_buffer_new(NULL, len, _sx_server_notify_header, NULL); 00163 00164 c = buf->data; 00165 strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'"); 00166 00167 if(s->ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", s->ns); } 00168 if(s->res_to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", s->res_to); } 00169 if(s->res_from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", s->res_from); } 00170 if(s->res_version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", s->res_version); } 00171 00172 c = strchr(c, '\0'); sprintf(c, " id='%s'>", id); 00173 assert(buf->len == strlen(buf->data) + 1); /* post-facto overrun detection */ 00174 buf->len --; 00175 00176 /* plugins can mess with the header too */ 00177 if(s->env != NULL) 00178 for(i = 0; i < s->env->nplugins; i++) 00179 if(s->env->plugins[i]->header != NULL) 00180 (s->env->plugins[i]->header)(s, s->env->plugins[i], buf); 00181 00182 _sx_debug(ZONE, "prepared stream response: %.*s", buf->len, buf->data); 00183 00184 /* off it goes */ 00185 jqueue_push(s->wbufq, buf, 0); 00186 00187 s->depth++; 00188 00189 /* we're alive */ 00190 XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end); 00191 XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata); 00192 XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start); 00193 00194 /* we have stuff to write */ 00195 s->want_write = 1; 00196 } 00197 00198 static void _sx_server_element_end(void *arg, const char *name) { 00199 sx_t s = (sx_t) arg; 00200 00201 if(s->fail) return; 00202 00203 s->depth--; 00204 } 00205 00207 static void _sx_server_ns_start(void *arg, const char *prefix, const char *uri) { 00208 sx_t s = (sx_t) arg; 00209 00210 /* only want the default namespace */ 00211 if(prefix != NULL) 00212 return; 00213 00214 /* sanity; MSXML-based clients have been known to send xmlns='' from time to time */ 00215 if(uri == NULL) 00216 return; 00217 00218 /* sanity check (should never happen if expat is doing its job) */ 00219 if(s->ns != NULL) 00220 return; 00221 00222 s->ns = strdup(uri); 00223 00224 /* done */ 00225 XML_SetStartNamespaceDeclHandler(s->expat, NULL); 00226 } 00227 00228 void sx_server_init(sx_t s, unsigned int flags) { 00229 int i; 00230 00231 assert((int) (s != NULL)); 00232 00233 /* can't do anything if we're alive already */ 00234 if(s->state != state_NONE) 00235 return; 00236 00237 _sx_debug(ZONE, "doing server init for sx %d", s->tag); 00238 00239 s->type = type_SERVER; 00240 s->flags = flags; 00241 00242 /* plugin */ 00243 if(s->env != NULL) 00244 for(i = 0; i < s->env->nplugins; i++) 00245 if(s->env->plugins[i]->server != NULL) 00246 (s->env->plugins[i]->server)(s, s->env->plugins[i]); 00247 00248 /* we want to read */ 00249 XML_SetElementHandler(s->expat, (void *) _sx_server_element_start, (void *) _sx_server_element_end); 00250 XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_server_ns_start); 00251 00252 _sx_debug(ZONE, "waiting for stream header"); 00253 00254 s->want_read = 1; 00255 _sx_event(s, event_WANT_READ, NULL); 00256 }