3 /* ------------------------------------------------
4 some pre-packaged Jabber XML
5 ------------------------------------------------ */
6 static const char* xml_parse_error = "<stream:stream xmlns:stream='http://etherx.jabber.org/streams'"
7 "version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'>"
8 "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
9 "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax error</text></stream:error></stream:stream>";
11 static const char* xml_login_ok = "<iq xmlns='jabber:client' id='asdfjkl' type='result'/>";
14 jserver* jserver_init() {
15 jserver* js = safe_malloc(sizeof(jserver));
16 js->mgr = safe_malloc(sizeof(socket_manager));
17 js->mgr->data_received = &jserver_handle_request;
19 js->mgr->on_socket_closed = &jserver_socket_closed;
25 void jserver_free(jserver* js) {
26 if(js == NULL) return;
29 node = js->client->next;
30 _jserver_remove_client(js, js->client->addr);
33 socket_manager_free(js->mgr);
37 void jserver_socket_closed(void* blob, int sock_id) {
38 jserver* js = (jserver*) blob;
39 if(js == NULL) return;
40 jclient_node* node = jserver_find_client_id(js, sock_id);
42 info_handler("Removing client %d - %s remote "
43 "site closed socket", sock_id, node->addr);
44 _jserver_remove_client(js, node->addr);
49 /* opens the inet and unix sockets that we're listening on */
50 int jserver_connect(jserver* js, int port, char* unix_path) {
51 if(js == NULL || js->mgr == NULL) return -1;
55 status = socket_open_tcp_server(js->mgr, port);
56 if(status == -1) return status;
59 if(unix_path != NULL) {
60 status = socket_open_unix_server(js->mgr, unix_path);
61 if(status == -1) return status;
67 void _free_jclient_node(jclient_node* node) {
68 if(node == NULL) return;
70 jserver_session_free(node->session);
74 /* allocates a new client node */
75 jclient_node* _new_jclient_node(int id) {
76 jclient_node* node = safe_malloc(sizeof(jclient_node));
79 node->session = jserver_session_init();
80 node->session->blob = node;
81 node->session->on_msg_complete = &jserver_client_handle_msg;
82 node->session->on_from_discovered = &jserver_client_from_found;
83 node->session->on_login_init = &jserver_client_login_init;
84 node->session->on_login_ok = &jserver_client_login_ok;
85 node->session->on_client_finish = &jserver_client_finish;
89 /* client has sent the end of it's session doc, we may now disconnect */
90 void jserver_client_finish(void* blob) {
91 jclient_node* node = (jclient_node*) blob;
92 if(node == NULL) return;
93 jserver_send_id(node->id, "</stream:stream>");
94 _jserver_remove_client(node->parent, node->addr);
98 void jserver_client_from_found(void* blob, char* from) {
99 jclient_node* node = (jclient_node*) blob;
100 if(node == NULL || from == NULL) return;
102 /* prevent duplicate login - kick off original */
103 _jserver_remove_client(node->parent, from);
104 info_handler("logged in: %s", from);
105 node->addr = strdup(from);
108 void jserver_client_login_init(void* blob, char* reply) {
109 debug_handler("here");
110 jclient_node* node = (jclient_node*) blob;
111 if(node == NULL || reply == NULL) return;
112 debug_handler("jserver handling login init");
113 jserver_send_id(node->id, reply);
116 void jserver_client_login_ok(void* blob) {
117 jclient_node* node = (jclient_node*) blob;
118 if(node == NULL) return;
119 info_handler("Client logging in ok => %d", node->id);
120 jserver_send_id(node->id, xml_login_ok);
123 void jserver_client_handle_msg(
124 void* blob, char* xml, char* from, char* to ) {
126 jclient_node* node = (jclient_node*) blob;
127 if(node == NULL || xml == NULL || to == NULL) return;
130 jclient_node* from_node = jserver_find_client(node->parent, from);
132 from_id = from_node->id;
135 debug_handler("Client %d received from %s message : %s",
136 node->id, from, xml );
138 jserver_send(node->parent, from_id, to, xml);
141 /* allocates a new client node and adds it to the set */
142 jclient_node* _jserver_add_client(jserver* js, int id) {
143 if(js == NULL) return NULL;
144 jclient_node* node = _new_jclient_node(id);
145 node->next = js->client;
152 /* removes and frees a client node */
153 void _jserver_remove_client(jserver* js, char* addr) {
154 if(js == NULL || js->client == NULL || addr == NULL) return;
156 jclient_node* node = js->client;
158 if(node->addr && !strcmp(node->addr,addr)) {
159 js->client = node->next;
160 debug_handler("Removing the first jserver client");
161 socket_disconnect(js->mgr, node->id);
162 _free_jclient_node(node);
166 debug_handler("Searching for jclient to remove");
167 jclient_node* tail_node = node;
171 if(node->addr && !strcmp(node->addr,addr)) {
172 tail_node->next = node->next;
173 debug_handler("Removing a jserver client");
174 socket_disconnect(js->mgr, node->id);
175 _free_jclient_node(node);
183 /* finds a client node by addr */
184 jclient_node* jserver_find_client(jserver* js, char* addr) {
185 if(js == NULL || addr == NULL) return NULL;
186 jclient_node* node = js->client;
188 if(node->addr && !strcmp(node->addr, addr))
195 jclient_node* jserver_find_client_id(jserver* js, int id) {
196 if(js == NULL) return NULL;
197 jclient_node* node = js->client;
206 /* sends msg to client at 'to_addr' */
207 int jserver_send(jserver* js, int from_id, char* to_addr, const char* msg_xml) {
208 debug_handler("sending message to %s : %s", to_addr, msg_xml);
209 if(to_addr == NULL || msg_xml == NULL) return -1;
211 jclient_node* node = jserver_find_client(js, to_addr);
214 info_handler("message to non-existent client %s", to_addr);
216 jclient_node* from = jserver_find_client_id(js, from_id);
219 info_handler("replying with error...");
221 memset(buf, 0, 2048);
222 snprintf(buf, 2047, "<message xmlns='jabber:client' type='error' from='%s' "
223 "to='%s'><error type='cancel' code='404'><item-not-found "
224 "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>"
225 "<body>NOT ADDING BODY</body></message>", to_addr, from->addr );
226 jserver_send_id(from_id, buf);
232 return jserver_send_id(node->id, msg_xml);
235 int jserver_send_id(int client_id, const char* msg_xml) {
236 if(msg_xml == NULL || client_id < 1) return -1;
237 return socket_send(client_id, msg_xml );
240 /* waits for any incoming data */
241 int jserver_wait(jserver* js) {
242 if(js == NULL) return -1;
244 if(socket_wait_all(js->mgr, -1) < 0)
246 "jserver_wait(): socket_wait_all() returned error");
252 int _jserver_push_client_data(jclient_node* node, char* data) {
253 if(node == NULL || data == NULL) return -1;
254 return jserver_session_push_data( node->session, data);
257 void jserver_handle_request(void* js_blob,
258 socket_manager* mgr, int sock_id, char* data, int parent_id ) {
260 jserver* js = (jserver*) js_blob;
262 debug_handler("jsever received data from socket %d (parent %d)", sock_id, parent_id );
264 jclient_node* node = jserver_find_client_id(js, sock_id);
266 debug_handler("We have a new client connection, adding to list");
267 node = _jserver_add_client(js, sock_id);
270 if(_jserver_push_client_data(node, data) == -1) {
271 warning_handler("Client sent bad data, disconnecting...");
272 jserver_send_id(node->id, xml_parse_error);
273 _jserver_remove_client(js, node->addr);
276 debug_handler("Client data successfully parsed");