void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType,
        const char * payload, int payloadLen, int sequence)
{
    // TODO - FIXME: if path is not full uri then map addr to Network address + append path(?)
    coap_packet_t notify;
    coap_transaction_t *transaction;
    NetworkAddress * remoteAddress = NetworkAddress_New(path, strlen(path));

    Lwm2m_Debug("Coap notify: %s\n", path);
    //Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr));
    //Lwm2m_Debug("Coap request port: %d\n", addr->Port);

    coap_init_message(&notify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());

    if (contentType != ContentType_None)
    {
        coap_set_header_content_format(&notify, contentType);
        coap_set_payload(&notify, payload, payloadLen);
    }

    coap_set_token(&notify, token, tokenSize);
    coap_set_header_observe(&notify, sequence);

    if ((transaction = coap_new_transaction(networkSocket, notify.mid, remoteAddress)))
    {
        transaction->packet_len = coap_serialize_message(&notify, transaction->packet);

        coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction();
    }
}
void coap_SendNotify(AddressType * addr, const char * path, const char * token, int tokenSize, ContentType contentType, const char * payload, int payloadLen, int sequence)
{
    coap_packet_t notify;
    coap_transaction_t *transaction;

    Lwm2m_Debug("Coap notify: %s\n", path);
    Lwm2m_Debug("Coap IPv6 request address: " PRINT6ADDR(&addr->Addr));
    Lwm2m_Debug("Coap request port: %d\n", addr->Port);

    coap_init_message(&notify, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());

    if (contentType != ContentType_None)
    {
        coap_set_header_content_format(&notify, contentType);
        coap_set_payload(&notify, payload, payloadLen);
    }

    coap_set_token(&notify, token, tokenSize);
    coap_set_header_observe(&notify, sequence);

    if ((transaction = coap_new_transaction(notify.mid, &addr->Addr, uip_htons(addr->Port))))
    {
        transaction->packet_len = coap_serialize_message(&notify, transaction->packet);

        coap_send_transaction(transaction); // for NON confirmable messages this will call coap_clear_transaction();
    }
}
Example #3
0
/*---------------------------------------------------------------------------*/
void
coap_notify_observers(resource_t *resource)
{
  /* build notification */
  coap_packet_t notification[1]; /* this way the packet can be treated as pointer as usual */
  coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0);
  coap_observer_t *obs = NULL;

  PRINTF("Observe: Notification from %s\n", resource->url);

  /* iterate over observers */
  for(obs = (coap_observer_t *)list_head(observers_list); obs;
      obs = obs->next) {
    if(obs->url == resource->url) {     /* using RESOURCE url pointer as handle */
      coap_transaction_t *transaction = NULL;

      /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */

      if((transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port))) {
        if(obs->obs_counter % COAP_OBSERVE_REFRESH_INTERVAL == 0) {
          PRINTF("           Force Confirmable for\n");
          notification->type = COAP_TYPE_CON;
        }

        PRINTF("           Observer ");
        PRINT6ADDR(&obs->addr);
        PRINTF(":%u\n", obs->port);

        /* update last MID for RST matching */
        obs->last_mid = transaction->mid;

        /* prepare response */
        notification->mid = transaction->mid;

        resource->get_handler(NULL, notification,
                              transaction->packet + COAP_MAX_HEADER_SIZE,
                              REST_MAX_CHUNK_SIZE, NULL);

        if(notification->code < BAD_REQUEST_4_00) {
          coap_set_header_observe(notification, (obs->obs_counter)++);
        }
        coap_set_token(notification, obs->token, obs->token_len);

        transaction->packet_len =
          coap_serialize_message(notification, transaction->packet);

        coap_send_transaction(transaction);
      }
    }
  }
}
Example #4
0
/*----------------------------------------------------------------------------*/
void
coap_separate_resume(void *response, coap_separate_t *separate_store,
                     uint8_t code)
{
    coap_init_message(response, separate_store->type, code,
                      separate_store->mid);
    if(separate_store->token_len) {
        coap_set_token(response, separate_store->token,
                       separate_store->token_len);
    }
    if(separate_store->block1_size) {
        coap_set_header_block1(response, separate_store->block1_num,
                               0, separate_store->block1_size);
    }
}
Example #5
0
int main(void)
{
  char alias[] = "temp";
  char cik[] = "a32c85ba9dda45823be416246cf8b433baa068d7";

  char host[] = "coap.exosite.com";
  char port[] = "5683";

  srand(time(NULL));

  // CoAP Message Setup
  #define MSG_BUF_LEN 64
  uint8_t msg_send_buf[MSG_BUF_LEN];
  coap_pdu msg_send = {msg_send_buf, 0, 64};
  uint8_t msg_recv_buf[MSG_BUF_LEN];
  coap_pdu msg_recv = {msg_recv_buf, 0, 64};

  uint16_t message_id_counter = rand();

  // Socket to Exosite
  int remotesock;
  size_t bytes_sent;
  ssize_t bytes_recv;
  int rv;

  struct addrinfo exohints, *servinfo, *q;

  memset(&exohints, 0, sizeof exohints);
  exohints.ai_family = AF_UNSPEC;
  exohints.ai_socktype = SOCK_DGRAM;
  exohints.ai_flags = AI_PASSIVE;

  if ((rv = getaddrinfo(host, port, &exohints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
  }


  // loop through all the results and make a socket
  for(q = servinfo; q != NULL; q = q->ai_next) {
    if ((remotesock = socket(q->ai_family, q->ai_socktype, q->ai_protocol)) == -1) {
      perror("bad socket");
      continue;
    }

    break;
  }

  if (q == NULL) {
      fprintf(stderr, "Failed to Bind Socket\n");
      return 2;
  }
 
  for (;;) 
  {
    printf("--------------------------------------------------------------------------------\n");

    // Build Message
    coap_init_pdu(&msg_send);
    //memset(msg_send, 0, msg_send_len);
    coap_set_version(&msg_send, COAP_V1);
    coap_set_type(&msg_send, CT_CON);
    coap_set_code(&msg_send, CC_GET); // or POST to write
    coap_set_mid(&msg_send, message_id_counter++);
    coap_set_token(&msg_send, rand(), 2);
    coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)"1a", 2);
    coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)alias, strlen(alias));
    coap_add_option(&msg_send, CON_URI_QUERY, (uint8_t*)cik, strlen(cik));
    // to write, set payload:
    //coap_set_payload(msg_send, &msg_send_len, MSG_BUF_LEN, (uint8_t*)"99", 2);

    // Send Message
    if ((bytes_sent = sendto(remotesock, msg_send.buf, msg_send.len, 0, q->ai_addr, q->ai_addrlen)) == -1){
      fprintf(stderr, "Failed to Send Message\n");
      return 2;
    }

    printf("Sent.\n");
    coap_pretty_print(&msg_send);

    // Wait for Response
    bytes_recv = recvfrom(remotesock, (void *)msg_recv.buf, msg_recv.max, 0, q->ai_addr, &q->ai_addrlen);
    if (bytes_recv < 0) {
      fprintf(stderr, "%s\n", strerror(errno));
      exit(EXIT_FAILURE);
    }

    msg_recv.len = bytes_recv;

    if(coap_validate_pkt(&msg_recv) == CE_NONE)
    {
      printf("Got Valid CoAP Packet\n");
      if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) &&
         coap_get_token(&msg_recv) == coap_get_token(&msg_send))
      {
        printf("Is Response to Last Message\n");
        coap_pretty_print(&msg_recv);
      }
    }else{
      printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len);
      hex_dump(msg_recv.buf, msg_recv.len);
    }

    sleep(1); // One Second
  }
}
Example #6
0
/*---------------------------------------------------------------------------*/
int
coap_engine_receive(coap_context_t *coap_ctx)
{
  erbium_status_code = NO_ERROR;
  coap_packet_t message[1]; /* this way the packet can be treated as pointer as usual */
  coap_packet_t response[1];
  coap_transaction_t *transaction = NULL;

  PRINTF("%s(): received data len %u\n", __FUNCTION__,
         (uint16_t)uip_appdatalen(coap_ctx->buf));

  if(uip_newdata(coap_ctx->buf)) {

    PRINTF("receiving UDP datagram from: ");
    PRINT6ADDR(&UIP_IP_BUF(coap_ctx->buf)->srcipaddr);
    PRINTF(":%u\n  Length: %u\n",
	   uip_ntohs(UIP_UDP_BUF(coap_ctx->buf)->srcport),
           uip_appdatalen(coap_ctx->buf));

    erbium_status_code =
    coap_parse_message(message, uip_appdata(coap_ctx->buf), uip_appdatalen(coap_ctx->buf));
    coap_set_context(message, coap_ctx);

    if(erbium_status_code == NO_ERROR) {

      NET_COAP_STAT(recv++);

      /*TODO duplicates suppression, if required by application */

      PRINTF("  Parsed: v %u, t %u, tkl %u, c %u, mid %u\n", message->version,
             message->type, message->token_len, message->code, message->mid);
      PRINTF("  URL[%d]: %.*s\n", message->uri_path_len, message->uri_path_len, message->uri_path);
      PRINTF("  Payload[%d]: %.*s\n", message->payload_len, message->payload_len, message->payload);

      /* handle requests */
      if(message->code >= COAP_GET && message->code <= COAP_DELETE) {

        /* use transaction buffer for response to confirmable request */
        if((transaction = coap_new_transaction(message->mid, coap_ctx,
                                               &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                               UIP_UDP_BUF(coap_ctx->buf)->srcport))) {
          uint32_t block_num = 0;
          uint16_t block_size = REST_MAX_CHUNK_SIZE;
          uint32_t block_offset = 0;
          int32_t new_offset = 0;

          /* prepare response */
          if(message->type == COAP_TYPE_CON) {
            /* reliable CON requests are answered with an ACK */
            coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
                              message->mid);
          } else {
            /* unreliable NON requests are answered with a NON as well */
            coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
                              coap_get_mid());
            /* mirror token */
          } if(message->token_len) {
            coap_set_token(response, message->token, message->token_len);
            /* get offset for blockwise transfers */
          }
          if(coap_get_header_block2
               (message, &block_num, NULL, &block_size, &block_offset)) {
            PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n",
                   (unsigned long)block_num, block_size, REST_MAX_CHUNK_SIZE, (unsigned long)block_offset);
            block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
            new_offset = block_offset;
          }

          /* invoke resource handler */
          if(service_cbk) {

            /* call REST framework and check if found and allowed */
            if(service_cbk
                 (message, response, transaction->packet + COAP_MAX_HEADER_SIZE,
                 block_size, &new_offset)) {

              if(erbium_status_code == NO_ERROR) {

                /* TODO coap_handle_blockwise(request, response, start_offset, end_offset); */

                /* resource is unaware of Block1 */
                if(IS_OPTION(message, COAP_OPTION_BLOCK1)
                   && response->code < BAD_REQUEST_4_00
                   && !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
                  PRINTF("Block1 NOT IMPLEMENTED\n");

                  erbium_status_code = NOT_IMPLEMENTED_5_01;
                  coap_error_message = "NoBlock1Support";

                  /* client requested Block2 transfer */
                } else if(IS_OPTION(message, COAP_OPTION_BLOCK2)) {

                  /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
                  if(new_offset == block_offset) {
                    PRINTF
                      ("Blockwise: unaware resource with payload length %u/%u\n",
                      response->payload_len, block_size);
                    if(block_offset >= response->payload_len) {
                      PRINTF
                        ("handle_incoming_data(): block_offset >= response->payload_len\n");

                      response->code = BAD_OPTION_4_02;
                      coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
                    } else {
                      coap_set_header_block2(response, block_num,
                                             response->payload_len -
                                             block_offset > block_size,
                                             block_size);
                      coap_set_payload(response,
                                       response->payload + block_offset,
                                       MIN(response->payload_len -
                                           block_offset, block_size));
                    } /* if(valid offset) */

                    /* resource provides chunk-wise data */
                  } else {
                    PRINTF("Blockwise: blockwise resource, new offset %ld\n",
                           (long)new_offset);
                    coap_set_header_block2(response, block_num,
                                           new_offset != -1
                                           || response->payload_len >
                                           block_size, block_size);

                    if(response->payload_len > block_size) {
                      coap_set_payload(response, response->payload,
                                       block_size);
                    }
                  } /* if(resource aware of blockwise) */

                  /* Resource requested Block2 transfer */
                } else if(new_offset != 0) {
                  PRINTF
                    ("Blockwise: no block option for blockwise resource, using block size %u\n",
                    COAP_MAX_BLOCK_SIZE);

                  coap_set_header_block2(response, 0, new_offset != -1,
                                         COAP_MAX_BLOCK_SIZE);
                  coap_set_payload(response, response->payload,
                                   MIN(response->payload_len,
                                       COAP_MAX_BLOCK_SIZE));
                } /* blockwise transfer handling */
              } /* no errors/hooks */
                /* successful service callback */
                /* serialize response */
            }
            if(erbium_status_code == NO_ERROR) {
              if((transaction->packet_len = coap_serialize_message(response,
                                                                   transaction->
                                                                   packet)) ==
                 0) {
                erbium_status_code = PACKET_SERIALIZATION_ERROR;
              }
            }
          } else {
            erbium_status_code = NOT_IMPLEMENTED_5_01;
            coap_error_message = "NoServiceCallbck"; /* no 'a' to fit into 16 bytes */
          } /* if(service callback) */
        } else {
          erbium_status_code = SERVICE_UNAVAILABLE_5_03;
          coap_error_message = "NoFreeTraBuffer";
        } /* if(transaction buffer) */

        /* handle responses */
      } else {

        if(message->type == COAP_TYPE_CON && message->code == 0) {
          PRINTF("Received Ping\n");
          erbium_status_code = PING_RESPONSE;
        } else if(message->type == COAP_TYPE_ACK) {
          /* transactions are closed through lookup below */
          PRINTF("Received ACK\n");
        } else if(message->type == COAP_TYPE_RST) {
          PRINTF("Received RST\n");
          /* cancel possible subscriptions */
          coap_remove_observer_by_mid(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                      UIP_UDP_BUF(coap_ctx->buf)->srcport, message->mid);
        }

        if((transaction = coap_get_transaction_by_mid(message->mid))) {
          /* free transaction memory before callback, as it may create a new transaction */
          restful_response_handler callback = transaction->callback;
          void *callback_data = transaction->callback_data;

          coap_clear_transaction(transaction);

          /* check if someone registered for the response */
          if(callback) {
            callback(callback_data, message);
          }
        }
        /* if(ACKed transaction) */
        transaction = NULL;

#if COAP_OBSERVE_CLIENT
	/* if observe notification */
        if((message->type == COAP_TYPE_CON || message->type == COAP_TYPE_NON)
              && IS_OPTION(message, COAP_OPTION_OBSERVE)) {
          PRINTF("Observe [%u]\n", message->observe);
          coap_handle_notification(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
                                   UIP_UDP_BUF(coap_ctx->buf)->srcport, message);
        }
#endif /* COAP_OBSERVE_CLIENT */
      } /* request or response */
    } else { /* parsed correctly */
      NET_COAP_STAT(recv_err++);
    }

    /* if(parsed correctly) */
    if(erbium_status_code == NO_ERROR) {
      if(transaction) {
        coap_send_transaction(transaction);
      }
    } else if(erbium_status_code == MANUAL_RESPONSE) {
      PRINTF("Clearing transaction for manual response");
      coap_clear_transaction(transaction);
    } else {
      coap_message_type_t reply_type = COAP_TYPE_ACK;

      PRINTF("ERROR %u: %s\n", erbium_status_code, coap_error_message);
      coap_clear_transaction(transaction);

      if(erbium_status_code == PING_RESPONSE) {
        erbium_status_code = 0;
        reply_type = COAP_TYPE_RST;
      } else if(erbium_status_code >= 192) {
        /* set to sendable error code */
        erbium_status_code = INTERNAL_SERVER_ERROR_5_00;
        /* reuse input buffer for error message */
      }
      coap_init_message(message, reply_type, erbium_status_code,
                        message->mid);
      coap_set_payload(message, coap_error_message,
                       strlen(coap_error_message));
      coap_send_message(coap_ctx, &UIP_IP_BUF(coap_ctx->buf)->srcipaddr,
			UIP_UDP_BUF(coap_ctx->buf)->srcport,
                        uip_appdata(coap_ctx->buf),
			coap_serialize_message(message,
					       uip_appdata(coap_ctx->buf)));
    }
  }

  /* if(new data) */
  return erbium_status_code;
}
Example #7
0
void* CoapClient(void* parg)
{
	socklen_t sin_size;
	struct sockaddr_in addr_remote;
	uint16_t message_id_counter;
	ssize_t bytes_sent;
	ssize_t bytes_recv;
	uint8_t msg_buf[MSG_BUF_LEN];
	int msg_len;
	
	int fifo_fd;
	char fifo[64] = {'\0'};
	
	struct timeval timeout;
	timeout.tv_sec = 3;
	timeout.tv_usec = 0;
	
	coapIP *ipdata = (coapIP *)parg;
	
	//注册信号
	(void)signal(COAP_CLOSE_SIGNAL, Close_Sig);
	(void)signal(FIFO_CREATE_SIGNAL, Fifo_Create_Sig);
	
	// CoAP Message Setup
	uint8_t msg_send_buf[MSG_BUF_LEN];
	coap_pdu msg_send = {msg_send_buf, 0, MSG_BUF_LEN};
	uint8_t msg_recv_buf[MSG_BUF_LEN];
	coap_pdu msg_recv = {msg_recv_buf, 0, MSG_BUF_LEN};
	
	srand(time(NULL));
	message_id_counter = rand();
	
	//创建套接字
	if( (ipdata->coapSocket = socket(AF_INET, SOCK_DGRAM, 0))==-1 )
	{
		zlog_error(zc, "create socket error!");
		exit(-1);
	}
	
	addr_remote.sin_family = AF_INET;
	addr_remote.sin_port = htons(COAP_PORT);
	addr_remote.sin_addr.s_addr = inet_addr( ipdata->ip );
 	memset(addr_remote.sin_zero, 0, 8);
 	
 	zlog_debug(zc, "coap client socket is %d, ip is %s,path is %s", ipdata->coapSocket, ipdata->ip, ipdata->path);
 	
 	//设置接收超时
 	setsockopt(ipdata->coapSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));
 	
 	GetfifoName( fifo, sizeof(fifo), getpid() );
	
	//等待fifo创建好的信号
	//pause();
	
	//以只读方式打开FIFO,返回文件描述符fd 
	fifo_fd = open(fifo,O_RDONLY);   
	if( fifo_fd == -1 )
	{
		printf("Open fifo error!\n");
		exit(1);
	}
	
	printf("coap client %d open fifo %s\r\n", getpid(), fifo);
 	 	
	while(1) 
	{
		//清空缓存
		memset(msg_send.buf, '\0', MSG_BUF_LEN);
		msg_send.len = 0;
		
		//从管道读数据
		msg_len = read(fifo_fd, msg_buf, MSG_BUF_LEN);
		//printf("fifo read is %s", msg_buf);
		
		// Build Message
		coap_init_pdu(&msg_send);
		coap_set_version(&msg_send, COAP_V1);
		coap_set_type(&msg_send, CT_CON);
		coap_set_code(&msg_send, CC_GET); // or POST to write
		coap_set_mid(&msg_send, message_id_counter++);
		coap_set_token(&msg_send, rand(), 2);
		coap_add_option(&msg_send, CON_URI_PATH, (uint8_t*)ipdata->path, strlen(ipdata->path));
	
		// to write, set payload:
		coap_set_payload( &msg_send, (uint8_t *)msg_buf, msg_len );
		
		// Send Message
		if ( (bytes_sent = sendto(ipdata->coapSocket, msg_send.buf, msg_send.len, 0, 
		(struct sockaddr*)&addr_remote, sizeof(struct sockaddr_in))) == -1 )
			zlog_error(zc, "Failed to Send Message!");
		else
		{
			//发送成功
			//printf("Sent.\n");
			//coap_pretty_print(&msg_send);
		
			sin_size = sizeof(struct sockaddr);
			// Wait for Response
			bytes_recv = recvfrom(ipdata->coapSocket, (void *)msg_recv.buf, msg_recv.max, 0, (struct sockaddr*)&addr_remote, &sin_size);
			if (bytes_recv < 0) 
			{
				zlog_error(zc, "Failed to socket recv Message!");
				continue;
			}
/*
			msg_recv.len = bytes_recv;

			if(coap_validate_pkt(&msg_recv) == CE_NONE)
			{
				printf("Got Valid CoAP Packet\n");
				if(coap_get_mid(&msg_recv) == coap_get_mid(&msg_send) && coap_get_token(&msg_recv) == coap_get_token(&msg_send))
				{
					printf("Is Response to Last Message\n");
					coap_pretty_print(&msg_recv);
				}
			}
			else
			{
				printf("Received %zi Bytes, Not Valid CoAP\n", msg_recv.len);
				hex_dump(msg_recv.buf, msg_recv.len);
			}
*/		
		}
	}
}
Example #8
0
/*---------------------------------------------------------------------------*/
int
coap_receive(oc_message_t *msg)
{
  erbium_status_code = NO_ERROR;

  LOG("\n\nCoAP Engine: received datalen=%u \n", (unsigned int) msg->length);

  /* static declaration reduces stack peaks and program code size */
  static coap_packet_t
    message[1]; /* this way the packet can be treated as pointer as usual */
  static coap_packet_t response[1];
  static coap_transaction_t *transaction = NULL;

  erbium_status_code = coap_parse_message(message, msg->data, msg->length);

  if (erbium_status_code == NO_ERROR) {

/*TODO duplicates suppression, if required by application */

#if DEBUG
    LOG("  Parsed: CoAP version: %u, token: 0x%02X%02X, mid: %u\n",
        message->version, message->token[0], message->token[1], message->mid);
    switch (message->type) {
    case COAP_TYPE_CON:
      LOG("  type: CON\n");
      break;
    case COAP_TYPE_NON:
      LOG("  type: NON\n");
      break;
    case COAP_TYPE_ACK:
      LOG("  type: ACK\n");
      break;
    case COAP_TYPE_RST:
      LOG("  type: RST\n");
      break;
    default:
      break;
    }
#endif

    /* handle requests */
    if (message->code >= COAP_GET && message->code <= COAP_DELETE) {

#if DEBUG
      switch (message->code) {
      case COAP_GET:
        LOG("  method: GET\n");
        break;
      case COAP_PUT:
        LOG("  method: PUT\n");
        break;
      case COAP_POST:
        LOG("  method: POST\n");
        break;
      case COAP_DELETE:
        LOG("  method: DELETE\n");
        break;
      }
      LOG("  URL: %.*s\n", (int) message->uri_path_len, message->uri_path);
      LOG("  Payload: %.*s\n", (int) message->payload_len, message->payload);
#endif
      /* use transaction buffer for response to confirmable request */
      if ((transaction = coap_new_transaction(message->mid, &msg->endpoint))) {
        uint32_t block_num = 0;
        uint16_t block_size = COAP_MAX_BLOCK_SIZE;
        uint32_t block_offset = 0;
        int32_t new_offset = 0;

        /* prepare response */
        if (message->type == COAP_TYPE_CON) {
          /* reliable CON requests are answered with an ACK */
          coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05,
                            message->mid);
        } else {
          /* unreliable NON requests are answered with a NON as well */
          coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05,
                            coap_get_mid());
          /* mirror token */
        }
        if (message->token_len) {
          coap_set_token(response, message->token, message->token_len);
          /* get offset for blockwise transfers */
        }
        if (coap_get_header_block2(message, &block_num, NULL, &block_size,
                                   &block_offset)) {
          LOG("\tBlockwise: block request %u (%u/%u) @ %u bytes\n", (unsigned int) block_num,
              block_size, COAP_MAX_BLOCK_SIZE, (unsigned int) block_offset);
          block_size = MIN(block_size, COAP_MAX_BLOCK_SIZE);
          new_offset = block_offset;
        }

        /* invoke resource handler in RI layer */
        if (oc_ri_invoke_coap_entity_handler(
              message, response,
              transaction->message->data + COAP_MAX_HEADER_SIZE, block_size,
              &new_offset, &msg->endpoint)) {

          if (erbium_status_code == NO_ERROR) {

            /* TODO coap_handle_blockwise(request, response, start_offset,
             * end_offset); */

            /* resource is unaware of Block1 */
            if (IS_OPTION(message, COAP_OPTION_BLOCK1) &&
                response->code < BAD_REQUEST_4_00 &&
                !IS_OPTION(response, COAP_OPTION_BLOCK1)) {
              LOG("\tBlock1 option NOT IMPLEMENTED\n");

              erbium_status_code = NOT_IMPLEMENTED_5_01;
              coap_error_message = "NoBlock1Support";

              /* client requested Block2 transfer */
            } else if (IS_OPTION(message, COAP_OPTION_BLOCK2)) {

              /* unchanged new_offset indicates that resource is unaware of
               * blockwise transfer */
              if (new_offset == block_offset) {
                LOG("\tBlockwise: unaware resource with payload length %u/%u\n",
                    response->payload_len, block_size);
                if (block_offset >= response->payload_len) {
                  LOG("\t\t: block_offset >= response->payload_len\n");

                  response->code = BAD_OPTION_4_02;
                  coap_set_payload(response, "BlockOutOfScope",
                                   15); /* a const char str[] and sizeof(str)
                                           produces larger code size */
                } else {
                  coap_set_header_block2(response, block_num,
                                         response->payload_len - block_offset >
                                           block_size,
                                         block_size);
                  coap_set_payload(
                    response, response->payload + block_offset,
                    MIN(response->payload_len - block_offset, block_size));
                } /* if(valid offset) */

                /* resource provides chunk-wise data */
              } else {
                LOG("\tBlockwise: blockwise resource, new offset %d\n",
                    (int) new_offset);
                coap_set_header_block2(response, block_num,
                                       new_offset != -1 ||
                                         response->payload_len > block_size,
                                       block_size);

                if (response->payload_len > block_size) {
                  coap_set_payload(response, response->payload, block_size);
                }
              } /* if(resource aware of blockwise) */

              /* Resource requested Block2 transfer */
            } else if (new_offset != 0) {
              LOG("\tBlockwise: no block option for blockwise resource, using "
                  "block size %u\n",
                  COAP_MAX_BLOCK_SIZE);

              coap_set_header_block2(response, 0, new_offset != -1,
                                     COAP_MAX_BLOCK_SIZE);
              coap_set_payload(response, response->payload,
                               MIN(response->payload_len, COAP_MAX_BLOCK_SIZE));
            } /* blockwise transfer handling */
          }   /* no errors/hooks */
          /* successful service callback */
          /* serialize response */
        }
        if (erbium_status_code == NO_ERROR) {
          if ((transaction->message->length = coap_serialize_message(
                 response, transaction->message->data)) == 0) {
            erbium_status_code = PACKET_SERIALIZATION_ERROR;
          }
        }
      } else {
        erbium_status_code = SERVICE_UNAVAILABLE_5_03;
        coap_error_message = "NoFreeTraBuffer";
      } /* if(transaction buffer) */

      /* handle responses */
    } else { // Fix this
      if (message->type == COAP_TYPE_CON) {
        erbium_status_code = EMPTY_ACK_RESPONSE;
      } else if (message->type == COAP_TYPE_ACK) {
        /* transactions are closed through lookup below */
      } else if (message->type == COAP_TYPE_RST) {
#ifdef OC_SERVER
        /* cancel possible subscriptions */
        coap_remove_observer_by_mid(&msg->endpoint, message->mid);
#endif
      }

      /* Open transaction now cleared for ACK since mid matches */
      if ((transaction = coap_get_transaction_by_mid(message->mid))) {
        coap_clear_transaction(transaction);
      }
      /* if(ACKed transaction) */
      transaction = NULL;

#ifdef OC_CLIENT // ACKs and RSTs sent to oc_ri.. RSTs cleared, ACKs sent to
                 // client
      oc_ri_invoke_client_cb(message, &msg->endpoint);
#endif

    } /* request or response */
  }   /* parsed correctly */

  /* if(parsed correctly) */
  if (erbium_status_code == NO_ERROR) {
    if (transaction) { // Server transactions sent from here
      coap_send_transaction(transaction);
    }
  } else if (erbium_status_code == CLEAR_TRANSACTION) {
    LOG("Clearing transaction for manual response");
    coap_clear_transaction(transaction); // used in server for separate response
  }
