示例#1
0
static
byte isdn_rc(ADAPTER * a,
             byte Rc,
             byte Id,
             byte Ch,
             word Ref)
{
  ENTITY  * this;
  byte e_no;

#ifdef	USE_EXTENDED_DEBUGS
	{
		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
		DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
	}
#else
  DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
#endif

        /* check for ready interrupt                                */
  if(Rc==READY_INT) {
    if(a->ReadyInt) {
      a->ReadyInt--;
      return 0;
    }
    return 2;
  }

        /* if we know this Id ...                                   */
  e_no = a->IdTable[Id];
  if(e_no) {

    this = entity_ptr(a,e_no);

    this->RcCh = Ch;

        /* if it is a return code to a REMOVE request, remove the   */
        /* Id from our table                                        */
    if(this->Req==REMOVE && Rc==OK) {
      free_entity(a, e_no);
      a->IdTable[Id] = 0;
      this->Id = 0;
/**************************************************************/
      if ((this->More & XMOREC) > 1) {
        this->More &= ~XMOREC;
	this->More |= 1;
	DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
      }
    }

    if (Rc==OK_FC) {
      this->Rc = Rc;
      this->More = (this->More & (~XBUSY | XMOREC)) | 1;
      this->complete = 0xFF;
      CALLBACK(a, this);
      return 0;
    }
    if(this->More &XMOREC)
      this->More--;

        /* call the application callback function                   */
    if(this->More &XMOREF && !(this->More &XMOREC)) {
      this->Rc = Rc;
      this->More &=~XBUSY;
      this->complete=0xff;
      CALLBACK(a, this);
    }
    return 0;
  }

        /* if it's an ASSIGN return code check if it's a return     */
        /* code to an ASSIGN request from us                        */
  if((Rc &0xf0)==ASSIGN_RC) {

    e_no = get_assign(a, Ref);

    if(e_no) {

      this = entity_ptr(a,e_no);

      this->Id = Id;

        /* call the application callback function                   */
      this->Rc = Rc;
      this->More &=~XBUSY;
      this->complete=0xff;
      CALLBACK(a, this);

      if(Rc==ASSIGN_OK) {
        a->IdTable[Id] = e_no;
      }
      else
      {
        free_entity(a, e_no);
        a->IdTable[Id] = 0;
        this->Id = 0;
      }
      return 1;
    }
  }
  return 2;
}
示例#2
0
void
loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
{
	static char mallocbuf[MALLOCSZ];
	const char *var;
	int i;

	if (version < USERBOOT_VERSION)
		abort();

	callbacks = cb;
	callbacks_arg = arg;
	userboot_disk_maxunit = ndisks;

	/*
	 * initialise the heap as early as possible.  Once this is done,
	 * alloc() is usable.
	 */
	setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf)));

	/*
	 * Hook up the console
	 */
	cons_probe();

	printf("\n%s", bootprog_info);
#if 0
	printf("Memory: %ld k\n", memsize() / 1024);
