/* SPDX-License-Identifier: MIT OR GPL-3.0-only */ /* common.h ** strophe XMPP client library -- internal common structures ** ** Copyright (C) 2005-2009 Collecta, Inc. ** ** This software is provided AS-IS with no warranty, either express or ** implied. ** ** This program is dual licensed under the MIT or GPLv3 licenses. */ /** @file * Internally used functions and structures. */ #ifndef __LIBSTROPHE_COMMON_H__ #define __LIBSTROPHE_COMMON_H__ #include #include #include "strophe.h" #include "ostypes.h" #include "sock.h" #include "tls.h" #include "hash.h" #include "util.h" #include "parser.h" #include "snprintf.h" /** handlers **/ typedef struct _xmpp_handlist_t xmpp_handlist_t; struct _xmpp_handlist_t { /* common members */ int user_handler; int (*handler)(); void *userdata; int enabled; /* handlers are added disabled and enabled after the * handler chain is processed to prevent stanzas from * getting processed by newly added handlers */ xmpp_handlist_t *next; union { /* timed handlers */ struct { unsigned long period; uint64_t last_stamp; }; /* id handlers */ struct { char *id; }; /* normal handlers */ struct { char *ns; char *name; char *type; }; } u; }; /** run-time context **/ typedef enum { XMPP_LOOP_NOTSTARTED, XMPP_LOOP_RUNNING, XMPP_LOOP_QUIT } xmpp_loop_status_t; typedef struct _xmpp_connlist_t { xmpp_conn_t *conn; struct _xmpp_connlist_t *next; } xmpp_connlist_t; struct _xmpp_ctx_t { const xmpp_mem_t *mem; const xmpp_log_t *log; int verbosity; xmpp_rand_t *rand; xmpp_loop_status_t loop_status; xmpp_connlist_t *connlist; xmpp_handlist_t *timed_handlers; unsigned long timeout; }; /* convenience functions for accessing the context */ void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size); void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size); char *strophe_strdup(const xmpp_ctx_t *ctx, const char *s); char *strophe_strndup(const xmpp_ctx_t *ctx, const char *s, size_t len); void strophe_free(const xmpp_ctx_t *ctx, void *p); #define strophe_free_and_null(ctx, p) \ do { \ if (p) { \ strophe_free(ctx, (p)); \ (p) = NULL; \ } \ } while (0) /* wrappers for xmpp_log at specific levels */ void strophe_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...); void strophe_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...); void strophe_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...); void strophe_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...); void strophe_debug_verbose( int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...); void strophe_log_internal(const xmpp_ctx_t *ctx, xmpp_log_level_t level, const char *area, const char *fmt, va_list ap); #if defined(__OpenBSD__) #define STR_MAYBE_NULL(p) (p) ? (p) : "(null)" #else #define STR_MAYBE_NULL(p) (p) #endif /** connection **/ /* opaque connection object */ typedef enum { XMPP_STATE_DISCONNECTED, XMPP_STATE_CONNECTING, XMPP_STATE_CONNECTED } xmpp_conn_state_t; typedef enum { XMPP_QUEUE_STROPHE = 0x1, XMPP_QUEUE_USER = 0x2, XMPP_QUEUE_SM = 0x800, XMPP_QUEUE_SM_STROPHE = XMPP_QUEUE_SM | XMPP_QUEUE_STROPHE, } xmpp_send_queue_owner_t; typedef struct _xmpp_send_queue_t xmpp_send_queue_t; struct _xmpp_send_queue_t { char *data; size_t len; size_t written; int wip; xmpp_send_queue_owner_t owner; void *userdata; uint32_t sm_h; xmpp_send_queue_t *prev, *next; }; #define UNUSED(x) ((void)(x)) #define MAX_DOMAIN_LEN 256 #define SASL_MASK_PLAIN (1 << 0) #define SASL_MASK_DIGESTMD5 (1 << 1) #define SASL_MASK_ANONYMOUS (1 << 2) #define SASL_MASK_SCRAMSHA1 (1 << 3) #define SASL_MASK_SCRAMSHA256 (1 << 4) #define SASL_MASK_SCRAMSHA512 (1 << 5) #define SASL_MASK_EXTERNAL (1 << 6) #define SASL_MASK_SCRAMSHA1_PLUS (1 << 7) #define SASL_MASK_SCRAMSHA256_PLUS (1 << 8) #define SASL_MASK_SCRAM_PLUS \ (SASL_MASK_SCRAMSHA1_PLUS | SASL_MASK_SCRAMSHA256_PLUS) #define SASL_MASK_SCRAM_WEAK \ (SASL_MASK_SCRAMSHA1 | SASL_MASK_SCRAMSHA256 | SASL_MASK_SCRAMSHA512) #define SASL_MASK_SCRAM (SASL_MASK_SCRAM_PLUS | SASL_MASK_SCRAM_WEAK) enum { XMPP_PORT_CLIENT = 5222, XMPP_PORT_CLIENT_LEGACY_SSL = 5223, XMPP_PORT_COMPONENT = 5347, }; typedef void (*xmpp_open_handler)(xmpp_conn_t *conn); typedef struct { xmpp_send_queue_t *head, *tail; } xmpp_queue_t; struct _xmpp_sm_t { xmpp_ctx_t *ctx; int sm_support; int sm_enabled; int can_resume, resume, dont_request_resume; xmpp_queue_t sm_queue; int r_sent; uint32_t sm_handled_nr; uint32_t sm_sent_nr; char *id, *previd, *bound_jid; xmpp_stanza_t *bind; }; struct conn_interface { int (*read)(struct conn_interface *intf, void *buff, size_t len); int (*write)(struct conn_interface *intf, const void *buff, size_t len); int (*flush)(struct conn_interface *intf); int (*pending)(struct conn_interface *intf); int (*get_error)(struct conn_interface *intf); int (*error_is_recoverable)(struct conn_interface *intf, int err); xmpp_conn_t *conn; }; int conn_interface_write(struct conn_interface *intf, const void *buff, size_t len); int conn_int_nop(struct conn_interface *intf); int compression_init(xmpp_conn_t *conn); void compression_free(xmpp_conn_t *conn); void compression_handle_feature_children(xmpp_conn_t *conn, const char *text); struct _xmpp_conn_t { struct conn_interface intf; unsigned int ref; xmpp_ctx_t *ctx; xmpp_conn_type_t type; int is_raw; xmpp_conn_state_t state; uint64_t timeout_stamp; int error; xmpp_stream_error_t *stream_error; xmpp_sock_t *xsock; sock_t sock; int ka_timeout; /* TCP keepalive timeout */ int ka_interval; /* TCP keepalive interval */ int ka_count; /* TCP keepalive count */ tls_t *tls; int tls_support; int tls_disabled; int tls_mandatory; int tls_legacy_ssl; int tls_trust; char *tls_cafile; char *tls_capath; char *tls_client_cert; char *tls_client_key; int tls_failed; /* set when tls fails, so we don't try again */ int sasl_support; /* if true, field is a bitfield of supported mechanisms */ int auth_legacy_enabled; int weak_auth_enabled; int secured; /* set when stream is secured with TLS */ xmpp_certfail_handler certfail_handler; xmpp_password_callback password_callback; void *password_callback_userdata; struct { char pass[1024]; unsigned char fname_hash[XMPP_SHA1_DIGEST_SIZE]; size_t passlen, fnamelen; } password_cache; unsigned int password_retries; /* if server returns or we must do them */ int bind_required; int session_required; int sm_disable; xmpp_sm_state_t *sm_state; struct { struct xmpp_compression *state; int allowed, supported, dont_reset; } compression; char *lang; char *domain; char *jid; char *pass; char *bound_jid; char *stream_id; /* send queue and parameters */ int blocking_send; int send_queue_max; int send_queue_len; int send_queue_user_len; xmpp_send_queue_t *send_queue_head; xmpp_send_queue_t *send_queue_tail; /* xml parser */ int reset_parser; parser_t *parser; /* timeouts */ unsigned int connect_timeout; /* event handlers */ /* stream open handler */ xmpp_open_handler open_handler; /* user handlers only get called after the stream negotiation has completed */ int stream_negotiation_completed; /* connection events handler */ xmpp_conn_handler conn_handler; void *userdata; /* other handlers */ xmpp_handlist_t *timed_handlers; hash_t *id_handlers; xmpp_handlist_t *handlers; xmpp_sockopt_callback sockopt_cb; }; void conn_disconnect(xmpp_conn_t *conn); void conn_disconnect_clean(xmpp_conn_t *conn); void conn_established(xmpp_conn_t *conn); void conn_open_stream(xmpp_conn_t *conn); int conn_tls_start(xmpp_conn_t *conn); void conn_prepare_reset(xmpp_conn_t *conn, xmpp_open_handler handler); void conn_parser_reset(xmpp_conn_t *conn); typedef enum { XMPP_STANZA_UNKNOWN, XMPP_STANZA_TEXT, XMPP_STANZA_TAG } xmpp_stanza_type_t; struct _xmpp_stanza_t { int ref; xmpp_ctx_t *ctx; xmpp_stanza_type_t type; xmpp_stanza_t *prev; xmpp_stanza_t *next; xmpp_stanza_t *children; xmpp_stanza_t *parent; char *data; hash_t *attributes; }; /* handler management */ void handler_fire_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza); uint64_t handler_fire_timed(xmpp_ctx_t *ctx); void handler_reset_timed(xmpp_conn_t *conn, int user_only); void handler_add_timed(xmpp_conn_t *conn, xmpp_timed_handler handler, unsigned long period, void *userdata); void handler_add_id(xmpp_conn_t *conn, xmpp_handler handler, const char *id, void *userdata); void handler_add(xmpp_conn_t *conn, xmpp_handler handler, const char *ns, const char *name, const char *type, void *userdata); void handler_system_delete_all(xmpp_conn_t *conn); /* utility functions */ void reset_sm_state(xmpp_sm_state_t *sm_state); void disconnect_mem_error(xmpp_conn_t *conn); /* auth functions */ void auth_handle_open(xmpp_conn_t *conn); void auth_handle_component_open(xmpp_conn_t *conn); void auth_handle_open_raw(xmpp_conn_t *conn); void auth_handle_open_stub(xmpp_conn_t *conn); /* queue functions */ void add_queue_back(xmpp_queue_t *queue, xmpp_send_queue_t *item); xmpp_send_queue_t *peek_queue_front(xmpp_queue_t *queue); xmpp_send_queue_t *pop_queue_front(xmpp_queue_t *queue); char *queue_element_free(xmpp_ctx_t *ctx, xmpp_send_queue_t *e); /* send functions */ void send_raw(xmpp_conn_t *conn, const char *data, size_t len, xmpp_send_queue_owner_t owner, void *userdata); /* this is a bit special as it will always mark the sent string as * owned by libstrophe */ void send_raw_string(xmpp_conn_t *conn, const char *fmt, ...); void send_stanza(xmpp_conn_t *conn, xmpp_stanza_t *stanza, xmpp_send_queue_owner_t owner); #endif /* __LIBSTROPHE_COMMON_H__ */