コード例 #1
0
ファイル: module-ghttp.c プロジェクト: StbLinux/oscam
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;
}
コード例 #2
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;
}
コード例 #3
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;
}
コード例 #4
0
ファイル: module-ghttp.c プロジェクト: StbLinux/oscam
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;
}