#endif

	setenv("screen-#rows", "24", 1);	/* optional */

	/*
	 * Set custom environment variables
	 */
	i = 0;
	while (1) {
		var = CALLBACK(getenv, i++);
		if (var == NULL)
			break;
		putenv(var);
	}

	archsw.arch_autoload = userboot_autoload;
	archsw.arch_getdev = userboot_getdev;
	archsw.arch_copyin = userboot_copyin;
	archsw.arch_copyout = userboot_copyout;
	archsw.arch_readin = userboot_readin;
	archsw.arch_zfs_probe = userboot_zfs_probe;

	/*
	 * March through the device switch probing for things.
	 */
	for (i = 0; devsw[i] != NULL; i++)
		if (devsw[i]->dv_init != NULL)
			(devsw[i]->dv_init)();

	extract_currdev();

	if (setjmp(jb))
		return;

	interact(NULL);			/* doesn't return */

	exit(0);
}
opts_t parseargs(int *argc, char** argv[], int *isok)
{ opts_t opts={0};
  int iarg,iopt;
  unsigned char *hit=0;  // flags to indicate an argv was used in option processing
  TRY(argc && argv && isok);
  *isok=0;
  TRY(hit=(unsigned char*)alloca(*argc));
  memset(hit,0,*argc);
  ARGV=(char**)*argv;
  ARGC=*argc;
  for(iarg=1;iarg<*argc;++iarg)
  { for(iopt=0;iopt<countof(SPEC);++iopt)
    { if( SAME(argv[0][iarg],SPEC[iopt].shortname)
        ||SAME(argv[0][iarg],SPEC[iopt].longname ))
      { CALLBACK(iopt,opts);
        hit[iarg]=1;
        if(!SPEC[iopt].is_flag)
        { if(!VALIDATE(iopt,argv[0][iarg+1]))
          { LOG("\tArgument validation error.\n\tOption \"%s\" got \"%s\".\n",argv[0][iarg],argv[0][iarg+1]);
            goto Error;
          }
          if(!PARSE(iopt,opts,argv[0][iarg+1]))
          { LOG("\tArgument parse error.\n\tOption \"%s\" got \"%s\".\n",argv[0][iarg],argv[0][iarg+1]);
            goto Error;
          }
          SPEC[iopt].state.is_found=1;
          iarg++; // consumes an argument
          hit[iarg]=1;
        }
      }
    }
  }
  // apply default value for missing arguments
  for(iopt=0;iopt<countof(SPEC);++iopt)
  { if(!SPEC[iopt].is_flag && !SPEC[iopt].state.is_found)
    { if(SPEC[iopt].def) // if a default exists...
      { if(!VALIDATE(iopt,SPEC[iopt].def))
        { LOG("\tDefault argument failed to validate.\n\tOption \"%s\" got \"%s\".\n",SPEC[iopt].shortname,SPEC[iopt].def);
          goto Error;
        }
        if(!PARSE(iopt,opts,SPEC[iopt].def))
        { LOG("\tDefault argument failed to parse.\n\tOption \"%s\" got \"%s\".\n",SPEC[iopt].shortname,SPEC[iopt].def);
          goto Error;
        }
      }
    }
  }
  // fixed place argument handling and sections
#undef CALLBACK
#undef VALIDATE
#undef PARSE  
#define CALLBACK(iopt,opts)      if(ARGS[iopt].callback) ARGS[iopt].callback(&opts)
#define VALIDATE(iopt,str)       (ARGS[iopt].validate==NULL || ARGS[iopt].validate(str))
#define PARSE(iopt,opts,str)     (ARGS[iopt].parse==NULL || ARGS[iopt].parse(&opts,str))
  for(iarg=1,iopt=0;(iarg<*argc)&&(iopt<countof(ARGS));++iarg)
  { if(hit[iarg]) continue;
    if(!VALIDATE(iopt,argv[0][iarg]))
    { LOG("\tPositional argument validation error.\n\tOption <%s> got \"%s\".\n",ARGS[iopt].name,argv[0][iarg]);
      goto Error;
    }
    if(!PARSE(iopt,opts,argv[0][iarg]))
    { LOG("\tPositional argument parse error.\n\tOption <%s> got \"%s\".\n",ARGS[iopt].name,argv[0][iarg]);
      goto Error;
    }
    ARGS[iopt++].state.is_found=1;
  }
  // The specified fixed place args must be found
  // Not too worried about extra args
  for(iopt=0;iopt<countof(ARGS);++iopt)
  { if(!ARGS[iopt].state.is_found)
    { LOG("\tMissing required positional argument <%s>.\n",ARGS[iopt].name);
      goto Error;
    }
  }
  *isok=1;
  return opts;
Error:
  if(isok) *isok=0;
  usage();
  return opts;
}
示例#4
0
size_t http_parser_execute (http_parser *parser,
                            const http_parser_settings *settings,
                            const char *data,
                            size_t len)
{
  char c, ch;
  const char *p = data, *pe;
  int64_t to_read;

  enum state state = (enum state) parser->state;
  enum header_states header_state = (enum header_states) parser->header_state;
  uint64_t index = parser->index;
  uint64_t nread = parser->nread;

  if (len == 0) {
    if (state == s_body_identity_eof) {
      CALLBACK2(message_complete);
    }
    return 0;
  }

  for (p=data, pe=data+len; p != pe; p++) {
    ch = *p;

    if (PARSING_HEADER(state)) {
      ++nread;
      /* Buffer overflow attack */
      if (nread > HTTP_MAX_HEADER_SIZE) goto error;
    }

    switch (state) {

      case s_dead:
        /* this state is used after a 'Connection: close' message
         * the parser will error out if it reads another message
         */
        goto error;

      case s_start_req_or_res:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (ch == 'H')
          state = s_res_or_resp_H;
        else {
          parser->type = HTTP_REQUEST;
          goto start_req_method_assign;
        }
        break;
      }

      case s_res_or_resp_H:
        if (ch == 'T') {
          parser->type = HTTP_RESPONSE;
          state = s_res_HT;
        } else {
          if (ch != 'E') goto error;
          parser->type = HTTP_REQUEST;
          parser->method = HTTP_HEAD;
          index = 2;
          state = s_req_method;
        }
        break;

      case s_start_res:
      {
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        switch (ch) {
          case 'H':
            state = s_res_H;
            break;

          case CR:
          case LF:
            break;

          default:
            goto error;
        }
        break;
      }

      case s_res_H:
        STRICT_CHECK(ch != 'T');
        state = s_res_HT;
        break;

      case s_res_HT:
        STRICT_CHECK(ch != 'T');
        state = s_res_HTT;
        break;

      case s_res_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_res_HTTP;
        break;

      case s_res_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_res_first_http_major;
        break;

      case s_res_first_http_major:
        if (ch < '1' || ch > '9') goto error;
        parser->http_major = ch - '0';
        state = s_res_http_major;
        break;

      /* major HTTP version or dot */
      case s_res_http_major:
      {
        if (ch == '.') {
          state = s_res_first_http_minor;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) goto error;
        break;
      }

      /* first digit of minor HTTP version */
      case s_res_first_http_minor:
        if (ch < '0' || ch > '9') goto error;
        parser->http_minor = ch - '0';
        state = s_res_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_res_http_minor:
      {
        if (ch == ' ') {
          state = s_res_first_status_code;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) goto error;
        break;
      }

      case s_res_first_status_code:
      {
        if (ch < '0' || ch > '9') {
          if (ch == ' ') {
            break;
          }
          goto error;
        }
        parser->status_code = ch - '0';
        state = s_res_status_code;
        break;
      }

      case s_res_status_code:
      {
        if (ch < '0' || ch > '9') {
          switch (ch) {
            case ' ':
              state = s_res_status;
              break;
            case CR:
              state = s_res_line_almost_done;
              break;
            case LF:
              state = s_header_field_start;
              break;
            default:
              goto error;
          }
          break;
        }

        parser->status_code *= 10;
        parser->status_code += ch - '0';

        if (parser->status_code > 999) goto error;
        break;
      }

      case s_res_status:
        /* the human readable status. e.g. "NOT FOUND"
         * we are not humans so just ignore this */
        if (ch == CR) {
          state = s_res_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }
        break;

      case s_res_line_almost_done:
        STRICT_CHECK(ch != LF);
        state = s_header_field_start;
        break;

      case s_start_req:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (ch < 'A' || 'Z' < ch) goto error;

      start_req_method_assign:
        parser->method = (enum http_method) 0;
        index = 1;
        switch (ch) {
          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
          case 'D': parser->method = HTTP_DELETE; break;
          case 'G': parser->method = HTTP_GET; break;
          case 'H': parser->method = HTTP_HEAD; break;
          case 'L': parser->method = HTTP_LOCK; break;
          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
          case 'N': parser->method = HTTP_NOTIFY; break;
          case 'O': parser->method = HTTP_OPTIONS; break;
          case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break;
          case 'R': parser->method = HTTP_REPORT; break;
          case 'S': parser->method = HTTP_SUBSCRIBE; break;
          case 'T': parser->method = HTTP_TRACE; break;
          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
          default: goto error;
        }
        state = s_req_method;
        break;
      }

      case s_req_method:
      {
        if (ch == '\0')
          goto error;

        const char *matcher = method_strings[parser->method];
        if (ch == ' ' && matcher[index] == '\0') {
          state = s_req_spaces_before_url;
        } else if (ch == matcher[index]) {
          ; /* nada */
        } else if (parser->method == HTTP_CONNECT) {
          if (index == 1 && ch == 'H') {
            parser->method = HTTP_CHECKOUT;
          } else if (index == 2  && ch == 'P') {
            parser->method = HTTP_COPY;
          }
        } else if (parser->method == HTTP_MKCOL) {
          if (index == 1 && ch == 'O') {
            parser->method = HTTP_MOVE;
          } else if (index == 1 && ch == 'E') {
            parser->method = HTTP_MERGE;
          } else if (index == 1 && ch == '-') {
            parser->method = HTTP_MSEARCH;
          } else if (index == 2 && ch == 'A') {
            parser->method = HTTP_MKACTIVITY;
          }
        } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') {
          parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
        } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') {
          parser->method = HTTP_PUT;
        } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
          parser->method = HTTP_UNSUBSCRIBE;
        } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
          parser->method = HTTP_PROPPATCH;
        } else {
          goto error;
        }

        ++index;
        break;
      }
      case s_req_spaces_before_url:
      {
        if (ch == ' ') break;

        if (ch == '/' || ch == '*') {
          MARK(url);
          MARK(path);
          state = s_req_path;
          break;
        }

        c = LOWER(ch);

        if (c >= 'a' && c <= 'z') {
          MARK(url);
          MARK(schema);
          MARK(host);
          state = s_req_schema;
          break;
        }

        goto error;
      }

      case s_req_schema:
      {
        c = LOWER(ch);

        if (c >= 'a' && c <= 'z') break;

        if (ch == ':') {
          CALLBACK(schema);
          state = s_req_schema_slash;
          break;
        } else if (ch == '.') {
          state = s_req_host;
          break;
        } else if ('0' <= ch && ch <= '9') {
          state = s_req_host;
          break;
        }

        goto error;
      }

      case s_req_schema_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_schema_slash_slash;
        break;

      case s_req_schema_slash_slash:
        STRICT_CHECK(ch != '/');
        MARK(host);
        state = s_req_host;
        break;

      case s_req_host:
      {
        c = LOWER(ch);
        if (c >= 'a' && c <= 'z') break;
        if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
        switch (ch) {
          case ':':
            CALLBACK(host);
            state = s_req_colon_before_port;
            break;
          case '/':
            CALLBACK(host);
            MARK(path);
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(host);
            CALLBACK(url);
            state = s_req_http_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_colon_before_port:
      {
        if (ch >= '0' && ch <= '9') {
          MARK(port);
          state = s_req_port;
          break;
        }

        goto error;
      }

      case s_req_port:
      {
        if (ch >= '0' && ch <= '9') break;
        switch (ch) {
          case '/':
            CALLBACK(port);
            MARK(path);
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com:1234 HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(port);
            CALLBACK(url);
            state = s_req_http_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_path:
      {
        if (normal_url_char[(unsigned char)ch]) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            CALLBACK(path);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(path);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(path);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            CALLBACK(path);
            state = s_req_query_string_start;
            break;
          case '#':
            CALLBACK(path);
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_query_string_start:
      {
        if (normal_url_char[(unsigned char)ch]) {
          MARK(query_string);
          state = s_req_query_string;
          break;
        }

        switch (ch) {
          case '?':
            break; /* XXX ignore extra '?' ... is this right? */
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_query_string:
      {
        if (normal_url_char[(unsigned char)ch]) break;

        switch (ch) {
          case '?':
            /* allow extra '?' in query string */
            break;
          case ' ':
            CALLBACK(url);
            CALLBACK(query_string);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(query_string);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(query_string);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            CALLBACK(query_string);
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_fragment_start:
      {
        if (normal_url_char[(unsigned char)ch]) {
          MARK(fragment);
          state = s_req_fragment;
          break;
        }

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            MARK(fragment);
            state = s_req_fragment;
            break;
          case '#':
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_fragment:
      {
        if (normal_url_char[(unsigned char)ch]) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            CALLBACK(fragment);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(fragment);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(fragment);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
          case '#':
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_http_start:
        switch (ch) {
          case 'H':
            state = s_req_http_H;
            break;
          case ' ':
            break;
          default:
            goto error;
        }
        break;

      case s_req_http_H:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HT;
        break;

      case s_req_http_HT:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HTT;
        break;

      case s_req_http_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_req_http_HTTP;
        break;

      case s_req_http_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_req_first_http_major;
        break;

      /* first digit of major HTTP version */
      case s_req_first_http_major:
        if (ch < '1' || ch > '9') goto error;
        parser->http_major = ch - '0';
        state = s_req_http_major;
        break;

      /* major HTTP version or dot */
      case s_req_http_major:
      {
        if (ch == '.') {
          state = s_req_first_http_minor;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) goto error;
        break;
      }

      /* first digit of minor HTTP version */
      case s_req_first_http_minor:
        if (ch < '0' || ch > '9') goto error;
        parser->http_minor = ch - '0';
        state = s_req_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_req_http_minor:
      {
        if (ch == CR) {
          state = s_req_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }

        /* XXX allow spaces after digit? */

        if (ch < '0' || ch > '9') goto error;

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) goto error;
        break;
      }

      /* end of request line */
      case s_req_line_almost_done:
      {
        if (ch != LF) goto error;
        state = s_header_field_start;
        break;
      }

      case s_header_field_start:
      {
        if (ch == CR) {
          state = s_headers_almost_done;
          break;
        }

        if (ch == LF) {
          /* they might be just sending \n instead of \r\n so this would be
           * the second \n to denote the end of headers*/
          state = s_headers_almost_done;
          goto headers_almost_done;
        }

        c = TOKEN(ch);

        if (!c) goto error;

        MARK(header_field);

        index = 0;
        state = s_header_field;

        switch (c) {
          case 'c':
            header_state = h_C;
            break;

          case 'p':
            header_state = h_matching_proxy_connection;
            break;

          case 't':
            header_state = h_matching_transfer_encoding;
            break;

          case 'u':
            header_state = h_matching_upgrade;
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_field:
      {
        c = TOKEN(ch);

        if (c) {
          switch (header_state) {
            case h_general:
              break;

            case h_C:
              index++;
              header_state = (c == 'o' ? h_CO : h_general);
              break;

            case h_CO:
              index++;
              header_state = (c == 'n' ? h_CON : h_general);
              break;

            case h_CON:
              index++;
              switch (c) {
                case 'n':
                  header_state = h_matching_connection;
                  break;
                case 't':
                  header_state = h_matching_content_length;
                  break;
                default:
                  header_state = h_general;
                  break;
              }
              break;

            /* connection */

            case h_matching_connection:
              index++;
              if (index > sizeof(CONNECTION)-1
                  || c != CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* proxy-connection */

            case h_matching_proxy_connection:
              index++;
              if (index > sizeof(PROXY_CONNECTION)-1
                  || c != PROXY_CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(PROXY_CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* content-length */

            case h_matching_content_length:
              index++;
              if (index > sizeof(CONTENT_LENGTH)-1
                  || c != CONTENT_LENGTH[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONTENT_LENGTH)-2) {
                header_state = h_content_length;
              }
              break;

            /* transfer-encoding */

            case h_matching_transfer_encoding:
              index++;
              if (index > sizeof(TRANSFER_ENCODING)-1
                  || c != TRANSFER_ENCODING[index]) {
                header_state = h_general;
              } else if (index == sizeof(TRANSFER_ENCODING)-2) {
                header_state = h_transfer_encoding;
              }
              break;

            /* upgrade */

            case h_matching_upgrade:
              index++;
              if (index > sizeof(UPGRADE)-1
                  || c != UPGRADE[index]) {
                header_state = h_general;
              } else if (index == sizeof(UPGRADE)-2) {
                header_state = h_upgrade;
              }
              break;

            case h_connection:
            case h_content_length:
            case h_transfer_encoding:
            case h_upgrade:
              if (ch != ' ') header_state = h_general;
              break;

            default:
              assert(0 && "Unknown header_state");
              break;
          }
          break;
        }

        if (ch == ':') {
          CALLBACK(header_field);
          state = s_header_value_start;
          break;
        }

        if (ch == CR) {
          state = s_header_almost_done;
          CALLBACK(header_field);
          break;
        }

        if (ch == LF) {
          CALLBACK(header_field);
          state = s_header_field_start;
          break;
        }

        goto error;
      }

      case s_header_value_start:
      {
        if (ch == ' ') break;

        MARK(header_value);

        state = s_header_value;
        index = 0;

        c = LOWER(ch);

        if (ch == CR) {
          CALLBACK(header_value);
          header_state = h_general;
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          state = s_header_field_start;
          break;
        }

        switch (header_state) {
          case h_upgrade:
            parser->flags |= F_UPGRADE;
            header_state = h_general;
            break;

          case h_transfer_encoding:
            /* looking for 'Transfer-Encoding: chunked' */
            if ('c' == c) {
              header_state = h_matching_transfer_encoding_chunked;
            } else {
              header_state = h_general;
            }
            break;

          case h_content_length:
            if (ch < '0' || ch > '9') goto error;
            parser->content_length = ch - '0';
            break;

          case h_connection:
            /* looking for 'Connection: keep-alive' */
            if (c == 'k') {
              header_state = h_matching_connection_keep_alive;
            /* looking for 'Connection: close' */
            } else if (c == 'c') {
              header_state = h_matching_connection_close;
            } else {
              header_state = h_general;
            }
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_value:
      {
        c = LOWER(ch);

        if (ch == CR) {
          CALLBACK(header_value);
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          goto header_almost_done;
        }

        switch (header_state) {
          case h_general:
            break;

          case h_connection:
          case h_transfer_encoding:
            assert(0 && "Shouldn't get here.");
            break;

          case h_content_length:
            if (ch == ' ') break;
            if (ch < '0' || ch > '9') goto error;
            parser->content_length *= 10;
            parser->content_length += ch - '0';
            break;

          /* Transfer-Encoding: chunked */
          case h_matching_transfer_encoding_chunked:
            index++;
            if (index > sizeof(CHUNKED)-1
                || c != CHUNKED[index]) {
              header_state = h_general;
            } else if (index == sizeof(CHUNKED)-2) {
              header_state = h_transfer_encoding_chunked;
            }
            break;

          /* looking for 'Connection: keep-alive' */
          case h_matching_connection_keep_alive:
            index++;
            if (index > sizeof(KEEP_ALIVE)-1
                || c != KEEP_ALIVE[index]) {
              header_state = h_general;
            } else if (index == sizeof(KEEP_ALIVE)-2) {
              header_state = h_connection_keep_alive;
            }
            break;

          /* looking for 'Connection: close' */
          case h_matching_connection_close:
            index++;
            if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
              header_state = h_general;
            } else if (index == sizeof(CLOSE)-2) {
              header_state = h_connection_close;
            }
            break;

          case h_transfer_encoding_chunked:
          case h_connection_keep_alive:
          case h_connection_close:
            if (ch != ' ') header_state = h_general;
            break;

          default:
            state = s_header_value;
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_almost_done:
      header_almost_done:
      {
        STRICT_CHECK(ch != LF);

        state = s_header_field_start;

        switch (header_state) {
          case h_connection_keep_alive:
            parser->flags |= F_CONNECTION_KEEP_ALIVE;
            break;
          case h_connection_close:
            parser->flags |= F_CONNECTION_CLOSE;
            break;
          case h_transfer_encoding_chunked:
            parser->flags |= F_CHUNKED;
            break;
          default:
            break;
        }
        break;
      }

      case s_headers_almost_done:
      headers_almost_done:
      {
        STRICT_CHECK(ch != LF);

        if (parser->flags & F_TRAILING) {
          /* End of a chunked request */
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
          break;
        }

        nread = 0;

        if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
          parser->upgrade = 1;
        }

        /* Here we call the headers_complete callback. This is somewhat
         * different than other callbacks because if the user returns 1, we
         * will interpret that as saying that this message has no body. This
         * is needed for the annoying case of recieving a response to a HEAD
         * request.
         */
        if (settings->on_headers_complete) {
          switch (settings->on_headers_complete(parser)) {
            case 0:
              break;

            case 1:
              parser->flags |= F_SKIPBODY;
              break;

            default:
              return p - data; /* Error */
          }
        }

        /* Exit, the rest of the connect is in a different protocol. */
        if (parser->upgrade) {
          CALLBACK2(message_complete);
          return (p - data);
        }

        if (parser->flags & F_SKIPBODY) {
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
        } else if (parser->flags & F_CHUNKED) {
          /* chunked encoding - ignore Content-Length header */
          state = s_chunk_size_start;
        } else {
          if (parser->content_length == 0) {
            /* Content-Length header given but zero: Content-Length: 0\r\n */
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          } else if (parser->content_length > 0) {
            /* Content-Length header given and non-zero */
            state = s_body_identity;
          } else {
            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
              /* Assume content-length 0 - read the next */
              CALLBACK2(message_complete);
              state = NEW_MESSAGE();
            } else {
              /* Read body until EOF */
              state = s_body_identity_eof;
            }
          }
        }

        break;
      }

      case s_body_identity:
        to_read = MIN(pe - p, (int64_t)parser->content_length);
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
          parser->content_length -= to_read;
          if (parser->content_length == 0) {
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          }
        }
        break;

      /* read until EOF */
      case s_body_identity_eof:
        to_read = pe - p;
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }
        break;

      case s_chunk_size_start:
      {
        assert(parser->flags & F_CHUNKED);

        c = unhex[(unsigned char)ch];
        if (c == -1) goto error;
        parser->content_length = c;
        state = s_chunk_size;
        break;
      }

      case s_chunk_size:
      {
        assert(parser->flags & F_CHUNKED);

        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }

        c = unhex[(unsigned char)ch];

        if (c == -1) {
          if (ch == ';' || ch == ' ') {
            state = s_chunk_parameters;
            break;
          }
          goto error;
        }

        parser->content_length *= 16;
        parser->content_length += c;
        break;
      }

      case s_chunk_parameters:
      {
        assert(parser->flags & F_CHUNKED);
        /* just ignore this shit. TODO check for overflow */
        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }
        break;
      }

      case s_chunk_size_almost_done:
      {
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);

        if (parser->content_length == 0) {
          parser->flags |= F_TRAILING;
          state = s_header_field_start;
        } else {
          state = s_chunk_data;
        }
        break;
      }

      case s_chunk_data:
      {
        assert(parser->flags & F_CHUNKED);

        to_read = MIN(pe - p, (int64_t)(parser->content_length));

        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }

        if (to_read == parser->content_length) {
          state = s_chunk_data_almost_done;
        }

        parser->content_length -= to_read;
        break;
      }

      case s_chunk_data_almost_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != CR);
        state = s_chunk_data_done;
        break;

      case s_chunk_data_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);
        state = s_chunk_size_start;
        break;

      default:
        assert(0 && "unhandled state");
        goto error;
    }
  }

  parser->state = state;
  parser->header_state = header_state;
  parser->index = index;
  parser->nread = nread;

  return len;

error:
  parser->state = s_dead;
  return (p - data);
}
示例#5
0
void cover_avail_callback(const char *fname, const char *artist, const char *album, void *user_data) {
    char *image_fname = COVERART->get_album_art(fname, artist, album, -1, CALLBACK(&cover_avail_callback), NULL);
    if (image_fname) {
        CoverArtWrapper::Instance()->openAndScaleCover(image_fname);
    }
}
示例#6
0
文件: host.c 项目: 2asoft/freebsd
static off_t
host_seek(struct open_file *f, off_t offset, int where)
{

	return (CALLBACK(seek, f->f_fsdata, offset, where));
}
示例#7
0
size_t http_parser_execute (http_parser *parser,
                            const http_parser_settings *settings,
                            const char *data,
                            size_t len)
{
  char c, ch;
  int8_t unhex_val;
  const char *p = data, *pe;
  int64_t to_read;
  enum state state;
  enum header_states header_state;
  uint64_t index = parser->index;
  uint64_t nread = parser->nread;

  /* technically we could combine all of these (except for url_mark) into one
     variable, saving stack space, but it seems more clear to have them
     separated. */
  const char *header_field_mark = 0;
  const char *header_value_mark = 0;
  const char *url_mark = 0;

  /* We're in an error state. Don't bother doing anything. */
  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
    return 0;
  }

  state = (enum state) parser->state;
  header_state = (enum header_states) parser->header_state;

  if (len == 0) {
    switch (state) {
      case s_body_identity_eof:
        CALLBACK2(message_complete);
        return 0;

      case s_dead:
      case s_start_req_or_res:
      case s_start_res:
      case s_start_req:
        return 0;

      default:
        SET_ERRNO(HPE_INVALID_EOF_STATE);
        return 1;
    }
  }


  if (state == s_header_field)
    header_field_mark = data;
  if (state == s_header_value)
    header_value_mark = data;
  if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
      || state == s_req_schema_slash_slash || state == s_req_port
      || state == s_req_query_string_start || state == s_req_query_string
      || state == s_req_host
      || state == s_req_fragment_start || state == s_req_fragment)
    url_mark = data;

  for (p=data, pe=data+len; p != pe; p++) {
    ch = *p;

    if (PARSING_HEADER(state)) {
      ++nread;
      /* Buffer overflow attack */
      if (nread > HTTP_MAX_HEADER_SIZE) {
        SET_ERRNO(HPE_HEADER_OVERFLOW);
        goto error;
      }
    }

    switch (state) {

      case s_dead:
        /* this state is used after a 'Connection: close' message
         * the parser will error out if it reads another message
         */
        SET_ERRNO(HPE_CLOSED_CONNECTION);
        goto error;

      case s_start_req_or_res:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (ch == 'H')
          state = s_res_or_resp_H;
        else {
          parser->type = HTTP_REQUEST;
          goto start_req_method_assign;
        }
        break;
      }

      case s_res_or_resp_H:
        if (ch == 'T') {
          parser->type = HTTP_RESPONSE;
          state = s_res_HT;
        } else {
          if (ch != 'E') {
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
          }

          parser->type = HTTP_REQUEST;
          parser->method = HTTP_HEAD;
          index = 2;
          state = s_req_method;
        }
        break;

      case s_start_res:
      {
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        switch (ch) {
          case 'H':
            state = s_res_H;
            break;

          case CR:
          case LF:
            break;

          default:
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
        }
        break;
      }

      case s_res_H:
        STRICT_CHECK(ch != 'T');
        state = s_res_HT;
        break;

      case s_res_HT:
        STRICT_CHECK(ch != 'T');
        state = s_res_HTT;
        break;

      case s_res_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_res_HTTP;
        break;

      case s_res_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_res_first_http_major;
        break;

      case s_res_first_http_major:
        if (ch < '0' || ch > '9') {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major = ch - '0';
        state = s_res_http_major;
        break;

      /* major HTTP version or dot */
      case s_res_http_major:
      {
        if (ch == '.') {
          state = s_res_first_http_minor;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* first digit of minor HTTP version */
      case s_res_first_http_minor:
        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor = ch - '0';
        state = s_res_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_res_http_minor:
      {
        if (ch == ' ') {
          state = s_res_first_status_code;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      case s_res_first_status_code:
      {
        if (!IS_NUM(ch)) {
          if (ch == ' ') {
            break;
          }

          SET_ERRNO(HPE_INVALID_STATUS);
          goto error;
        }
        parser->status_code = ch - '0';
        state = s_res_status_code;
        break;
      }

      case s_res_status_code:
      {
        if (!IS_NUM(ch)) {
          switch (ch) {
            case ' ':
              state = s_res_status;
              break;
            case CR:
              state = s_res_line_almost_done;
              break;
            case LF:
              state = s_header_field_start;
              break;
            default:
              SET_ERRNO(HPE_INVALID_STATUS);
              goto error;
          }
          break;
        }

        parser->status_code *= 10;
        parser->status_code += ch - '0';

        if (parser->status_code > 999) {
          SET_ERRNO(HPE_INVALID_STATUS);
          goto error;
        }

        break;
      }

      case s_res_status:
        /* the human readable status. e.g. "NOT FOUND"
         * we are not humans so just ignore this */
        if (ch == CR) {
          state = s_res_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }
        break;

      case s_res_line_almost_done:
        STRICT_CHECK(ch != LF);
        state = s_header_field_start;
        break;

      case s_start_req:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (!IS_ALPHA(ch)) {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

      start_req_method_assign:
        parser->method = (enum http_method) 0;
        index = 1;
        switch (ch) {
          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
          case 'D': parser->method = HTTP_DELETE; break;
          case 'G': parser->method = HTTP_GET; break;
          case 'H': parser->method = HTTP_HEAD; break;
          case 'L': parser->method = HTTP_LOCK; break;
          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
          case 'N': parser->method = HTTP_NOTIFY; break;
          case 'O': parser->method = HTTP_OPTIONS; break;
          case 'P': parser->method = HTTP_POST;
            /* or PROPFIND or PROPPATCH or PUT or PATCH */
            break;
          case 'R': parser->method = HTTP_REPORT; break;
          case 'S': parser->method = HTTP_SUBSCRIBE; break;
          case 'T': parser->method = HTTP_TRACE; break;
          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
          default:
            SET_ERRNO(HPE_INVALID_METHOD);
            goto error;
        }
        state = s_req_method;
        break;
      }

      case s_req_method:
      {
        const char *matcher;
        if (ch == '\0') {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

        matcher = method_strings[parser->method];
        if (ch == ' ' && matcher[index] == '\0') {
          state = s_req_spaces_before_url;
        } else if (ch == matcher[index]) {
          ; /* nada */
        } else if (parser->method == HTTP_CONNECT) {
          if (index == 1 && ch == 'H') {
            parser->method = HTTP_CHECKOUT;
          } else if (index == 2  && ch == 'P') {
            parser->method = HTTP_COPY;
          } else {
            goto error;
          }
        } else if (parser->method == HTTP_MKCOL) {
          if (index == 1 && ch == 'O') {
            parser->method = HTTP_MOVE;
          } else if (index == 1 && ch == 'E') {
            parser->method = HTTP_MERGE;
          } else if (index == 1 && ch == '-') {
            parser->method = HTTP_MSEARCH;
          } else if (index == 2 && ch == 'A') {
            parser->method = HTTP_MKACTIVITY;
          } else {
            goto error;
          }
        } else if (index == 1 && parser->method == HTTP_POST) {
          if (ch == 'R') {
            parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
          } else if (ch == 'U') {
            parser->method = HTTP_PUT;
          } else if (ch == 'A') {
            parser->method = HTTP_PATCH;
          } else {
            goto error;
          }
        } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
          parser->method = HTTP_UNSUBSCRIBE;
        } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
          parser->method = HTTP_PROPPATCH;
        } else {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

        ++index;
        break;
      }
      case s_req_spaces_before_url:
      {
        if (ch == ' ') break;

        if (ch == '/' || ch == '*') {
          MARK(url);
          state = s_req_path;
          break;
        }

        /* Proxied requests are followed by scheme of an absolute URI (alpha).
         * CONNECT is followed by a hostname, which begins with alphanum.
         * All other methods are followed by '/' or '*' (handled above).
         */
        if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) {
          MARK(url);
          state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema;
          break;
        }

        SET_ERRNO(HPE_INVALID_URL);
        goto error;
      }

      case s_req_schema:
      {
        if (IS_ALPHA(ch)) break;

        if (ch == ':') {
          state = s_req_schema_slash;
          break;
        }

        SET_ERRNO(HPE_INVALID_URL);
        goto error;
      }

      case s_req_schema_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_schema_slash_slash;
        break;

      case s_req_schema_slash_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_host;
        break;

      case s_req_host:
      {
        if (IS_HOST_CHAR(ch)) break;
        switch (ch) {
          case ':':
            state = s_req_port;
            break;
          case '/':
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_HOST);
            goto error;
        }
        break;
      }

      case s_req_port:
      {
        if (IS_NUM(ch)) break;
        switch (ch) {
          case '/':
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com:1234 HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_PORT);
            goto error;
        }
        break;
      }

      case s_req_path:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_PATH);
            goto error;
        }
        break;
      }

      case s_req_query_string_start:
      {
        if (IS_URL_CHAR(ch)) {
          state = s_req_query_string;
          break;
        }

        switch (ch) {
          case '?':
            break; /* XXX ignore extra '?' ... is this right? */
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_QUERY_STRING);
            goto error;
        }
        break;
      }

      case s_req_query_string:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case '?':
            /* allow extra '?' in query string */
            break;
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_QUERY_STRING);
            goto error;
        }
        break;
      }

      case s_req_fragment_start:
      {
        if (IS_URL_CHAR(ch)) {
          state = s_req_fragment;
          break;
        }

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            state = s_req_fragment;
            break;
          case '#':
            break;
          default:
            SET_ERRNO(HPE_INVALID_FRAGMENT);
            goto error;
        }
        break;
      }

      case s_req_fragment:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
          case '#':
            break;
          default:
            SET_ERRNO(HPE_INVALID_FRAGMENT);
            goto error;
        }
        break;
      }

      case s_req_http_start:
        switch (ch) {
          case 'H':
            state = s_req_http_H;
            break;
          case ' ':
            break;
          default:
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
        }
        break;

      case s_req_http_H:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HT;
        break;

      case s_req_http_HT:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HTT;
        break;

      case s_req_http_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_req_http_HTTP;
        break;

      case s_req_http_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_req_first_http_major;
        break;

      /* first digit of major HTTP version */
      case s_req_first_http_major:
        if (ch < '1' || ch > '9') {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major = ch - '0';
        state = s_req_http_major;
        break;

      /* major HTTP version or dot */
      case s_req_http_major:
      {
        if (ch == '.') {
          state = s_req_first_http_minor;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* first digit of minor HTTP version */
      case s_req_first_http_minor:
        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor = ch - '0';
        state = s_req_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_req_http_minor:
      {
        if (ch == CR) {
          state = s_req_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }

        /* XXX allow spaces after digit? */

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* end of request line */
      case s_req_line_almost_done:
      {
        if (ch != LF) {
          SET_ERRNO(HPE_LF_EXPECTED);
          goto error;
        }

        state = s_header_field_start;
        break;
      }

      case s_header_field_start:
      header_field_start:
      {
        if (ch == CR) {
          state = s_headers_almost_done;
          break;
        }

        if (ch == LF) {
          /* they might be just sending \n instead of \r\n so this would be
           * the second \n to denote the end of headers*/
          state = s_headers_almost_done;
          goto headers_almost_done;
        }

        c = TOKEN(ch);

        if (!c) {
          SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
          goto error;
        }

        MARK(header_field);

        index = 0;
        state = s_header_field;

        switch (c) {
          case 'c':
            header_state = h_C;
            break;

          case 'p':
            header_state = h_matching_proxy_connection;
            break;

          case 't':
            header_state = h_matching_transfer_encoding;
            break;

          case 'u':
            header_state = h_matching_upgrade;
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_field:
      {
        c = TOKEN(ch);

        if (c) {
          switch (header_state) {
            case h_general:
              break;

            case h_C:
              index++;
              header_state = (c == 'o' ? h_CO : h_general);
              break;

            case h_CO:
              index++;
              header_state = (c == 'n' ? h_CON : h_general);
              break;

            case h_CON:
              index++;
              switch (c) {
                case 'n':
                  header_state = h_matching_connection;
                  break;
                case 't':
                  header_state = h_matching_content_length;
                  break;
                default:
                  header_state = h_general;
                  break;
              }
              break;

            /* connection */

            case h_matching_connection:
              index++;
              if (index > sizeof(CONNECTION)-1
                  || c != CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* proxy-connection */

            case h_matching_proxy_connection:
              index++;
              if (index > sizeof(PROXY_CONNECTION)-1
                  || c != PROXY_CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(PROXY_CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* content-length */

            case h_matching_content_length:
              index++;
              if (index > sizeof(CONTENT_LENGTH)-1
                  || c != CONTENT_LENGTH[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONTENT_LENGTH)-2) {
                header_state = h_content_length;
              }
              break;

            /* transfer-encoding */

            case h_matching_transfer_encoding:
              index++;
              if (index > sizeof(TRANSFER_ENCODING)-1
                  || c != TRANSFER_ENCODING[index]) {
                header_state = h_general;
              } else if (index == sizeof(TRANSFER_ENCODING)-2) {
                header_state = h_transfer_encoding;
              }
              break;

            /* upgrade */

            case h_matching_upgrade:
              index++;
              if (index > sizeof(UPGRADE)-1
                  || c != UPGRADE[index]) {
                header_state = h_general;
              } else if (index == sizeof(UPGRADE)-2) {
                header_state = h_upgrade;
              }
              break;

            case h_connection:
            case h_content_length:
            case h_transfer_encoding:
            case h_upgrade:
              if (ch != ' ') header_state = h_general;
              break;

            default:
              assert(0 && "Unknown header_state");
              break;
          }
          break;
        }

        if (ch == ':') {
          CALLBACK(header_field);
          state = s_header_value_start;
          break;
        }

        if (ch == CR) {
          state = s_header_almost_done;
          CALLBACK(header_field);
          break;
        }

        if (ch == LF) {
          CALLBACK(header_field);
          state = s_header_field_start;
          break;
        }

        SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
        goto error;
      }

      case s_header_value_start:
      {
        if (ch == ' ' || ch == '\t') break;

        MARK(header_value);

        state = s_header_value;
        index = 0;

        if (ch == CR) {
          CALLBACK(header_value);
          header_state = h_general;
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          state = s_header_field_start;
          break;
        }

        c = LOWER(ch);

        switch (header_state) {
          case h_upgrade:
            parser->flags |= F_UPGRADE;
            header_state = h_general;
            break;

          case h_transfer_encoding:
            /* looking for 'Transfer-Encoding: chunked' */
            if ('c' == c) {
              header_state = h_matching_transfer_encoding_chunked;
            } else {
              header_state = h_general;
            }
            break;

          case h_content_length:
            if (!IS_NUM(ch)) {
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
              goto error;
            }

            parser->content_length = ch - '0';
            break;

          case h_connection:
            /* looking for 'Connection: keep-alive' */
            if (c == 'k') {
              header_state = h_matching_connection_keep_alive;
            /* looking for 'Connection: close' */
            } else if (c == 'c') {
              header_state = h_matching_connection_close;
            } else {
              header_state = h_general;
            }
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_value:
      {

        if (ch == CR) {
          CALLBACK(header_value);
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          goto header_almost_done;
        }

        c = LOWER(ch);

        switch (header_state) {
          case h_general:
            break;

          case h_connection:
          case h_transfer_encoding:
            assert(0 && "Shouldn't get here.");
            break;

          case h_content_length:
            if (ch == ' ') break;
            if (!IS_NUM(ch)) {
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
              goto error;
            }

            parser->content_length *= 10;
            parser->content_length += ch - '0';
            break;

          /* Transfer-Encoding: chunked */
          case h_matching_transfer_encoding_chunked:
            index++;
            if (index > sizeof(CHUNKED)-1
                || c != CHUNKED[index]) {
              header_state = h_general;
            } else if (index == sizeof(CHUNKED)-2) {
              header_state = h_transfer_encoding_chunked;
            }
            break;

          /* looking for 'Connection: keep-alive' */
          case h_matching_connection_keep_alive:
            index++;
            if (index > sizeof(KEEP_ALIVE)-1
                || c != KEEP_ALIVE[index]) {
              header_state = h_general;
            } else if (index == sizeof(KEEP_ALIVE)-2) {
              header_state = h_connection_keep_alive;
            }
            break;

          /* looking for 'Connection: close' */
          case h_matching_connection_close:
            index++;
            if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
              header_state = h_general;
            } else if (index == sizeof(CLOSE)-2) {
              header_state = h_connection_close;
            }
            break;

          case h_transfer_encoding_chunked:
          case h_connection_keep_alive:
          case h_connection_close:
            if (ch != ' ') header_state = h_general;
            break;

          default:
            state = s_header_value;
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_almost_done:
      header_almost_done:
      {
        STRICT_CHECK(ch != LF);

        state = s_header_value_lws;

        switch (header_state) {
          case h_connection_keep_alive:
            parser->flags |= F_CONNECTION_KEEP_ALIVE;
            break;
          case h_connection_close:
            parser->flags |= F_CONNECTION_CLOSE;
            break;
          case h_transfer_encoding_chunked:
            parser->flags |= F_CHUNKED;
            break;
          default:
            break;
        }
        break;
      }

      case s_header_value_lws:
      {
        if (ch == ' ' || ch == '\t')
          state = s_header_value_start;
        else
        {
          state = s_header_field_start;
          goto header_field_start;
        }
        break;
      }

      case s_headers_almost_done:
      headers_almost_done:
      {
        STRICT_CHECK(ch != LF);

        if (parser->flags & F_TRAILING) {
          /* End of a chunked request */
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
          break;
        }

        nread = 0;

        if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
          parser->upgrade = 1;
        }

        /* Here we call the headers_complete callback. This is somewhat
         * different than other callbacks because if the user returns 1, we
         * will interpret that as saying that this message has no body. This
         * is needed for the annoying case of recieving a response to a HEAD
         * request.
         */
        if (settings->on_headers_complete) {
          switch (settings->on_headers_complete(parser)) {
            case 0:
              break;

            case 1:
              parser->flags |= F_SKIPBODY;
              break;

            default:
              parser->state = state;
              SET_ERRNO(HPE_CB_headers_complete);
              return p - data; /* Error */
          }
        }

        /* Exit, the rest of the connect is in a different protocol. */
        if (parser->upgrade) {
          CALLBACK2(message_complete);
          return (p - data) + 1;
        }

        if (parser->flags & F_SKIPBODY) {
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
        } else if (parser->flags & F_CHUNKED) {
          /* chunked encoding - ignore Content-Length header */
          state = s_chunk_size_start;
        } else {
          if (parser->content_length == 0) {
            /* Content-Length header given but zero: Content-Length: 0\r\n */
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          } else if (parser->content_length > 0) {
            /* Content-Length header given and non-zero */
            state = s_body_identity;
          } else {
            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
              /* Assume content-length 0 - read the next */
              CALLBACK2(message_complete);
              state = NEW_MESSAGE();
            } else {
              /* Read body until EOF */
              state = s_body_identity_eof;
            }
          }
        }

        break;
      }

      case s_body_identity:
        to_read = MIN(pe - p, (int64_t)parser->content_length);
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
          parser->content_length -= to_read;
          if (parser->content_length == 0) {
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          }
        }
        break;

      /* read until EOF */
      case s_body_identity_eof:
        to_read = pe - p;
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }
        break;

      case s_chunk_size_start:
      {
        assert(nread == 1);
        assert(parser->flags & F_CHUNKED);

        unhex_val = unhex[(unsigned char)ch];
        if (unhex_val == -1) {
          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
          goto error;
        }

        parser->content_length = unhex_val;
        state = s_chunk_size;
        break;
      }

      case s_chunk_size:
      {
        assert(parser->flags & F_CHUNKED);

        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }

        unhex_val = unhex[(unsigned char)ch];

        if (unhex_val == -1) {
          if (ch == ';' || ch == ' ') {
            state = s_chunk_parameters;
            break;
          }

          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
          goto error;
        }

        parser->content_length *= 16;
        parser->content_length += unhex_val;
        break;
      }

      case s_chunk_parameters:
      {
        assert(parser->flags & F_CHUNKED);
        /* just ignore this shit. TODO check for overflow */
        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }
        break;
      }

      case s_chunk_size_almost_done:
      {
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);

        nread = 0;

        if (parser->content_length == 0) {
          parser->flags |= F_TRAILING;
          state = s_header_field_start;
        } else {
          state = s_chunk_data;
        }
        break;
      }

      case s_chunk_data:
      {
        assert(parser->flags & F_CHUNKED);

        to_read = MIN(pe - p, (int64_t)(parser->content_length));

        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }

        if (to_read == parser->content_length) {
          state = s_chunk_data_almost_done;
        }

        parser->content_length -= to_read;
        break;
      }

      case s_chunk_data_almost_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != CR);
        state = s_chunk_data_done;
        break;

      case s_chunk_data_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);
        state = s_chunk_size_start;
        break;

      default:
        assert(0 && "unhandled state");
        SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
        goto error;
    }
  }

