rtsp_message.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #include "rtsp_message.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <strings.h>
  6. #include <sys/socket.h>
  7. #include "esp_log.h"
  8. #include "rtsp_crypto.h"
  9. static const char *TAG = "rtsp_message";
  10. const uint8_t *rtsp_find_header_end(const uint8_t *data, size_t len) {
  11. for (size_t i = 0; i + 3 < len; i++) {
  12. if (data[i] == '\r' && data[i + 1] == '\n' && data[i + 2] == '\r' &&
  13. data[i + 3] == '\n') {
  14. return data + i;
  15. }
  16. }
  17. return NULL;
  18. }
  19. int rtsp_parse_cseq(const char *request) {
  20. const char *cseq = strstr(request, "CSeq:");
  21. if (cseq) {
  22. return (int)strtol(cseq + 5, NULL, 10);
  23. }
  24. return 1;
  25. }
  26. int rtsp_parse_content_length(const char *request) {
  27. const char *cl = strstr(request, "Content-Length:");
  28. if (!cl) {
  29. cl = strstr(request, "content-length:");
  30. }
  31. if (cl) {
  32. return (int)strtol(cl + 15, NULL, 10);
  33. }
  34. return 0;
  35. }
  36. const uint8_t *rtsp_get_body(const char *request, size_t request_len,
  37. size_t *body_len) {
  38. const char *body = strstr(request, "\r\n\r\n");
  39. if (body) {
  40. body += 4;
  41. *body_len = request_len - (body - request);
  42. return (const uint8_t *)body;
  43. }
  44. *body_len = 0;
  45. return NULL;
  46. }
  47. // Parse Transport header for client ports (AirPlay 1)
  48. // Format: Transport:
  49. // RTP/AVP/UDP;unicast;mode=record;control_port=6001;timing_port=6002
  50. void rtsp_parse_transport(const char *request, uint16_t *control_port,
  51. uint16_t *timing_port) {
  52. if (control_port) {
  53. *control_port = 0;
  54. }
  55. if (timing_port) {
  56. *timing_port = 0;
  57. }
  58. // RTSP header names and Transport-header parameter names are
  59. // case-insensitive (RFC 2326), so match accordingly.
  60. const char *transport = strcasestr(request, "Transport:");
  61. if (!transport) {
  62. return;
  63. }
  64. // Find end of Transport header line
  65. const char *line_end = strstr(transport, "\r\n");
  66. if (!line_end) {
  67. line_end = transport + strlen(transport);
  68. }
  69. // Parse control_port
  70. const char *cp = strcasestr(transport, "control_port=");
  71. if (cp && cp < line_end && control_port) {
  72. *control_port = (uint16_t)strtoul(cp + 13, NULL, 10);
  73. }
  74. // Parse timing_port
  75. const char *tp = strcasestr(transport, "timing_port=");
  76. if (tp && tp < line_end && timing_port) {
  77. *timing_port = (uint16_t)strtoul(tp + 12, NULL, 10);
  78. }
  79. }
  80. int rtsp_request_parse(const uint8_t *data, size_t len, rtsp_request_t *req) {
  81. if (!data || !req || len == 0) {
  82. return -1;
  83. }
  84. memset(req, 0, sizeof(*req));
  85. // Find header end
  86. const uint8_t *header_end = rtsp_find_header_end(data, len);
  87. if (!header_end) {
  88. return -1;
  89. }
  90. // Parse first line: METHOD PATH PROTOCOL. The socket buffer is not
  91. // guaranteed to be NUL-terminated, so copy only the request line.
  92. const uint8_t *line_end = memchr(data, '\n', (size_t)(header_end - data));
  93. if (!line_end) {
  94. return -1;
  95. }
  96. size_t line_len = (size_t)(line_end - data);
  97. if (line_len > 0 && data[line_len - 1] == '\r') {
  98. line_len--;
  99. }
  100. char first_line[320];
  101. if (line_len >= sizeof(first_line)) {
  102. return -1;
  103. }
  104. memcpy(first_line, data, line_len);
  105. first_line[line_len] = '\0';
  106. if (sscanf(first_line, "%31s %255s %15s", req->method, req->path,
  107. req->protocol) < 2) {
  108. return -1;
  109. }
  110. // Parse CSeq
  111. req->cseq = rtsp_parse_cseq((const char *)data);
  112. // Parse Content-Length
  113. req->content_length = (size_t)rtsp_parse_content_length((const char *)data);
  114. // Parse Content-Type
  115. const char *ct = strstr((const char *)data, "Content-Type:");
  116. if (ct) {
  117. sscanf(ct, "Content-Type: %63s", req->content_type);
  118. }
  119. // Get body
  120. req->body = rtsp_get_body((const char *)data, len, &req->body_len);
  121. return 0;
  122. }
  123. // Internal: send all data, handling partial sends
  124. static int send_all(int socket, const uint8_t *data, size_t len) {
  125. size_t sent = 0;
  126. while (sent < len) {
  127. ssize_t r = send(socket, data + sent, len - sent, 0);
  128. if (r <= 0) {
  129. return -1;
  130. }
  131. sent += (size_t)r;
  132. }
  133. return 0;
  134. }
  135. int rtsp_send_response(int socket, rtsp_conn_t *conn, int status_code,
  136. const char *status_text, int cseq,
  137. const char *extra_headers, const char *body,
  138. size_t body_len) {
  139. char header[1024];
  140. int header_len;
  141. if (extra_headers && body && body_len > 0) {
  142. header_len =
  143. snprintf(header, sizeof(header),
  144. "RTSP/1.0 %d %s\r\n"
  145. "CSeq: %d\r\n"
  146. "Server: AirTunes/377.40.00\r\n"
  147. "%s"
  148. "Content-Length: %zu\r\n"
  149. "\r\n",
  150. status_code, status_text, cseq, extra_headers, body_len);
  151. } else if (extra_headers) {
  152. header_len = snprintf(header, sizeof(header),
  153. "RTSP/1.0 %d %s\r\n"
  154. "CSeq: %d\r\n"
  155. "Server: AirTunes/377.40.00\r\n"
  156. "%s"
  157. "\r\n",
  158. status_code, status_text, cseq, extra_headers);
  159. } else if (body && body_len > 0) {
  160. header_len = snprintf(header, sizeof(header),
  161. "RTSP/1.0 %d %s\r\n"
  162. "CSeq: %d\r\n"
  163. "Server: AirTunes/377.40.00\r\n"
  164. "Content-Length: %zu\r\n"
  165. "\r\n",
  166. status_code, status_text, cseq, body_len);
  167. } else {
  168. header_len = snprintf(header, sizeof(header),
  169. "RTSP/1.0 %d %s\r\n"
  170. "CSeq: %d\r\n"
  171. "Server: AirTunes/377.40.00\r\n"
  172. "\r\n",
  173. status_code, status_text, cseq);
  174. }
  175. // Build complete response
  176. size_t total_len = (size_t)header_len + body_len;
  177. uint8_t *response = malloc(total_len);
  178. if (!response) {
  179. ESP_LOGE(TAG, "Failed to allocate response buffer");
  180. return -1;
  181. }
  182. memcpy(response, header, (size_t)header_len);
  183. if (body && body_len > 0) {
  184. memcpy(response + header_len, body, body_len);
  185. }
  186. // Send encrypted or plain depending on mode
  187. int result;
  188. if (conn && conn->encrypted_mode) {
  189. result = rtsp_crypto_write_frame(socket, conn, response, total_len);
  190. } else {
  191. result = (send_all(socket, response, total_len) < 0) ? -1 : 0;
  192. if (result < 0) {
  193. ESP_LOGE(TAG, "Failed to send RTSP response");
  194. }
  195. }
  196. free(response);
  197. return result;
  198. }
  199. int rtsp_send_ok(int socket, rtsp_conn_t *conn, int cseq) {
  200. return rtsp_send_response(socket, conn, 200, "OK", cseq, NULL, NULL, 0);
  201. }
  202. int rtsp_send_http_response(int socket, rtsp_conn_t *conn, int status_code,
  203. const char *status_text, const char *content_type,
  204. const char *body, size_t body_len) {
  205. char header[512];
  206. int header_len = snprintf(header, sizeof(header),
  207. "HTTP/1.1 %d %s\r\n"
  208. "Content-Type: %s\r\n"
  209. "Content-Length: %zu\r\n"
  210. "Server: AirTunes/377.40.00\r\n"
  211. "CSeq: 1\r\n"
  212. "\r\n",
  213. status_code, status_text, content_type, body_len);
  214. // Build complete response
  215. size_t total_len = (size_t)header_len + body_len;
  216. uint8_t *response = malloc(total_len);
  217. if (!response) {
  218. ESP_LOGE(TAG, "Failed to allocate response buffer");
  219. return -1;
  220. }
  221. memcpy(response, header, (size_t)header_len);
  222. if (body && body_len > 0) {
  223. memcpy(response + header_len, body, body_len);
  224. }
  225. // Send encrypted or plain depending on mode
  226. int result;
  227. if (conn && conn->encrypted_mode) {
  228. result = rtsp_crypto_write_frame(socket, conn, response, total_len);
  229. } else {
  230. result = (send_all(socket, response, total_len) < 0) ? -1 : 0;
  231. if (result < 0) {
  232. ESP_LOGE(TAG, "Failed to send HTTP response");
  233. }
  234. }
  235. free(response);
  236. return result;
  237. }