|
- #include "rtsp-server-aio.h"
- #include "aio-socket.h"
- #include "sys/atomic.h"
- #include "sys/locker.h"
- #include "sockutil.h"
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- struct rtsp_udp_transport_t
- {
- int32_t ref;
- int running;
- socket_t socket;
- aio_socket_t aio;
-
- size_t size; // udp buffer size
-
- struct rtsp_handler_t handler;
- void* param;
- };
-
- struct rtsp_udp_session_t
- {
- struct rtsp_udp_transport_t* transport;
- struct rtsp_server_t *rtsp;
- struct sockaddr_storage addr;
- socklen_t addrlen;
- };
-
- static void rtsp_transport_udp_release(struct rtsp_udp_transport_t* t);
- static void rtsp_transport_udp_recv(struct rtsp_udp_transport_t* t);
- static void rtsp_transport_udp_onrecv(void* param, int code, size_t bytes, const struct sockaddr* addr, socklen_t addrlen);
- static int rtsp_transport_udp_send(void* param, const void* data, size_t bytes);
-
- void* rtsp_transport_udp_create(const char* ip, int port, struct rtsp_handler_t* handler, void* param)
- {
- struct rtsp_udp_transport_t* t;
- t = (struct rtsp_udp_transport_t*)calloc(1, sizeof(*t));
- if (t)
- {
- t->ref = 1;
- t->size = 4 * 1024; // 2k
- t->running = 1;
- t->param = param;
- memcpy(&t->handler, handler, sizeof(t->handler));
- handler->send = rtsp_transport_udp_send;
-
- t->socket = socket_udp_bind(0 /*AF_UNSPEC*/, ip, (u_short)port, 0, 1);
- if (socket_invalid == t->socket)
- {
- free(t);
- return NULL;
- }
-
- t->aio = aio_socket_create(t->socket, 1);
-
- rtsp_transport_udp_recv(t);
- }
-
- return t;
- }
-
- void rtsp_transport_udp_destroy(void* transport)
- {
- struct rtsp_udp_transport_t* t;
- t = (struct rtsp_udp_transport_t*)transport;
- t->running = 0;
- rtsp_transport_udp_release(t);
- }
-
- static struct rtsp_udp_session_t* rtsp_udp_session_create(struct rtsp_udp_transport_t* t)
- {
- struct rtsp_udp_session_t* session;
- session = (struct rtsp_udp_session_t*)malloc(sizeof(*session) + t->size /*udp recv buffer*/);
- if (session)
- {
- atomic_increment32(&t->ref);
- session->transport = t;
- }
- return session;
- }
-
- static void rtsp_udp_session_destroy(struct rtsp_udp_session_t* session)
- {
- struct rtsp_udp_transport_t* transport;
- transport = (struct rtsp_udp_transport_t*)session->transport;
- rtsp_transport_udp_release(transport);
-
- // TODO: reuse rtsp server
- if (session->rtsp)
- {
- rtsp_server_destroy(session->rtsp);
- session->rtsp = NULL;
- }
-
- free(session);
- }
-
- static void rtsp_transport_udp_ondestroy(void* param)
- {
- struct rtsp_udp_transport_t* t;
- t = (struct rtsp_udp_transport_t*)param;
- free(t);
- }
-
- static void rtsp_transport_udp_release(struct rtsp_udp_transport_t* t)
- {
- if (0 == atomic_decrement32(&t->ref))
- {
- assert(invalid_aio_socket != t->aio);
- aio_socket_destroy(t->aio, rtsp_transport_udp_ondestroy, t);
- }
- }
-
- static void rtsp_transport_udp_recv(struct rtsp_udp_transport_t* t)
- {
- void* buffer;
- struct rtsp_udp_session_t* session;
- session = rtsp_udp_session_create(t);
- if (session)
- {
- buffer = session + 1;
- if (!t->running || 0 != aio_socket_recvfrom(t->aio, buffer, t->size, rtsp_transport_udp_onrecv, session))
- rtsp_udp_session_destroy(session);
- }
- else
- {
- // do nothing
- }
- }
-
- static void rtsp_transport_udp_onrecv(void* param, int code, size_t bytes, const struct sockaddr* addr, socklen_t addrlen)
- {
- char ip[65];
- unsigned short port;
- struct rtsp_udp_session_t* session;
- struct rtsp_udp_transport_t* transport;
- session = (struct rtsp_udp_session_t*)param;
- transport = (struct rtsp_udp_transport_t*)session->transport;
-
- if (0 == code && bytes > 0)
- {
- size_t remain = bytes;
- rtsp_transport_udp_recv(transport); // recv more
-
- socket_addr_to(addr, addrlen, ip, &port);
- assert(addrlen <= sizeof(session->addr));
- session->addrlen = addrlen < sizeof(session->addr) ? addrlen : sizeof(session->addr);
- memcpy(&session->addr, addr, session->addrlen); // save client ip/port
- session->rtsp = rtsp_server_create(ip, port, &session->transport->handler, session->transport->param, session);
- code = rtsp_server_input(session->rtsp, session + 1, &remain);
- }
-
- if (0 != code || bytes < 1)
- {
- assert(0);
- rtsp_udp_session_destroy(session);
- }
- }
-
- static void rtsp_transport_udp_onsend(void* param, int code, size_t bytes)
- {
- struct rtsp_udp_session_t* session;
- session = (struct rtsp_udp_session_t*)param;
- // session->server->onsend(session, code, bytes);
- rtsp_udp_session_destroy(session);
- }
-
- static int rtsp_transport_udp_send(void* param, const void* data, size_t bytes)
- {
- int r;
- struct rtsp_udp_session_t* session;
- struct rtsp_udp_transport_t* transport;
- session = (struct rtsp_udp_session_t*)param;
- transport = (struct rtsp_udp_transport_t*)session->transport;
- if (transport->running)
- r = socket_sendto(transport->socket, data, bytes, 0, (struct sockaddr*)&session->addr, session->addrlen);
- else
- r = -1;
- rtsp_transport_udp_onsend(session, r, r);
- return 0;
- }
|