Пример #1
0
struct pico_device *pico_vde_create(char *sock, char *name, uint8_t *mac)
{
    struct pico_device_vde *vde = pico_zalloc(sizeof(struct pico_device_vde));
    struct vde_open_args open_args = {
        .mode = 0700
    };
    char vdename[] = "picotcp";

    if (!vde)
        return NULL;

    if( 0 != pico_device_init((struct pico_device *)vde, name, mac)) {
        dbg ("Vde init failed.\n");
        pico_vde_destroy((struct pico_device *)vde);
        return NULL;
    }

    vde->dev.overhead = 0;
    vde->sock = pico_zalloc(strlen(sock) + 1);
    memcpy(vde->sock, sock, strlen(sock));
    vde->conn = vde_open(sock, vdename, &open_args);
    if (!vde->conn) {
        pico_vde_destroy((struct pico_device *)vde);
        return NULL;
    }

    vde->dev.send = pico_vde_send;
    vde->dev.poll = pico_vde_poll;
    vde->dev.destroy = pico_vde_destroy;
    dbg("Device %s created.\n", vde->dev.name);
    return (struct pico_device *)vde;
}
Пример #2
0
static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_prefix *hdr, uint16_t len, struct pico_dns_query_suffix *suffix,
                                                        void (*callback)(char *, void *), void *arg)
{
    struct pico_dns_query *q = NULL, *found = NULL;

    q = pico_zalloc(sizeof(struct pico_dns_query));
    if (!q)
        return NULL;

    q->query = (char *)hdr;
    q->len = len;
    q->id = short_be(hdr->id);
    q->qtype = short_be(suffix->qtype);
    q->qclass = short_be(suffix->qclass);
    q->retrans = 1;
    q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
    q->callback = callback;
    q->arg = arg;
    q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
    if (!q->s) {
        pico_free(q);
        return NULL;
    }

    found = pico_tree_insert(&DNSTable, q);
    if (found) {
        pico_err = PICO_ERR_EAGAIN;
        pico_socket_close(q->s);
        pico_free(q);
        return NULL;
    }

    return q;
}
Пример #3
0
static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr)
{
    struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};

    dns = pico_zalloc(sizeof(struct pico_dns_ns));
    if (!dns) {
        pico_err = PICO_ERR_ENOMEM;
        return NULL;
    }

    dns->ns = *ns_addr;

    found = pico_tree_insert(&NSTable, dns);
    if (found) { /* nameserver already present */
        pico_free(dns);
        return found;
    }

    /* default NS found, remove it */
    pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
    found = pico_tree_findKey(&NSTable, &test);
    if (found && (found->ns.addr != ns_addr->addr))
        pico_dns_client_del_ns(&found->ns);

    return dns;
}
Пример #4
0
static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
{
    struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = {
        0
    };

    test.xid = xid;
    found = pico_tree_findKey(&DHCPCookies, &test);
    if (found) {
        pico_err = PICO_ERR_EAGAIN;
        return NULL;
    }

    dhcpc = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
    if (!dhcpc) {
        pico_err = PICO_ERR_ENOMEM;
        return NULL;
    }

    dhcpc->state = DHCP_CLIENT_STATE_INIT;
    dhcpc->status = DHCP_CLIENT_STATUS_INIT;
    dhcpc->xid = xid;
    dhcpc->uid = uid;
    *(dhcpc->uid) = 0;
    dhcpc->cb = cb;
    dhcpc->dev = dev;

    pico_tree_insert(&DHCPCookies, dhcpc);
    return dhcpc;
}
Пример #5
0
static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting)
{
  uint16_t port = PICO_DHCPD_PORT;
  struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = {0};
  struct pico_ipv4_link *link = NULL;
  
  link = pico_ipv4_link_get(&setting->server_ip);
  if (!link) {
    pico_err = PICO_ERR_EINVAL;
    return NULL;
  }
  test.dev = setting->dev;
  found = pico_tree_findKey(&DHCPSettings, &test);
  if (found) {
    pico_err = PICO_ERR_EINVAL;
    return NULL;
  }
  dhcps = pico_zalloc(sizeof(struct pico_dhcp_server_setting));
  if (!dhcps) {
    pico_err = PICO_ERR_ENOMEM;
    return NULL;
  }

  dhcps->lease_time = setting->lease_time;
  dhcps->pool_start = setting->pool_start;
  dhcps->pool_next = setting->pool_next;
  dhcps->pool_end = setting->pool_end;
  dhcps->dev = link->dev;
  dhcps->server_ip = link->address;
  dhcps->netmask = link->netmask;

  /* default values if not provided */
  if (!dhcps->pool_start)
    dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START;
  if (!dhcps->pool_end)
    dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END;
  if (!dhcps->lease_time)
    dhcps->lease_time = DHCP_SERVER_LEASE_TIME;
  dhcps->pool_next = dhcps->pool_start;

  dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
  if (!dhcps->s) {
    dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err));
    pico_free(dhcps);
    return NULL;
  }
  if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) {
    dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err));
    pico_free(dhcps);
    return NULL;
  }
  
  pico_tree_insert(&DHCPSettings, dhcps);
  return dhcps;
}
Пример #6
0
static void next_ping(uint32_t now, void *arg)
{
  struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
  IGNORE_PARAMETER(now);

	if(pico_tree_findKey(&Pings,cookie)){
    if (cookie->seq < cookie->count) {
      newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
      if (!newcookie)
        return;
      memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
      newcookie->seq++;

	    pico_tree_insert(&Pings,newcookie);
      send_ping(newcookie);
    }
  }
}
Пример #7
0
static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr)
{
  struct pico_dhcp_server_negotiation *dhcpn = NULL;
  struct pico_dhcp_server_setting test = {0};
  struct pico_ip4 *ciaddr = NULL;

  if (pico_dhcp_server_find_negotiation(hdr->xid))
    return NULL;

  dhcpn = pico_zalloc(sizeof(struct pico_dhcp_server_negotiation));
  if (!dhcpn) {
    pico_err = PICO_ERR_ENOMEM;
    return NULL;
  }

  dhcpn->xid = hdr->xid;
  dhcpn->state = PICO_DHCP_STATE_DISCOVER;
  memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH);

  test.dev = dev;
  dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test);
  if (!dhcpn->dhcps) {
    dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name);
    pico_free(dhcpn);
    return NULL;
  }

  ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr);
  if (!ciaddr) {
    dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next;
    dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1);
    pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev);
  } else {
    dhcpn->ciaddr = *ciaddr;
  }

  pico_tree_insert(&DHCPNegotiations, dhcpn);
  return dhcpn; 
}
Пример #8
0
int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
{
  static uint16_t next_id = 0x91c0;
  struct pico_icmp4_ping_cookie *cookie;

  if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)){
    pico_err = PICO_ERR_EINVAL;
    return -1;
  }

  cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
  if (!cookie) {
    pico_err = PICO_ERR_ENOMEM;
    return -1;
  }

  if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) {
    pico_err = PICO_ERR_EINVAL;
    pico_free(cookie);
    return -1;
  }
  cookie->seq = 1;
  cookie->id = next_id++;
  cookie->err = PICO_PING_ERR_PENDING;
  cookie->size = (uint16_t)size;
  cookie->interval = interval;
  cookie->timeout = timeout;
  cookie->cb = cb;
  cookie->count = count;

  pico_tree_insert(&Pings,cookie);
  send_ping(cookie);

  return 0;

}
Пример #9
0
void serverWakeup(uint16_t ev, uint16_t conn)
{
    static FILE *f;
    char buffer[SIZE];

    if(ev & EV_HTTP_CON)
    {
        printf("New connection received....\n");
        pico_http_server_accept();
    }

    if(ev & EV_HTTP_REQ) /* new header received */
    {
        uint16_t read;
        char *resource;
        int method;
        printf("Header request was received...\n");
        printf("> Resource : %s\n", pico_http_getResource(conn));
        resource = pico_http_getResource(conn);
        method = pico_http_getMethod(conn);

        if(strcmp(resource, "/") == 0 || strcmp(resource, "index.html") == 0 || strcmp(resource, "/index.html") == 0)
        {
            if(method == HTTP_METHOD_GET)
            {
                /* Accepting request */
                printf("Received GET request\n");
                pico_http_respond(conn, HTTP_RESOURCE_FOUND);
                f = fopen("test/examples/form.html", "r");

                if(!f)
                {
                    fprintf(stderr, "Unable to open the file /test/examples/form.html\n");
                }

                read = (uint16_t)fread(buffer, 1u, SIZE, f);
                pico_http_submitData(conn, buffer, read);
            }
            else if(method == HTTP_METHOD_POST)
            {
                printf("Received POST request\n");
                printf("Form fields: %s\n", pico_http_getBody(conn));
                pico_http_respond(conn, HTTP_RESOURCE_FOUND);
                strcpy(buffer, "Thanks for posting your data");
                if(pico_http_submitData(conn, buffer, (uint16_t)strlen(buffer)) == HTTP_RETURN_ERROR)
                {
                    printf("error submitting data\n");
                }
                else
                {
                    printf("data submitted correctly\n");
                }
            }
        }
        else if(strcmp(resource, "/download") == 0)
        {
            const char download_url_field [] = "download_url=";
            char *download_url = NULL;
            char *download_basename = NULL;
            char *decoded_download_url = NULL;
            char *http_body = NULL;

            http_body = pico_http_getBody(conn);

            if(http_body != NULL)
            {
                download_url = strstr(http_body, download_url_field);
                if(download_url != NULL)
                {
                    download_url = download_url + strlen(download_url_field);
                    decoded_download_url = pico_zalloc(strlen(download_url) + 1);
                    url_decode(decoded_download_url, download_url);
                    printf("Download url: %s\n", decoded_download_url);

                    if(pico_http_client_open(decoded_download_url, wget_callback) < 0)
                    {
                        fprintf(stderr, " error opening the url : %s, please check the format\n", decoded_download_url);
                        pico_http_respond(conn, HTTP_RESOURCE_NOT_FOUND);
                    }

                    download_basename = basename(decoded_download_url);
                    url_filename = pico_zalloc(strlen(download_basename) + 1);
                    strcpy(url_filename, download_basename);

                    pico_free(decoded_download_url);

                    pico_http_respond(conn, HTTP_RESOURCE_FOUND);
                    strcpy(buffer, "Download started");
                    if(pico_http_submitData(conn, buffer, (uint16_t)strlen(buffer)) == HTTP_RETURN_ERROR)
                    {
                        printf("error submitting data\n");
                    }
                }
                else
                {
                    printf("no download url\n");
                    pico_http_respond(conn, HTTP_RESOURCE_NOT_FOUND);
                }
            }
            else
            {
                printf("no http body\n");
                pico_http_respond(conn, HTTP_RESOURCE_NOT_FOUND);
            }
        }
        else
        { /* reject */
            printf("Rejected connection...\n");
            pico_http_respond(conn, HTTP_RESOURCE_NOT_FOUND);
        }

    }

    if(ev & EV_HTTP_PROGRESS) /* submitted data was sent */
    {
        uint16_t sent, total;
        pico_http_getProgress(conn, &sent, &total);
        printf("Chunk statistics : %d/%d sent\n", sent, total);
    }

    if(ev & EV_HTTP_SENT) /* submitted data was fully sent */
    {
        int method;
        method = pico_http_getMethod(conn);
        if(method == HTTP_METHOD_GET)
        {
            uint16_t read;
            read = (uint16_t)fread(buffer, 1, SIZE, f);
            printf("Chunk was sent...\n");
            if(read > 0)
            {
                printf("Sending another chunk...\n");
                pico_http_submitData(conn, buffer, read);
            }
            else
            {
                printf("Last chunk get !\n");
                pico_http_submitData(conn, NULL, 0); /* send the final chunk */
                fclose(f);
            }
        }
        else if(method == HTTP_METHOD_POST)
        {
            printf("Last chunk post !\n");
            pico_http_submitData(conn, NULL, 0); /* send the final chunk */
        }
    }

    if(ev & EV_HTTP_CLOSE)
    {
        printf("Close request...\n");
        pico_http_close(conn);
    }

    if(ev & EV_HTTP_ERROR)
    {
        printf("Error on server...\n");
        pico_http_close(conn);
    }
}
static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
{
  char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
  struct dns_message_hdr *hdr;
  struct dns_query_suffix query_suf;
  struct dns_answer_suffix answer_suf;
  struct pico_dns_key test, *key;
  char *answer;
  char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
  uint8_t valid_suffix = 0;
  uint16_t compression = 0;
  int i = 0, r = 0;

  if (ev & PICO_SOCK_EV_RD) {
    r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
    pico_socket_close(s);
    if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
      dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
      return;
    }

    /* Check header validity */
    a_hdr = dns_answer;
    hdr = (struct dns_message_hdr *) a_hdr;
    pico_dns_client_hdr_ntoh(hdr);
    if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY 
        || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
      dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
      return;
    }

    if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
            + hdr->ancount * sizeof(struct dns_answer_suffix))) {
      dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
      return;
    }

    /* Find DNS key */
    test.id = hdr->id;

    key = pico_tree_findKey(&DNSTable,&test);
    if (!key) {
      dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
      return;
    }
    key->retrans = 0;

    /* Check query suffix validity */
    q_qname = a_hdr + sizeof(struct dns_message_hdr);
    q_suf = pico_dns_client_seek(q_qname);
    query_suf = *(struct dns_query_suffix *) q_suf;
    if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
      dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
      return;
    }

    /* Seek answer suffix */
    a_qname = q_suf + sizeof(struct dns_query_suffix);
    a_suf = a_qname;
    while(i++ < hdr->ancount) {
      uint16_t comp_h = short_from(a_suf);
      compression = short_be(comp_h);
      switch (compression >> 14)
      {
        case PICO_DNS_POINTER:
          while (compression >> 14 == PICO_DNS_POINTER) {
            dns_dbg("DNS: pointer\n");
            a_suf += sizeof(uint16_t);
            comp_h = short_from(a_suf);
            compression = short_be(comp_h);
          }
          break;

        case PICO_DNS_LABEL:
          dns_dbg("DNS: label\n");
          a_suf = pico_dns_client_seek(a_qname);
          break;

        default:
          dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
          return;
      }

      /* Check answer suffix validity */
      answer_suf = *(struct dns_answer_suffix *)a_suf;
      if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
        dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
        continue;
      }

      if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
        dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
        continue;
      }

      valid_suffix = 1;
      break;
    }

    if (!valid_suffix) {
       dns_dbg("DNS ERROR: invalid dns answer suffix\n");
       return;
    }

    a_rdata = a_suf + sizeof(struct dns_answer_suffix);
    if (key->qtype == PICO_DNS_TYPE_A) {
      uint32_t ip_h = long_from(a_rdata);
      dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h));
      answer = pico_zalloc(16);
      pico_ipv4_to_string(answer, ip_h);
      key->callback(answer, key->arg);
    } else if (key->qtype == PICO_DNS_TYPE_PTR) {
      pico_dns_client_reverse_label((char *) a_rdata);
      dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
      answer = pico_zalloc(answer_suf.rdlength - 1);
      memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
      key->callback(answer, key->arg);
    } else {
      dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
      return;
    }
  }
