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 /** if you change these, reflect your changes in the defines in sx.h */
24 static const char *_stream_errors[] = {
25     "bad-format",
26     "bad-namespace-prefix",
27     "conflict",
28     "connection-timeout",
29     "host-gone",
30     "host-unknown",
31     "improper-addressing",
32     "internal-server-error",
33     "invalid-from",
34     "invalid-id",
35     "invalid-namespace",
36     "invalid-xml",
37     "not-authorized",
38     "policy-violation",
39     "remote-connection-failed",
40     "restricted-xml",
41     "resource-constraint",
42     "see-other-host",
43     "system-shutdown",
44     "undefined-condition",
45     "unsupported-encoding",
46     "unsupported-stanza-type",
47     "unsupported-version",
48     "xml-not-well-formed",
49     NULL
50 };
51 
52 /** send an error */
_sx_error(sx_t s,int err,const char * text)53 void _sx_error(sx_t s, int err, const char *text) {
54     int len = 0;
55     sx_buf_t buf;
56 
57     /* open stream if not already */
58     if(s->state < state_STREAM) {
59         if (s->flags & SX_WEBSOCKET_WRAPPER)
60             jqueue_push(s->wbufq, _sx_buffer_new("<open xmlns='" uri_XFRAMING "' version='1.0' />", sizeof(uri_XFRAMING) + 30, NULL, NULL), 0);
61         else
62             jqueue_push(s->wbufq, _sx_buffer_new("<stream:stream xmlns:stream='" uri_STREAMS "' version='1.0'>", sizeof(uri_STREAMS) + 44, NULL, NULL), 0);
63     }
64 
65     /* build the error */
66     len = strlen(uri_STREAMS) + strlen(uri_STREAM_ERR) + strlen(_stream_errors[err]) + 58;
67     if(text != NULL) len += strlen(uri_STREAM_ERR) + strlen(text) + 22;
68 
69     buf = _sx_buffer_new(NULL, len, NULL, NULL);
70 
71     if(text == NULL)
72         len = sprintf(buf->data, "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/></stream:error>", _stream_errors[err]);
73     else
74         len = sprintf(buf->data, "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/><text xmlns='" uri_STREAM_ERR "'>%s</text></stream:error>", _stream_errors[err], text);
75 
76     buf->len--;
77     assert(len == buf->len);
78 
79     _sx_debug(ZONE, "prepared error: %.*s", buf->len, buf->data);
80     jqueue_push(s->wbufq, buf, 0);
81 
82     /* close the stream if needed */
83     if(s->state < state_STREAM) {
84         if (s->flags & SX_WEBSOCKET_WRAPPER)
85             jqueue_push(s->wbufq, _sx_buffer_new("<close xmlns='" uri_XFRAMING "' />", sizeof(uri_XFRAMING) + 17, NULL, NULL), 0);
86         else
87             jqueue_push(s->wbufq, _sx_buffer_new("</stream:stream>", 16, NULL, NULL), 0);
88     }
89 
90     /* stuff to write */
91     s->want_write = 1;
92 }
93 
sx_error(sx_t s,int err,const char * text)94 void sx_error(sx_t s, int err, const char *text) {
95     assert(s != NULL);
96     assert(err >= 0 && err < stream_err_LAST);
97 
98     _sx_error(s, err, text);
99 
100     _sx_event(s, event_WANT_WRITE, NULL);
101 }
102 
103 //** send an extended error with custom contents other than text */
104 // Ideally should be merged with sx_error.  sx_error should permit additional content beneath the <stream:error> element, other than a <text> node.
_sx_error_extended(sx_t s,int err,const char * content)105 void _sx_error_extended(sx_t s, int err, const char *content) {
106     int len = 0;
107     sx_buf_t buf;
108 
109     /* build the string */
110     if(s->state < state_STREAM) len = strlen(uri_STREAMS) + 61;
111     len += strlen(uri_STREAMS) + strlen(uri_STREAM_ERR) + strlen(_stream_errors[err]) + 58;
112     if(content != NULL) len += strlen(content) + strlen(_stream_errors[err]) + 2;
113 
114     buf = _sx_buffer_new(NULL, len, NULL, NULL);
115     len = 0;
116 
117     if(s->state < state_STREAM)
118         len = sprintf(buf->data, "<stream:stream xmlns:stream='" uri_STREAMS "' version='1.0'>");
119 
120     if(content == NULL)
121         len += sprintf(&(buf->data[len]), "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'/></stream:error>", _stream_errors[err]);
122     else
123         len += sprintf(&(buf->data[len]), "<stream:error xmlns:stream='" uri_STREAMS "'><%s xmlns='" uri_STREAM_ERR "'>%s</%s></stream:error>", _stream_errors[err], content, _stream_errors[err]);
124 
125     if(s->state < state_STREAM)
126         len += sprintf(&(buf->data[len]), "</stream:stream>");
127 
128     buf->len--;
129     assert(len == buf->len);
130 
131     _sx_debug(ZONE, "prepared error: %.*s", buf->len, buf->data);
132 
133     /* go */
134     jqueue_push(s->wbufq, buf, 0);
135 
136     /* stuff to write */
137     s->want_write = 1;
138 }
139 
sx_error_extended(sx_t s,int err,const char * content)140 void sx_error_extended(sx_t s, int err, const char *content) {
141     assert(s != NULL);
142     assert(err >= 0 && err < stream_err_LAST);
143 
144     _sx_error_extended(s, err, content);
145 
146     _sx_event(s, event_WANT_WRITE, NULL);
147 }
148