1 #define MODULE_LOG_PREFIX "csp"
6 * Created on: 20.12.2011
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
23 #define TYPE_PINGREQ 3
24 #define TYPE_PINGRPL 4
25 #define TYPE_RESENDREQ 5
27 #define FAKE_ONID 0xFFFF
32 static void *csp_server(struct s_client
*client
__attribute__((unused
)), uchar
*mbuf
__attribute__((unused
)), int32_t n
__attribute__((unused
)))
37 static int32_t csp_send_ping(struct s_client
*cl
, uint32_t now
)
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
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
;
58 case E_FOUND
: // we have the cw
62 case E_UNHANDLED
: // request pending - not yet used?
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
; }
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);
89 memcpy(buf
+ 13, er
->cw
, sizeof(er
->cw
));
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
);
112 static uint8_t parse_request(struct ecm_request_t
*er
, uchar
*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);
124 er
->ecm
[0] = commandTag
;
130 static int32_t csp_recv(struct s_client
*client
, uchar
*buf
, int32_t l
)
133 if(!client
->udp_fd
) { return (-9); }
134 if(client
->is_udp
&& client
->typ
== 'c')
136 rs
= recv_from_udpipe(buf
); // whats this?
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
149 case TYPE_REPLY
: // request hash + reply received:
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];
160 if(chk_csp_ctab(er
, &cfg
.csp
.filter_caidtab
))
162 memcpy(er
->cw
, buf
+ 13, sizeof(er
->cw
));
163 uchar orgname
[32] = {0};
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
); }
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
); }
200 client
->last
= time((time_t *) 0);
201 uint32_t port
= b2i(4, buf
+ 9);
202 SIN_GET_PORT(client
->udp_sa
) = htons(port
);
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
);
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
;
224 case TYPE_RESENDREQ
: // sent as a result of delay alert in a remote cache
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
);
240 memcpy(er
->cw
, result
->cw
, 16);
241 er
->grp
|= result
->grp
;
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
);
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
);
256 cs_log_dbg(D_TRACE
, "unknown csp cache message received: %d", type
);
262 void module_csp(struct s_module
*ph
)
265 ph
->ptab
.ports
[0].s_port
= cfg
.csp_port
;
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
;
274 ph
->c_cache_push
= csp_cache_push_out
;