axl_bool __myqtt_web_socket_session_setup (MyQttCtx * ctx, MyQttConn * conn, MyQttConnOpts * options, axlPointer user_data) { noPollConn * nopoll_conn = user_data; if (nopoll_conn_socket (nopoll_conn) < 0) { myqtt_log (MYQTT_LEVEL_CRITICAL, "Failed to create MQTT over WebSocket connection to %s:%s because socket is invalid or connection is not connected (socket: %d)", nopoll_conn_host (nopoll_conn), nopoll_conn_port (nopoll_conn), nopoll_conn_socket (nopoll_conn)); return axl_false; } /* end if */ myqtt_log (MYQTT_LEVEL_DEBUG, "Creating new MQTT over WebSocket connection to %s:%s (socket: %d)", nopoll_conn_host (nopoll_conn), nopoll_conn_port (nopoll_conn), nopoll_conn_socket (nopoll_conn)); /* set socket on the connection */ conn->session = nopoll_conn_socket (nopoll_conn); /* associate the connection to its websocket transport */ __myqtt_web_socket_common_association (conn, nopoll_conn); /* configure this connection to have no preread */ conn->preread_handler = NULL; conn->preread_user_data = NULL; return axl_true; }
int create_listener(const char * port) { memset(serverResponseBuffer, 0xab, 33000); instanceID = strdup("server"); noPollCtx * ctx = nopoll_ctx_new (); if (!ctx) { LogPrintf("Could not create context"); return 1; } if (debug_nopoll) { nopoll_log_set_handler(ctx, noPollLogger, NULL); } noPollConn * listener = nopoll_listener_new(ctx, "0.0.0.0", port); if (!nopoll_conn_is_ok (listener)) { LogPrintf("Could not listen on port %s", port); return 1; } LogPrintf("noPoll listener started at: %s:%s", nopoll_conn_host(listener), nopoll_conn_port(listener)); nopoll_ctx_set_on_msg(ctx, listener_on_message, NULL); nopoll_loop_wait(ctx, 0); nopoll_ctx_unref(ctx); return 0; }
noPollPtr ssl_context_creator (noPollCtx * ctx, noPollConn * conn, noPollConnOpts * opts, nopoll_bool is_client, noPollPtr user_data) { SSL_CTX * ssl_ctx; noPollConn * listener; /* very basic context creation using default settings provided * by OpenSSL */ if (is_client) { #if OPENSSL_VERSION_NUMBER < 0x10100000L return SSL_CTX_new (TLSv1_client_method ()); #else return SSL_CTX_new (TLS_client_method ()); #endif } /* end if */ /* get the ssl context */ #if OPENSSL_VERSION_NUMBER < 0x10100000L ssl_ctx = SSL_CTX_new (TLSv1_server_method ()); #else ssl_ctx = SSL_CTX_new (TLS_server_method ()); #endif /* get a reference to the listener */ listener = nopoll_conn_get_listener (conn); if (nopoll_cmp ("1239", nopoll_conn_port (listener))) { printf ("ACCEPTED ssl connection on port: %s (for conn %p)\n", nopoll_conn_port (listener), conn); /* ok, especiall case where we require a certain * certificate from renote side */ if (SSL_CTX_load_verify_locations (ssl_ctx, "client-side-cert-auth-cacert.crt", NULL) != 1) { printf ("ERROR: unable to add ca certificate...\n"); } /* make server to ask for a certificate to the client * .... and verify it */ SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); } /* end if */ printf ("RETURNING: ssl context reference %p\n", ssl_ctx); return ssl_ctx; }
/** * @brief Allows to create a new MQTT connection to a MQTT * broker/server running MQTT over WebSocket. * * @param ctx The context where the operation will take place. * * @param client_identifier The client identifier that uniquely * identifies this MQTT client from others. It can be NULL to let * MQTT 3.1.1 servers to assign a default client identifier BUT * clean_session must be set to axl_true. This is done automatically * by the library (setting clean_session to axl_true when NULL is * provided). * * @param clean_session Flag to clean client session or to reuse the * existing one. If set to axl_false, you must provide a valid * client_identifier (otherwise the function will fail). * * @param keep_alive Keep alive configuration in seconds after which * the server/broker will close the connection if it doesn't detect * any activity. Setting 0 will disable keep alive mechanism. * * @param conn A reference to an established noPollConn connection * that is connecting to the MQTT over WebSocket server we want to * connect to. * * @param opts Optional connection options. See \ref myqtt_conn_opts_new * * @param on_connected Async notification handler that will be called * once the connection fails or it is completed. In the case this * handler is configured the caller will not be blocked. In the case * this parameter is NULL, the caller will be blocked until the * connection completes or fails. * * @param user_data User defined pointer that will be passed to the on_connected handler (in case it is defined). * * @return A reference to the newli created connection or NULL if * on_connected handler is provided. In both cases, the reference * returned (or received at the on_connected handler) must be checked * with \ref myqtt_conn_is_ok. * * <b>About pending messages / queued messages </b> * * After successful connection with clean_session set to axl_false and * defined client identifier, the library will resend any queued or in * flight QoS1/QoS2 messages (as well as QoS0 if they were * stored). This is done in background without intefering the caller. * * If you need to get the number of queued messages that are going to * be sent use \ref myqtt_storage_queued_messages_offline. In the case * you need the number remaining during the process use \ref * myqtt_storage_queued_messages. * * See \ref myqtt_conn_new for more information. * * <b>About reconnecting</b> * * If you enable automatic reconnect support after connection close * (\ref myqtt_conn_opts_set_reconnect), remember to also configure * the recover handler by using \ref myqtt_conn_opts_set_init_session_setup_ptr. That function should * implement a complete reconnect and return a noPollConn reference * used by the internal session setup. If you don't configure this, * the function will disable reconnect support even if you enable it. * */ MyQttConn * myqtt_web_socket_conn_new (MyQttCtx * ctx, const char * client_identifier, axl_bool clean_session, int keep_alive, noPollConn * conn, MyQttConnOpts * opts, MyQttConnNew on_connected, axlPointer user_data) { /* check if the conn reference is not defined. In that case, try to craete it with the init session setup ptr */ if (conn == NULL && opts && opts->init_session_setup_ptr) conn = opts->init_session_setup_ptr (ctx, NULL, opts->init_user_data, opts->init_user_data2, opts->init_user_data3); /* report what we are doing */ myqtt_log (MYQTT_LEVEL_DEBUG, "Creating new MQTT over WebSocket connection to %s:%s (is ready:%d, socket: %d)", nopoll_conn_host (conn), nopoll_conn_port (conn), nopoll_conn_is_ready (conn), nopoll_conn_socket (conn)); /* check and disable reconnect if it is not configured the recover handler */ if (opts && opts->reconnect) { if (opts->init_session_setup_ptr == NULL) { myqtt_log (MYQTT_LEVEL_CRITICAL, "Disable reconnect flag because user didn't provide a recover handler (myqtt_conn_opts_set_recover_session_setup_ptr)"); opts->reconnect = axl_false; /* disable it */ } /* end if */ } /* end opts */ /* associate context */ __myqtt_web_socket_associate_ctx (ctx, nopoll_conn_ctx (conn)); /* call to create the connection */ return myqtt_conn_new_full_common (ctx, client_identifier, clean_session, keep_alive, /* destination host and port but only as a matter of reporting because we are handling everything through the setup handler */ nopoll_conn_host (conn), nopoll_conn_port (conn), /* this is the handler that will establish the connection on top of the provided noPoll connection */ __myqtt_web_socket_session_setup, conn, /* additional user handlers */ on_connected, -1, opts, user_data); }
/** * @brief Allows to start a MQTT server on the provided local host * address and port running MQTT over WebSocket protocol. * * <b>Important note:</b> you must call to \ref myqtt_storage_set_path * to define the path first before creating any listener. This is * because creating a listener activates all server side code which * among other things includes the storage loading (client * subscriptions, offline publishing, etc). In the case direction, * once the storage path is loaded it cannot be changed after * restarting the particular context used in this operation (\ref * MyQttCtx). * * @param ctx The context where the operation takes place. * * @param listener The webSocket listener connection created on top of which MQTT over WebSocket is expected. * * @param opts Optional connection options to modify default behaviour. * * @param on_ready Optional on ready notification handler that gets * called when the listener is created or a failure was * found. Providing this handler makes this function to not block the * caller. * * @param user_data Optional user defined pointer that is passed into * the on_ready function (in the case the former is defined too). * * See \ref myqtt_listener_new for more information. * * @return A newly created connection listener reference (\ref * MyQttConn). Use \ref myqtt_conn_is_ok to check listener was created * without errors. */ MyQttConn * myqtt_web_socket_listener_new (MyQttCtx * ctx, noPollConn * listener, MyQttConnOpts * opts, MyQttListenerReady on_ready, axlPointer user_data) { MyQttWebSocketReady * websocket_ready = NULL; MyQttConn * myqtt_listener; if (! nopoll_conn_is_ok (listener)) { myqtt_log (MYQTT_LEVEL_CRITICAL, "Unable to create listener, received reference is not working"); return NULL; } /* end if */ /* create object for the function proxy but only in the user on_ready function is defined */ if (on_ready) { websocket_ready = axl_new (MyQttWebSocketReady, 1); if (websocket_ready == NULL) { myqtt_log (MYQTT_LEVEL_CRITICAL, "Unable to allocate memory to start the listener.."); return NULL; } /* end if */ websocket_ready->user_data = user_data; websocket_ready->listener = listener; websocket_ready->user_on_ready = on_ready; } /* end if */ /* associate context */ __myqtt_web_socket_associate_ctx (ctx, nopoll_conn_ctx (listener)); myqtt_listener = __myqtt_listener_new_common (ctx, nopoll_conn_host (listener), __myqtt_listener_get_port (nopoll_conn_port (listener)), /* register connection and socket */ axl_true, nopoll_conn_socket (listener), opts, on_ready, MYQTT_IPv6, __myqtt_web_socket_accept_connection, /* configure proxy on ready */ __myqtt_web_socket_listener_ready, websocket_ready); if (myqtt_listener) { /* configure here reference to the noPoll listener */ myqtt_conn_set_data_full (myqtt_listener, "__my:ws:lstnr", listener, NULL, (axlDestroyFunc) __myqtt_web_socket_close_conn); /* configure on ready */ } /* end if */ return myqtt_listener; }
int main (int argc, char ** argv) { noPollConn * listener; noPollConn * listener_6; noPollConn * listener2; noPollConn * listener_62; #if defined(NOPOLL_HAVE_SSLv23_ENABLED) noPollConn * listener3; #endif #if defined(NOPOLL_HAVE_SSLv3_ENABLED) noPollConn * listener4; #endif #if defined(NOPOLL_HAVE_TLSv11_ENABLED) noPollConn * listener5; noPollConn * listener_65; #endif noPollConn * listener6; #if defined(NOPOLL_HAVE_TLSv12_ENABLED) noPollConn * listener7; #endif int iterator; noPollConnOpts * opts; signal (SIGTERM, __terminate_listener); #if defined(__NOPOLL_PTHREAD_SUPPORT__) printf ("INFO: install default threading functions to check noPoll locking code..\n"); nopoll_thread_handlers (__nopoll_regtest_mutex_create, __nopoll_regtest_mutex_destroy, __nopoll_regtest_mutex_lock, __nopoll_regtest_mutex_unlock); #endif /* create the context */ ctx = nopoll_ctx_new (); iterator = 1; while (iterator < argc) { /* check for debug */ printf ("Checking agument: %s\n", argv[iterator]); if (nopoll_cmp (argv[iterator], "--debug")) { printf ("Activating debug..\n"); nopoll_log_enable (ctx, nopoll_true); #if !defined(NOPOLL_OS_WIN32) nopoll_log_color_enable (ctx, nopoll_true); #endif } /* end if */ /* next position */ iterator++; } /* call to create a listener */ listener = nopoll_listener_new (ctx, "0.0.0.0", "1234"); if (! nopoll_conn_is_ok (listener)) { printf ("ERROR: Expected to find proper listener connection status, but found..\n"); return -1; } printf ("noPoll listener started at: %s:%s (refs: %d)..\n", nopoll_conn_host (listener), nopoll_conn_port (listener), nopoll_conn_ref_count (listener)); /* call to create a listener */ listener_6 = nopoll_listener_new6 (ctx, "::1", "2234"); if (! nopoll_conn_is_ok (listener_6)) { printf ("ERROR: Expected to find proper listener connection status, but found (IPv6 -- .1.1)..\n"); return -1; } /* end if */ printf ("noPoll listener started at (IPv6): %s:%s (refs: %d)..\n", nopoll_conn_host (listener_6), nopoll_conn_port (listener_6), nopoll_conn_ref_count (listener_6)); /* now start a TLS version */ printf ("Test: starting listener with TLS (TLSv1) at :1235\n"); listener2 = nopoll_listener_tls_new (ctx, "0.0.0.0", "1235"); if (! nopoll_conn_is_ok (listener2)) { printf ("ERROR: Expected to find proper listener TLS connection status, but found..\n"); return -1; } /* end if */ /* configure certificates to be used by this listener */ if (! nopoll_listener_set_certificate (listener2, "test-certificate.crt", "test-private.key", NULL)) { printf ("ERROR: unable to configure certificates for TLS websocket..\n"); return -1; } /* register certificates at context level */ if (! nopoll_ctx_set_certificate (ctx, NULL, "test-certificate.crt", "test-private.key", NULL)) { printf ("ERROR: unable to setup certificates at context level..\n"); return -1; } /* now start a TLS version */ printf ("Test: starting listener with TLS IPv6 (TLSv1) at :2235\n"); listener_62 = nopoll_listener_tls_new6 (ctx, "::1", "2235"); if (! nopoll_conn_is_ok (listener_62)) { printf ("ERROR: Expected to find proper listener TLS connection status, but found..\n"); return -1; } /* end if */ /* configure certificates to be used by this listener */ if (! nopoll_listener_set_certificate (listener_62, "test-certificate.crt", "test-private.key", NULL)) { printf ("ERROR: unable to configure certificates for TLS websocket..\n"); return -1; } /* register certificates at context level */ if (! nopoll_ctx_set_certificate (ctx, NULL, "test-certificate.crt", "test-private.key", NULL)) { printf ("ERROR: unable to setup certificates at context level..\n"); return -1; } #if defined(NOPOLL_HAVE_SSLv23_ENABLED) /* start listener with sslv23 */ printf ("Test: starting listener with TLS (SSLv23) at :1236 (all methods)\n"); opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV23); listener3 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1236"); if (! nopoll_conn_is_ok (listener3)) { printf ("ERROR: Expected to find proper listener TLS connection status (:1236, SSLv23), but found..\n"); return -1; } /* end if */ #endif #if defined(NOPOLL_HAVE_SSLv3_ENABLED) printf ("Test: starting listener with TLS (SSLv3) at :1237\n"); opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_SSLV3); listener4 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1237"); if (! nopoll_conn_is_ok (listener4)) { printf ("ERROR: Expected to find proper listener TLS connection status (:1237, SSLv3), but found..\n"); return -1; } /* end if */ #endif #if defined(NOPOLL_HAVE_TLSv11_ENABLED) printf ("Test: starting listener with TLS (TLSv1.1) at :1238\n"); opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_1); listener5 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1238"); if (! nopoll_conn_is_ok (listener5)) { printf ("ERROR: Expected to find proper listener TLS connection status (:1238, TLSv1.1), but found..\n"); return -1; } /* end if */ printf ("Test: starting listener with TLS (TLSv1.1) (IPv6) at :2238\n"); opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_1); listener_65 = nopoll_listener_tls_new_opts6 (ctx, opts, "::1", "2238"); if (! nopoll_conn_is_ok (listener_65)) { printf ("ERROR: Expected to find proper listener TLS connection status (::1:2238, TLSv1.1, IPv6), but found..\n"); return -1; } /* end if */ #endif #if defined(NOPOLL_HAVE_TLSv12_ENABLED) printf ("Test: starting listener with TLS (TLSv1.2) at :1240\n"); opts = nopoll_conn_opts_new (); nopoll_conn_opts_set_ssl_protocol (opts, NOPOLL_METHOD_TLSV1_2); listener7 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1240"); if (! nopoll_conn_is_ok (listener7)) { printf ("ERROR: Expected to find proper listener TLS connection status (:1240, TLSv1.2), but found..\n"); return -1; } /* end if */ #endif opts = nopoll_conn_opts_new (); /* configure server certificates (server.pem) signed by the * provided ca (root.pem) also configured in the last * parameter */ if (! nopoll_conn_opts_set_ssl_certs (opts, "server.pem", "server.pem", NULL, "root.pem")) { printf ("ERROR: unable to setup certificates...\n"); return -1; } /* configure peer verification */ nopoll_conn_opts_ssl_peer_verify (opts, nopoll_true); listener6 = nopoll_listener_tls_new_opts (ctx, opts, "0.0.0.0", "1239"); if (! nopoll_conn_is_ok (listener6)) { printf ("ERROR: Expected to find proper listener TLS connection status (:1236, SSLv23), but found..\n"); return -1; } /* end if */ /* configure ssl context creator */ /* nopoll_ctx_set_ssl_context_creator (ctx, ssl_context_creator, NULL); */ /* set on message received */ nopoll_ctx_set_on_msg (ctx, listener_on_message, NULL); /* set on open */ nopoll_ctx_set_on_open (ctx, on_connection_opened, NULL); /* process events */ nopoll_loop_wait (ctx, 0); /* unref connection */ nopoll_conn_close (listener); nopoll_conn_close (listener_6); /* ipv6 */ nopoll_conn_close (listener2); nopoll_conn_close (listener_62); /* ipv6 */ #if defined(NOPOLL_HAVE_SSLv23_ENABLED) nopoll_conn_close (listener3); #endif #if defined(NOPOLL_HAVE_SSLv3_ENABLED) nopoll_conn_close (listener4); #endif #if defined(NOPOLL_HAVE_TLSv12_ENABLED) nopoll_conn_close (listener5); nopoll_conn_close (listener_65); #endif nopoll_conn_close (listener6); #if defined(NOPOLL_HAVE_TLSv12_ENABLED) nopoll_conn_close (listener7); #endif /* finish */ printf ("Listener: finishing references: %d\n", nopoll_ctx_ref_count (ctx)); if (previous_msg) { printf ("..reference counting for previous msg: %d\n", nopoll_msg_ref_count (previous_msg)); nopoll_msg_unref (previous_msg); } /* end if */ nopoll_ctx_unref (ctx); /* call to release all pending memory allocated as a * consequence of using nopoll (especially TLS) */ nopoll_cleanup_library (); return 0; }