int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
{
  struct pico_dns_ns test, *key = NULL;

  if (!ns) {
    pico_err = PICO_ERR_EINVAL;
    return -1;
  }

  switch (flag)
  {
    case PICO_DNS_NS_ADD:
      key = pico_zalloc(sizeof(struct pico_dns_ns));
      if (!key) {
        pico_err = PICO_ERR_ENOMEM;
        return -1;
      }
      key->ns = *ns;

      if(pico_tree_insert(&NSTable,key)){
        dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
        pico_err = PICO_ERR_EINVAL;
        pico_free(key);
        return -1; /* Element key already exists */
      }
      dns_dbg("DNS: nameserver %08X added\n", ns->addr);
      /* If default NS found, remove it */
      pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
      if (ns->addr != test.ns.addr) {

          key = pico_tree_findKey(&NSTable,&test);
        if (key) {
            if(pico_tree_delete(&NSTable,key)) {
            dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
            pico_free(key);
          } else {
            pico_err = PICO_ERR_EAGAIN;
            return -1;
          }
        }
      }
      break;

    case PICO_DNS_NS_DEL:
      test.ns = *ns;

      key = pico_tree_findKey(&NSTable,&test);
      if (!key) {
        dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
        pico_err = PICO_ERR_EINVAL;
        return -1;
      }
      /* RB_REMOVE returns pointer to removed element, NULL to indicate error */

            if(pico_tree_delete(&NSTable,key)) {
        dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
        pico_free(key);
      } else {
        pico_err = PICO_ERR_EAGAIN;
        return -1;
      }
      /* If no NS left, add default NS */
      if(pico_tree_first(&NSTable) == NULL){
        dns_dbg("DNS: add default nameserver\n");
        return pico_dns_client_init();
      }
      break;

    default:
      pico_err = PICO_ERR_EINVAL;
      return -1;
  }
  return 0;
}
Пример #12
0
int8_t pico_processURI(const char * uri, struct pico_http_uri * urikey)
{

    uint16_t lastIndex = 0, index;

    if(!uri || !urikey || uri[0] == '/')
    {
        pico_err = PICO_ERR_EINVAL;
        goto error;
    }

    // detect protocol => search for  "://"
    if(memcmp(uri,HTTP_PROTO_TOK,HTTP_PROTO_LEN) == 0) // could be optimized
    {   // protocol identified, it is http
        urikey->protoHttp = TRUE;
        lastIndex = HTTP_PROTO_LEN;
    }
    else
    {
        if(strstr(uri,"://")) // different protocol specified
        {
            urikey->protoHttp = FALSE;
            goto error;
        }
        // no protocol specified, assuming by default it's http
        urikey->protoHttp = TRUE;
    }

    // detect hostname
    index = lastIndex;
    while(uri[index] && uri[index]!='/' && uri[index]!=':') index++;

    if(index == lastIndex)
    {
        // wrong format
        urikey->host = urikey->resource = NULL;
        urikey->port = urikey->protoHttp = 0u;

        goto error;
    }
    else
    {
        // extract host
        urikey->host = (char *)pico_zalloc((uint32_t)(index-lastIndex+1));

        if(!urikey->host)
        {
            // no memory
            goto error;
        }
        memcpy(urikey->host,uri+lastIndex,(size_t)(index-lastIndex));
    }

    if(!uri[index])
    {
        // nothing specified
        urikey->port = 80u;
        urikey->resource = pico_zalloc(2u);
        urikey->resource[0] = '/';
        return HTTP_RETURN_OK;
    }
    else if(uri[index] == '/')
    {
        urikey->port = 80u;
    }
    else if(uri[index] == ':')
    {
        urikey->port = 0u;
        index++;
        while(uri[index] && uri[index]!='/')
        {
            // should check if every component is a digit
            urikey->port = (uint16_t)(urikey->port*10 + (uri[index] - '0'));
            index++;
        }
    }

    // extract resource
    if(!uri[index])
    {
        urikey->resource = pico_zalloc(2u);
        urikey->resource[0] = '/';
    }
    else
    {
        lastIndex = index;
        while(uri[index] && uri[index]!='?' && uri[index]!='&' && uri[index]!='#') index++;
        urikey->resource = (char *)pico_zalloc((size_t)(index-lastIndex+1));

        if(!urikey->resource)
        {
            // no memory
            pico_err = PICO_ERR_ENOMEM;
            goto error;
        }

        memcpy(urikey->resource,uri+lastIndex,(size_t)(index-lastIndex));
    }

    return HTTP_RETURN_OK;

error :
    if(urikey->resource)
    {
        pico_free(urikey->resource);
        urikey->resource = NULL;
    }
    if(urikey->host)
    {
        pico_free(urikey->host);
        urikey->host = NULL;
    }

    return HTTP_RETURN_ERROR;
}
Пример #13
0
static void dhcpd_make_reply(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msg_type)
{
  int r = 0, optlen = 0, offset = 0;
  struct pico_ip4 broadcast = {0}, dns = {0}, destination = { .addr = 0xFFFFFFFF};
  struct pico_dhcp_hdr *hdr = NULL;

  dns.addr = DHCP_SERVER_OPENDNS;
  broadcast.addr = dhcpn->dhcps->server_ip.addr | ~(dhcpn->dhcps->netmask.addr);

  optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_SERVERID + PICO_DHCP_OPTLEN_LEASETIME + PICO_DHCP_OPTLEN_NETMASK + PICO_DHCP_OPTLEN_ROUTER 
          + PICO_DHCP_OPTLEN_BROADCAST + PICO_DHCP_OPTLEN_DNS + PICO_DHCP_OPTLEN_END;
  hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen);

  hdr->op = PICO_DHCP_OP_REPLY;
  hdr->htype = PICO_DHCP_HTYPE_ETH;
  hdr->hlen = PICO_SIZE_ETH;
  hdr->xid = dhcpn->xid;
  hdr->yiaddr = dhcpn->ciaddr.addr;
  hdr->siaddr = dhcpn->dhcps->server_ip.addr;
  hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
  memcpy(hdr->hwaddr, dhcpn->hwaddr.addr, PICO_SIZE_ETH);

  /* options */
  offset += pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type);
  offset += pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpn->dhcps->server_ip);
  offset += pico_dhcp_opt_leasetime(&hdr->options[offset], dhcpn->dhcps->lease_time);
  offset += pico_dhcp_opt_netmask(&hdr->options[offset], &dhcpn->dhcps->netmask);
  offset += pico_dhcp_opt_router(&hdr->options[offset], &dhcpn->dhcps->server_ip);
  offset += pico_dhcp_opt_broadcast(&hdr->options[offset], &broadcast);
  offset += pico_dhcp_opt_dns(&hdr->options[offset], &dns);
  offset += pico_dhcp_opt_end(&hdr->options[offset]);

  destination.addr = hdr->yiaddr;
  r = pico_socket_sendto(dhcpn->dhcps->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen), &destination, PICO_DHCP_CLIENT_PORT);
  if (r < 0)
    dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err));

  return;
}