#if defined(HTTP_PARSER_USE_RESTART)
  if (url_mark) return (url_mark - data);
  if (header_field_mark) return (header_field_mark - data);
  if (header_value_mark) return (header_value_mark - data);
#else
  CALLBACK(header_field);
  CALLBACK(header_value);
  CALLBACK(url);
#endif

  parser->state = state;
  parser->header_state = header_state;
  parser->index = index;
  parser->nread = nread;

  return len;

error:
  if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
    SET_ERRNO(HPE_UNKNOWN);
  }

  return (p - data);
}
示例#8
0
/*
 * Traverse the file system in the post-order way.  The description
 * and example is in the header file.
 *
 * The callback function should return 0, on success and non-zero on
 * failure.  If the callback function returns non-zero return value,
 * the traversing stops.
 */
int
traverse_post(struct fs_traverse *ftp)
{
	char path[PATH_MAX + 1]; /* full path name of the current dir */
	char nm[NAME_MAX + 1]; /* directory entry name */
	char *lp; /* last position on the path */
	int next_dir, rv;
	int pl, el; /* path and directory entry length */
	cstack_t *sp;
	fs_fhandle_t pfh, efh;
	struct stat64 pst, est;
	traverse_state_t *tsp;
	struct fst_node pn, en; /* parent and entry nodes */

	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		errno = EINVAL;
		return (-1);
	}

	/* set the default log function if it's not already set */
	if (!ftp->ft_logfp) {
		ftp->ft_logfp = (ft_log_t)syslog;
		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
	}

	/* set the logical path to physical path if it's not already set */
	if (!ftp->ft_lpath) {
		NDMP_LOG(LOG_DEBUG,
		    "report the same paths: \"%s\"", ftp->ft_path);
		ftp->ft_lpath = ftp->ft_path;
	}

	pl = strlen(ftp->ft_lpath);
	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
		errno = ENAMETOOLONG;
		return (-1);
	}
	(void) strcpy(path, ftp->ft_lpath);
	(void) memset(&pfh, 0, sizeof (pfh));
	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);

	if (rv != 0) {
		NDMP_LOG(LOG_DEBUG,
		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
		return (rv);
	}

	if (!S_ISDIR(pst.st_mode)) {
		pn.tn_path = ftp->ft_lpath;
		pn.tn_fh = &pfh;
		pn.tn_st = &pst;
		en.tn_path = NULL;
		en.tn_fh = NULL;
		en.tn_st = NULL;
		rv = CALLBACK(&pn, &en);
		if (VERBOSE(ftp))
			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
		free(pfh.fh_fpath);
		return (rv);
	}

	sp = cstack_new();
	if (!sp) {
		errno = ENOMEM;
		free(pfh.fh_fpath);
		return (-1);
	}
	tsp = new_tsp(path);
	if (!tsp) {
		cstack_delete(sp);
		errno = ENOMEM;
		free(pfh.fh_fpath);
		return (-1);
	}
	tsp->ts_ent = tsp->ts_end;
	tsp->ts_fh = pfh;
	tsp->ts_st = pst;
	pn.tn_path = path;
	pn.tn_fh = &tsp->ts_fh;
	pn.tn_st = &tsp->ts_st;

	rv = 0;
	next_dir = 1;
	do {
		if (next_dir) {
			traverse_stats.fss_newdirs++;

			*tsp->ts_end = '\0';
			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);
		}

		next_dir = 0;
		do {
			el = NAME_MAX;
			rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
			    &tsp->ts_dpos, nm, &el,
			    &efh, &est);

			if (rv != 0) {
				free(efh.fh_fpath);
				traverse_stats.fss_readdir_err++;

				NDMP_LOG(LOG_DEBUG,
				    "Error %d on readdir(%s) pos %d",
				    rv, path, tsp->ts_dpos);
				if (STOP_ONERR(ftp))
					break;
				rv = SKIP_ENTRY;

				continue;
			}

			/* done with this directory */
			if (el == 0) {
				if (VERBOSE(ftp))
					NDMP_LOG(LOG_DEBUG,
					    "Done(%s)", pn.tn_path);
				break;
			}
			nm[el] = '\0';

			if (rootfs_dot_or_dotdot(nm)) {
				free(efh.fh_fpath);
				continue;
			}

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
				    tsp->ts_dpos, nm);

			if (pl + 1 + el > PATH_MAX) {
				traverse_stats.fss_longpath_err++;

				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    path, nm);
				if (STOP_ONLONG(ftp))
					rv = ENAMETOOLONG;
				free(efh.fh_fpath);
				continue;
			}

			/*
			 * Push the current directory on to the stack and
			 * dive into the entry found.
			 */
			if (S_ISDIR(est.st_mode)) {

				assert(tsp != NULL);
				if (cstack_push(sp, tsp, 0)) {
					rv = ENOMEM;
					free(efh.fh_fpath);
					break;
				}
				traverse_stats.fss_pushes++;

				/*
				 * Concatenate the current entry with the
				 * current path.  This will be the path of
				 * the new directory to be scanned.
				 *
				 * Note:
				 * sprintf(tsp->ts_end, "/%s", de->d_name);
				 * could be used here, but concatenating
				 * strings like this might be faster.
				 * The length of the new path has been
				 * checked above.  So strcpy() can be
				 * safe and should not lead to a buffer
				 * over-run.
				 */
				lp = tsp->ts_end;
				*tsp->ts_end = '/';
				(void) strcpy(tsp->ts_end + 1, nm);

				tsp = new_tsp(path);
				if (!tsp) {
					free(efh.fh_fpath);
					rv = ENOMEM;
				} else {
					next_dir = 1;
					pl += el;
					tsp->ts_fh = efh;
					tsp->ts_st = est;
					tsp->ts_ent = lp;
					pn.tn_fh = &tsp->ts_fh;
					pn.tn_st = &tsp->ts_st;
				}
				break;
			} else {
				/*
				 * The entry is not a directory so the
				 * callback function must be called.
				 */
				traverse_stats.fss_nondir_calls++;

				en.tn_path = nm;
				en.tn_fh = &efh;
				en.tn_st = &est;
				rv = CALLBACK(&pn, &en);
				free(efh.fh_fpath);
				if (VERBOSE(ftp))
					NDMP_LOG(LOG_DEBUG,
					    "CALLBACK(%s/%s): %d",
					    pn.tn_path, en.tn_path, rv);

				if (rv != 0)
					break;
			}
		} while (rv == 0);

		/*
		 * A new directory must be processed, go to the start of
		 * the loop, open it and process it.
		 */
		if (next_dir)
			continue;

		if (rv == SKIP_ENTRY)
			rv = 0; /* We should skip the current directory */

		if (rv == 0) {
			/*
			 * Remove the ent from the end of path and send it
			 * as an entry of the path.
			 */
			lp = tsp->ts_ent;
			*lp = '\0';
			efh = tsp->ts_fh;
			est = tsp->ts_st;
			free(tsp);
			if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
				break;

			assert(tsp != NULL);
			pl = tsp->ts_end - path;

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "poped pl %d 0x%p \"%s\"",
				    pl, tsp, path);

			traverse_stats.fss_pops++;
			traverse_stats.fss_dir_calls++;

			pn.tn_fh = &tsp->ts_fh;
			pn.tn_st = &tsp->ts_st;
			en.tn_path = lp + 1;
			en.tn_fh = &efh;
			en.tn_st = &est;

			rv = CALLBACK(&pn, &en);
			free(efh.fh_fpath);
			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "CALLBACK(%s/%s): %d",
				    pn.tn_path, en.tn_path, rv);
			/*
			 * Does not need to free tsp here.  It will be released
			 * later.
			 */
		}

		if (rv != 0 && tsp) {
			free(tsp->ts_fh.fh_fpath);
			free(tsp);
		}

	} while (rv == 0);

	/*
	 * For the 'ftp->ft_path' directory itself.
	 */
	if (rv == 0) {
		traverse_stats.fss_dir_calls++;

		pn.tn_fh = &efh;
		pn.tn_st = &est;
		en.tn_path = NULL;
		en.tn_fh = NULL;
		en.tn_st = NULL;
		rv = CALLBACK(&pn, &en);
		if (VERBOSE(ftp))
			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);
	}

	/*
	 * Pop and free all the remaining entries on the stack.
	 */
	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
		traverse_stats.fss_stack_residue++;

		free(tsp->ts_fh.fh_fpath);
		free(tsp);
	}

	cstack_delete(sp);
	return (rv);
}
示例#9
0
/*
 * In one pass, read all the directory entries of the specified
 * directory and call the callback function for non-directory
 * entries.
 *
 * On return:
 *    0: Lets the directory to be scanned for directory entries.
 *    < 0: Completely stops traversing.
 *    FST_SKIP: stops further scanning of the directory.  Traversing
 *        will continue with the next directory in the hierarchy.
 *    SKIP_ENTRY: Failed to get the directory entries, so the caller
 *	  should skip this entry.
 */
