1 | /*
|
---|
2 | * module-csp.c
|
---|
3 | *
|
---|
4 | * Created on: 20.12.2011
|
---|
5 | * Author: Corsair
|
---|
6 | */
|
---|
7 |
|
---|
8 | #include "globals.h"
|
---|
9 |
|
---|
10 | #ifdef CS_CACHEEX
|
---|
11 |
|
---|
12 | #include "module-cacheex.h"
|
---|
13 | #include "oscam-cache.h"
|
---|
14 | #include "oscam-ecm.h"
|
---|
15 | #include "oscam-net.h"
|
---|
16 | #include "oscam-string.h"
|
---|
17 | #include "oscam-time.h"
|
---|
18 |
|
---|
19 | #define TYPE_REQUEST 1
|
---|
20 | #define TYPE_REPLY 2
|
---|
21 | #define TYPE_PINGREQ 3
|
---|
22 | #define TYPE_PINGRPL 4
|
---|
23 | #define TYPE_RESENDREQ 5
|
---|
24 |
|
---|
25 | #define FAKE_ONID 0xFFFF
|
---|
26 | #define FAKE_TAG 0x80
|
---|
27 |
|
---|
28 | #define PING_INTVL 4
|
---|
29 |
|
---|
30 | static void *csp_server(struct s_client *client __attribute__((unused)), uchar *mbuf __attribute__((unused)), int32_t n __attribute__((unused)))
|
---|
31 | {
|
---|
32 | return NULL;
|
---|
33 | }
|
---|
34 |
|
---|
35 | static int32_t csp_send_ping(struct s_client *cl, uint32_t now)
|
---|
36 | {
|
---|
37 | uchar buf[13] = {0};
|
---|
38 |
|
---|
39 | buf[0] = TYPE_PINGREQ;
|
---|
40 | i2b_buf(4, now, buf + 1);
|
---|
41 | i2b_buf(4, cfg.csp_port, buf + 9);
|
---|
42 |
|
---|
43 | int32_t status = sendto(cl->udp_fd, buf, sizeof(buf), 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
|
---|
44 |
|
---|
45 | cl->lastecm = time((time_t *) 0); // use this to indicate last ping sent for now
|
---|
46 | return status;
|
---|
47 | }
|
---|
48 |
|
---|
49 | static int32_t csp_cache_push_out(struct s_client *cl, struct ecm_request_t *er)
|
---|
50 | {
|
---|
51 | int8_t rc = (er->rc < E_NOTFOUND) ? E_FOUND : er->rc;
|
---|
52 | uint8_t size = 0, type;
|
---|
53 |
|
---|
54 | switch(rc)
|
---|
55 | {
|
---|
56 | case E_FOUND: // we have the cw
|
---|
57 | size = 29;
|
---|
58 | type = TYPE_REPLY;
|
---|
59 | break;
|
---|
60 | case E_UNHANDLED: // request pending - not yet used?
|
---|
61 | size = 12;
|
---|
62 | type = TYPE_REQUEST;
|
---|
63 | break;
|
---|
64 | default:
|
---|
65 | return -1;
|
---|
66 |
|
---|
67 | }
|
---|
68 |
|
---|
69 | uchar *buf;
|
---|
70 | if(!cs_malloc(&buf, size)) { return -1; }
|
---|
71 |
|
---|
72 | uint16_t onid = er->onid;
|
---|
73 | if(onid == 0) { onid = FAKE_ONID; }
|
---|
74 | uint8_t tag = er->ecm[0];
|
---|
75 | if(tag != 0x80 && tag != 0x81) { tag = FAKE_TAG; }
|
---|
76 |
|
---|
77 | buf[0] = type;
|
---|
78 | buf[1] = tag;
|
---|
79 | i2b_buf(2, er->srvid, buf + 2);
|
---|
80 | i2b_buf(2, onid, buf + 4);
|
---|
81 | i2b_buf(2, er->caid, buf + 6);
|
---|
82 | i2b_buf(4, er->csp_hash, buf + 8);
|
---|
83 |
|
---|
84 | if(rc == E_FOUND)
|
---|
85 | {
|
---|
86 | buf[12] = tag;
|
---|
87 | memcpy(buf + 13, er->cw, sizeof(er->cw));
|
---|
88 | }
|
---|
89 |
|
---|
90 | struct timeb tpe;
|
---|
91 | cs_ftime(&tpe);
|
---|
92 |
|
---|
93 | if(tpe.time - cl->lastecm > PING_INTVL) { csp_send_ping(cl, 1000 * tpe.time + tpe.millitm); }
|
---|
94 |
|
---|
95 | cs_ddump_mask(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);
|
---|
96 |
|
---|
97 | /*
|
---|
98 | struct SOCKADDR peer_sa = {0};
|
---|
99 | SIN_GET_FAMILY(peer_sa) = SIN_GET_FAMILY(cl->udp_sa);
|
---|
100 | cs_inet_addr("127.0.0.1", &SIN_GET_ADDR(peer_sa));
|
---|
101 | SIN_GET_PORT(peer_sa) = htons(12346);
|
---|
102 | int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *)&peer_sa, sizeof(peer_sa));
|
---|
103 | */
|
---|
104 |
|
---|
105 | int32_t status = sendto(cl->udp_fd, buf, size, 0, (struct sockaddr *) &cl->udp_sa, cl->udp_sa_len);
|
---|
106 | NULLFREE(buf);
|
---|
107 | return status;
|
---|
108 | }
|
---|
109 |
|
---|
110 | static uint8_t parse_request(struct ecm_request_t *er, uchar *buf)
|
---|
111 | {
|
---|
112 | uint8_t commandTag = buf[0]; // first ecm byte indicating odd or even (0x80 or 0x81)
|
---|
113 | uint16_t srvid = b2i(2, buf + 1);
|
---|
114 | uint16_t onid = b2i(2, buf + 3);
|
---|
115 | uint16_t caid = b2i(2, buf + 5);
|
---|
116 | int32_t hash = b2i(4, buf + 7);
|
---|
117 |
|
---|
118 | er->caid = caid;
|
---|
119 | er->onid = onid;
|
---|
120 | er->srvid = srvid;
|
---|
121 | er->csp_hash = hash;
|
---|
122 | er->ecm[0] = commandTag;
|
---|
123 | er->from_csp = 1;
|
---|
124 |
|
---|
125 | return commandTag;
|
---|
126 | }
|
---|
127 |
|
---|
128 | static int32_t csp_recv(struct s_client *client, uchar *buf, int32_t l)
|
---|
129 | {
|
---|
130 | int32_t rs = 0;
|
---|
131 | if(!client->udp_fd) { return (-9); }
|
---|
132 | if(client->is_udp && client->typ == 'c')
|
---|
133 | {
|
---|
134 | rs = recv_from_udpipe(buf); // whats this?
|
---|
135 | }
|
---|
136 | else
|
---|
137 | {
|
---|
138 | rs = recv(client->udp_fd, buf, client->is_udp ? l : 36, 0);
|
---|
139 | }
|
---|
140 | //cs_ddump_mask(D_TRACE, buf, rs, "received %d bytes from csp", rs);
|
---|
141 |
|
---|
142 | uint8_t type = buf[0]; // TYPE
|
---|
143 |
|
---|
144 | switch(type)
|
---|
145 | {
|
---|
146 |
|
---|
147 | case TYPE_REPLY: // request hash + reply received:
|
---|
148 | if(rs >= 29)
|
---|
149 | {
|
---|
150 | ECM_REQUEST *er = get_ecmtask();
|
---|
151 | if(!er) { return -1; }
|
---|
152 |
|
---|
153 | uint8_t commandTag = parse_request(er, buf + 1);
|
---|
154 | uint8_t rplTag = buf[12];
|
---|
155 |
|
---|
156 | er->rc = E_FOUND;
|
---|
157 |
|
---|
158 | if(chk_csp_ctab(er, &cfg.csp.filter_caidtab))
|
---|
159 | {
|
---|
160 | memcpy(er->cw, buf + 13, sizeof(er->cw));
|
---|
161 | uchar orgname[32] = {0};
|
---|
162 | if(rs >= 31)
|
---|
163 | {
|
---|
164 | // origin connector name included
|
---|
165 | uint16_t namelen = (buf[29] << 8) | buf[30];
|
---|
166 | if(namelen > sizeof(orgname)) { namelen = sizeof(orgname); }
|
---|
167 | memcpy(orgname, buf + 31, namelen);
|
---|
168 | }
|
---|
169 | cs_ddump_mask(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);
|
---|
170 | cacheex_add_to_cache_from_csp(client, er);
|
---|
171 | }
|
---|
172 | else { NULLFREE(er); }
|
---|
173 | }
|
---|
174 | break;
|
---|
175 |
|
---|
176 | case TYPE_REQUEST: // pending request notification hash received
|
---|
177 | if(rs == 12) // ignore requests for arbitration (csp "pre-requests", size 20)
|
---|
178 | {
|
---|
179 | ECM_REQUEST *er = get_ecmtask();
|
---|
180 | if(!er) { return -1; }
|
---|
181 |
|
---|
182 | uint8_t commandTag = parse_request(er, buf + 1);
|
---|
183 |
|
---|
184 | er->rc = E_UNHANDLED;
|
---|
185 |
|
---|
186 | if(chk_csp_ctab(er, &cfg.csp.filter_caidtab) && cfg.csp.allow_request)
|
---|
187 | {
|
---|
188 | cs_ddump_mask(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);
|
---|
189 | cacheex_add_to_cache_from_csp(client, er);
|
---|
190 | }
|
---|
191 | else { NULLFREE(er); }
|
---|
192 | }
|
---|
193 | break;
|
---|
194 |
|
---|
195 | case TYPE_PINGREQ:
|
---|
196 | if(rs >= 13)
|
---|
197 | {
|
---|
198 | client->last = time((time_t *) 0);
|
---|
199 | uint32_t port = b2i(4, buf + 9);
|
---|
200 | SIN_GET_PORT(client->udp_sa) = htons(port);
|
---|
201 |
|
---|
202 | uchar pingrpl[9];
|
---|
203 | pingrpl[0] = TYPE_PINGRPL;
|
---|
204 | memcpy(pingrpl + 1, buf + 1, 8);
|
---|
205 | int32_t status = sendto(client->udp_fd, pingrpl, sizeof(pingrpl), 0, (struct sockaddr *) &client->udp_sa, client->udp_sa_len);
|
---|
206 | cs_debug_mask(D_TRACE, "received ping from cache peer: %s:%d (replied: %d)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port, status);
|
---|
207 | }
|
---|
208 | break;
|
---|
209 |
|
---|
210 | case TYPE_PINGRPL:
|
---|
211 | if(rs >= 9)
|
---|
212 | {
|
---|
213 | struct timeb tpe;
|
---|
214 | cs_ftime(&tpe);
|
---|
215 | uint32_t ping = b2i(4, buf + 1);
|
---|
216 | uint32_t now = tpe.time * 1000 + tpe.millitm;
|
---|
217 | cs_debug_mask(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);
|
---|
218 | client->cwcacheexping = now - ping;
|
---|
219 | }
|
---|
220 | break;
|
---|
221 |
|
---|
222 | case TYPE_RESENDREQ: // sent as a result of delay alert in a remote cache
|
---|
223 | if(rs >= 16)
|
---|
224 | {
|
---|
225 | uint32_t port = b2i(4, buf + 1);
|
---|
226 | ECM_REQUEST *er = get_ecmtask();
|
---|
227 | if(!er) { return -1; }
|
---|
228 |
|
---|
229 | parse_request(er, buf + 5);
|
---|
230 |
|
---|
231 | ECM_REQUEST *result = check_cache(er, client);
|
---|
232 |
|
---|
233 | if(result)
|
---|
234 | {
|
---|
235 |
|
---|
236 | er->rc = E_FOUND;
|
---|
237 | er->rcEx = 0;
|
---|
238 | memcpy(er->cw, result->cw, 16);
|
---|
239 | er->grp |= result->grp;
|
---|
240 | NULLFREE(result);
|
---|
241 |
|
---|
242 | int32_t status = csp_cache_push_out(client, er);
|
---|
243 | cs_debug_mask(D_TRACE, "received resend request from cache peer: %s:%d (replied: %d)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port, status);
|
---|
244 | }
|
---|
245 | else
|
---|
246 | {
|
---|
247 | cs_debug_mask(D_TRACE, "received resend request from cache peer: %s:%d (not found)", cs_inet_ntoa(SIN_GET_ADDR(client->udp_sa)), port);
|
---|
248 | }
|
---|
249 | NULLFREE(er);
|
---|
250 | }
|
---|
251 | break;
|
---|
252 |
|
---|
253 | default:
|
---|
254 | cs_debug_mask(D_TRACE, "unknown csp cache message received: %d", type);
|
---|
255 | }
|
---|
256 |
|
---|
257 | return rs;
|
---|
258 | }
|
---|
259 |
|
---|
260 | void module_csp(struct s_module *ph)
|
---|
261 | {
|
---|
262 | ph->ptab.nports = 1;
|
---|
263 | ph->ptab.ports[0].s_port = cfg.csp_port;
|
---|
264 |
|
---|
265 | ph->desc = "csp";
|
---|
266 | ph->type = MOD_CONN_UDP;
|
---|
267 | ph->large_ecm_support = 1;
|
---|
268 | ph->listenertype = LIS_CSPUDP;
|
---|
269 | IP_ASSIGN(ph->s_ip, cfg.csp_srvip);
|
---|
270 | ph->s_handler = csp_server;
|
---|
271 | ph->recv = csp_recv;
|
---|
272 | ph->c_cache_push = csp_cache_push_out;
|
---|
273 | ph->num = R_CSP;
|
---|
274 | }
|
---|
275 |
|
---|
276 | #endif
|
---|