5151
5252static int _disconnect_cleanup (xmpp_conn_t * const conn ,
5353 void * const userdata );
54-
54+ static char * _conn_build_stream_tag (xmpp_conn_t * const conn ,
55+ char * * attributes , size_t attributes_len );
56+ static void _conn_attributes_new (xmpp_conn_t * conn , char * * attrs ,
57+ char * * * attributes , size_t * attributes_len );
58+ static void _conn_attributes_destroy (xmpp_conn_t * conn , char * * attributes ,
59+ size_t attributes_len );
5560static void _handle_stream_start (char * name , char * * attrs ,
5661 void * const userdata );
5762static void _handle_stream_end (char * name ,
@@ -536,9 +541,8 @@ int xmpp_connect_component(xmpp_conn_t * const conn, const char * const server,
536541 * the only required configuration is a domain (or full jid) passed via
537542 * xmpp_conn_set_jid().
538543 *
539- * Next step should be xmpp_conn_raw_open_stream(). In case of legacy SSL,
540- * user might want to call xmpp_conn_raw_tls_start() before opening the
541- * stream.
544+ * Next step should be xmpp_conn_open_stream(). In case of legacy SSL,
545+ * user might want to call xmpp_conn_tls_start() before opening the stream.
542546 *
543547 * @see xmpp_connect_client()
544548 *
@@ -580,15 +584,18 @@ void conn_established(xmpp_conn_t * const conn)
580584 }
581585}
582586
583- /** Send an opening stream tag.
587+ /** Send the default opening stream tag.
588+ * The default tag is the one sent by xmpp_connect_client().
584589 * User's connection handler is called with event XMPP_CONN_CONNECT when
585590 * server replies with its opening tag.
586591 *
587592 * @return XMPP_EOK (0) on success a number less than 0 on failure
588593 *
594+ * @note The connection must be connected with xmpp_connect_raw().
595+ *
589596 * @ingroup Connections
590597 */
591- int xmpp_conn_raw_open_stream (xmpp_conn_t * const conn )
598+ int xmpp_conn_open_stream_default (xmpp_conn_t * const conn )
592599{
593600 if (!conn -> is_raw )
594601 return XMPP_EINVOP ;
@@ -599,11 +606,48 @@ int xmpp_conn_raw_open_stream(xmpp_conn_t * const conn)
599606 return XMPP_EOK ;
600607}
601608
609+ /** Send an opening stream tag.
610+ * User's connection handler is called with event XMPP_CONN_CONNECT when
611+ * server replies with its opening tag.
612+ *
613+ * @param conn a Strophe connection object
614+ * @param attributes Array of strings in format: even index points to
615+ * an attribute name and odd index points to its value
616+ * @param attributes_len Number of elements in the attributes array, it
617+ * should be number of attributes multiplied by 2
618+ *
619+ * @return XMPP_EOK (0) on success a number less than 0 on failure
620+ *
621+ * @note The connection must be connected with xmpp_connect_raw().
622+ *
623+ * @ingroup Connections
624+ */
625+ int xmpp_conn_open_stream (xmpp_conn_t * const conn , char * * attributes ,
626+ size_t attributes_len )
627+ {
628+ char * tag ;
629+
630+ if (!conn -> is_raw )
631+ return XMPP_EINVOP ;
632+
633+ tag = _conn_build_stream_tag (conn , attributes , attributes_len );
634+ if (!tag )
635+ return XMPP_EMEM ;
636+
637+ conn_prepare_reset (conn , auth_handle_open_raw );
638+ xmpp_send_raw_string (conn , "<?xml version=\"1.0\"?>%s" , tag );
639+ xmpp_free (conn -> ctx , tag );
640+
641+ return XMPP_EOK ;
642+ }
643+
602644/** Start synchronous TLS handshake with the server.
603645 *
604646 * @return XMPP_EOK (0) on success a number less than 0 on failure
647+ *
648+ * @ingroup Connections
605649 */
606- int xmpp_conn_raw_tls_start (xmpp_conn_t * const conn )
650+ int xmpp_conn_tls_start (xmpp_conn_t * const conn )
607651{
608652 return conn_tls_start (conn );
609653}
@@ -659,18 +703,6 @@ void conn_parser_reset(xmpp_conn_t * const conn)
659703 parser_reset (conn -> parser );
660704}
661705
662- /* timed handler for cleanup if normal disconnect procedure takes too long */
663- static int _disconnect_cleanup (xmpp_conn_t * const conn ,
664- void * const userdata )
665- {
666- xmpp_debug (conn -> ctx , "xmpp" ,
667- "disconnection forced by cleanup timeout" );
668-
669- conn_disconnect (conn );
670-
671- return 0 ;
672- }
673-
674706/** Initiate termination of the connection to the XMPP server.
675707 * This function starts the disconnection sequence by sending
676708 * </stream:stream> to the XMPP server. This function will do nothing
@@ -1025,34 +1057,111 @@ void xmpp_conn_free_tlscert(xmpp_ctx_t *ctx, struct _tlscert_t *cert)
10251057 xmpp_free (ctx , cert );
10261058}
10271059
1028- static void _log_open_tag (xmpp_conn_t * conn , char * * attrs )
1060+ /* timed handler for cleanup if normal disconnect procedure takes too long */
1061+ static int _disconnect_cleanup (xmpp_conn_t * const conn ,
1062+ void * const userdata )
10291063{
1030- char buf [4096 ];
1031- size_t pos ;
1032- int len ;
1033- int i ;
1034- char * attr ;
1035-
1036- if (!attrs ) return ;
1037-
1038- pos = 0 ;
1039- len = xmpp_snprintf (buf , 4096 , "<stream:stream" );
1040- if (len < 0 ) return ;
1041-
1042- pos += len ;
1043- for (i = 0 ; attrs [i ]; i += 2 ) {
1044- attr = parser_attr_name (conn -> ctx , attrs [i ]);
1045- len = xmpp_snprintf (& buf [pos ], 4096 - pos , " %s='%s'" ,
1046- attr , attrs [i + 1 ]);
1047- xmpp_free (conn -> ctx , attr );
1048- if (len < 0 ) return ;
1049- pos += len ;
1064+ xmpp_debug (conn -> ctx , "xmpp" ,
1065+ "disconnection forced by cleanup timeout" );
1066+
1067+ conn_disconnect (conn );
1068+
1069+ return 0 ;
1070+ }
1071+
1072+ static char * _conn_build_stream_tag (xmpp_conn_t * const conn ,
1073+ char * * attributes , size_t attributes_len )
1074+ {
1075+ char * tag ;
1076+ size_t len ;
1077+ size_t i ;
1078+
1079+ static const char * tag_head = "<stream:stream" ;
1080+ static const char * tag_tail = ">" ;
1081+
1082+ /* ignore the last element unless number is even */
1083+ attributes_len &= ~(size_t )1 ;
1084+
1085+ len = strlen (tag_head ) + strlen (tag_tail );
1086+ for (i = 0 ; i < attributes_len ; ++ i )
1087+ len += strlen (attributes [i ]) + 2 ;
1088+ tag = xmpp_alloc (conn -> ctx , len + 1 );
1089+ if (!tag ) return NULL ;
1090+
1091+ strcpy (tag , tag_head );
1092+ for (i = 0 ; i < attributes_len ; ++ i ) {
1093+ if ((i & 1 ) == 0 ) {
1094+ strcat (tag , " " );
1095+ strcat (tag , attributes [i ]);
1096+ strcat (tag , "=\"" );
1097+ } else {
1098+ strcat (tag , attributes [i ]);
1099+ strcat (tag , "\"" );
1100+ }
10501101 }
1102+ strcat (tag , tag_tail );
10511103
1052- len = xmpp_snprintf (& buf [pos ], 4096 - pos , ">" );
1053- if (len < 0 ) return ;
1104+ if (strlen (tag ) != len ) {
1105+ xmpp_error (conn -> ctx , "xmpp" , "Internal error in "
1106+ "_conn_build_stream_tag()." );
1107+ xmpp_free (conn -> ctx , tag );
1108+ tag = NULL ;
1109+ }
1110+
1111+ return tag ;
1112+ }
1113+
1114+ static void _conn_attributes_new (xmpp_conn_t * conn , char * * attrs ,
1115+ char * * * attributes , size_t * attributes_len )
1116+ {
1117+ char * * array = NULL ;
1118+ size_t nr = 0 ;
1119+ size_t i ;
1120+
1121+ if (attrs ) {
1122+ for (; attrs [nr ]; ++ nr );
1123+ array = xmpp_alloc (conn -> ctx , sizeof (* array ) * nr );
1124+ for (i = 0 ; array && i < nr ; ++ i ) {
1125+ array [i ] = (i & 1 ) == 0 ? parser_attr_name (conn -> ctx , attrs [i ])
1126+ : xmpp_strdup (conn -> ctx , attrs [i ]);
1127+ if (array [i ] == NULL ) break ;
1128+ }
1129+ if (!array || i < nr ) {
1130+ xmpp_error (conn -> ctx , "xmpp" , "Memory allocation error." );
1131+ _conn_attributes_destroy (conn , array , i );
1132+ array = NULL ;
1133+ nr = 0 ;
1134+ }
1135+ }
1136+ * attributes = array ;
1137+ * attributes_len = nr ;
1138+ }
10541139
1055- xmpp_debug (conn -> ctx , "xmpp" , "RECV: %s" , buf );
1140+ static void _conn_attributes_destroy (xmpp_conn_t * conn , char * * attributes ,
1141+ size_t attributes_len )
1142+ {
1143+ size_t i ;
1144+
1145+ if (attributes ) {
1146+ for (i = 0 ; i < attributes_len ; ++ i )
1147+ xmpp_free (conn -> ctx , attributes [i ]);
1148+ xmpp_free (conn -> ctx , attributes );
1149+ }
1150+ }
1151+
1152+ static void _log_open_tag (xmpp_conn_t * conn , char * * attrs )
1153+ {
1154+ char * * attributes ;
1155+ char * tag ;
1156+ size_t nr ;
1157+
1158+ _conn_attributes_new (conn , attrs , & attributes , & nr );
1159+ tag = _conn_build_stream_tag (conn , attributes , nr );
1160+ if (tag ) {
1161+ xmpp_debug (conn -> ctx , "xmpp" , "RECV: %s" , tag );
1162+ xmpp_free (conn -> ctx , tag );
1163+ }
1164+ _conn_attributes_destroy (conn , attributes , nr );
10561165}
10571166
10581167static char * _get_stream_attribute (char * * attrs , char * name )
@@ -1073,6 +1182,7 @@ static void _handle_stream_start(char *name, char **attrs,
10731182{
10741183 xmpp_conn_t * conn = (xmpp_conn_t * )userdata ;
10751184 char * id ;
1185+ int failed = 0 ;
10761186
10771187 if (conn -> stream_id ) xmpp_free (conn -> ctx , conn -> stream_id );
10781188 conn -> stream_id = NULL ;
@@ -1083,17 +1193,17 @@ static void _handle_stream_start(char *name, char **attrs,
10831193 if (id )
10841194 conn -> stream_id = xmpp_strdup (conn -> ctx , id );
10851195
1086- /* check and log errors */
1087- if (!id )
1088- xmpp_error (conn -> ctx , "conn" , "No id attribute." );
1089- else if (!conn -> stream_id )
1196+ if (id && !conn -> stream_id ) {
10901197 xmpp_error (conn -> ctx , "conn" , "Memory allocation failed." );
1198+ failed = 1 ;
1199+ }
10911200 } else {
10921201 xmpp_error (conn -> ctx , "conn" , "Server did not open valid stream."
10931202 " name = %s." , name );
1203+ failed = 1 ;
10941204 }
10951205
1096- if (conn -> stream_id ) {
1206+ if (! failed ) {
10971207 /* call stream open handler */
10981208 conn -> open_handler (conn );
10991209 } else {
0 commit comments