static int
traverse_level_nondir(struct fs_traverse *ftp,
    traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
{
	int pl; /* path length */
	int rv;
	struct fst_node en; /* entry node */
	longlong_t cookie_verf;
	fs_dent_info_t *dent;
	struct dirent *buf;
	size_t len = 0;
	int fd;

	rv = 0;
	pl = strlen(pnp->tn_path);

	buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (buf == NULL)
		return (errno);

	fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
	if (fd == -1) {
		free(buf);
		return (errno);
	}

	while (rv == 0) {
		long i, n_entries;

		darg->da_end = 0;
		n_entries = 0;
		rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
		    &cookie_verf, &n_entries, darg);
		if (rv < 0) {
			traverse_stats.fss_readdir_err++;

			NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
			    rv, pnp->tn_path, tsp->ts_dpos);
			if (STOP_ONERR(ftp))
				break;
			/*
			 * We cannot read the directory entry, we should
			 * skip to the next directory.
			 */
			rv = SKIP_ENTRY;
			continue;
		} else {
			/* Break at the end of directory */
			if (rv > 0)
				rv = 0;
			else
				break;
		}

		/* LINTED imporper alignment */
		dent = (fs_dent_info_t *)darg->da_buf;
		/* LINTED imporper alignment */
		for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
		    ((char *)dent + dent->fd_len)) {

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
				    dent->fd_fh.fh_fid, dent->fd_name);

			if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
				traverse_stats.fss_longpath_err++;

				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    pnp->tn_path, dent->fd_name);
				if (STOP_ONLONG(ftp))
					rv = -ENAMETOOLONG;
				free(dent->fd_fh.fh_fpath);
				continue;
			}

			/*
			 * The entry is not a directory so the callback
			 * function must be called.
			 */
			if (!S_ISDIR(dent->fd_attr.st_mode)) {
				traverse_stats.fss_nondir_calls++;

				en.tn_path = dent->fd_name;
				en.tn_fh = &dent->fd_fh;
				en.tn_st = &dent->fd_attr;
				rv = CALLBACK(pnp, &en);
				dent->fd_fh.fh_fpath = NULL;
				if (rv < 0)
					break;
				if (rv == FST_SKIP) {
					traverse_stats.fss_nondir_skipped++;
					break;
				}
			}
		}
	}

	free(buf);
	(void) close(fd);
	return (rv);
}
示例#10
0
文件: di.c 项目: E-LLP/n900
/*------------------------------------------------------------------*/
byte isdn_rc(ADAPTER * a,
             byte Rc,
             byte Id,
             byte Ch,
             word Ref,
             dword extended_info_type,
             dword extended_info)
{
  ENTITY  * this;
  byte e_no;
  word i;
  int cancel_rc;
#ifdef USE_EXTENDED_DEBUGS
  {
    DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc))
  }
