1 #include <opensrf/transport_session.h>
5 // ---------------------------------------------------------------------------------
6 // returns a built and allocated transport_session object.
7 // This codes does no network activity, only memory initilization
8 // ---------------------------------------------------------------------------------
9 transport_session* init_transport( const char* server,
10 int port, const char* unix_path, void* user_data, int component ) {
12 /* create the session struct */
13 transport_session* session =
14 (transport_session*) safe_malloc( sizeof(transport_session) );
16 session->user_data = user_data;
18 session->component = component;
20 /* initialize the data buffers */
21 session->body_buffer = buffer_init( JABBER_BODY_BUFSIZE );
22 session->subject_buffer = buffer_init( JABBER_SUBJECT_BUFSIZE );
23 session->thread_buffer = buffer_init( JABBER_THREAD_BUFSIZE );
24 session->from_buffer = buffer_init( JABBER_JID_BUFSIZE );
25 session->status_buffer = buffer_init( JABBER_STATUS_BUFSIZE );
26 session->recipient_buffer = buffer_init( JABBER_JID_BUFSIZE );
27 session->message_error_type = buffer_init( JABBER_JID_BUFSIZE );
28 session->session_id = buffer_init( 64 );
30 /* for OpenSRF extensions */
31 session->router_to_buffer = buffer_init( JABBER_JID_BUFSIZE );
32 session->router_from_buffer = buffer_init( JABBER_JID_BUFSIZE );
33 session->osrf_xid_buffer = buffer_init( JABBER_JID_BUFSIZE );
34 session->router_class_buffer = buffer_init( JABBER_JID_BUFSIZE );
35 session->router_command_buffer = buffer_init( JABBER_JID_BUFSIZE );
38 if( session->body_buffer == NULL || session->subject_buffer == NULL ||
39 session->thread_buffer == NULL || session->from_buffer == NULL ||
40 session->status_buffer == NULL || session->recipient_buffer == NULL ||
41 session->router_to_buffer == NULL || session->router_from_buffer == NULL ||
42 session->router_class_buffer == NULL || session->router_command_buffer == NULL ||
43 session->session_id == NULL ) {
45 osrfLogError(OSRF_LOG_MARK, "init_transport(): buffer_init returned NULL" );
50 /* initialize the jabber state machine */
51 session->state_machine = (jabber_machine*) safe_malloc( sizeof(jabber_machine) );
53 /* initialize the sax push parser */
54 session->parser_ctxt = xmlCreatePushParserCtxt(SAXHandler, session, "", 0, NULL);
56 /* initialize the transport_socket structure */
57 session->sock_mgr = (socket_manager*) safe_malloc( sizeof(socket_manager) );
59 session->sock_mgr->data_received = &grab_incoming;
60 session->sock_mgr->blob = session;
63 session->server = strdup(server);
65 session->unix_path = strdup(unix_path);
66 else session->unix_path = NULL;
75 /* XXX FREE THE BUFFERS */
76 int session_free( transport_session* session ) {
77 if( ! session ) { return 0; }
80 socket_manager_free(session->sock_mgr);
82 if( session->state_machine ) free( session->state_machine );
83 if( session->parser_ctxt) {
84 xmlFreeDoc( session->parser_ctxt->myDoc );
85 xmlFreeParserCtxt(session->parser_ctxt);
88 xmlCleanupCharEncodingHandlers();
92 buffer_free(session->body_buffer);
93 buffer_free(session->subject_buffer);
94 buffer_free(session->thread_buffer);
95 buffer_free(session->from_buffer);
96 buffer_free(session->recipient_buffer);
97 buffer_free(session->status_buffer);
98 buffer_free(session->message_error_type);
99 buffer_free(session->router_to_buffer);
100 buffer_free(session->router_from_buffer);
101 buffer_free(session->osrf_xid_buffer);
102 buffer_free(session->router_class_buffer);
103 buffer_free(session->router_command_buffer);
104 buffer_free(session->session_id);
106 free(session->server);
107 free(session->unix_path);
114 int session_wait( transport_session* session, int timeout ) {
115 if( ! session || ! session->sock_mgr ) {
119 int ret = socket_wait( session->sock_mgr, timeout, session->sock_id );
122 osrfLogDebug(OSRF_LOG_MARK, "socket_wait returned error code %d", ret);
123 session->state_machine->connected = 0;
128 int session_send_msg(
129 transport_session* session, transport_message* msg ) {
131 if( ! session ) { return -1; }
133 if( ! session->state_machine->connected ) {
134 osrfLogWarning(OSRF_LOG_MARK, "State machine is not connected in send_msg()");
138 message_prepare_xml( msg );
139 //tcp_send( session->sock_obj, msg->msg_xml );
140 return socket_send( session->sock_id, msg->msg_xml );
145 /* connects to server and connects to jabber */
146 int session_connect( transport_session* session,
147 const char* username, const char* password,
148 const char* resource, int connect_timeout, enum TRANSPORT_AUTH_TYPE auth_type ) {
154 osrfLogWarning(OSRF_LOG_MARK, "session is null in connect" );
159 //char* server = session->sock_obj->server;
160 char* server = session->server;
162 if( ! session->sock_id ) {
164 if(session->port > 0) {
165 if( (session->sock_id = socket_open_tcp_client(
166 session->sock_mgr, session->port, session->server)) <= 0 )
169 } else if(session->unix_path != NULL) {
170 if( (session->sock_id = socket_open_unix_client(
171 session->sock_mgr, session->unix_path)) <= 0 )
175 osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" );
180 if( session->component ) {
182 /* the first Jabber connect stanza */
183 char* our_hostname = getenv("HOSTNAME");
184 size1 = 150 + strlen( server );
185 char stanza1[ size1 ];
186 snprintf( stanza1, sizeof(stanza1),
187 "<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' "
188 "xmlns='jabber:component:accept' to='%s' from='%s' xml:lang='en'>",
189 username, our_hostname );
191 /* send the first stanze */
192 session->state_machine->connecting = CONNECTING_1;
194 // if( ! tcp_send( session->sock_obj, stanza1 ) ) {
195 if( socket_send( session->sock_id, stanza1 ) ) {
196 osrfLogWarning(OSRF_LOG_MARK, "error sending");
201 //tcp_wait( session->sock_obj, connect_timeout ); /* make the timeout smarter XXX */
202 socket_wait(session->sock_mgr, connect_timeout, session->sock_id);
204 /* server acknowledges our existence, now see if we can login */
205 if( session->state_machine->connecting == CONNECTING_2 ) {
207 int ss = session->session_id->n_used + strlen(password) + 5;
209 snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
211 char* hash = shahash( hashstuff );
212 size2 = 100 + strlen( hash );
213 char stanza2[ size2 ];
214 snprintf( stanza2, sizeof(stanza2), "<handshake>%s</handshake>", hash );
216 //if( ! tcp_send( session->sock_obj, stanza2 ) ) {
217 if( socket_send( session->sock_id, stanza2 ) ) {
218 osrfLogWarning(OSRF_LOG_MARK, "error sending");
223 } else { /* we're not a component */
225 /* the first Jabber connect stanza */
226 size1 = 100 + strlen( server );
227 char stanza1[ size1 ];
228 snprintf( stanza1, sizeof(stanza1),
229 "<stream:stream to='%s' xmlns='jabber:client' "
230 "xmlns:stream='http://etherx.jabber.org/streams'>",
234 /* send the first stanze */
235 session->state_machine->connecting = CONNECTING_1;
236 //if( ! tcp_send( session->sock_obj, stanza1 ) ) {
237 if( socket_send( session->sock_id, stanza1 ) ) {
238 osrfLogWarning(OSRF_LOG_MARK, "error sending");
244 //tcp_wait( session->sock_obj, connect_timeout ); /* make the timeout smarter XXX */
245 socket_wait( session->sock_mgr, connect_timeout, session->sock_id ); /* make the timeout smarter XXX */
247 if( auth_type == AUTH_PLAIN ) {
249 /* the second jabber connect stanza including login info*/
250 size2 = 150 + strlen( username ) + strlen(password) + strlen(resource);
251 char stanza2[ size2 ];
252 snprintf( stanza2, sizeof(stanza2),
253 "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
254 "<username>%s</username><password>%s</password><resource>%s</resource></query></iq>",
255 username, password, resource );
257 /* server acknowledges our existence, now see if we can login */
258 if( session->state_machine->connecting == CONNECTING_2 ) {
259 //if( ! tcp_send( session->sock_obj, stanza2 ) ) {
260 if( socket_send( session->sock_id, stanza2 ) ) {
261 osrfLogWarning(OSRF_LOG_MARK, "error sending");
266 } else if( auth_type == AUTH_DIGEST ) {
268 int ss = session->session_id->n_used + strlen(password) + 5;
270 snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
272 char* hash = shahash( hashstuff );
274 /* the second jabber connect stanza including login info*/
275 size2 = 150 + strlen( hash ) + strlen(password) + strlen(resource);
276 char stanza2[ size2 ];
277 snprintf( stanza2, sizeof(stanza2),
278 "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
279 "<username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>",
280 username, hash, resource );
282 /* server acknowledges our existence, now see if we can login */
283 if( session->state_machine->connecting == CONNECTING_2 ) {
284 //if( ! tcp_send( session->sock_obj, stanza2 ) ) {
285 if( socket_send( session->sock_id, stanza2 ) ) {
286 osrfLogWarning(OSRF_LOG_MARK, "error sending");
297 //tcp_wait( session->sock_obj, connect_timeout );
298 socket_wait( session->sock_mgr, connect_timeout, session->sock_id );
300 if( session->state_machine->connected ) {
308 // ---------------------------------------------------------------------------------
309 // TCP data callback. Shove the data into the push parser.
310 // ---------------------------------------------------------------------------------
311 //void grab_incoming( void * session, char* data ) {
312 void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* data, int parent) {
313 transport_session* ses = (transport_session*) blob;
314 if( ! ses ) { return; }
315 xmlParseChunk(ses->parser_ctxt, data, strlen(data), 0);
319 void startElementHandler(
320 void *session, const xmlChar *name, const xmlChar **atts) {
322 transport_session* ses = (transport_session*) session;
323 if( ! ses ) { return; }
326 if( strcmp( (char*) name, "message" ) == 0 ) {
327 ses->state_machine->in_message = 1;
328 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
329 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
330 buffer_add( ses->router_from_buffer, get_xml_attr( atts, "router_from" ) );
331 buffer_add( ses->osrf_xid_buffer, get_xml_attr( atts, "osrf_xid" ) );
332 buffer_add( ses->router_to_buffer, get_xml_attr( atts, "router_to" ) );
333 buffer_add( ses->router_class_buffer, get_xml_attr( atts, "router_class" ) );
334 buffer_add( ses->router_command_buffer, get_xml_attr( atts, "router_command" ) );
335 char* broadcast = get_xml_attr( atts, "broadcast" );
337 ses->router_broadcast = atoi( broadcast );
342 if( ses->state_machine->in_message ) {
344 if( strcmp( (char*) name, "body" ) == 0 ) {
345 ses->state_machine->in_message_body = 1;
349 if( strcmp( (char*) name, "subject" ) == 0 ) {
350 ses->state_machine->in_subject = 1;
354 if( strcmp( (char*) name, "thread" ) == 0 ) {
355 ses->state_machine->in_thread = 1;
361 if( strcmp( (char*) name, "presence" ) == 0 ) {
362 ses->state_machine->in_presence = 1;
363 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
364 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
368 if( strcmp( (char*) name, "status" ) == 0 ) {
369 ses->state_machine->in_status = 1;
374 if( strcmp( (char*) name, "stream:error" ) == 0 ) {
375 ses->state_machine->in_error = 1;
376 ses->state_machine->connected = 0;
377 osrfLogWarning( OSRF_LOG_MARK, "Received <stream:error> message from Jabber server" );
382 /* first server response from a connect attempt */
383 if( strcmp( (char*) name, "stream:stream" ) == 0 ) {
384 if( ses->state_machine->connecting == CONNECTING_1 ) {
385 ses->state_machine->connecting = CONNECTING_2;
386 buffer_add( ses->session_id, get_xml_attr(atts, "id") );
390 if( strcmp( (char*) name, "handshake" ) == 0 ) {
391 ses->state_machine->connected = 1;
392 ses->state_machine->connecting = 0;
397 if( strcmp( (char*) name, "error" ) == 0 ) {
398 ses->state_machine->in_message_error = 1;
399 buffer_add( ses->message_error_type, get_xml_attr( atts, "type" ) );
400 ses->message_error_code = atoi( get_xml_attr( atts, "code" ) );
401 osrfLogInfo( OSRF_LOG_MARK, "Received <error> message with type %s and code %s",
402 get_xml_attr( atts, "type"), get_xml_attr( atts, "code") );
406 if( strcmp( (char*) name, "iq" ) == 0 ) {
407 ses->state_machine->in_iq = 1;
409 if( strcmp( get_xml_attr(atts, "type"), "result") == 0
410 && ses->state_machine->connecting == CONNECTING_2 ) {
411 ses->state_machine->connected = 1;
412 ses->state_machine->connecting = 0;
416 if( strcmp( get_xml_attr(atts, "type"), "error") == 0 ) {
417 osrfLogWarning( OSRF_LOG_MARK, "Error connecting to jabber" );
423 char* get_xml_attr( const xmlChar** atts, char* attr_name ) {
426 for(i = 0;(atts[i] != NULL);i++) {
427 if( strcmp( (char*) atts[i++], attr_name ) == 0 ) {
428 if( atts[i] != NULL ) {
429 return (char*) atts[i];
438 // ------------------------------------------------------------------
439 // See which tags are ending
440 // ------------------------------------------------------------------
441 void endElementHandler( void *session, const xmlChar *name) {
442 transport_session* ses = (transport_session*) session;
443 if( ! ses ) { return; }
445 if( strcmp( (char*) name, "message" ) == 0 ) {
448 /* pass off the message info the callback */
449 if( ses->message_callback ) {
451 /* here it's ok to pass in the raw buffers because
452 message_init allocates new space for the chars
454 transport_message* msg = message_init(
455 ses->body_buffer->buf,
456 ses->subject_buffer->buf,
457 ses->thread_buffer->buf,
458 ses->recipient_buffer->buf,
459 ses->from_buffer->buf );
461 message_set_router_info( msg,
462 ses->router_from_buffer->buf,
463 ses->router_to_buffer->buf,
464 ses->router_class_buffer->buf,
465 ses->router_command_buffer->buf,
466 ses->router_broadcast );
468 message_set_osrf_xid( msg, ses->osrf_xid_buffer->buf );
470 if( ses->message_error_type->n_used > 0 ) {
471 set_msg_error( msg, ses->message_error_type->buf, ses->message_error_code );
474 if( msg == NULL ) { return; }
475 ses->message_callback( ses->user_data, msg );
478 ses->state_machine->in_message = 0;
479 reset_session_buffers( session );
483 if( strcmp( (char*) name, "body" ) == 0 ) {
484 ses->state_machine->in_message_body = 0;
488 if( strcmp( (char*) name, "subject" ) == 0 ) {
489 ses->state_machine->in_subject = 0;
493 if( strcmp( (char*) name, "thread" ) == 0 ) {
494 ses->state_machine->in_thread = 0;
498 if( strcmp( (char*) name, "iq" ) == 0 ) {
499 ses->state_machine->in_iq = 0;
500 if( ses->message_error_code > 0 ) {
501 osrfLogWarning( OSRF_LOG_MARK, "Error in IQ packet: code %d", ses->message_error_code );
502 osrfLogWarning( OSRF_LOG_MARK, "Error 401 means not authorized" );
504 reset_session_buffers( session );
508 if( strcmp( (char*) name, "presence" ) == 0 ) {
509 ses->state_machine->in_presence = 0;
511 if( ses->presence_callback ) {
512 // call the callback with the status, etc.
515 reset_session_buffers( session );
519 if( strcmp( (char*) name, "status" ) == 0 ) {
520 ses->state_machine->in_status = 0;
524 if( strcmp( (char*) name, "error" ) == 0 ) {
525 ses->state_machine->in_message_error = 0;
529 if( strcmp( (char*) name, "error:error" ) == 0 ) {
530 ses->state_machine->in_error = 0;
535 int reset_session_buffers( transport_session* ses ) {
536 buffer_reset( ses->body_buffer );
537 buffer_reset( ses->subject_buffer );
538 buffer_reset( ses->thread_buffer );
539 buffer_reset( ses->from_buffer );
540 buffer_reset( ses->recipient_buffer );
541 buffer_reset( ses->router_from_buffer );
542 buffer_reset( ses->osrf_xid_buffer );
543 buffer_reset( ses->router_to_buffer );
544 buffer_reset( ses->router_class_buffer );
545 buffer_reset( ses->router_command_buffer );
546 buffer_reset( ses->message_error_type );
547 buffer_reset( ses->session_id );
552 // ------------------------------------------------------------------
553 // takes data out of the body of the message and pushes it into
554 // the appropriate buffer
555 // ------------------------------------------------------------------
556 void characterHandler(
557 void *session, const xmlChar *ch, int len) {
560 strncpy( data, (char*) ch, len );
563 //printf( "Handling characters: %s\n", data );
564 transport_session* ses = (transport_session*) session;
565 if( ! ses ) { return; }
567 /* set the various message parts */
568 if( ses->state_machine->in_message ) {
570 if( ses->state_machine->in_message_body ) {
571 buffer_add( ses->body_buffer, data );
574 if( ses->state_machine->in_subject ) {
575 buffer_add( ses->subject_buffer, data );
578 if( ses->state_machine->in_thread ) {
579 buffer_add( ses->thread_buffer, data );
583 /* set the presence status */
584 if( ses->state_machine->in_presence && ses->state_machine->in_status ) {
585 buffer_add( ses->status_buffer, data );
588 if( ses->state_machine->in_error ) {
590 osrfLogWarning( OSRF_LOG_MARK, "ERROR XML fragment: %s\n", ch );
595 /* XXX change to warning handlers */
596 void parseWarningHandler( void *session, const char* msg, ... ) {
600 fprintf(stdout, "transport_session XML WARNING");
601 vfprintf(stdout, msg, args);
603 fprintf(stderr, "XML WARNING: %s\n", msg );
606 void parseErrorHandler( void *session, const char* msg, ... ){
610 fprintf(stdout, "transport_session XML ERROR");
611 vfprintf(stdout, msg, args);
613 fprintf(stderr, "XML ERROR: %s\n", msg );
617 int session_disconnect( transport_session* session ) {
618 if( session == NULL ) { return 0; }
619 //tcp_send( session->sock_obj, "</stream:stream>");
620 socket_send(session->sock_id, "</stream:stream>");
621 socket_disconnect(session->sock_mgr, session->sock_id);
623 //return tcp_disconnect( session->sock_obj );