279 lines
7.1 KiB
C
279 lines
7.1 KiB
C
#define MODULE_LOG_PREFIX "csp"
|
|
|
|
/*
|
|
* module-csp.c
|
|
*
|
|
* Created on: 20.12.2011
|
|
* Author: Corsair
|
|
*/
|
|
|
|
#include "globals.h"
|
|
|
|
#ifdef CS_CACHEEX
|
|
|
|
#include "module-cacheex.h"
|
|
#include "oscam-cache.h"
|
|
#include "oscam-ecm.h"
|
|
#include "oscam-net.h"
|
|
#include "oscam-string.h"
|
|
#include "oscam-time.h"
|
|
|
|
#define TYPE_REQUEST 1
|
|
#define TYPE_REPLY 2
|
|
#define TYPE_PINGREQ 3
|
|
#define TYPE_PINGRPL 4
|
|
#define TYPE_RESENDREQ 5
|
|
|
|
#define FAKE_ONID 0xFFFF
|
|
#define FAKE_TAG 0x80
|
|
|
|
#define PING_INTVL 4
|
|
|
|
static void *csp_server(struct s_client *client __attribute__((unused)), uint8_t *mbuf __attribute__((unused)), int32_t n __attribute__((unused)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static int32_t csp_send_ping(struct s_client *cl, uint32_t now)
|
|
{
|
|
uint8_t buf[13] = {0};
|
|
|
|
buf[0] = TYPE_PINGREQ;
|
|
i2b_buf(4, now, buf + 1);
|
|
i2b_buf(4, cfg.csp_port, buf + 9);
|
|
|
|
int32_t status = sendto(cl->udp_fd, buf, sizeof(buf), 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
|
|
|
|
cl->lastecm = time((time_t *) 0); // use this to indicate last ping sent for now
|
|
return status;
|
|
}
|
|
|
|
static int32_t csp_cache_push_out(struct s_client *cl, struct ecm_request_t *er)
|
|
{
|
|
int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
|
|
uint8_t size = 0, type;
|
|
|
|
switch(rc)
|
|
{
|
|
case E_FOUND: // we have the cw
|
|
size = 29;
|
|
type = TYPE_REPLY;
|
|
break;
|
|
case E_UNHANDLED: // request pending - not yet used?
|
|
size = 12;
|
|
type = TYPE_REQUEST;
|
|
break;
|
|
default:
|
|
return -1;
|
|
|
|
}
|
|
|
|
uint8_t *buf;
|
|
if(!cs_malloc(&buf, size)) { return -1; }
|
|
|
|
uint16_t onid = er->onid;
|
|
if(onid == 0) { onid = FAKE_ONID; }
|
|
uint8_t tag = er->ecm[0];
|
|
if(tag != 0x80 && tag != 0x81) { tag = FAKE_TAG; }
|
|
|
|
buf[0] = type;
|
|
buf[1] = tag;
|
|
i2b_buf(2, er->srvid, buf + 2);
|
|
i2b_buf(2, onid, buf + 4);
|
|
i2b_buf(2, er->caid, buf + 6);
|
|
i2b_buf(4, er->csp_hash, buf + 8);
|
|
|
|
if(rc == E_FOUND)
|
|
{
|
|
buf[12] = tag;
|
|
memcpy(buf + 13, er->cw, sizeof(er->cw));
|
|
}
|
|
|
|
struct timeb tpe;
|
|
cs_ftime(&tpe);
|
|
|
|
if(tpe.time - cl->lastecm > PING_INTVL) { csp_send_ping(cl, 1000 * tpe.time + tpe.millitm); }
|
|
|
|
cs_log_dump_dbg(D_TRACE, buf, size, "pushing cache update to csp onid=%04X caid=%04X srvid=%04X hash=%08X (tag: %02X)", onid, er->caid, er->srvid, er->csp_hash, tag);
|
|
|
|
/*
|
|
struct SOCKADDR peer_sa = {0};
|
|
SIN_GET_FAMILY(peer_sa) = SIN_GET_FAMILY(cl->udp_sa);
|
|
cs_inet_addr("127.0.0.1", &SIN_GET_ADDR(peer_sa));
|
|
SIN_GET_PORT(peer_sa) = htons(12346);
|
|
int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *)&peer_sa, sizeof(peer_sa));
|
|
*/
|
|
|
|
int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
|
|
NULLFREE(buf);
|
|
return status;
|
|
}
|
|
|
|
static uint8_t parse_request(struct ecm_request_t *er, uint8_t *buf)
|
|
{
|
|
uint8_t commandTag = buf[0]; // first ecm byte indicating odd or even (0x80 or 0x81)
|
|
uint16_t srvid = b2i(2, buf + 1);
|
|
uint16_t onid = b2i(2, buf + 3);
|
|
uint16_t caid = b2i(2, buf + 5);
|
|
uint32_t hash = b2i(4, buf + 7);
|
|
|
|
er->caid = caid;
|
|
er->onid = onid;
|
|
er->srvid = srvid;
|
|
er->csp_hash = hash;
|
|
er->ecm[0] = commandTag;
|
|
er->from_csp = 1;
|
|
|
|
return commandTag;
|
|
}
|
|
|
|
static int32_t csp_recv(struct s_client *client, uint8_t *buf, int32_t l)
|
|
{
|
|
int32_t rs = 0;
|
|
if(!client->udp_fd) { return (-9); }
|
|
if(client->is_udp && client->typ == 'c')
|
|
{
|
|
rs = recv_from_udpipe(buf); // whats this?
|
|
}
|
|
else
|
|
{
|
|
rs = cs_recv(client->udp_fd, buf, client->is_udp ? l : 36, 0);
|
|
}
|
|
//cs_log_dump_dbg(D_TRACE, buf, rs, "received %d bytes from csp", rs);
|
|
|
|
uint8_t type = buf[0]; // TYPE
|
|
|
|
switch(type)
|
|
{
|
|
|
|
case TYPE_REPLY: // request hash + reply received:
|
|
if(rs >= 29)
|
|
{
|
|
ECM_REQUEST *er = get_ecmtask();
|
|
if(!er) { return -1; }
|
|
|
|
uint8_t commandTag = parse_request(er, buf + 1);
|
|
uint8_t rplTag = buf[12];
|
|
|
|
er->rc = E_FOUND;
|
|
|
|
if(chk_csp_ctab(er, &cfg.csp.filter_caidtab))
|
|
{
|
|
memcpy(er->cw, buf + 13, sizeof(er->cw));
|
|
uint8_t orgname[32] = {0};
|
|
if(rs >= 31)
|
|
{
|
|
// origin connector name included
|
|
uint16_t namelen = (buf[29] << 8) | buf[30];
|
|
if(namelen > sizeof(orgname)) { namelen = sizeof(orgname); }
|
|
memcpy(orgname, buf + 31, namelen);
|
|
}
|
|
cs_log_dump_dbg(D_TRACE, er->cw, sizeof(er->cw), "received cw from csp onid=%04X caid=%04X srvid=%04X hash=%08X (org connector: %s, tags: %02X/%02X)", er->onid, er->caid, er->srvid, er->csp_hash, orgname, commandTag, rplTag);
|
|
cacheex_add_to_cache_from_csp(client, er);
|
|
}
|
|
else { NULLFREE(er); }
|
|
}
|
|
break;
|
|
|
|
case TYPE_REQUEST: // pending request notification hash received
|
|
if(rs == 12) // ignore requests for arbitration (csp "pre-requests", size 20)
|
|
{
|
|
ECM_REQUEST *er = get_ecmtask();
|
|
if(!er) { return -1; }
|
|
|
|
uint8_t commandTag = parse_request(er, buf + 1);
|
|
|
|
er->rc = E_UNHANDLED;
|
|
|
|
if(chk_csp_ctab(er, &cfg.csp.filter_caidtab) && cfg.csp.allow_request)
|
|
{
|
|
cs_log_dump_dbg(D_TRACE, buf, l, "received ecm request from csp onid=%04X caid=%04X srvid=%04X hash=%08X (tag: %02X)", er->onid, er->caid, er->srvid, er->csp_hash, commandTag);
|
|
cacheex_add_to_cache_from_csp(client, er);
|
|
}
|
|
else { NULLFREE(er); }
|
|
}
|
|
break;
|
|
|
|
case TYPE_PINGREQ:
|
|
if(rs >= 13)
|
|
{
|
|
client->last = time((time_t *) 0);
|
|
uint32_t port = b2i(4, buf + 9);
|
|
SIN_GET_PORT(client->udp_sa) = htons(port);
|
|
|
|
uint8_t pingrpl[9];
|
|
pingrpl[0] = TYPE_PINGRPL;
|
|
memcpy(pingrpl + 1, buf + 1, 8);
|
|
int32_t status = sendto(client->udp_fd, pingrpl, sizeof(pingrpl), 0, (struct sockaddr *) &client->udp_sa, client->udp_sa_len);
|
|
cs_log_dbg(D_TRACE, "received ping from cache peer: %s:%d (replied: %d)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port, status);
|
|
}
|
|
break;
|
|
|
|
case TYPE_PINGRPL:
|
|
if(rs >= 9)
|
|
{
|
|
struct timeb tpe;
|
|
cs_ftime(&tpe);
|
|
uint32_t ping = b2i(4, buf + 1);
|
|
uint32_t now = tpe.time * 1000 + tpe.millitm;
|
|
cs_log_dbg(D_TRACE, "received ping reply from cache peer: %s:%d (%d ms)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), ntohs(SIN_GET_PORT(client->udp_sa)), now - ping);
|
|
client->cwcacheexping = now - ping;
|
|
}
|
|
break;
|
|
|
|
case TYPE_RESENDREQ: // sent as a result of delay alert in a remote cache
|
|
if(rs >= 16)
|
|
{
|
|
uint32_t port = b2i(4, buf + 1);
|
|
ECM_REQUEST *er = get_ecmtask();
|
|
if(!er) { return -1; }
|
|
|
|
parse_request(er, buf + 5);
|
|
|
|
ECM_REQUEST *result = check_cache(er, client);
|
|
|
|
if(result)
|
|
{
|
|
|
|
er->rc = E_FOUND;
|
|
er->rcEx = 0;
|
|
memcpy(er->cw, result->cw, 16);
|
|
er->grp |= result->grp;
|
|
NULLFREE(result);
|
|
|
|
int32_t status = csp_cache_push_out(client, er);
|
|
cs_log_dbg(D_TRACE, "received resend request from cache peer: %s:%d (replied: %d)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port, status);
|
|
}
|
|
else
|
|
{
|
|
cs_log_dbg(D_TRACE, "received resend request from cache peer: %s:%d (not found)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port);
|
|
}
|
|
NULLFREE(er);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
cs_log_dbg(D_TRACE, "unknown csp cache message received: %d", type);
|
|
}
|
|
|
|
return rs;
|
|
}
|
|
|
|
void module_csp(struct s_module *ph)
|
|
{
|
|
ph->ptab.nports = 1;
|
|
ph->ptab.ports[0].s_port = cfg.csp_port;
|
|
|
|
ph->desc = "csp";
|
|
ph->type = MOD_CONN_UDP;
|
|
ph->large_ecm_support = 1;
|
|
ph->listenertype = LIS_CSPUDP;
|
|
IP_ASSIGN(ph->s_ip, cfg.csp_srvip);
|
|
ph->s_handler = csp_server;
|
|
ph->recv = csp_recv;
|
|
ph->c_cache_push = csp_cache_push_out;
|
|
ph->num = R_CSP;
|
|
}
|
|
|
|
#endif
|