#else
  dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
#endif
        /* check for ready interrupt                                */
  if(Rc==READY_INT) {
    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0);
    if(a->ReadyInt) {
      a->ReadyInt--;
      return 0;
    }
    return 2;
  }
        /* if we know this Id ...                                   */
  e_no = a->IdTable[Id];
  if(e_no) {
    this = entity_ptr(a,e_no);
    xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
    this->RcCh = Ch;
        /* if it is a return code to a REMOVE request, remove the   */
        /* Id from our table                                        */
    if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
        (Rc==OK)) {
      if (a->IdTypeTable[e_no] == NL_ID) {
        if (a->RcExtensionSupported &&
            (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
        dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
                        XDI_A_NR(a),Id));
          return (0);
        }
        if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
          a->RcExtensionSupported = true;
      }
      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
      a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
      free_entity(a, e_no);
      for (i = 0; i < 256; i++)
      {
        if (a->FlowControlIdTable[i] == Id)
          a->FlowControlIdTable[i] = 0;
      }
      a->IdTable[Id] = 0;
      this->Id = 0;
      /* ---------------------------------------------------------------
        If we send N_DISC or N_DISK_ACK after we have received OK_FC
        then the card will respond with OK_FC and later with RC==OK.
        If we send N_REMOVE in this state we will receive only RC==OK
        This will create the state in that the XDI is waiting for the
        additional RC and does not delivery the RC to the client. This
        code corrects the counter of outstanding RC's in this case.
      --------------------------------------------------------------- */
      if ((this->More & XMOREC) > 1) {
        this->More &= ~XMOREC;
        this->More |= 1;
        dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
                     XDI_A_NR(a),Id));
      }
    }
    if (Rc==OK_FC) {
      a->FlowControlIdTable[Ch] = Id;
      a->FlowControlSkipTable[Ch] = false;
      this->Rc = Rc;
      this->More &= ~(XBUSY | XMOREC);
      this->complete=0xff;
      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
      CALLBACK(a, this);
      return 0;
    }
    /*
      New protocol code sends return codes that comes from release
      of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
      information element type.
      If like return code arrives then application is able to process
      all return codes self and XDI should not cances return codes.
      This return code does not decrement XMOREC partial return code
      counter due to fact that it was no request for this return code,
      also XMOREC was not incremented.
      */
    if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
      a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
      this->Rc = Rc;
      this->complete=0xff;
      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
      DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
      XDI_A_NR(a), Id, Ch, Rc))
      CALLBACK(a, this);
      return 0;
    }
    cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
    if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
    {
      a->FlowControlIdTable[Ch] = 0;
      if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
      {
        this->Rc = Rc;
        if (Ch == this->ReqCh)
        {
          this->More &=~(XBUSY | XMOREC);
          this->complete=0xff;
        }
        xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
        CALLBACK(a, this);
      }
      return 0;
    }
    if (this->More &XMOREC)
      this->More--;
        /* call the application callback function                   */
    if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
      this->Rc = Rc;
      this->More &=~XBUSY;
      this->complete=0xff;
      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
      CALLBACK(a, this);
    }
    return 0;
  }
        /* if it's an ASSIGN return code check if it's a return     */
        /* code to an ASSIGN request from us                        */
  if((Rc &0xf0)==ASSIGN_RC) {
    e_no = get_assign(a, Ref);
    if(e_no) {
      this = entity_ptr(a,e_no);
      this->Id = Id;
      xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
        /* call the application callback function                   */
      this->Rc = Rc;
      this->More &=~XBUSY;
      this->complete=0xff;
#if defined(DIVA_ISTREAM) /* { */
      if ((Rc == ASSIGN_OK) && a->ram_offset &&
          (a->IdTypeTable[this->No] == NL_ID) &&
          ((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
          (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
          extended_info) {
        dword offset = (*(a->ram_offset)) (a);
        dword tmp[2];
        extended_info -= offset;
#ifdef PLATFORM_GT_32BIT
        a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2);
#else
        a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2);
#endif
        a->tx_stream[Id]  = tmp[0];
        a->rx_stream[Id]  = tmp[1];
        if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
          DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
                    Id, a->tx_stream[Id], a->rx_stream[Id]))
          a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
        } else {
          DBG_TRC(("Id=0x%x CMA=%08x:%08x",
                    Id, a->tx_stream[Id], a->rx_stream[Id]))
          a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
          a->rx_pos[Id]     = 0;
          a->rx_stream[Id] -= offset;
        }
        a->tx_pos[Id]     = 0;
        a->tx_stream[Id] -= offset;
      } else {
        a->tx_stream[Id] = 0;
        a->rx_stream[Id] = 0;
        a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
      }
#endif /* } */
      CALLBACK(a, this);
      if(Rc==ASSIGN_OK) {
        a->IdTable[Id] = e_no;
      }
      else
      {
        free_entity(a, e_no);
        for (i = 0; i < 256; i++)
        {
          if (a->FlowControlIdTable[i] == Id)
            a->FlowControlIdTable[i] = 0;
        }
        a->IdTable[Id] = 0;
        this->Id = 0;
      }
      return 1;
    }
  }
  return 2;
}
示例#11
0
文件: di.c 项目: E-LLP/n900
/*------------------------------------------------------------------*/
byte isdn_ind(ADAPTER * a,
              byte Ind,
              byte Id,
              byte Ch,
              PBUFFER * RBuffer,
              byte MInd,
              word MLength)
{
  ENTITY  * this;
  word clength;
  word offset;
  BUFFERS  *R;
  byte* cma = NULL;
#ifdef USE_EXTENDED_DEBUGS
  {
    DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind))
  }
#else
  dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
#endif
  if(a->IdTable[Id]) {
    this = entity_ptr(a,a->IdTable[Id]);
    this->IndCh = Ch;
    xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
                  0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
        /* if the Receive More flag is not yet set, this is the     */
        /* first buffer of the packet                               */
    if(this->RCurrent==0xff) {
        /* check for receive buffer chaining                        */
      if(Ind==this->MInd) {
        this->complete = 0;
        this->Ind = MInd;
      }
      else {
        this->complete = 1;
        this->Ind = Ind;
      }
        /* call the application callback function for the receive   */
        /* look ahead                                               */
      this->RLength = MLength;
#if defined(DIVA_ISTREAM)
      if ((a->rx_stream[this->Id] ||
           (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
          ((Ind == N_DATA) ||
           (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
        PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
        if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
#if defined(DIVA_IDI_RX_DMA)
          dword d;
          diva_get_dma_map_entry (\
                   (struct _diva_dma_map_entry*)IoAdapter->dma_map,
                   (int)a->rx_stream[this->Id], (void**)&cma, &d);
#else
          cma = &a->stream_buffer[0];
          cma[0] = cma[1] = cma[2] = cma[3] = 0;
#endif
          this->RLength = MLength = (word)*(dword*)cma;
          cma += 4;
        } else {
        int final = 0;
        cma = &a->stream_buffer[0];
        this->RLength = MLength = (word)diva_istream_read (a,
                                                     Id,
                                                     cma,
                                                     sizeof(a->stream_buffer),
                                                     &final, NULL, NULL);
        }
        IoAdapter->RBuffer.length = min(MLength, (word)270);
        if (IoAdapter->RBuffer.length != MLength) {
          this->complete = 0;
        } else {
          this->complete = 1;
        }
        memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ;
        this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
      }
#endif
      if (!cma) {
        a->ram_look_ahead(a, RBuffer, this);
      }
      this->RNum = 0;
      CALLBACK(a, this);
        /* map entity ptr, selector could be re-mapped by call to   */
        /* IDI from within callback                                 */
      this = entity_ptr(a,a->IdTable[Id]);
      xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
          1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
        /* check for RNR                                            */
      if(this->RNR==1) {
        this->RNR = 0;
        return 1;
      }
        /* if no buffers are provided by the application, the       */
        /* application want to copy the data itself including       */
        /* N_MDATA/LL_MDATA chaining                                */
      if(!this->RNR && !this->RNum) {
        xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
            2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
        return 0;
      }
        /* if there is no RNR, set the More flag                    */
      this->RCurrent = 0;
      this->ROffset = 0;
    }
示例#12
0
    return 0;
}

FUNCTION(url)
FUNCTION(path)
FUNCTION(query_string)
FUNCTION(fragment)
FUNCTION_PUSH(header_field)
FUNCTION_PUSH(header_value)
FUNCTION_APPEND(body)
FUNCTION_CALLBACK(headers_complete)
FUNCTION_CALLBACK(message_begin)
FUNCTION_CALLBACK(message_complete)

http_parser_settings httpSettings = {
    /* callbacks */
    CALLBACK(url),
    CALLBACK(query_string),
    CALLBACK(fragment),
    CALLBACK(path),
    CALLBACK(body),
    CALLBACK(header_field),
    CALLBACK(header_value),

    /* callbacks with no data  */
    CALLBACK(headers_complete),
    CALLBACK(message_begin),
    CALLBACK(message_complete)
};
示例#13
0
		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_sdp_data),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_cc_data),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_ic_data),
		ACTION_SUCCESS(hidhost_connect_action, NULL),
		CALLBACK_STATE(CB_HH_CONNECTION_STATE,
						BTHH_CONN_STATE_CONNECTING),
		CALLBACK_STATE(CB_HH_CONNECTION_STATE,
						BTHH_CONN_STATE_CONNECTED),
		ACTION_SUCCESS(hidhost_set_report_action, NULL),
		CALLBACK(CB_EMU_CONFIRM_SEND_DATA),
	),
	TEST_CASE_BREDRLE("HidHost SendData Success",
		ACTION_SUCCESS(bluetooth_enable_action, NULL),
		CALLBACK_STATE(CB_BT_ADAPTER_STATE_CHANGED, BT_STATE_ON),
		ACTION_SUCCESS(emu_setup_powered_remote_action, NULL),
		ACTION_SUCCESS(emu_set_ssp_mode_action, NULL),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_sdp_data),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_cc_data),
		ACTION_SUCCESS(emu_add_l2cap_server_action,
							&l2cap_setup_ic_data),
		ACTION_SUCCESS(hidhost_connect_action, NULL),
		CALLBACK_STATE(CB_HH_CONNECTION_STATE,
						BTHH_CONN_STATE_CONNECTED),