static void pico_dhcp_server_recv(struct pico_socket *s, uint8_t *buf, uint32_t len)
{
  uint8_t msgtype = 0;
  int32_t optlen = (int32_t)(len - sizeof(struct pico_dhcp_hdr));
  struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
  struct pico_dhcp_server_negotiation *dhcpn = NULL;
  struct pico_ip4 reqip = {0}, server_id = {0};
  struct pico_device *dev = NULL;

  if (!pico_dhcp_are_options_valid(hdr->options, optlen))
    return;

  dev = pico_ipv4_link_find(&s->local_addr.ip4);
  dhcpn = pico_dhcp_server_find_negotiation(hdr->xid);
  if (!dhcpn)
    dhcpn = pico_dhcp_server_add_negotiation(dev, hdr);
 
  if (!ip_inrange(dhcpn->ciaddr.addr))
    return;

  do {
    switch (opt->code)
    {
      case PICO_DHCP_OPT_PAD:
        break;

      case PICO_DHCP_OPT_END:
        break;

      case PICO_DHCP_OPT_MSGTYPE:
        msgtype = opt->ext.msg_type.type;
        dhcps_dbg("DHCP server: message type %u\n", msgtype);
        break;

      case PICO_DHCP_OPT_REQIP:
        reqip = opt->ext.req_ip.ip;
        dhcps_dbg("DHCP server: requested IP %08X\n", reqip.addr);
        break;

      case PICO_DHCP_OPT_SERVERID:
        server_id = opt->ext.server_id.ip;
        dhcps_dbg("DHCP server: server ID %08X\n", server_id.addr);
        break;        

      default:
        dhcps_dbg("DHCP server WARNING: unsupported option %u\n", opt->code);
        break;
    }
  } while (pico_dhcp_next_option(&opt));

  switch (msgtype)
  {
    case PICO_DHCP_MSG_DISCOVER:
      dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_OFFER);
      dhcpn->state = PICO_DHCP_STATE_OFFER;
      break;

    case PICO_DHCP_MSG_REQUEST:
      if ((dhcpn->state == PICO_DHCP_STATE_BOUND) && (!reqip.addr) && (!server_id.addr) && (hdr->ciaddr == dhcpn->ciaddr.addr))
        dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
      if (dhcpn->state == PICO_DHCP_STATE_OFFER) {
        dhcpn->state = PICO_DHCP_STATE_BOUND;
        dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
      }
      break;

    default:
      dhcps_dbg("DHCP server WARNING: unsupported message type %u\n", msgtype);
      break;
  }
  return;
}