#ifdef OC_CLIENT
  else if (erbium_status_code == EMPTY_ACK_RESPONSE) {
    coap_init_message(message, COAP_TYPE_ACK, 0, message->mid);
    oc_message_t *response = oc_allocate_message();
    if (response) {
      memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint));
      response->length = coap_serialize_message(message, response->data);
      coap_send_message(response);
    }
  }
#endif /* OC_CLIENT */
#ifdef OC_SERVER
  else { // framework errors handled here
    coap_message_type_t reply_type = COAP_TYPE_RST;

    coap_clear_transaction(transaction);

    coap_init_message(message, reply_type, SERVICE_UNAVAILABLE_5_03,
                      message->mid);

    oc_message_t *response = oc_allocate_message();
    if (response) {
      memcpy(&response->endpoint, &msg->endpoint, sizeof(msg->endpoint));
      response->length = coap_serialize_message(message, response->data);
      coap_send_message(response);
    }
  }
#endif /* OC_SERVER */

  /* if(new data) */
  return erbium_status_code;
}
void coap_createCoapRequest(coap_method_t method, const char * uri, ContentType contentType, ObserveState observeState,
        const char * payload, int payloadLen, TransactionCallback callback, void * context)
{
    coap_packet_t request;
    char path[MAX_COAP_PATH] =
    { 0 };
    char query[128] =
    { 0 };
    coap_transaction_t *transaction;
    NetworkAddress * remoteAddress = NetworkAddress_New(uri, strlen(uri));

    coap_getPathQueryFromURI(uri, path, query);

    Lwm2m_Info("Coap request: %s\n", uri);
    //Lwm2m_Debug("Coap request path: %s\n", path);
    //Lwm2m_Debug("Coap request query: %s\n", query);

    coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid());

    coap_set_header_uri_path(&request, path);
    if (strlen(query) > 0)
        coap_set_header_uri_query(&request, query);
    // TODO - REVIEW: Erbium must copy path/query from request - else mem out of scope

    if (contentType != ContentType_None)
    {
        if ((method == COAP_POST) || (method == COAP_PUT))
        {
            coap_set_header_content_format(&request, contentType);
            coap_set_payload(&request, payload, payloadLen);
        }
        else
        {
            coap_set_header_accept(&request, contentType);
        }
    }


    if (method == COAP_GET)
    {
        if (observeState == ObserveState_Establish)
        {
            coap_set_header_observe(&request, 0);
            int token = addObserve(remoteAddress, path, callback, context);
            if (token != 0)
                coap_set_token(&request, (const uint8_t *) &token, sizeof(token));

        }
        else if (observeState == ObserveState_Cancel)
        {
            coap_set_header_observe(&request, 1);
            int token = removeObserve(remoteAddress, path);
            if (token != 0)
                coap_set_token(&request, (const uint8_t *) &token, sizeof(token));
        }
    }

    if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr)
    {
        Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex,
                CurrentTransaction[CurrentTransactionIndex].TransactionPtr);
        coap_clear_transaction(&CurrentTransaction[CurrentTransactionIndex].TransactionPtr);
    }

    //if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port))))
    if ((transaction = coap_new_transaction(networkSocket, request.mid, remoteAddress)))
    {
        transaction->callback = coap_CoapRequestCallback;
        memcpy(CurrentTransaction[CurrentTransactionIndex].Path, path, MAX_COAP_PATH);
        CurrentTransaction[CurrentTransactionIndex].Callback = callback;
        CurrentTransaction[CurrentTransactionIndex].Context = context;
        CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true;
        CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction;
        NetworkAddress_SetAddressType(remoteAddress, &CurrentTransaction[CurrentTransactionIndex].Address);

        transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex];

        transaction->packet_len = coap_serialize_message(&request, transaction->packet);

        Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr);
        coap_send_transaction(transaction);

        CurrentTransactionIndex++;

        if (CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS)
        {
            CurrentTransactionIndex = 0;
        }
    }
}