示例#14
0
size_t http_parser_execute (http_parser *parser,
                            const http_parser_settings *settings,
                            const char *data,
                            size_t len)
{
  char c, ch;
  const char *p = data, *pe;
  ssize_t to_read;

  enum state state = (enum state) parser->state;
  enum header_states header_state = (enum header_states) parser->header_state;
  size_t index = parser->index;
  size_t nread = parser->nread;

  if (len == 0) {
    if (state == s_body_identity_eof) {
      CALLBACK2(message_complete);
    }
    return 0;
  }

  if (parser->header_field_mark)   parser->header_field_mark   = data;
  if (parser->header_value_mark)   parser->header_value_mark   = data;
  if (parser->fragment_mark)       parser->fragment_mark       = data;
  if (parser->query_string_mark)   parser->query_string_mark   = data;
  if (parser->path_mark)           parser->path_mark           = data;
  if (parser->url_mark)            parser->url_mark            = data;

  for (p=data, pe=data+len; p != pe; p++) {
    ch = *p;

    if (++nread > HTTP_MAX_HEADER_SIZE && PARSING_HEADER(state)) {
      /* Buffer overflow attack */
      goto error;
    }

    switch (state) {

      case s_dead:
        /* this state is used after a 'Connection: close' message
         * the parser will error out if it reads another message
         */
        goto error;

      case s_start_res:
      {
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        switch (ch) {
          case 'H':
            state = s_res_H;
            break;

          case CR:
          case LF:
            break;

          default:
            goto error;
        }
        break;
      }

      case s_res_H:
        STRICT_CHECK(ch != 'T');
        state = s_res_HT;
        break;

      case s_res_HT:
        STRICT_CHECK(ch != 'T');
        state = s_res_HTT;
        break;

      case s_res_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_res_HTTP;
        break;

      case s_res_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_res_first_http_major;
        break;

      case s_res_first_http_major:
        if (ch < '1' || ch > '9') goto error;
        parser->http_major = ch - '0';
        state = s_res_http_major;
        break;

      /* major HTTP version or dot */
      case s_res_http_major:
      {
        if (ch == '.') {
          state = s_res_first_http_minor;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) goto error;
        break;
      }

      /* first digit of minor HTTP version */
      case s_res_first_http_minor:
        if (ch < '0' || ch > '9') goto error;
        parser->http_minor = ch - '0';
        state = s_res_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_res_http_minor:
      {
        if (ch == ' ') {
          state = s_res_first_status_code;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) goto error;
        break;
      }

      case s_res_first_status_code:
      {
        if (ch < '0' || ch > '9') {
          if (ch == ' ') {
            break;
          }
          goto error;
        }
        parser->status_code = ch - '0';
        state = s_res_status_code;
        break;
      }

      case s_res_status_code:
      {
        if (ch < '0' || ch > '9') {
          switch (ch) {
            case ' ':
              state = s_res_status;
              break;
            case CR:
              state = s_res_line_almost_done;
              break;
            case LF:
              state = s_header_field_start;
              break;
            default:
              goto error;
          }
          break;
        }

        parser->status_code *= 10;
        parser->status_code += ch - '0';

        if (parser->status_code > 999) goto error;
        break;
      }

      case s_res_status:
        /* the human readable status. e.g. "NOT FOUND"
         * we are not humans so just ignore this */
        if (ch == CR) {
          state = s_res_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }
        break;

      case s_res_line_almost_done:
        STRICT_CHECK(ch != LF);
        state = s_header_field_start;
        break;

      case s_start_req:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (ch < 'A' || 'Z' < ch) goto error;

        parser->method = (enum http_method) 0;
        index = 0;
        parser->buffer[0] = ch;
        state = s_req_method;
        break;
      }

      case s_req_method:
        if (ch == ' ') {
          assert(index+1 < HTTP_PARSER_MAX_METHOD_LEN);
          parser->buffer[index+1] = '\0';

          switch (index+1) {
            case 3:
              if (ngx_str3_cmp(parser->buffer, 'G', 'E', 'T')) {
                parser->method = HTTP_GET;
                break;
              }

              if (ngx_str3_cmp(parser->buffer, 'P', 'U', 'T')) {
                parser->method = HTTP_PUT;
                break;
              }

              break;

            case 4:
              if (ngx_str4cmp(parser->buffer, 'P', 'O', 'S', 'T')) {
                parser->method = HTTP_POST;
                break;
              }

              if (ngx_str4cmp(parser->buffer, 'H', 'E', 'A', 'D')) {
                parser->method = HTTP_HEAD;
                break;
              }

              if (ngx_str4cmp(parser->buffer, 'C', 'O', 'P', 'Y')) {
                parser->method = HTTP_COPY;
                break;
              }

              if (ngx_str4cmp(parser->buffer, 'M', 'O', 'V', 'E')) {
                parser->method = HTTP_MOVE;
                break;
              }

              break;

            case 5:
              if (ngx_str5cmp(parser->buffer, 'M', 'K', 'C', 'O', 'L')) {
                parser->method = HTTP_MKCOL;
                break;
              }

              if (ngx_str5cmp(parser->buffer, 'T', 'R', 'A', 'C', 'E')) {
                parser->method = HTTP_TRACE;
                break;
              }

              break;

            case 6:
              if (ngx_str6cmp(parser->buffer, 'D', 'E', 'L', 'E', 'T', 'E')) {
                parser->method = HTTP_DELETE;
                break;
              }

              if (ngx_str6cmp(parser->buffer, 'U', 'N', 'L', 'O', 'C', 'K')) {
                parser->method = HTTP_UNLOCK;
                break;
              }

              break;

            case 7:
              if (ngx_str7_cmp(parser->buffer,
                    'O', 'P', 'T', 'I', 'O', 'N', 'S', '\0')) {
                parser->method = HTTP_OPTIONS;
                break;
              }

              if (ngx_str7_cmp(parser->buffer,
                    'C', 'O', 'N', 'N', 'E', 'C', 'T', '\0')) {
                parser->method = HTTP_CONNECT;
                break;
              }

              break;

            case 8:
              if (ngx_str8cmp(parser->buffer,
                    'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D')) {
                parser->method = HTTP_PROPFIND;
                break;
              }

              break;

            case 9:
              if (ngx_str9cmp(parser->buffer, 
                    'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H')) {
                parser->method = HTTP_PROPPATCH;
                break;
              }

              break;
          }
          state = s_req_spaces_before_url;
          break;
        }

        if (ch < 'A' || 'Z' < ch) goto error;

        if (++index >= HTTP_PARSER_MAX_METHOD_LEN - 1) {
          goto error;
        }

        parser->buffer[index] = ch;

        break;

      case s_req_spaces_before_url:
      {
        if (ch == ' ') break;

        if (ch == '/') {
          MARK(url);
          MARK(path);
          state = s_req_path;
          break;
        }

        c = LOWER(ch);

        if (c >= 'a' && c <= 'z') {
          MARK(url);
          state = s_req_schema;
          break;
        }

        goto error;
      }

      case s_req_schema:
      {
        c = LOWER(ch);

        if (c >= 'a' && c <= 'z') break;

        if (ch == ':') {
          state = s_req_schema_slash;
          break;
        }

        goto error;
      }

      case s_req_schema_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_schema_slash_slash;
        break;

      case s_req_schema_slash_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_host;
        break;

      case s_req_host:
      {
        c = LOWER(ch);
        if (c >= 'a' && c <= 'z') break;
        if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break;
        switch (ch) {
          case ':':
            state = s_req_port;
            break;
          case '/':
            MARK(path);
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_port:
      {
        if (ch >= '0' && ch <= '9') break;
        switch (ch) {
          case '/':
            MARK(path);
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com:1234 HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_path:
      {
        if (USUAL(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            CALLBACK(path);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(path);
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(path);
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            CALLBACK(path);
            state = s_req_query_string_start;
            break;
          case '#':
            CALLBACK(path);
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_query_string_start:
      {
        if (USUAL(ch)) {
          MARK(query_string);
          state = s_req_query_string;
          break;
        }

        switch (ch) {
          case '?':
            break; // XXX ignore extra '?' ... is this right?
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_query_string:
      {
        if (USUAL(ch)) break;

        switch (ch) {
          case '?':
            // allow extra '?' in query string
            break;
          case ' ':
            CALLBACK(url);
            CALLBACK(query_string);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(query_string);
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(query_string);
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            CALLBACK(query_string);
            state = s_req_fragment_start;
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_fragment_start:
      {
        if (USUAL(ch)) {
          MARK(fragment);
          state = s_req_fragment;
          break;
        }

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            MARK(fragment);
            state = s_req_fragment;
            break;
          case '#':
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_fragment:
      {
        if (USUAL(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            CALLBACK(fragment);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            CALLBACK(fragment);
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            CALLBACK(fragment);
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
          case '#':
            break;
          default:
            goto error;
        }
        break;
      }

      case s_req_http_start:
        switch (ch) {
          case 'H':
            state = s_req_http_H;
            break;
          case ' ':
            break;
          default:
            goto error;
        }
        break;

      case s_req_http_H:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HT;
        break;

      case s_req_http_HT:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HTT;
        break;

      case s_req_http_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_req_http_HTTP;
        break;

      case s_req_http_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_req_first_http_major;
        break;

      /* first digit of major HTTP version */
      case s_req_first_http_major:
        if (ch < '1' || ch > '9') goto error;
        parser->http_major = ch - '0';
        state = s_req_http_major;
        break;

      /* major HTTP version or dot */
      case s_req_http_major:
      {
        if (ch == '.') {
          state = s_req_first_http_minor;
          break;
        }

        if (ch < '0' || ch > '9') goto error;

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) goto error;
        break;
      }

      /* first digit of minor HTTP version */
      case s_req_first_http_minor:
        if (ch < '0' || ch > '9') goto error;
        parser->http_minor = ch - '0';
        state = s_req_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_req_http_minor:
      {
        if (ch == CR) {
          state = s_req_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }

        /* XXX allow spaces after digit? */

        if (ch < '0' || ch > '9') goto error;

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) goto error;
        break;
      }

      /* end of request line */
      case s_req_line_almost_done:
      {
        if (ch != LF) goto error;
        state = s_header_field_start;
        break;
      }

      case s_header_field_start:
      {
        if (ch == CR) {
          state = s_headers_almost_done;
          break;
        }

        if (ch == LF) {
          /* they might be just sending \n instead of \r\n so this would be
           * the second \n to denote the end of headers*/
          state = s_headers_almost_done;
          goto headers_almost_done;
        }

        c = LOWER(ch);

        if (c < 'a' || 'z' < c) goto error;

        MARK(header_field);

        index = 0;
        state = s_header_field;

        switch (c) {
          case 'c':
            header_state = h_C;
            break;

          case 'p':
            header_state = h_matching_proxy_connection;
            break;

          case 't':
            header_state = h_matching_transfer_encoding;
            break;

          case 'u':
            header_state = h_matching_upgrade;
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_field:
      {
        c = lowcase[(int)ch];

        if (c) {
          switch (header_state) {
            case h_general:
              break;

            case h_C:
              index++;
              header_state = (c == 'o' ? h_CO : h_general);
              break;

            case h_CO:
              index++;
              header_state = (c == 'n' ? h_CON : h_general);
              break;

            case h_CON:
              index++;
              switch (c) {
                case 'n':
                  header_state = h_matching_connection;
                  break;
                case 't':
                  header_state = h_matching_content_length;
                  break;
                default:
                  header_state = h_general;
                  break;
              }
              break;

            /* connection */

            case h_matching_connection:
              index++;
              if (index > sizeof(CONNECTION)-1
                  || c != CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* proxy-connection */

            case h_matching_proxy_connection:
              index++;
              if (index > sizeof(PROXY_CONNECTION)-1
                  || c != PROXY_CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(PROXY_CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* content-length */

            case h_matching_content_length:
              index++;
              if (index > sizeof(CONTENT_LENGTH)-1
                  || c != CONTENT_LENGTH[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONTENT_LENGTH)-2) {
                header_state = h_content_length;
              }
              break;

            /* transfer-encoding */

            case h_matching_transfer_encoding:
              index++;
              if (index > sizeof(TRANSFER_ENCODING)-1
                  || c != TRANSFER_ENCODING[index]) {
                header_state = h_general;
              } else if (index == sizeof(TRANSFER_ENCODING)-2) {
                header_state = h_transfer_encoding;
              }
              break;

            /* upgrade */

            case h_matching_upgrade:
              index++;
              if (index > sizeof(UPGRADE)-1
                  || c != UPGRADE[index]) {
                header_state = h_general;
              } else if (index == sizeof(UPGRADE)-2) {
                header_state = h_upgrade;
              }
              break;

            case h_connection:
            case h_content_length:
            case h_transfer_encoding:
            case h_upgrade:
              if (ch != ' ') header_state = h_general;
              break;

            default:
              assert(0 && "Unknown header_state");
              break;
          }
          break;
        }

        if (ch == ':') {
          CALLBACK(header_field);
          state = s_header_value_start;
          break;
        }

        if (ch == CR) {
          state = s_header_almost_done;
          CALLBACK(header_field);
          break;
        }

        if (ch == LF) {
          CALLBACK(header_field);
          state = s_header_field_start;
          break;
        }

        goto error;
      }

      case s_header_value_start:
      {
        if (ch == ' ') break;

        MARK(header_value);

        state = s_header_value;
        index = 0;

        c = lowcase[(int)ch];

        if (!c) {
          if (ch == CR) {
            header_state = h_general;
            state = s_header_almost_done;
            break;
          }

          if (ch == LF) {
            state = s_header_field_start;
            break;
          }

          header_state = h_general;
          break;
        }

        switch (header_state) {
          case h_upgrade:
            parser->flags |= F_UPGRADE;
            header_state = h_general;
            break;

          case h_transfer_encoding:
            /* looking for 'Transfer-Encoding: chunked' */
            if ('c' == c) {
              header_state = h_matching_transfer_encoding_chunked;
            } else {
              header_state = h_general;
            }
            break;

          case h_content_length:
            if (ch < '0' || ch > '9') goto error;
            parser->content_length = ch - '0';
            break;

          case h_connection:
            /* looking for 'Connection: keep-alive' */
            if (c == 'k') {
              header_state = h_matching_connection_keep_alive;
            /* looking for 'Connection: close' */
            } else if (c == 'c') {
              header_state = h_matching_connection_close;
            } else {
              header_state = h_general;
            }
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_value:
      {
        c = lowcase[(int)ch];

        if (!c) {
          if (ch == CR) {
            CALLBACK(header_value);
            state = s_header_almost_done;
            break;
          }

          if (ch == LF) {
            CALLBACK(header_value);
            goto header_almost_done;
          }
          break;
        }

        switch (header_state) {
          case h_general:
            break;

          case h_connection:
          case h_transfer_encoding:
            assert(0 && "Shouldn't get here.");
            break;

          case h_content_length:
            if (ch < '0' || ch > '9') goto error;
            parser->content_length *= 10;
            parser->content_length += ch - '0';
            break;

          /* Transfer-Encoding: chunked */
          case h_matching_transfer_encoding_chunked:
            index++;
            if (index > sizeof(CHUNKED)-1
                || c != CHUNKED[index]) {
              header_state = h_general;
            } else if (index == sizeof(CHUNKED)-2) {
              header_state = h_transfer_encoding_chunked;
            }
            break;

          /* looking for 'Connection: keep-alive' */
          case h_matching_connection_keep_alive:
            index++;
            if (index > sizeof(KEEP_ALIVE)-1
                || c != KEEP_ALIVE[index]) {
              header_state = h_general;
            } else if (index == sizeof(KEEP_ALIVE)-2) {
              header_state = h_connection_keep_alive;
            }
            break;

          /* looking for 'Connection: close' */
          case h_matching_connection_close:
            index++;
            if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
              header_state = h_general;
            } else if (index == sizeof(CLOSE)-2) {
              header_state = h_connection_close;
            }
            break;

          case h_transfer_encoding_chunked:
          case h_connection_keep_alive:
          case h_connection_close:
            if (ch != ' ') header_state = h_general;
            break;

          default:
            state = s_header_value;
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_almost_done:
      header_almost_done:
      {
        STRICT_CHECK(ch != LF);

        state = s_header_field_start;

        switch (header_state) {
          case h_connection_keep_alive:
            parser->flags |= F_CONNECTION_KEEP_ALIVE;
            break;
          case h_connection_close:
            parser->flags |= F_CONNECTION_CLOSE;
            break;
          case h_transfer_encoding_chunked:
            parser->flags |= F_CHUNKED;
            break;
          default:
            break;
        }
        break;
      }

      case s_headers_almost_done:
      headers_almost_done:
      {
        STRICT_CHECK(ch != LF);

        if (parser->flags & F_TRAILING) {
          /* End of a chunked request */
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
          break;
        }

        parser->body_read = 0;
        nread = 0;

        if (parser->flags & F_UPGRADE) parser->upgrade = 1;

        CALLBACK2(headers_complete);

        // Exit, the rest of the connect is in a different protocol.
        if (parser->flags & F_UPGRADE) {
          CALLBACK2(message_complete);
          return (p - data);
        }

        if (parser->flags & F_CHUNKED) {
          /* chunked encoding - ignore Content-Length header */
          state = s_chunk_size_start;
        } else {
          if (parser->content_length == 0) {
            /* Content-Length header given but zero: Content-Length: 0\r\n */
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          } else if (parser->content_length > 0) {
            /* Content-Length header given and non-zero */
            state = s_body_identity;
          } else {
            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
              /* Assume content-length 0 - read the next */
              CALLBACK2(message_complete);
              state = NEW_MESSAGE();
            } else {
              /* Read body until EOF */
              state = s_body_identity_eof;
            }
          }
        }

        break;
      }

      case s_body_identity:
        to_read = MIN(pe - p, (ssize_t)(parser->content_length - parser->body_read));
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
          parser->body_read += to_read;
          if (parser->body_read == parser->content_length) {
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          }
        }
        break;

      /* read until EOF */
      case s_body_identity_eof:
        to_read = pe - p;
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
          parser->body_read += to_read;
        }
        break;

      case s_chunk_size_start:
      {
        assert(parser->flags & F_CHUNKED);

        c = unhex[(int)ch];
        if (c == -1) goto error;
        parser->content_length = c;
        state = s_chunk_size;
        break;
      }

      case s_chunk_size:
      {
        assert(parser->flags & F_CHUNKED);

        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }

        c = unhex[(int)ch];

        if (c == -1) {
          if (ch == ';' || ch == ' ') {
            state = s_chunk_parameters;
            break;
          }
          goto error;
        }

        parser->content_length *= 16;
        parser->content_length += c;
        break;
      }

      case s_chunk_parameters:
      {
        assert(parser->flags & F_CHUNKED);
        /* just ignore this shit. TODO check for overflow */
        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }
        break;
      }

      case s_chunk_size_almost_done:
      {
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);

        if (parser->content_length == 0) {
          parser->flags |= F_TRAILING;
          state = s_header_field_start;
        } else {
          state = s_chunk_data;
        }
        break;
      }

      case s_chunk_data:
      {
        assert(parser->flags & F_CHUNKED);

        to_read = MIN(pe - p, (ssize_t)(parser->content_length));

        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }

        if (to_read == parser->content_length) {
          state = s_chunk_data_almost_done;
        }

        parser->content_length -= to_read;
        break;
      }

      case s_chunk_data_almost_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != CR);
        state = s_chunk_data_done;
        break;

      case s_chunk_data_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);
        state = s_chunk_size_start;
        break;

      default:
        assert(0 && "unhandled state");
        goto error;
    }
  }

  CALLBACK_NOCLEAR(header_field);
  CALLBACK_NOCLEAR(header_value);
  CALLBACK_NOCLEAR(fragment);
  CALLBACK_NOCLEAR(query_string);
  CALLBACK_NOCLEAR(path);
  CALLBACK_NOCLEAR(url);

  parser->state = state;
  parser->header_state = header_state;
  parser->index = index;
  parser->nread = nread;

  return len;

error:
  return (p - data);
}
示例#15
0
static
byte isdn_ind(ADAPTER * a,
              byte Ind,
              byte Id,
              byte Ch,
              PBUFFER * RBuffer,
              byte MInd,
              word MLength)
{
  ENTITY  * this;
  word clength;
  word offset;
  BUFFERS  *R;

#ifdef	USE_EXTENDED_DEBUGS
	{
		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
		DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
	}
#else
  DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
#endif

  if(a->IdTable[Id]) {

    this = entity_ptr(a,a->IdTable[Id]);

    this->IndCh = Ch;

        /* if the Receive More flag is not yet set, this is the     */
        /* first buffer of the packet                               */
    if(this->RCurrent==0xff) {

        /* check for receive buffer chaining                        */
      if(Ind==this->MInd) {
        this->complete = 0;
        this->Ind = MInd;
      }
      else {
        this->complete = 1;
        this->Ind = Ind;
      }

        /* call the application callback function for the receive   */
        /* look ahead                                               */
      this->RLength = MLength;

      a->ram_look_ahead(a, RBuffer, this);

      this->RNum = 0;
      CALLBACK(a, this);

        /* map entity ptr, selector could be re-mapped by call to   */
        /* IDI from within callback                                 */
      this = entity_ptr(a,a->IdTable[Id]);

        /* check for RNR                                            */
      if(this->RNR==1) {
        this->RNR = 0;
        return 1;
      }

        /* if no buffers are provided by the application, the       */
        /* application want to copy the data itself including       */
        /* N_MDATA/LL_MDATA chaining                                */
      if(!this->RNR && !this->RNum) {
        return 0;
      }

        /* if there is no RNR, set the More flag                    */
      this->RCurrent = 0;
      this->ROffset = 0;
    }

    if(this->RNR==2) {
      if(Ind!=this->MInd) {
        this->RCurrent = 0xff;
        this->RNR = 0;
      }
      return 0;
    }
        /* if we have received buffers from the application, copy   */
        /* the data into these buffers                              */
    offset = 0;
    R = PTR_R(a,this);
    do {
      if(this->ROffset==R[this->RCurrent].PLength) {
        this->ROffset = 0;
        this->RCurrent++;
      }
      clength = a->ram_inw(a, &RBuffer->length)-offset;
      if (clength > R[this->RCurrent].PLength-this->ROffset)
	      clength = R[this->RCurrent].PLength-this->ROffset;
      if(R[this->RCurrent].P) {
        a->ram_in_buffer(a,
                         &RBuffer->P[offset],
                         PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
                         clength);
      }
      offset +=clength;
      this->ROffset +=clength;
    } while(offset<(a->ram_inw(a, &RBuffer->length)));

        /* if it's the last buffer of the packet, call the          */
        /* application callback function for the receive complete   */
        /* call                                                     */
    if(Ind!=this->MInd) {
      R[this->RCurrent].PLength = this->ROffset;
      if(this->ROffset) this->RCurrent++;
      this->RNum = this->RCurrent;
      this->RCurrent = 0xff;
      this->Ind = Ind;
      this->complete = 2;
      CALLBACK(a, this);
    }
    return 0;
  }
  return 2;
}
示例#16
0
/*
 * Traverse the file system in the level-order way.  The description
 * and example is in the header file.
 */
int
traverse_level(struct fs_traverse *ftp)
{
	char path[PATH_MAX + 1];	/* full path name of the current dir */
	char nm[NAME_MAX + 1];	/* directory entry name */
	char *lp;		/* last position on the path */
	int next_dir, rv;
	int pl, el;		/* path and directory entry length */

	cstack_t *sp;
	fs_fhandle_t pfh, efh;
	struct stat64 pst, est;
	traverse_state_t *tsp;
	struct fst_node pn, en;  /* parent and entry nodes */
	dent_arg_t darg;

	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		errno = EINVAL;
		return (-1);
	}
	/* set the default log function if it's not already set */
	if (!ftp->ft_logfp) {
		ftp->ft_logfp = (ft_log_t)syslog;
		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
	}
	if (!ftp->ft_lpath) {
		NDMP_LOG(LOG_DEBUG,
		    "report the same paths \"%s\"", ftp->ft_path);
		ftp->ft_lpath = ftp->ft_path;
	}

	pl = strlen(ftp->ft_lpath);
	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
		errno = ENAMETOOLONG;
		return (-1);
	}
	(void) strcpy(path, ftp->ft_lpath);
	(void) memset(&pfh, 0, sizeof (pfh));
	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
	if (rv != 0) {
		NDMP_LOG(LOG_DEBUG,
		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
		return (-1);
	}

	en.tn_path = NULL;
	en.tn_fh = NULL;
	en.tn_st = NULL;
	if (!S_ISDIR(pst.st_mode)) {
		pn.tn_path = ftp->ft_lpath;
		pn.tn_fh = &pfh;
		pn.tn_st = &pst;
		rv = CALLBACK(&pn, &en);
		if (VERBOSE(ftp))
			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);

		free(pfh.fh_fpath);
		return (rv);
	}

	sp = cstack_new();
	if (!sp) {
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}
	tsp = new_tsp(path);
	if (!tsp) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}

	darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (!darg.da_buf) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		free(tsp);
		errno = ENOMEM;
		return (-1);
	}
	darg.da_size = MAX_DENT_BUF_SIZE;

	tsp->ts_ent = tsp->ts_end;
	tsp->ts_fh = pfh;
	tsp->ts_st = pst;
	pn.tn_path = path;
	pn.tn_fh = &tsp->ts_fh;
	pn.tn_st = &tsp->ts_st;

	/* call the callback function on the path itself */
	traverse_stats.fss_dir_calls++;
	rv = CALLBACK(&pn, &en);
	if (rv < 0) {
		free(tsp);
		goto end;
	}
	if (rv == FST_SKIP) {
		traverse_stats.fss_dir_skipped++;
		free(tsp);
		rv = 0;
		goto end;
	}

	rv = 0;
	next_dir = 1;
	do {
		if (next_dir) {
			traverse_stats.fss_newdirs++;

			*tsp->ts_end = '\0';
			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);

			rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
			if (rv < 0) {
				NEGATE(rv);
				free(tsp->ts_fh.fh_fpath);
				free(tsp);
				break;
			}
			/*
			 * If skipped by the callback function or
			 * error happened reading the information
			 */
			if (rv == FST_SKIP || rv == SKIP_ENTRY) {
				/*
				 * N.B. next_dir should be set to 0 as
				 * well. This prevents the infinite loop.
				 * If it's not set the same directory will
				 * be poped from the stack and will be
				 * scanned again.
				 */
				next_dir = 0;
				rv = 0;
				goto skip_dir;
			}

			/* re-start reading entries of the directory */
			tsp->ts_dpos = 0;
		}

		next_dir = 0;
		do {
			el = NAME_MAX;
			rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
			    &tsp->ts_dpos, nm, &el, &efh,
			    &est);
			if (rv != 0) {
				traverse_stats.fss_readdir_err++;

				NDMP_LOG(LOG_DEBUG,
				    "Error %d on readdir(%s) pos %d",
				    rv, path, tsp->ts_dpos);
				if (STOP_ONERR(ftp))
					break;
				rv = SKIP_ENTRY;
				continue;
			}

			/* done with this directory */
			if (el == 0)
				break;

			nm[el] = '\0';

			if (rootfs_dot_or_dotdot(nm)) {
				free(efh.fh_fpath);
				continue;
			}

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
				    tsp->ts_dpos, nm);

			if (pl + 1 + el > PATH_MAX) {
				/*
				 * The long paths were already encountered
				 * when processing non-dir entries in.
				 * traverse_level_nondir.
				 * We don't increase fss_longpath_err
				 * counter for them again here.
				 */
				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    path, nm);
				if (STOP_ONLONG(ftp))
					rv = ENAMETOOLONG;
				free(efh.fh_fpath);
				continue;
			}

			if (!S_ISDIR(est.st_mode))
				continue;

			/*
			 * Call the callback function for the new
			 * directory found, then push the current
			 * directory on to the stack.  Then dive
			 * into the entry found.
			 */
			traverse_stats.fss_dir_calls++;
			en.tn_path = nm;
			en.tn_fh = &efh;
			en.tn_st = &est;
			rv = CALLBACK(&pn, &en);

			if (rv < 0) {
				NEGATE(rv);
				free(efh.fh_fpath);
				break;
			}
			if (rv == FST_SKIP) {
				traverse_stats.fss_dir_skipped++;
				free(efh.fh_fpath);
				rv = 0;
				continue;
			}

			/*
			 * Push the current directory on to the stack and
			 * dive into the entry found.
			 */
			if (cstack_push(sp, tsp, 0)) {
				rv = ENOMEM;
			} else {
				traverse_stats.fss_pushes++;

				lp = tsp->ts_end;
				*tsp->ts_end = '/';
				(void) strcpy(tsp->ts_end + 1, nm);

				tsp = new_tsp(path);
				if (!tsp)
					rv = ENOMEM;
				else {
					next_dir = 1;
					pl += el + 1;
					tsp->ts_fh = efh;
					tsp->ts_st = est;
					tsp->ts_ent = lp;
					pn.tn_fh = &tsp->ts_fh;
					pn.tn_st = &tsp->ts_st;
				}
			}
			break;

		} while (rv == 0);

		/*
		 * A new directory must be processed, go to the start of
		 * the loop, open it and process it.
		 */
		if (next_dir)
			continue;
skip_dir:
		if (tsp) {
			free(tsp->ts_fh.fh_fpath);
			free(tsp);
		}

		if (rv == SKIP_ENTRY)
			rv = 0;

		if (rv == 0) {
			if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
				break;

			traverse_stats.fss_pops++;

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG,
				    "Poped pl %d \"%s\"", pl, path);

			*tsp->ts_end = '\0';
			pl = tsp->ts_end - path;
			pn.tn_fh = &tsp->ts_fh;
			pn.tn_st = &tsp->ts_st;
		}
	} while (rv == 0);

	/*
	 * Pop and free all the remaining entries on the stack.
	 */
	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
		traverse_stats.fss_stack_residue++;

		free(tsp->ts_fh.fh_fpath);
		free(tsp);
	}
