static int32_t ghttp_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf)) { uint32_t hash; s_ghttp *context = (s_ghttp *)client->ghttp; if(_is_pid_ignored(er)) { cs_debug_mask(D_CLIENT, "%s: ca context found in ignore list, ecm blocked: %x-%x-%x pid %x", client->reader->label, er->onid, er->tsid, er->srvid, er->pid); return -1; } if(!context->host_id) { context->host_id = (uchar *)cs_strdup(client->reader->device); } ll_append(context->ecm_q, er); if(ll_count(context->ecm_q) > 1) { cs_debug_mask(D_CLIENT, "%s: %d simultaneous ecms...", client->reader->label, ll_count(context->ecm_q)); } if(_is_post_context(context->post_contexts, er, false)) { _ghttp_post_ecmdata(client, er); } else { hash = javastring_hashcode(er->ecm + 3, er->ecmlen - 3); _ghttp_http_get(client, hash, er->ecm[0] == 0x81); } return 0; }
static int32_t ghttp_send_ecm(struct s_client *client, ECM_REQUEST *er, uchar *UNUSED(buf)) { uint32_t hash; // int32_t ret; s_ghttp* context = (s_ghttp*)client->ghttp; context->prev_sid = context->last_ecm.srvid; if(context->prev_sid != er->srvid) { cs_debug_mask(D_CLIENT, "%s: zap detected? prev %x, current %x", client->reader->label, context->prev_sid, er->srvid); context->do_post_next = 1; } client->reader->msg_idx = er->idx; if(context->do_post_next) { _ghttp_post_ecmdata(client, er); } else { hash = javastring_hashcode(er->ecm + 3, er->ecmlen - 3); _ghttp_http_get(client, hash, er->ecm[0] == 0x81); } context->last_ecm = *er; //struct copy return 0; }
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t UNUSED(n)) { char* data; char* lenstr; int rcode, len = 0; s_ghttp* context = (s_ghttp*)client->ghttp; ECM_REQUEST *er = &context->last_ecm; data = strstr((char*)buf, "HTTP/1.1"); if(!data) { cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response/disconnect: %s", client->reader->label, buf); network_tcp_connection_close(client->reader, "receive error or idle timeout"); return -1; } data = data + strlen("HTTP/1.1 "); rcode = atoi(data); if(rcode < 200 || rcode > 204) { cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode); data = strstr(data, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect? if(data) // we have error info string in data { lenstr = strstr((char*)buf, "Content-Length: "); if(lenstr) { lenstr = lenstr + strlen("Content-Length: "); len = atoi(lenstr); } data = strstr(data, "\r\n\r\n") + 4; if(data) { data[len] = '\0'; cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, data); } } if(rcode == 503) { context->prev_sid = 0; if(context->do_post_next) { cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label); network_tcp_connection_close(client->reader, "timeout"); return -1; } else { // on 503 timeout, switch to POST context->do_post_next = 1; cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); *rc = 0; memset(dcw, 0, 16); return -1; } } else if(rcode == 401) { cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); context->do_post_next = 1; NULLFREE(context->session_id); _ghttp_post_ecmdata(client, er); *rc = 0; memset(dcw, 0, 16); return -1; } return -1; } // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client if(context->do_post_next && context->last_ecm.srvid == context->prev_sid) { if(client->cwlastresptime > 0 && client->cwlastresptime < 800) { cs_debug_mask(D_CLIENT, "%s: prev resp time for same sid was %d ms, switching back to cache get for next req", client->reader->label, client->cwlastresptime); context->do_post_next = 0; } } data = strstr((char*)buf, "Set-Cookie: GSSID="); if(data) { data += strlen("Set-Cookie: GSSID="); NULLFREE(context->session_id); if(cs_malloc(&context->session_id, 7)) { // todo dont assume session id of length 6 strncpy((char*)context->session_id, data, 6); context->session_id[6] = '\0'; cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id); } } data = strstr((char*)buf, "Content-Length: 16"); if(data) { data = strstr((char*)buf, "\r\n\r\n"); data += 4; memcpy(dcw, data, 16); *rc = 1; char tmp_dbg[33]; cs_debug_mask(D_CLIENT, "%s: recv chk - %s", client->reader->label, cs_hexdump(0, dcw, 16, tmp_dbg, sizeof (tmp_dbg))); return client->reader->msg_idx; } else { cs_debug_mask(D_CLIENT, "%s: recv_chk fail!", client->reader->label); } return -1; }
static int32_t ghttp_recv_chk(struct s_client *client, uchar *dcw, int32_t *rc, uchar *buf, int32_t n) { char *data; char *hdrstr; uchar *content; int rcode, len, clen = 0; s_ghttp *context = (s_ghttp *)client->ghttp; ECM_REQUEST *er = NULL; if(n < 5) { return -1; } data = strstr((char *)buf, "HTTP/1.1 "); if(!data || ll_count(context->ecm_q) > 6) { cs_debug_mask(D_CLIENT, "%s: non http or otherwise corrupt response: %s", client->reader->label, buf); cs_ddump_mask(D_CLIENT, buf, n, "%s: ", client->reader->label); network_tcp_connection_close(client->reader, "receive error"); NULLFREE(context->session_id); ll_clear(context->ecm_q); return -1; } LL_ITER itr = ll_iter_create(context->ecm_q); er = (ECM_REQUEST *)ll_iter_next(&itr); rcode = _get_int_header(buf, "HTTP/1.1 "); clen = _get_int_header(buf, "Content-Length: "); content = (uchar *)(strstr(data, "\r\n\r\n") + 4); hdrstr = _get_header_substr(buf, "ETag: \"", "\"\r\n"); if(hdrstr) { NULLFREE(context->host_id); context->host_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new name: %s", client->reader->label, context->host_id); len = b64decode(context->host_id); if(len == 0 || len >= 64) { NULLFREE(context->host_id); } else { cs_debug_mask(D_CLIENT, "%s: redirected...", client->reader->label); NULLFREE(context->session_id); ll_clear_data(ghttp_ignored_contexts); ll_clear(context->ecm_q); return -1; } } hdrstr = _get_header_substr(buf, "ETag: W/\"", "\"\r\n"); if(hdrstr) { NULLFREE(context->fallback_id); context->fallback_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: new fallback name: %s", client->reader->label, context->fallback_id); len = b64decode(context->fallback_id); if(len == 0 || len >= 64) { NULLFREE(context->fallback_id); } } hdrstr = _get_header(buf, "Set-Cookie: GSSID="); if(hdrstr) { NULLFREE(context->session_id); context->session_id = (uchar *)hdrstr; cs_debug_mask(D_CLIENT, "%s: set session_id to: %s", client->reader->label, context->session_id); } // buf[n] = '\0'; // cs_ddump_mask(D_TRACE, content, clen, "%s: reply\n%s", client->reader->label, buf); if(rcode < 200 || rcode > 204) { cs_debug_mask(D_CLIENT, "%s: http error code %d", client->reader->label, rcode); data = strstr((char *)buf, "Content-Type: application/octet-stream"); // if not octet-stream, google error. need reconnect? if(data) // we have error info string in the post content { if(clen > 0) { content[clen] = '\0'; cs_debug_mask(D_CLIENT, "%s: http error message: %s", client->reader->label, content); } } if(rcode == 503) { if(er && _is_post_context(context->post_contexts, er, false)) { if(_swap_hosts(context)) { cs_debug_mask(D_CLIENT, "%s: switching to fallback", client->reader->label); } else { cs_debug_mask(D_CLIENT, "%s: recv_chk got 503 despite post, trying reconnect", client->reader->label); network_tcp_connection_close(client->reader, "reconnect"); ll_clear(context->ecm_q); } } else { // on 503 cache timeout, retry with POST immediately (and switch to POST for subsequent) if(er) { _set_pid_status(context->post_contexts, er->onid, er->tsid, er->srvid, 0); cs_debug_mask(D_CLIENT, "%s: recv_chk got 503, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } } else if(rcode == 401) { NULLFREE(context->session_id); if(er) { cs_debug_mask(D_CLIENT, "%s: session expired, trying direct post", client->reader->label); _ghttp_post_ecmdata(client, er); } } else if(rcode == 403) { client->reader->enable = 0; network_tcp_connection_close(client->reader, "login failure"); ll_clear(context->ecm_q); cs_log("%s: invalid username/password, disabling reader.", client->reader->label); } // not sure if this is needed on failure, copied from newcamd *rc = 0; memset(dcw, 0, 16); return -1; } // successful http reply (200 ok or 204 no content) hdrstr = _get_header(buf, "Pragma: context-ignore="); if(hdrstr) { if(clen > 1) { cs_ddump_mask(D_CLIENT, content, clen, "%s: pmt ignore reply - %s (%d pids)", client->reader->label, hdrstr, clen / 2); uint32_t onid = 0, tsid = 0, sid = 0; if(sscanf(hdrstr, "%4x-%4x-%4x", &onid, &tsid, &sid) == 3) { _set_pids_status(ghttp_ignored_contexts, onid, tsid, sid, content, clen); } NULLFREE(hdrstr); return -1; } NULLFREE(hdrstr); } data = strstr((char *)buf, "Pragma: context-ignore-clear"); if(data) { cs_debug_mask(D_CLIENT, "%s: clearing local ignore list (size %d)", client->reader->label, ll_count(ghttp_ignored_contexts)); ll_clear_data(ghttp_ignored_contexts); } // switch back to cache get after rapid ecm response (arbitrary atm), only effect is a slight bw save for client if(!er || _is_post_context(context->post_contexts, er, false)) { data = strstr((char *)buf, "Pragma: cached"); if(data || (client->cwlastresptime > 0 && client->cwlastresptime < 640)) { cs_debug_mask(D_CLIENT, "%s: probably cached cw (%d ms), switching back to cache get for next req", client->reader->label, client->cwlastresptime); if(er) { _is_post_context(context->post_contexts, er, true); } } } if(clen == 16) // cw in content { memcpy(dcw, content, 16); *rc = 1; er = ll_remove_first(context->ecm_q); if(!er) { return -1; } cs_ddump_mask(D_TRACE, dcw, 16, "%s: cw recv chk for idx %d", client->reader->label, er->idx); return er->idx; } else { if(clen != 0) { cs_ddump_mask(D_CLIENT, content, clen, "%s: recv_chk fail, clen = %d", client->reader->label, clen); } } return -1; }