184 lines
4.7 KiB
C++
184 lines
4.7 KiB
C++
#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;
|
|
}
|