end:
	free(darg.da_buf);
	cstack_delete(sp);
	return (rv);
}
示例#17
0
文件: host.c 项目: 2asoft/freebsd
/*
 * Copy a portion of a file into memory.
 */
static int
host_read(struct open_file *f, void *start, size_t size, size_t *resid)
{

	return (CALLBACK(read, f->f_fsdata, start, size, resid));
}
示例#18
0
size_t json_parser_execute (json_parser *parser,
                            const char *data,
                            size_t len,
                            size_t depth)
{
  char c, ch;
  const char *p = data, *pe;
  enum state state = parser->state;
  size_t stack_size = parser->stack_size;
  unsigned char *stack = parser->stack;

  for (p=data, pe=data+len; p != pe; p++) {
    ch = *p;

    /* skip ws */
    switch (state) {
        case s_start_value:
        case s_separator_or_end:
        case s_start_key_string:
        case s_eof:
        case s_colon:
            if (WS(ch))
                continue;
        default:
            break;
    }

    switch (state) {
        case s_start_value:
          /* start of a strings */
          if (ch == '"') {
              state = s_string;
              break;
          }
          /* start of a number */
          if (ch == 0x2D) {
            state = s_start_int;
            CALLBACK2(minus);
            break;
          }
          if (ch == '0') {
            MARK;
            state = s_start_frac_or_exp;
            break;
          }
          if (ch >= '1' && ch <= '9') {
              MARK;
              state = s_int;
              break;
          }
          /* start of an array */
          if (ch == '[') {
            CHECK_DEPTH;
            set_stack(stack, stack_size++, ss_array);
            state = s_start_value;
            CALLBACK2(array_begin);
            break;
          }
          /* start of an object */
          if (ch == '{') {
            CHECK_DEPTH;
            set_stack(stack, stack_size++, ss_object);
            state = s_start_key_string;
            CALLBACK2(object_begin);
            break;
          }
          goto error;
        end_of_value:
          if (stack_size == 1) {
            state = s_eof;
            if (WS(ch)) {
              break;
            }
            goto error;
          } else {
            state = s_separator_or_end;
          }
          if (WS(ch)) {
            break;
          }
        case s_separator_or_end:
          if (get_stack(stack, stack_size-1) == ss_array && ch == ',') {
            CALLBACK2(separator);
            state = s_start_value;
            break;
          }
          if ((get_stack(stack, stack_size-1) == ss_array && ch == ']') 
           || (get_stack(stack, stack_size-1) == ss_object && ch == '}')) {
            CALLBACK2(end);
            --stack_size;
            if (stack_size == 1) {
              state = s_eof;
            }
            break;
          }
          if (get_stack(stack, stack_size-1) == ss_object && ch == ',') {
            CALLBACK2(separator);
            state = s_start_key_string;
            break;
          }
          if (stack_size == 1 && WS(ch)) {
            state = s_eof;
            break;
          }
          goto error;
        case s_string:
          if (ch == '"') {
            CALLBACK(string);
            state = s_separator_or_end;
            break;
          }
          break;
        case s_start_int:
          if (ch == '0') {
            MARK;
            state = s_start_frac_or_exp;
            break;
          }
          if (ch >= '1' && ch <= '9') {
              MARK;
              state = s_int;
              break;
          }
          goto error;
        case s_int:
          if (ch >= '0' && ch <= '9') {
            break;
          }
          CALLBACK(int);
          if (ch == '.') {
            state = s_frac;
            break;
          }
          if (ch == 'e') {
            state = s_exp;
            break;
          }
          goto end_of_value;
        case s_start_frac_or_exp:
          CALLBACK(int);
          if (ch == '.') {
            state = s_frac;
            break;
          }
          if (ch == 'e') {
            state = s_exp;
            break;
          }
          goto end_of_value;
        case s_frac:
          if (! parser->data_mark && ch <= '0' && ch >= '9') {
            goto error;
          }
          if (ch >= '0' && ch <= '9') {
            if (! parser->data_mark)
              MARK;
            break;
          }
          CALLBACK(frac);
          if (ch == 'e') {
            state = s_start_exp;
            break;
          }
          goto end_of_value;
        case s_start_exp:
            if (ch == '-' || ch == '+') {
              MARK;
              state = s_exp;
              break;
            }
            goto error;
        case s_exp:
          if (! parser->data_mark && ch <= '0' && ch >= '9') {
            goto error;
          }
          if (ch >= '0' && ch <= '9') {
            break;
          }
          CALLBACK(exp);
          goto end_of_value;
        case s_start_key_string:
          if (ch == '"') {
            state = s_key_string;
            break;
          }
          goto error;
        case s_key_string:
          if (! parser->data_mark) {
            MARK;
          }
          if (ch == '"') {
            CALLBACK(string);
            state = s_colon;
            break;
          }
          break;
        case s_colon:
          if (ch == ':') {
            CALLBACK2(separator);
            state = s_start_value;
            break;
          }
          goto error;
        case s_eof:
          goto error;
        default:
            goto error;
    }
  }

  switch (state) {
    case s_key_string:
    case s_string:
      CALLBACK(string);
      break;
    case s_int:
    case s_start_frac_or_exp:
      CALLBACK(int);
      break;
    case s_frac:
      CALLBACK(frac);
      break;
    case s_exp:
      CALLBACK(exp);
      break;
  }

  parser->state = state;
  parser->stack_size = stack_size;
  return len;

error:
  parser->state = state;
  return (p - data);
}
示例#19
0
文件: EventLoop.cpp 项目: rosrad/rct
inline bool EventLoop::sendTimers()
{
    std::set<uint64_t> fired;
    std::unique_lock<std::mutex> locker(mutex);
    const uint64_t now = currentTime();
    for (;;) {
        auto timer = timersByTime.begin();
        if (timer == timersByTime.end())
            return !fired.empty();
        TimerData* timerData = *timer;
        int currentId = timerData->id;
        while (fired.count(currentId)) {
            // already fired this round, ignore for now
            ++timer;
            if (timer == timersByTime.end())
                return !fired.empty();
            timerData = *timer;
            currentId = timerData->id;
        }
        if (timerData->when > now)
            return !fired.empty();
        if (timerData->flags & Timer::SingleShot) {
            // remove the timer before firing
            std::function<void(int)> func = std::move(timerData->callback);
            timersByTime.erase(timer);
            timersById.erase(timerData);
            delete timerData;
            fired.insert(currentId);

            // fire
            locker.unlock();
            CALLBACK(func(currentId));
            locker.lock();
        } else {
            // silly std::set/multiset doesn't have a way of forcing a resort.
            // take the item out and reinsert it

            // luckily we have the exact iterator
            timersByTime.erase(timer);

            // update the fire time
            const int64_t overtime = now - timerData->when;
            timerData->when = (now - overtime) + timerData->interval;

            // reinsert with the updated time
            timersByTime.insert(timerData);

            // take a copy of the callback in case the timer gets
            // removed before we get a chance to call it
            // ### is this heavy?
            std::function<void(int)> cb = timerData->callback;
            fired.insert(currentId);

            // fire
            locker.unlock();
            CALLBACK(cb(currentId));
            locker.lock();
        }
    }
    return !fired.empty();
}
示例#20
0
/*
 * There is an ELF kernel and one or more ELF modules loaded.
 * We wish to start executing the kernel image, so make such
 * preparations as are required, and do so.
 */
