|
|
@@ -12,26 +12,34 @@
|
|
|
|
|
|
#include "lwip/sockets.h"
|
|
|
|
|
|
-#define WIFI_SSID "TOCHTECH"
|
|
|
-#define WIFI_PASS "Smarturns2017"
|
|
|
+#include <stdbool.h>
|
|
|
+#include "mbedtls/md5.h"
|
|
|
|
|
|
-#define ASTERISK_IP "192.168.68.93"
|
|
|
-#define ASTERISK_PORT 5038 // Asterisk AMI port (safe TCP test)
|
|
|
+#define WIFI_SSID "WIFI-95E4 2.4"
|
|
|
+#define WIFI_PASS "beard1354canyon"
|
|
|
|
|
|
-static const char *TAG = "PING_TEST";
|
|
|
+#define ASTERISK_IP "10.0.0.167"
|
|
|
+#define SIP_PORT 5060
|
|
|
|
|
|
-/* ---------------- WIFI ---------------- */
|
|
|
+static const char *TAG = "SIP";
|
|
|
+static volatile bool wifi_ready = false;
|
|
|
+
|
|
|
+/* ================= WIFI ================= */
|
|
|
|
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
|
int32_t event_id, void *event_data)
|
|
|
{
|
|
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
|
esp_wifi_connect();
|
|
|
- } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
|
+ }
|
|
|
+ else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
|
|
ESP_LOGI(TAG, "WiFi disconnected, retrying...");
|
|
|
+ wifi_ready = false;
|
|
|
esp_wifi_connect();
|
|
|
- } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
|
+ }
|
|
|
+ else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
|
ESP_LOGI(TAG, "WiFi connected!");
|
|
|
+ wifi_ready = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -60,74 +68,273 @@ void wifi_init(void)
|
|
|
esp_wifi_start();
|
|
|
}
|
|
|
|
|
|
-/* ---------------- TCP CHECK ---------------- */
|
|
|
+/* ================= MD5 HELPERS ================= */
|
|
|
|
|
|
-void check_asterisk(void)
|
|
|
+static void md5_calc(const unsigned char *input, size_t len, unsigned char output[16])
|
|
|
{
|
|
|
- while (1) {
|
|
|
- struct sockaddr_in dest;
|
|
|
- dest.sin_addr.s_addr = inet_addr(ASTERISK_IP);
|
|
|
- dest.sin_family = AF_INET;
|
|
|
- dest.sin_port = htons(ASTERISK_PORT);
|
|
|
-
|
|
|
- int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
- if (sock < 0) {
|
|
|
- ESP_LOGE(TAG, "Socket create failed");
|
|
|
- vTaskDelay(pdMS_TO_TICKS(2000));
|
|
|
- continue;
|
|
|
- }
|
|
|
+ mbedtls_md5_context ctx;
|
|
|
+ mbedtls_md5_init(&ctx);
|
|
|
+ mbedtls_md5_starts(&ctx);
|
|
|
+ mbedtls_md5_update(&ctx, input, len);
|
|
|
+ mbedtls_md5_finish(&ctx, output);
|
|
|
+ mbedtls_md5_free(&ctx);
|
|
|
+}
|
|
|
|
|
|
- ESP_LOGI(TAG, "Checking Asterisk at %s:%d...", ASTERISK_IP, ASTERISK_PORT);
|
|
|
+static void md5_to_hex(unsigned char *md5, char *out)
|
|
|
+{
|
|
|
+ for (int i = 0; i < 16; i++) {
|
|
|
+ sprintf(out + i * 2, "%02x", md5[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- int err = connect(sock, (struct sockaddr*)&dest, sizeof(dest));
|
|
|
+/* ================= SIP DIGEST ================= */
|
|
|
|
|
|
- if (err == 0) {
|
|
|
- ESP_LOGI(TAG, "TCP connected → sending AMI login");
|
|
|
+void sip_compute_response(
|
|
|
+ const char *username,
|
|
|
+ const char *realm,
|
|
|
+ const char *password,
|
|
|
+ const char *nonce,
|
|
|
+ const char *uri,
|
|
|
+ char *out_response)
|
|
|
+{
|
|
|
+ unsigned char ha1_md5[16], ha2_md5[16], final_md5[16];
|
|
|
+ char ha1_hex[64], ha2_hex[64], final_str[256];
|
|
|
+ char ha1[128], ha2[128];
|
|
|
|
|
|
- const char *login =
|
|
|
- "Action: Login\r\n"
|
|
|
- "Username: esp32s3\r\n"
|
|
|
- "Secret: 1234\r\n"
|
|
|
- "Events: off\r\n"
|
|
|
- "\r\n";
|
|
|
+ snprintf(ha1, sizeof(ha1), "%s:%s:%s", username, realm, password);
|
|
|
+ md5_calc((unsigned char*)ha1, strlen(ha1), ha1_md5);
|
|
|
+ md5_to_hex(ha1_md5, ha1_hex);
|
|
|
|
|
|
- send(sock, login, strlen(login), 0);
|
|
|
+ snprintf(ha2, sizeof(ha2), "REGISTER:%s", uri);
|
|
|
+ md5_calc((unsigned char*)ha2, strlen(ha2), ha2_md5);
|
|
|
+ md5_to_hex(ha2_md5, ha2_hex);
|
|
|
|
|
|
- char buf[512];
|
|
|
- int len = recv(sock, buf, sizeof(buf) - 1, 0);
|
|
|
+ snprintf(final_str, sizeof(final_str),
|
|
|
+ "%s:%s:%s", ha1_hex, nonce, ha2_hex);
|
|
|
|
|
|
- if (len > 0) {
|
|
|
- buf[len] = 0;
|
|
|
- ESP_LOGI(TAG, "AMI RESPONSE:\n%s", buf);
|
|
|
+ md5_calc((unsigned char*)final_str, strlen(final_str), final_md5);
|
|
|
+ md5_to_hex(final_md5, out_response);
|
|
|
+}
|
|
|
|
|
|
- if (strstr(buf, "Success")) {
|
|
|
- ESP_LOGI(TAG, "✅ AMI LOGIN SUCCESS");
|
|
|
- } else {
|
|
|
- ESP_LOGW(TAG, "❌ AMI LOGIN FAILED");
|
|
|
- }
|
|
|
- } else {
|
|
|
- ESP_LOGW(TAG, "No AMI response");
|
|
|
+/* ================= SIP TASK ================= */
|
|
|
+
|
|
|
+void sip_register_task(void *pvParameters)
|
|
|
+{
|
|
|
+ struct sockaddr_in server = {0};
|
|
|
+ server.sin_family = AF_INET;
|
|
|
+ server.sin_port = htons(SIP_PORT);
|
|
|
+ server.sin_addr.s_addr = inet_addr(ASTERISK_IP);
|
|
|
+
|
|
|
+ int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
+
|
|
|
+ if (sock < 0) {
|
|
|
+ ESP_LOGE(TAG, "Socket failed");
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
-} else {
|
|
|
- ESP_LOGW(TAG, "❌ Asterisk NOT reachable");
|
|
|
-}
|
|
|
+ struct timeval timeout = {
|
|
|
+ .tv_sec = 3,
|
|
|
+ .tv_usec = 0
|
|
|
+ };
|
|
|
+
|
|
|
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
|
|
+
|
|
|
+ /* ================= FIRST REGISTER ================= */
|
|
|
+
|
|
|
+ char register_msg[512];
|
|
|
+
|
|
|
+ snprintf(register_msg, sizeof(register_msg),
|
|
|
+ "REGISTER sip:%s SIP/2.0\r\n"
|
|
|
+ "Via: SIP/2.0/UDP 0.0.0.0:5062\r\n"
|
|
|
+ "From: <sip:1001@%s>;tag=1234\r\n"
|
|
|
+ "To: <sip:1001@%s>\r\n"
|
|
|
+ "Call-ID: esp32-0001\r\n"
|
|
|
+ "CSeq: 1 REGISTER\r\n"
|
|
|
+ "Contact: <sip:1001@0.0.0.0:5062>\r\n"
|
|
|
+ "Expires: 300\r\n"
|
|
|
+ "Content-Length: 0\r\n"
|
|
|
+ "\r\n",
|
|
|
+ ASTERISK_IP,
|
|
|
+ ASTERISK_IP,
|
|
|
+ ASTERISK_IP);
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Sending REGISTER...");
|
|
|
+ sendto(sock, register_msg, strlen(register_msg), 0,
|
|
|
+ (struct sockaddr*)&server, sizeof(server));
|
|
|
+
|
|
|
+ /* ================= RECEIVE 401 ================= */
|
|
|
+
|
|
|
+ char response[1024];
|
|
|
+ socklen_t addr_len = sizeof(server);
|
|
|
+
|
|
|
+ int len = recvfrom(sock, response, sizeof(response) - 1, 0,
|
|
|
+ (struct sockaddr*)&server, &addr_len);
|
|
|
+
|
|
|
+ if (len <= 0) {
|
|
|
+ ESP_LOGE(TAG, "No response");
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
+ response[len] = '\0';
|
|
|
+ printf("401 RESPONSE:\n%s\n", response);
|
|
|
+
|
|
|
+ if (!strstr(response, "401")) {
|
|
|
+ ESP_LOGE(TAG, "Expected 401 Unauthorized");
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ================= EXTRACT NONCE ================= */
|
|
|
+
|
|
|
+ char sip_nonce[256] = {0};
|
|
|
+
|
|
|
+ char *n = strstr(response, "nonce=\"");
|
|
|
+ if (!n) {
|
|
|
+ ESP_LOGE(TAG, "No nonce found");
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ n += 7;
|
|
|
+
|
|
|
+ char *end = strchr(n, '"');
|
|
|
+ if (!end) {
|
|
|
+ ESP_LOGE(TAG, "Bad nonce format");
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t nlen = end - n;
|
|
|
+
|
|
|
+ if (nlen >= sizeof(sip_nonce)) {
|
|
|
+ ESP_LOGE(TAG, "Nonce too long");
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ strncpy(sip_nonce, n, nlen);
|
|
|
+ sip_nonce[nlen] = '\0';
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Nonce: %s", sip_nonce);
|
|
|
+
|
|
|
+ /* ================= EXTRACT REALM ================= */
|
|
|
+
|
|
|
+ char sip_realm[128] = {0};
|
|
|
+
|
|
|
+ char *r = strstr(response, "realm=\"");
|
|
|
+ if (r) {
|
|
|
+ r += 7;
|
|
|
+ char *rend = strchr(r, '"');
|
|
|
+ if (rend) {
|
|
|
+ size_t rlen = rend - r;
|
|
|
+ if (rlen < sizeof(sip_realm)) {
|
|
|
+ strncpy(sip_realm, r, rlen);
|
|
|
+ sip_realm[rlen] = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sip_realm[0] == '\0') {
|
|
|
+ ESP_LOGE(TAG, "Realm not found");
|
|
|
close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- vTaskDelay(pdMS_TO_TICKS(5000));
|
|
|
+ ESP_LOGI(TAG, "Realm: %s", sip_realm);
|
|
|
+
|
|
|
+ /* ================= AUTH DIGEST ================= */
|
|
|
+
|
|
|
+ char response_hash[64];
|
|
|
+
|
|
|
+ sip_compute_response(
|
|
|
+ "1001",
|
|
|
+ sip_realm,
|
|
|
+ "secret123",
|
|
|
+ sip_nonce,
|
|
|
+ "sip:10.0.0.167",
|
|
|
+ response_hash
|
|
|
+ );
|
|
|
+
|
|
|
+ /* ================= AUTH REGISTER ================= */
|
|
|
+
|
|
|
+ char auth[1024];
|
|
|
+
|
|
|
+ snprintf(auth, sizeof(auth),
|
|
|
+ "REGISTER sip:%s SIP/2.0\r\n"
|
|
|
+ "Via: SIP/2.0/UDP 0.0.0.0:5062\r\n"
|
|
|
+ "From: <sip:1001@%s>;tag=1234\r\n"
|
|
|
+ "To: <sip:1001@%s>\r\n"
|
|
|
+ "Call-ID: esp32-0001\r\n"
|
|
|
+ "CSeq: 2 REGISTER\r\n"
|
|
|
+ "Contact: <sip:1001@0.0.0.0:5062>\r\n"
|
|
|
+ "Authorization: Digest username=\"1001\", realm=\"%s\", nonce=\"%s\", uri=\"sip:%s\", response=\"%s\"\r\n"
|
|
|
+ "Expires: 300\r\n"
|
|
|
+ "Content-Length: 0\r\n"
|
|
|
+ "\r\n",
|
|
|
+ ASTERISK_IP,
|
|
|
+ ASTERISK_IP,
|
|
|
+ ASTERISK_IP,
|
|
|
+ sip_realm,
|
|
|
+ sip_nonce,
|
|
|
+ ASTERISK_IP,
|
|
|
+ response_hash);
|
|
|
+
|
|
|
+ ESP_LOGI(TAG, "Sending AUTH REGISTER...");
|
|
|
+ sendto(sock, auth, strlen(auth), 0,
|
|
|
+ (struct sockaddr*)&server, sizeof(server));
|
|
|
+
|
|
|
+ /* ================= FINAL RESPONSE ================= */
|
|
|
+
|
|
|
+ char final_resp[1024];
|
|
|
+
|
|
|
+ int len2 = recvfrom(sock,
|
|
|
+ final_resp,
|
|
|
+ sizeof(final_resp) - 1,
|
|
|
+ 0,
|
|
|
+ (struct sockaddr*)&server,
|
|
|
+ &addr_len);
|
|
|
+
|
|
|
+ if (len2 > 0) {
|
|
|
+ final_resp[len2] = '\0';
|
|
|
+ printf("FINAL RESPONSE:\n%s\n", final_resp);
|
|
|
+
|
|
|
+ if (strstr(final_resp, "200 OK")) {
|
|
|
+ ESP_LOGI(TAG, "🎉 SIP REGISTER SUCCESS");
|
|
|
+ } else {
|
|
|
+ ESP_LOGW(TAG, "REGISTER FAILED");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ESP_LOGW(TAG, "No final response");
|
|
|
}
|
|
|
+
|
|
|
+ close(sock);
|
|
|
+ vTaskDelete(NULL);
|
|
|
}
|
|
|
|
|
|
-/* ---------------- MAIN ---------------- */
|
|
|
+/* ================= MAIN ================= */
|
|
|
|
|
|
void app_main(void)
|
|
|
{
|
|
|
- ESP_LOGI(TAG, "Starting minimal Asterisk connectivity test");
|
|
|
+ ESP_LOGI(TAG, "Starting SIP client...");
|
|
|
|
|
|
wifi_init();
|
|
|
|
|
|
- vTaskDelay(pdMS_TO_TICKS(5000)); // wait for WiFi
|
|
|
+ while (!wifi_ready) {
|
|
|
+ vTaskDelay(pdMS_TO_TICKS(500));
|
|
|
+ }
|
|
|
|
|
|
- xTaskCreate(check_asterisk, "check_asterisk", 4096, NULL, 5, NULL);
|
|
|
+ xTaskCreate(sip_register_task,
|
|
|
+ "sip_register",
|
|
|
+ 12288,
|
|
|
+ NULL,
|
|
|
+ 5,
|
|
|
+ NULL);
|
|
|
}
|