1 #include <opensrf/transport_session.h>
4 @file transport_session.c
5 @brief Routines to manage a connection to a Jabber server.
7 In all cases, a transport_session acts as a client with regard to Jabber.
10 // ---------------------------------------------------------------------------------
11 // Callback for handling the startElement event. Much of the jabber logic occurs
12 // in this and the characterHandler callbacks.
13 // Here we check for the various top level jabber elements: body, iq, etc.
14 // ---------------------------------------------------------------------------------
15 static void startElementHandler(
16 void *session, const xmlChar *name, const xmlChar **atts);
18 // ---------------------------------------------------------------------------------
19 // Callback for handling the endElement event. Updates the Jabber state machine
20 // to let us know the element is over.
21 // ---------------------------------------------------------------------------------
22 static void endElementHandler( void *session, const xmlChar *name);
24 // ---------------------------------------------------------------------------------
25 // This is where we extract XML text content. In particular, this is useful for
26 // extracting Jabber message bodies.
27 // ---------------------------------------------------------------------------------
28 static void characterHandler(
29 void *session, const xmlChar *ch, int len);
31 static void parseWarningHandler( void *session, const char* msg, ... );
32 static void parseErrorHandler( void *session, const char* msg, ... );
34 // ---------------------------------------------------------------------------------
35 // Tells the SAX parser which functions will be used as event callbacks
36 // ---------------------------------------------------------------------------------
37 static xmlSAXHandler SAXHandlerStruct = {
38 NULL, /* internalSubset */
39 NULL, /* isStandalone */
40 NULL, /* hasInternalSubset */
41 NULL, /* hasExternalSubset */
42 NULL, /* resolveEntity */
44 NULL, /* entityDecl */
45 NULL, /* notationDecl */
46 NULL, /* attributeDecl */
47 NULL, /* elementDecl */
48 NULL, /* unparsedEntityDecl */
49 NULL, /* setDocumentLocator */
50 NULL, /* startDocument */
51 NULL, /* endDocument */
52 startElementHandler, /* startElement */
53 endElementHandler, /* endElement */
55 characterHandler, /* characters */
56 NULL, /* ignorableWhitespace */
57 NULL, /* processingInstruction */
59 parseWarningHandler, /* xmlParserWarning */
60 parseErrorHandler, /* xmlParserError */
61 NULL, /* xmlParserFatalError : unused */
62 NULL, /* getParameterEntity */
63 NULL, /* cdataBlock; */
64 NULL, /* externalSubset; */
67 NULL, /* startElementNs */
68 NULL, /* endElementNs */
69 NULL /* xmlStructuredErrorFunc */
72 // ---------------------------------------------------------------------------------
73 // Our SAX handler pointer.
74 // ---------------------------------------------------------------------------------
75 static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
78 #define HOST_NAME_MAX 256
81 static void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* data, int parent);
82 static int reset_session_buffers( transport_session* session );
83 static char* get_xml_attr( const xmlChar** atts, const char* attr_name );
86 @brief Allocate and initialize a transport_session.
87 @param server Hostname or IP address where the Jabber server resides.
88 @param port Port used for connecting to Jabber (0 if using UNIX domain socket).
89 @param unix_path Name of Jabber's socket in file system (if using UNIX domain socket).
90 @param user_data An opaque pointer stored on behalf of the calling code.
91 @param component Boolean; true if we're a component.
92 @return Pointer to a newly allocated transport_session.
94 This function initializes memory but does not open any sockets or otherwise access
97 If @a port is greater than zero, we will use TCP to connect to Jabber, and ignore
98 @a unix_path. Otherwise we will open a UNIX domain socket using @a unix_path.
100 The calling code is responsible for freeing the transport_session by calling
103 transport_session* init_transport( const char* server,
104 int port, const char* unix_path, void* user_data, int component ) {
109 /* create the session struct */
110 transport_session* session =
111 (transport_session*) safe_malloc( sizeof(transport_session) );
113 session->user_data = user_data;
115 session->component = component;
117 /* initialize the data buffers */
118 session->body_buffer = buffer_init( JABBER_BODY_BUFSIZE );
119 session->subject_buffer = buffer_init( JABBER_SUBJECT_BUFSIZE );
120 session->thread_buffer = buffer_init( JABBER_THREAD_BUFSIZE );
121 session->from_buffer = buffer_init( JABBER_JID_BUFSIZE );
122 session->status_buffer = buffer_init( JABBER_STATUS_BUFSIZE );
123 session->recipient_buffer = buffer_init( JABBER_JID_BUFSIZE );
124 session->message_error_type = buffer_init( JABBER_JID_BUFSIZE );
125 session->session_id = buffer_init( 64 );
127 session->message_error_code = 0;
129 /* for OpenSRF extensions */
130 session->router_to_buffer = buffer_init( JABBER_JID_BUFSIZE );
131 session->router_from_buffer = buffer_init( JABBER_JID_BUFSIZE );
132 session->osrf_xid_buffer = buffer_init( JABBER_JID_BUFSIZE );
133 session->router_class_buffer = buffer_init( JABBER_JID_BUFSIZE );
134 session->router_command_buffer = buffer_init( JABBER_JID_BUFSIZE );
136 session->router_broadcast = 0;
138 /* initialize the jabber state machine */
139 session->state_machine = (jabber_machine*) safe_malloc( sizeof(jabber_machine) );
140 session->state_machine->connected = 0;
141 session->state_machine->connecting = 0;
142 session->state_machine->in_message = 0;
143 session->state_machine->in_message_body = 0;
144 session->state_machine->in_thread = 0;
145 session->state_machine->in_subject = 0;
146 session->state_machine->in_error = 0;
147 session->state_machine->in_message_error = 0;
148 session->state_machine->in_iq = 0;
149 session->state_machine->in_presence = 0;
150 session->state_machine->in_status = 0;
152 /* initialize the sax push parser */
153 session->parser_ctxt = xmlCreatePushParserCtxt(SAXHandler, session, "", 0, NULL);
155 /* initialize the socket_manager structure */
156 session->sock_mgr = (socket_manager*) safe_malloc( sizeof(socket_manager) );
158 session->sock_mgr->data_received = &grab_incoming;
159 session->sock_mgr->on_socket_closed = NULL;
160 session->sock_mgr->socket = NULL;
161 session->sock_mgr->blob = session;
163 session->port = port;
164 session->server = strdup(server);
166 session->unix_path = strdup(unix_path);
167 else session->unix_path = NULL;
169 session->sock_id = 0;
170 session->message_callback = NULL;
177 @brief Destroy a transport_session, and close its socket.
178 @param session Pointer to the transport_session to be destroyed.
179 @return 1 if successful, or 0 if not.
181 The only error condition is a NULL pointer argument.
183 int session_free( transport_session* session ) {
184 if( ! session ) { return 0; }
186 if( session->sock_id )
187 session_disconnect( session );
189 if(session->sock_mgr)
190 socket_manager_free(session->sock_mgr);
192 if( session->state_machine ) free( session->state_machine );
193 if( session->parser_ctxt) {
194 xmlFreeDoc( session->parser_ctxt->myDoc );
195 xmlFreeParserCtxt(session->parser_ctxt);
198 xmlCleanupCharEncodingHandlers();
202 buffer_free(session->body_buffer);
203 buffer_free(session->subject_buffer);
204 buffer_free(session->thread_buffer);
205 buffer_free(session->from_buffer);
206 buffer_free(session->recipient_buffer);
207 buffer_free(session->status_buffer);
208 buffer_free(session->message_error_type);
209 buffer_free(session->router_to_buffer);
210 buffer_free(session->router_from_buffer);
211 buffer_free(session->osrf_xid_buffer);
212 buffer_free(session->router_class_buffer);
213 buffer_free(session->router_command_buffer);
214 buffer_free(session->session_id);
216 free(session->server);
217 free(session->unix_path);
225 @brief Wait on the client socket connected to Jabber, and process any resulting input.
226 @param session Pointer to the transport_session.
227 @param timeout How seconds to wait before timing out (see notes).
228 @return 0 if successful, or -1 if a timeout or other error occurs, or if the server
229 closes the connection at the other end.
231 If @a timeout is -1, wait indefinitely for input activity to appear. If @a timeout is
232 zero, don't wait at all. If @a timeout is positive, wait that number of seconds
233 before timing out. If @a timeout has a negative value other than -1, the results are not
236 Read all available input from the socket and pass it through grab_incoming() (a previously
237 designated callback function). There is no guarantee that we will get a complete message
240 int session_wait( transport_session* session, int timeout ) {
241 if( ! session || ! session->sock_mgr ) {
245 int ret = socket_wait( session->sock_mgr, timeout, session->sock_id );
248 osrfLogDebug(OSRF_LOG_MARK, "socket_wait returned error code %d", ret);
249 session->state_machine->connected = 0;
255 @brief Wrap a message in XML and send it to Jabber.
256 @param session Pointer to the transport_session.
257 @param msg Pointer to a transport_message enclosing the message.
258 @return 0 if successful, or -1 upon error.
260 int session_send_msg(
261 transport_session* session, transport_message* msg ) {
263 if( ! session ) { return -1; }
265 if( ! session->state_machine->connected ) {
266 osrfLogWarning(OSRF_LOG_MARK, "State machine is not connected in send_msg()");
270 message_prepare_xml( msg );
271 return socket_send( session->sock_id, msg->msg_xml );
277 @brief Connect to the Jabber server as a client and open a Jabber session.
278 @param session Pointer to a transport_session.
279 @param username Jabber user name.
280 @param password Jabber password.
281 @param resource name of Jabber resource.
282 @param connect_timeout Timeout interval, in seconds, for receiving data (see notes).
283 @param auth_type An enum: either AUTH_PLAIN or AUTH_DIGEST (see notes).
284 @return 1 if successful, or 0 upon error.
286 If @a connect_timeout is -1, wait indefinitely for input activity to appear. If
287 @a connect_timeout is zero, don't wait at all. If @a timeout is positive, wait that
288 number of seconds before timing out. If @a connect_timeout has a negative value other
289 than -1, the results are not well defined.
291 If we connect as a Jabber component, we send the password as an SHA1 hash. Otherwise
292 we look at the @a auth_type. If it's AUTH_PLAIN, we send the password as plaintext; if
293 it's AUTH_DIGEST, we send it as a hash.
295 At this writing, we only use AUTH_DIGEST.
297 int session_connect( transport_session* session,
298 const char* username, const char* password,
299 const char* resource, int connect_timeout, enum TRANSPORT_AUTH_TYPE auth_type ) {
305 osrfLogWarning(OSRF_LOG_MARK, "session is null in session_connect()" );
309 if( session->sock_id != 0 ) {
310 osrfLogWarning(OSRF_LOG_MARK, "transport session is already open, on socket %d",
315 // Open a client socket connecting to the Jabber server
316 if(session->port > 0) { // use TCP
317 session->sock_id = socket_open_tcp_client(
318 session->sock_mgr, session->port, session->server );
319 if( session->sock_id <= 0 ) {
320 session->sock_id = 0;
323 } else if(session->unix_path != NULL) { // use UNIX domain
324 session->sock_id = socket_open_unix_client( session->sock_mgr, session->unix_path );
325 if( session->sock_id <= 0 ) {
326 session->sock_id = 0;
331 osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" );
335 const char* server = session->server;
337 if( session->component ) {
339 /* the first Jabber connect stanza */
340 char our_hostname[HOST_NAME_MAX + 1] = "";
341 gethostname(our_hostname, sizeof(our_hostname) );
342 our_hostname[HOST_NAME_MAX] = '\0';
343 size1 = 150 + strlen( username ) + strlen( our_hostname );
344 char stanza1[ size1 ];
345 snprintf( stanza1, sizeof(stanza1),
346 "<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' "
347 "xmlns='jabber:component:accept' to='%s' from='%s' xml:lang='en'>",
348 username, our_hostname );
350 /* send the first stanze */
351 session->state_machine->connecting = CONNECTING_1;
353 if( socket_send( session->sock_id, stanza1 ) ) {
354 osrfLogWarning(OSRF_LOG_MARK, "error sending");
355 socket_disconnect( session->sock_mgr, session->sock_id );
356 session->sock_id = 0;
361 socket_wait(session->sock_mgr, connect_timeout, session->sock_id);
363 /* server acknowledges our existence, now see if we can login */
364 if( session->state_machine->connecting == CONNECTING_2 ) {
366 int ss = session->session_id->n_used + strlen(password) + 5;
368 snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
370 char* hash = shahash( hashstuff );
371 size2 = 100 + strlen( hash );
372 char stanza2[ size2 ];
373 snprintf( stanza2, sizeof(stanza2), "<handshake>%s</handshake>", hash );
375 if( socket_send( session->sock_id, stanza2 ) ) {
376 osrfLogWarning(OSRF_LOG_MARK, "error sending");
377 socket_disconnect( session->sock_mgr, session->sock_id );
378 session->sock_id = 0;
383 } else { /* we're not a component */
385 /* the first Jabber connect stanza */
386 size1 = 100 + strlen( server );
387 char stanza1[ size1 ];
388 snprintf( stanza1, sizeof(stanza1),
389 "<stream:stream to='%s' xmlns='jabber:client' "
390 "xmlns:stream='http://etherx.jabber.org/streams'>",
393 /* send the first stanze */
394 session->state_machine->connecting = CONNECTING_1;
395 if( socket_send( session->sock_id, stanza1 ) ) {
396 osrfLogWarning(OSRF_LOG_MARK, "error sending");
397 socket_disconnect( session->sock_mgr, session->sock_id );
398 session->sock_id = 0;
404 socket_wait( session->sock_mgr, connect_timeout, session->sock_id ); /* make the timeout smarter XXX */
406 if( auth_type == AUTH_PLAIN ) {
408 /* the second jabber connect stanza including login info*/
409 size2 = 150 + strlen( username ) + strlen( password ) + strlen( resource );
410 char stanza2[ size2 ];
411 snprintf( stanza2, sizeof(stanza2),
412 "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
413 "<username>%s</username><password>%s</password><resource>%s</resource></query></iq>",
414 username, password, resource );
416 /* server acknowledges our existence, now see if we can login */
417 if( session->state_machine->connecting == CONNECTING_2 ) {
418 if( socket_send( session->sock_id, stanza2 ) ) {
419 osrfLogWarning(OSRF_LOG_MARK, "error sending");
420 socket_disconnect( session->sock_mgr, session->sock_id );
421 session->sock_id = 0;
426 } else if( auth_type == AUTH_DIGEST ) {
428 int ss = session->session_id->n_used + strlen(password) + 5;
430 snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
432 char* hash = shahash( hashstuff );
434 /* the second jabber connect stanza including login info*/
435 size2 = 150 + strlen( username ) + strlen( hash ) + strlen(resource);
436 char stanza2[ size2 ];
437 snprintf( stanza2, sizeof(stanza2),
438 "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
439 "<username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>",
440 username, hash, resource );
442 /* server acknowledges our existence, now see if we can login */
443 if( session->state_machine->connecting == CONNECTING_2 ) {
444 if( socket_send( session->sock_id, stanza2 ) ) {
445 osrfLogWarning(OSRF_LOG_MARK, "error sending");
446 socket_disconnect( session->sock_mgr, session->sock_id );
447 session->sock_id = 0;
453 osrfLogWarning(OSRF_LOG_MARK, "Invalid auth_type parameter: %d",
455 socket_disconnect( session->sock_mgr, session->sock_id );
456 session->sock_id = 0;
463 /* wait for reply to login request */
464 socket_wait( session->sock_mgr, connect_timeout, session->sock_id );
466 if( session->state_machine->connected ) {
470 socket_disconnect( session->sock_mgr, session->sock_id );
471 session->sock_id = 0;
476 // ---------------------------------------------------------------------------------
477 // TCP data callback. Takes data from the socket handler and pushes it directly
478 // into the push parser
479 // ---------------------------------------------------------------------------------
480 static void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* data, int parent) {
481 transport_session* ses = (transport_session*) blob;
482 if( ! ses ) { return; }
483 xmlParseChunk(ses->parser_ctxt, data, strlen(data), 0);
487 static void startElementHandler(
488 void *session, const xmlChar *name, const xmlChar **atts) {
490 transport_session* ses = (transport_session*) session;
491 if( ! ses ) { return; }
494 if( strcmp( (char*) name, "message" ) == 0 ) {
495 ses->state_machine->in_message = 1;
496 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
497 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
498 buffer_add( ses->router_from_buffer, get_xml_attr( atts, "router_from" ) );
499 buffer_add( ses->osrf_xid_buffer, get_xml_attr( atts, "osrf_xid" ) );
500 buffer_add( ses->router_to_buffer, get_xml_attr( atts, "router_to" ) );
501 buffer_add( ses->router_class_buffer, get_xml_attr( atts, "router_class" ) );
502 buffer_add( ses->router_command_buffer, get_xml_attr( atts, "router_command" ) );
503 char* broadcast = get_xml_attr( atts, "broadcast" );
505 ses->router_broadcast = atoi( broadcast );
510 if( ses->state_machine->in_message ) {
512 if( strcmp( (char*) name, "body" ) == 0 ) {
513 ses->state_machine->in_message_body = 1;
517 if( strcmp( (char*) name, "subject" ) == 0 ) {
518 ses->state_machine->in_subject = 1;
522 if( strcmp( (char*) name, "thread" ) == 0 ) {
523 ses->state_machine->in_thread = 1;
529 if( strcmp( (char*) name, "presence" ) == 0 ) {
530 ses->state_machine->in_presence = 1;
531 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
532 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
536 if( strcmp( (char*) name, "status" ) == 0 ) {
537 ses->state_machine->in_status = 1;
542 if( strcmp( (char*) name, "stream:error" ) == 0 ) {
543 ses->state_machine->in_error = 1;
544 ses->state_machine->connected = 0;
545 osrfLogWarning( OSRF_LOG_MARK, "Received <stream:error> message from Jabber server" );
550 /* first server response from a connect attempt */
551 if( strcmp( (char*) name, "stream:stream" ) == 0 ) {
552 if( ses->state_machine->connecting == CONNECTING_1 ) {
553 ses->state_machine->connecting = CONNECTING_2;
554 buffer_add( ses->session_id, get_xml_attr(atts, "id") );
558 if( strcmp( (char*) name, "handshake" ) == 0 ) {
559 ses->state_machine->connected = 1;
560 ses->state_machine->connecting = 0;
565 if( strcmp( (char*) name, "error" ) == 0 ) {
566 ses->state_machine->in_message_error = 1;
567 buffer_add( ses->message_error_type, get_xml_attr( atts, "type" ) );
568 ses->message_error_code = atoi( get_xml_attr( atts, "code" ) );
569 osrfLogInfo( OSRF_LOG_MARK, "Received <error> message with type %s and code %s",
570 get_xml_attr( atts, "type"), get_xml_attr( atts, "code") );
574 if( strcmp( (char*) name, "iq" ) == 0 ) {
575 ses->state_machine->in_iq = 1;
577 if( strcmp( get_xml_attr(atts, "type"), "result") == 0
578 && ses->state_machine->connecting == CONNECTING_2 ) {
579 ses->state_machine->connected = 1;
580 ses->state_machine->connecting = 0;
584 if( strcmp( get_xml_attr(atts, "type"), "error") == 0 ) {
585 osrfLogWarning( OSRF_LOG_MARK, "Error connecting to jabber" );
591 // ------------------------------------------------------------------
592 // Returns the value of the given XML attribute
593 // The xmlChar** construct is commonly returned from SAX event
594 // handlers. Pass that in with the name of the attribute you want
596 // ------------------------------------------------------------------
597 static char* get_xml_attr( const xmlChar** atts, const char* attr_name ) {
600 for(i = 0;(atts[i] != NULL);i++) {
601 if( strcmp( (char*) atts[i++], attr_name ) == 0 ) {
602 if( atts[i] != NULL ) {
603 return (char*) atts[i];
612 // ------------------------------------------------------------------
613 // See which tags are ending
614 // ------------------------------------------------------------------
615 static void endElementHandler( void *session, const xmlChar *name) {
616 transport_session* ses = (transport_session*) session;
617 if( ! ses ) { return; }
619 if( strcmp( (char*) name, "message" ) == 0 ) {
622 /* pass off the message info the callback */
623 if( ses->message_callback ) {
625 /* here it's ok to pass in the raw buffers because
626 message_init allocates new space for the chars
628 transport_message* msg = message_init(
629 ses->body_buffer->buf,
630 ses->subject_buffer->buf,
631 ses->thread_buffer->buf,
632 ses->recipient_buffer->buf,
633 ses->from_buffer->buf );
635 message_set_router_info( msg,
636 ses->router_from_buffer->buf,
637 ses->router_to_buffer->buf,
638 ses->router_class_buffer->buf,
639 ses->router_command_buffer->buf,
640 ses->router_broadcast );
642 message_set_osrf_xid( msg, ses->osrf_xid_buffer->buf );
644 if( ses->message_error_type->n_used > 0 ) {
645 set_msg_error( msg, ses->message_error_type->buf, ses->message_error_code );
648 if( msg == NULL ) { return; }
649 ses->message_callback( ses->user_data, msg );
652 ses->state_machine->in_message = 0;
653 reset_session_buffers( session );
657 if( strcmp( (const char*) name, "body" ) == 0 ) {
658 ses->state_machine->in_message_body = 0;
662 if( strcmp( (const char*) name, "subject" ) == 0 ) {
663 ses->state_machine->in_subject = 0;
667 if( strcmp( (const char*) name, "thread" ) == 0 ) {
668 ses->state_machine->in_thread = 0;
672 if( strcmp( (const char*) name, "iq" ) == 0 ) {
673 ses->state_machine->in_iq = 0;
674 if( ses->message_error_code > 0 ) {
675 osrfLogWarning( OSRF_LOG_MARK, "Error in IQ packet: code %d", ses->message_error_code );
676 osrfLogWarning( OSRF_LOG_MARK, "Error 401 means not authorized" );
678 reset_session_buffers( session );
682 if( strcmp( (const char*) name, "presence" ) == 0 ) {
683 ses->state_machine->in_presence = 0;
685 if( ses->presence_callback ) {
686 // call the callback with the status, etc.
689 reset_session_buffers( session );
693 if( strcmp( (const char*) name, "status" ) == 0 ) {
694 ses->state_machine->in_status = 0;
698 if( strcmp( (const char*) name, "error" ) == 0 ) {
699 ses->state_machine->in_message_error = 0;
703 if( strcmp( (const char*) name, "error:error" ) == 0 ) {
704 ses->state_machine->in_error = 0;
709 static int reset_session_buffers( transport_session* ses ) {
710 buffer_reset( ses->body_buffer );
711 buffer_reset( ses->subject_buffer );
712 buffer_reset( ses->thread_buffer );
713 buffer_reset( ses->from_buffer );
714 buffer_reset( ses->recipient_buffer );
715 buffer_reset( ses->router_from_buffer );
716 buffer_reset( ses->osrf_xid_buffer );
717 buffer_reset( ses->router_to_buffer );
718 buffer_reset( ses->router_class_buffer );
719 buffer_reset( ses->router_command_buffer );
720 buffer_reset( ses->message_error_type );
721 buffer_reset( ses->session_id );
726 // ------------------------------------------------------------------
727 // takes data out of the body of the message and pushes it into
728 // the appropriate buffer
729 // ------------------------------------------------------------------
730 static void characterHandler(
731 void *session, const xmlChar *ch, int len) {
733 const char* p = (const char*) ch;
735 transport_session* ses = (transport_session*) session;
736 if( ! ses ) { return; }
738 /* set the various message parts */
739 if( ses->state_machine->in_message ) {
741 if( ses->state_machine->in_message_body ) {
742 buffer_add_n( ses->body_buffer, p, len );
745 if( ses->state_machine->in_subject ) {
746 buffer_add_n( ses->subject_buffer, p, len );
749 if( ses->state_machine->in_thread ) {
750 buffer_add_n( ses->thread_buffer, p, len );
754 /* set the presence status */
755 if( ses->state_machine->in_presence && ses->state_machine->in_status ) {
756 buffer_add_n( ses->status_buffer, p, len );
759 if( ses->state_machine->in_error ) {
761 osrfLogWarning( OSRF_LOG_MARK, "ERROR XML fragment: %s\n", ch );
766 /* XXX change to warning handlers */
767 static void parseWarningHandler( void *session, const char* msg, ... ) {
771 fprintf(stdout, "transport_session XML WARNING");
772 vfprintf(stdout, msg, args);
774 fprintf(stderr, "XML WARNING: %s\n", msg );
777 static void parseErrorHandler( void *session, const char* msg, ... ){
781 fprintf(stdout, "transport_session XML ERROR");
782 vfprintf(stdout, msg, args);
784 fprintf(stderr, "XML ERROR: %s\n", msg );
789 @brief Disconnect from Jabber, and close the socket.
790 @param session Pointer to the transport_session to be disconnected.
791 @return 0 in all cases.
793 int session_disconnect( transport_session* session ) {
794 if( session && session->sock_id != 0 ) {
795 socket_send(session->sock_id, "</stream:stream>");
796 socket_disconnect(session->sock_mgr, session->sock_id);
797 session->sock_id = 0;