static int
elf64_exec(struct preloaded_file *fp)
{
	struct file_metadata	*md;
	Elf_Ehdr 		*ehdr;
	vm_offset_t		modulep, kernend;
	int			err;
	int			i;
	uint32_t		stack[1024];
	p4_entry_t		PT4[512];
	p3_entry_t		PT3[512];
	p2_entry_t		PT2[512];
	uint64_t		gdtr[3];

	if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
		return(EFTYPE);
	ehdr = (Elf_Ehdr *)&(md->md_data);

	err = bi_load64(fp->f_args, &modulep, &kernend);
	if (err != 0)
		return(err);

	bzero(PT4, PAGE_SIZE);
	bzero(PT3, PAGE_SIZE);
	bzero(PT2, PAGE_SIZE);

	/*
	 * Build a scratch stack at physical 0x1000, page tables:
	 *	PT4 at 0x2000,
	 *	PT3 at 0x3000,
	 *	PT2 at 0x4000,
	 *      gdtr at 0x5000,
	 */

	/*
	 * This is kinda brutal, but every single 1GB VM memory segment
	 * points to the same first 1GB of physical memory.  But it is
	 * more than adequate.
	 */
	for (i = 0; i < 512; i++) {
		/* Each slot of the level 4 pages points to the same level 3 page */
		PT4[i] = (p4_entry_t) 0x3000;
		PT4[i] |= PG_V | PG_RW | PG_U;

		/* Each slot of the level 3 pages points to the same level 2 page */
		PT3[i] = (p3_entry_t) 0x4000;
		PT3[i] |= PG_V | PG_RW | PG_U;

		/* The level 2 page slots are mapped with 2MB pages for 1GB. */
		PT2[i] = i * (2 * 1024 * 1024);
		PT2[i] |= PG_V | PG_RW | PG_PS | PG_U;
	}

#ifdef DEBUG
	printf("Start @ %#llx ...\n", ehdr->e_entry);
#endif

	dev_cleanup();

	stack[0] = 0;		/* return address */
	stack[1] = modulep;
	stack[2] = kernend;
	CALLBACK(copyin, stack, 0x1000, sizeof(stack));
	CALLBACK(copyin, PT4, 0x2000, sizeof(PT4));
	CALLBACK(copyin, PT3, 0x3000, sizeof(PT3));
	CALLBACK(copyin, PT2, 0x4000, sizeof(PT2));
	CALLBACK(setreg, 4, 0x1000);

	CALLBACK(setmsr, MSR_EFER, EFER_LMA | EFER_LME);
	CALLBACK(setcr, 4, CR4_PAE | CR4_VMXE);
	CALLBACK(setcr, 3, 0x2000);
	CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE);

	setup_freebsd_gdt(gdtr);
	CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr));
        CALLBACK(setgdt, 0x5000, sizeof(gdtr));

	CALLBACK(exec, ehdr->e_entry);

	panic("exec returned");
}
示例#21
0
文件: var.c 项目: 0xheart0/vlc
{
    const char *psz_name;
    vlc_callback_t callback;
} vlc_input_callback_t;

static void InputAddCallbacks( input_thread_t *, const vlc_input_callback_t * );
static void InputDelCallbacks( input_thread_t *, const vlc_input_callback_t * );

#ifdef CALLBACK /* For windows */
# undef CALLBACK /* We don't care of this one here */
#endif
/* List all callbacks added by input */
#define CALLBACK(name,cb) { name, cb }
static const vlc_input_callback_t p_input_callbacks[] =
{
    CALLBACK( "state", StateCallback ),
    CALLBACK( "rate", RateCallback ),
    CALLBACK( "position", PositionCallback ),
    CALLBACK( "position-offset", PositionCallback ),
    CALLBACK( "time", TimeCallback ),
    CALLBACK( "time-offset", TimeOffsetCallback ),
    CALLBACK( "bookmark", BookmarkCallback ),
    CALLBACK( "program", ProgramCallback ),
    CALLBACK( "title", TitleCallback ),
    CALLBACK( "chapter", SeekpointCallback ),
    CALLBACK( "audio-delay", EsDelayCallback ),
    CALLBACK( "spu-delay", EsDelayCallback ),
    CALLBACK( "video-es", ESCallback ),
    CALLBACK( "audio-es", ESCallback ),
    CALLBACK( "spu-es", ESCallback ),
    CALLBACK( "record", RecordCallback ),
示例#22
0
void
delay(int usec)
{

	CALLBACK(delay, usec);
}
示例#23
0
void
loader_main(struct loader_callbacks *cb, void *arg, int version, int ndisks)
{
	static char mallocbuf[MALLOCSZ];
	char *var;
	int i;

	if (version < USERBOOT_VERSION)
		abort();

	callbacks = cb;
	callbacks_arg = arg;
	userboot_disk_maxunit = ndisks;

	/*
	 * initialise the heap as early as possible.  Once this is done,
	 * alloc() is usable.
	 */
	setheap((void *)mallocbuf, (void *)(mallocbuf + sizeof(mallocbuf)));

	/*
	 * Hook up the console
	 */
	cons_probe();

	printf("\n%s", bootprog_info);
#if 0
	printf("Memory: %ld k\n", memsize() / 1024);
#endif

	setenv("LINES", "24", 1);	/* optional */

	/*
	 * Set custom environment variables
	 */
	i = 0;
	while (1) {
		var = CALLBACK(getenv, i++);
		if (var == NULL)
			break;
		putenv(var);
	}

	archsw.arch_autoload = userboot_autoload;
	archsw.arch_getdev = userboot_getdev;
	archsw.arch_copyin = userboot_copyin;
	archsw.arch_copyout = userboot_copyout;
	archsw.arch_readin = userboot_readin;
#if defined(USERBOOT_ZFS_SUPPORT)
	archsw.arch_zfs_probe = userboot_zfs_probe;
#endif

	/*
	 * Initialise the block cache. Set the upper limit.
	 */
	bcache_init(32768, 512);
	/*
	 * March through the device switch probing for things.
	 */
	for (i = 0; devsw[i] != NULL; i++)
		if (devsw[i]->dv_init != NULL)
			(devsw[i]->dv_init)();

	extract_currdev();

	/*
	 * Checking the interpreter isn't worth the overhead unless we
	 * actually have the swap_interpreter callback, so we actually version
	 * check here rather than later on.
	 */
	if (version >= USERBOOT_VERSION_5)
		check_interpreter();

	if (setjmp(jb))
		return;

	interact();			/* doesn't return */

	exit(0);
}
示例#24
0
static irq_return_t btm_bt_us_handler(unsigned int irq_num, void *dev_id) {

	CALLBACK(__bt_rx)(btm_bt_read_len, btm_bt_read_buff);

	return IRQ_HANDLED;
}