[gbx] - more generalized routing info in cw msg
[oscam.git] / module-csp.c
blob468b83562115020daebce7a9f5d43cf1c9367c40
1 #define MODULE_LOG_PREFIX "csp"
3 /*
4 * module-csp.c
6 * Created on: 20.12.2011
7 * Author: Corsair
8 */
10 #include "globals.h"
12 #ifdef CS_CACHEEX
14 #include "module-cacheex.h"
15 #include "oscam-cache.h"
16 #include "oscam-ecm.h"
17 #include "oscam-net.h"
18 #include "oscam-string.h"
19 #include "oscam-time.h"
21 #define TYPE_REQUEST 1
22 #define TYPE_REPLY 2
23 #define TYPE_PINGREQ 3
24 #define TYPE_PINGRPL 4
25 #define TYPE_RESENDREQ 5
27 #define FAKE_ONID 0xFFFF
28 #define FAKE_TAG 0x80
30 #define PING_INTVL 4
32 static void *csp_server(struct s_client *client __attribute__((unused)), uint8_t *mbuf __attribute__((unused)), int32_t n __attribute__((unused)))
34 return NULL;
37 static int32_t csp_send_ping(struct s_client *cl, uint32_t now)
39 uint8_t buf[13] = {0};
41 buf[0] = TYPE_PINGREQ;
42 i2b_buf(4, now, buf + 1);
43 i2b_buf(4, cfg.csp_port, buf + 9);
45 int32_t status = sendto(cl->udp_fd, buf, sizeof(buf), 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
47 cl->lastecm = time((time_t *) 0); // use this to indicate last ping sent for now
48 return status;
51 static int32_t csp_cache_push_out(struct s_client *cl, struct ecm_request_t *er)
53 int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
54 uint8_t size = 0, type;
56 switch(rc)
58 case E_FOUND: // we have the cw
59 size = 29;
60 type = TYPE_REPLY;
61 break;
62 case E_UNHANDLED: // request pending - not yet used?
63 size = 12;
64 type = TYPE_REQUEST;
65 break;
66 default:
67 return -1;
71 uint8_t *buf;
72 if(!cs_malloc(&buf, size)) { return -1; }
74 uint16_t onid = er->onid;
75 if(onid == 0) { onid = FAKE_ONID; }
76 uint8_t tag = er->ecm[0];
77 if(tag != 0x80 && tag != 0x81) { tag = FAKE_TAG; }
79 buf[0] = type;
80 buf[1] = tag;
81 i2b_buf(2, er->srvid, buf + 2);
82 i2b_buf(2, onid, buf + 4);
83 i2b_buf(2, er->caid, buf + 6);
84 i2b_buf(4, er->csp_hash, buf + 8);
86 if(rc == E_FOUND)
88 buf[12] = tag;
89 memcpy(buf + 13, er->cw, sizeof(er->cw));
92 struct timeb tpe;
93 cs_ftime(&tpe);
95 if(tpe.time - cl->lastecm > PING_INTVL) { csp_send_ping(cl, 1000 * tpe.time + tpe.millitm); }
97 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);
100 struct SOCKADDR peer_sa = {0};
101 SIN_GET_FAMILY(peer_sa) = SIN_GET_FAMILY(cl->udp_sa);
102 cs_inet_addr("127.0.0.1", &SIN_GET_ADDR(peer_sa));
103 SIN_GET_PORT(peer_sa) = htons(12346);
104 int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *)&peer_sa, sizeof(peer_sa));
107 int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
108 NULLFREE(buf);
109 return status;
112 static uint8_t parse_request(struct ecm_request_t *er, uint8_t *buf)
114 uint8_t commandTag = buf[0]; // first ecm byte indicating odd or even (0x80 or 0x81)
115 uint16_t srvid = b2i(2, buf + 1);
116 uint16_t onid = b2i(2, buf + 3);
117 uint16_t caid = b2i(2, buf + 5);
118 uint32_t hash = b2i(4, buf + 7);
120 er->caid = caid;
121 er->onid = onid;
122 er->srvid = srvid;
123 er->csp_hash = hash;
124 er->ecm[0] = commandTag;
125 er->from_csp = 1;
127 return commandTag;
130 static int32_t csp_recv(struct s_client *client, uint8_t *buf, int32_t l)
132 int32_t rs = 0;
133 if(!client->udp_fd) { return (-9); }
134 if(client->is_udp && client->typ == 'c')
136 rs = recv_from_udpipe(buf); // whats this?
138 else
140 rs = cs_recv(client->udp_fd, buf, client->is_udp ? l : 36, 0);
142 //cs_log_dump_dbg(D_TRACE, buf, rs, "received %d bytes from csp", rs);
144 uint8_t type = buf[0]; // TYPE
146 switch(type)
149 case TYPE_REPLY: // request hash + reply received:
150 if(rs >= 29)
152 ECM_REQUEST *er = get_ecmtask();
153 if(!er) { return -1; }
155 uint8_t commandTag = parse_request(er, buf + 1);
156 uint8_t rplTag = buf[12];
158 er->rc = E_FOUND;
160 if(chk_csp_ctab(er, &cfg.csp.filter_caidtab))
162 memcpy(er->cw, buf + 13, sizeof(er->cw));
163 uint8_t orgname[32] = {0};
164 if(rs >= 31)
166 // origin connector name included
167 uint16_t namelen = (buf[29] << 8) | buf[30];
168 if(namelen > sizeof(orgname)) { namelen = sizeof(orgname); }
169 memcpy(orgname, buf + 31, namelen);
171 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);
172 cacheex_add_to_cache_from_csp(client, er);
174 else { NULLFREE(er); }
176 break;
178 case TYPE_REQUEST: // pending request notification hash received
179 if(rs == 12) // ignore requests for arbitration (csp "pre-requests", size 20)
181 ECM_REQUEST *er = get_ecmtask();
182 if(!er) { return -1; }
184 uint8_t commandTag = parse_request(er, buf + 1);
186 er->rc = E_UNHANDLED;
188 if(chk_csp_ctab(er, &cfg.csp.filter_caidtab) && cfg.csp.allow_request)
190 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);
191 cacheex_add_to_cache_from_csp(client, er);
193 else { NULLFREE(er); }
195 break;
197 case TYPE_PINGREQ:
198 if(rs >= 13)
200 client->last = time((time_t *) 0);
201 uint32_t port = b2i(4, buf + 9);
202 SIN_GET_PORT(client->udp_sa) = htons(port);
204 uint8_t pingrpl[9];
205 pingrpl[0] = TYPE_PINGRPL;
206 memcpy(pingrpl + 1, buf + 1, 8);
207 int32_t status = sendto(client->udp_fd, pingrpl, sizeof(pingrpl), 0, (struct sockaddr *) &client->udp_sa, client->udp_sa_len);
208 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);
210 break;
212 case TYPE_PINGRPL:
213 if(rs >= 9)
215 struct timeb tpe;
216 cs_ftime(&tpe);
217 uint32_t ping = b2i(4, buf + 1);
218 uint32_t now = tpe.time * 1000 + tpe.millitm;
219 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);
220 client->cwcacheexping = now - ping;
222 break;
224 case TYPE_RESENDREQ: // sent as a result of delay alert in a remote cache
225 if(rs >= 16)
227 uint32_t port = b2i(4, buf + 1);
228 ECM_REQUEST *er = get_ecmtask();
229 if(!er) { return -1; }
231 parse_request(er, buf + 5);
233 ECM_REQUEST *result = check_cache(er, client);
235 if(result)
238 er->rc = E_FOUND;
239 er->rcEx = 0;
240 memcpy(er->cw, result->cw, 16);
241 er->grp |= result->grp;
242 NULLFREE(result);
244 int32_t status = csp_cache_push_out(client, er);
245 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);
247 else
249 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);
251 NULLFREE(er);
253 break;
255 default:
256 cs_log_dbg(D_TRACE, "unknown csp cache message received: %d", type);
259 return rs;
262 void module_csp(struct s_module *ph)
264 ph->ptab.nports = 1;
265 ph->ptab.ports[0].s_port = cfg.csp_port;
267 ph->desc = "csp";
268 ph->type = MOD_CONN_UDP;
269 ph->large_ecm_support = 1;
270 ph->listenertype = LIS_CSPUDP;
271 IP_ASSIGN(ph->s_ip, cfg.csp_srvip);
272 ph->s_handler = csp_server;
273 ph->recv = csp_recv;
274 ph->c_cache_push = csp_cache_push_out;
275 ph->num = R_CSP;
278 #endif