/*-----------------------------------------------------------------------------------*/ void coap_observe_handler(resource_t *resource, void *request, void *response) { static char content[26]; if (response && ((coap_packet_t *)response)->code<128) /* response without error code */ { if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_OBSERVE)) { if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_TOKEN)) { if (coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, ((coap_packet_t *)request)->token, ((coap_packet_t *)request)->token_len, resource->url)) { coap_set_header_observe(response, 0); coap_set_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); } else { ((coap_packet_t *)response)->code = SERVICE_UNAVAILABLE_503; coap_set_payload(response, (uint8_t *)"Too many observers", 18); } /* if (added observer) */ } else /* if (token) */ { ((coap_packet_t *)response)->code = TOKEN_OPTION_REQUIRED; coap_set_payload(response, (uint8_t *)"Observing requires token", 24); } /* if (token) */ } else /* if (observe) */ { /* Remove client if it is currently observing. */ coap_remove_observer_by_client(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport); } /* if (observe) */ } }
int options_parser_option_arg_ref3(t_opt *opt, const t_refoption *ref, char **av, unsigned int *i) { if (ref->isvalue == 3 && av[*i + 1] == NULL) { printf("%s: option requires an argument -- '%s'\n", BINARY_NAME, (IS_EXTOPTION(av[*i]) == 1) ? &av[*i][2] : &av[*i][1]); return (EXIT_FAILURE); } else if (ref->isvalue == 3) { if (!IS_OPTION(av[*i + 1])) { while (av[*i + 1] && !IS_OPTION(av[*i + 1])) { char *tmp = opt->value; if ((opt->value = malloc(sizeof(char) * \ (strlen(av[*i + 1]) + strlen(tmp)) + 2)) == NULL) return (EXIT_FAILURE); bzero(opt->value, (strlen(av[*i + 1]) + strlen(tmp)) + 2); sprintf(opt->value, "%s %s", tmp, av[*i + 1]); if (tmp) free(tmp); ++(*i); } } } return (EXIT_SUCCESS); }
static int prv_checkFinished(lwm2m_transaction_t * transacP, coap_packet_t * receivedMessage) { int len; const uint8_t* token; coap_packet_t * transactionMessage = transacP->message; if (COAP_DELETE < transactionMessage->code) { // response return transacP->ack_received ? 1 : 0; } if (!IS_OPTION(transactionMessage, COAP_OPTION_TOKEN)) { // request without token return transacP->ack_received ? 1 : 0; } len = coap_get_header_token(receivedMessage, &token); if (transactionMessage->token_len == len) { if (memcmp(transactionMessage->token, token, len)==0) return 1; } return 0; }
/*-----------------------------------------------------------------------------------*/ void coap_observe_handler(resource_t *resource, void *request, void *response) { coap_packet_t *const coap_req = (coap_packet_t *) request; coap_packet_t *const coap_res = (coap_packet_t *) response; static char content[16]; if (coap_req->code==COAP_GET && coap_res->code<128) /* GET request and response without error code */ { if (IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) { if (coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->token_len, resource->url)) { coap_set_header_observe(coap_res, 0); /* * For demonstration purposes only. A subscription should return the same representation as a normal GET. * TODO: Comment the following line for any real application. */ coap_set_payload(coap_res, content, snprintf(content, sizeof(content), "Added %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); } else { coap_res->code = SERVICE_UNAVAILABLE_5_03; coap_set_payload(coap_res, "TooManyObservers", 16); } /* if (added observer) */ } else /* if (observe) */ { /* Remove client if it is currently observing. */ coap_remove_observer_by_url(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, resource->url); } /* if (observe) */ } }
static void ICACHE_FLASH_ATTR prv_obsRequestCallback(lwm2m_transaction_t * transacP, void * message) { lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData; coap_packet_t * packet = (coap_packet_t *)message; uint8_t code; switch (observationP->status) { case STATE_DEREG_PENDING: // Observation was canceled by the user. observation_remove(((lwm2m_client_t*)transacP->peerP), observationP); return; case STATE_REG_PENDING: observationP->status = STATE_REGISTERED; break; default: break; } if (message == NULL) { code = COAP_503_SERVICE_UNAVAILABLE; } else if (packet->code == COAP_205_CONTENT && !IS_OPTION(packet, COAP_OPTION_OBSERVE)) { code = COAP_405_METHOD_NOT_ALLOWED; } else { code = packet->code; } if (code != COAP_205_CONTENT) { observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID, &observationP->uri, code, LWM2M_CONTENT_TEXT, NULL, 0, observationP->userData); observation_remove(((lwm2m_client_t*)transacP->peerP), observationP); } else { observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID, &observationP->uri, 0, packet->content_type, packet->payload, packet->payload_len, observationP->userData); } }
coap_status_t handle_dm_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, uint8_t * fromAddr, size_t fromAddrLen, coap_packet_t * message, coap_packet_t * response) { coap_status_t result; switch (message->code) { case COAP_GET: { char * buffer = NULL; int length = 0; result = object_read(contextP, uriP, &buffer, &length); if (result == COAP_205_CONTENT) { if (IS_OPTION(message, COAP_OPTION_OBSERVE)) { result = handle_observe_request(contextP, uriP, fromAddr, fromAddrLen, message, response); } if (result == COAP_205_CONTENT) { coap_set_payload(response, buffer, length); // lwm2m_handle_packet will free buffer } } } break; case COAP_POST: { result = object_create_execute(contextP, uriP, (char *)message->payload, message->payload_len); } break; case COAP_PUT: { result = object_write(contextP, uriP, (char *)message->payload, message->payload_len); } break; case COAP_DELETE: { result = object_delete(contextP, uriP); } break; default: result = BAD_REQUEST_4_00; break; } return result; }
bool ParseCommandLine( const char *cmdline, char *trapparms, char *servparms, bool *oneshot ) /*******************************************************************************************/ { const char *start; const char *ptr; char *buff; *oneshot = FALSE; *trapparms = '\0'; *servparms = '\0'; #if defined(__AXP__) && defined(__NT__) //NYI: temp until we can get all the unaligned stuff straightened out. SetErrorMode( SEM_NOALIGNMENTFAULTEXCEPT ); #endif ptr = SkipSpaces( cmdline ); if( WantUsage( ptr ) ) { StartupErr( ServUsage ); return( FALSE ); } while( IS_OPTION( *ptr ) ) { ptr = SkipSpaces( ptr + 1 ); start = ptr; #undef isalpha while( isalpha( *ptr ) ) ++ptr; if( ptr == start ) { StartupErr( TRP_ERR_expect_option ); return( FALSE ); } else if( strnicmp( "trap", start, ptr - start ) == 0 ) { ptr = SkipSpaces( ptr ); if( *ptr != '=' && *ptr != '#' ) { StartupErr( TRP_ERR_expect_equal ); return( FALSE ); } ptr = SkipSpaces( GetFilename( ptr + 1, trapparms ) ); if( *ptr == TRAP_PARM_SEPARATOR ) { buff = trapparms + strlen( trapparms ); *buff++ = TRAP_PARM_SEPARATOR; ptr = CollectTrapParm( SkipSpaces( ptr + 1 ), buff ); } else if( *ptr == '{'/*}*/ ) { buff = trapparms + strlen( trapparms ); *buff++ = TRAP_PARM_SEPARATOR; ptr = CollectTrapParm( ptr, buff ); } } else if( strnicmp( "once", start, ptr - start ) == 0 ) { *oneshot = TRUE; } ptr = SkipSpaces( ptr ); } CollectTrapParm( ptr, servparms ); TrapVersion.remote = TRUE; return( TRUE ); }
/*---------------------------------------------------------------------------*/ void coap_observe_handler(resource_t *resource, void *request, void *response) { coap_packet_t *const coap_req = (coap_packet_t *)request; coap_packet_t *const coap_res = (coap_packet_t *)response; coap_observer_t * obs; if(coap_req->code == COAP_GET && coap_res->code < 128) { /* GET request and response without error code */ if(IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) { if(coap_req->observe == 0) { obs = coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->token_len, resource->url); if(obs) { coap_set_header_observe(coap_res, (obs->obs_counter)++); /* * Following payload is for demonstration purposes only. * A subscription should return the same representation as a normal GET. * Uncomment if you want an information about the avaiable observers. */ #if 0 static char content[16]; coap_set_payload(coap_res, content, snprintf(content, sizeof(content), "Added %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); #endif } else { coap_res->code = SERVICE_UNAVAILABLE_5_03; coap_set_payload(coap_res, "TooManyObservers", 16); } } else if(coap_req->observe == 1) { /* remove client if it is currently observe */ coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->token_len); } } } }
/** * \brief Block 1 support within a coap-ressource * * This function will help you to use block 1. If target is null * error handling and response configuration is active. On return * value 0, the last block was recived, while on return value 1 * more blocks will follow. With target, len and maxlen this * function will assemble the blocks. * * You can find an example in: * examples/er-rest-example/resources/res-b1-sep-b2.c * * \param request Request pointer from the handler * \param response Response pointer from the handler * \param target Pointer to the buffer where the request payload can be assembled * \param len Pointer to the variable, where the function stores the actual length * \param max_len Length of the "target"-Buffer * * \return 0 if initialisation was successful * -1 if initialisation failed */ int coap_block1_handler(void *request, void *response, uint8_t *target, size_t *len, size_t max_len) { const uint8_t *payload = 0; int pay_len = REST.get_request_payload(request, &payload); if(!pay_len || !payload) { erbium_status_code = REST.status.BAD_REQUEST; coap_error_message = "NoPayload"; return -1; } coap_packet_t *packet = (coap_packet_t *)request; if(packet->block1_offset + pay_len > max_len) { erbium_status_code = REST.status.REQUEST_ENTITY_TOO_LARGE; coap_error_message = "Message to big"; return -1; } if(target && len) { memcpy(target + packet->block1_offset, payload, pay_len); *len = packet->block1_offset + pay_len; } if(IS_OPTION(packet, COAP_OPTION_BLOCK1)) { PRINTF("Blockwise: block 1 request: Num: %u, More: %u, Size: %u, Offset: %u\n", packet->block1_num, packet->block1_more, packet->block1_size, packet->block1_offset); coap_set_header_block1(response, packet->block1_num, packet->block1_more, packet->block1_size); if(packet->block1_more) { coap_set_status_code(response, CONTINUE_2_31); return 1; } } return 0; }
static void prv_obsRequestCallback(lwm2m_transaction_t * transacP, void * message) { lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData; coap_packet_t * packet = (coap_packet_t *)message; uint8_t code; if (message == NULL) { code = COAP_503_SERVICE_UNAVAILABLE; } else if (packet->code == COAP_205_CONTENT && !IS_OPTION(packet, COAP_OPTION_OBSERVE)) { code = COAP_405_METHOD_NOT_ALLOWED; } else { code = packet->code; } if (code != COAP_205_CONTENT) { observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID, &observationP->uri, code, NULL, 0, observationP->userData); prv_observationRemove(((lwm2m_client_t*)transacP->peerP), observationP); } else { observationP->status = STATE_REGISTERED; observationP->callback(((lwm2m_client_t*)transacP->peerP)->internalID, &observationP->uri, COAP_205_CONTENT, packet->payload, packet->payload_len, observationP->userData); } }
int options_parser_option(t_opt *opt, char **av, unsigned int *i, unsigned int *pos) { const t_refoption *ref; if (IS_OPTION(av[*i]) == 0 && av[*i + 1] == NULL) { opt[*pos].eopt = OPT_EXT; if (strncpy(opt[*pos].value, av[*i], strlen(av[*i])) == NULL) return (EXIT_FAILURE); } else if ((ref = options_exist(av[*i])) != NULL && options_get(ref->eopt) == NULL) { if (options_parser_option_arg(&opt[*pos], ref, av, i) == EXIT_FAILURE) return (EXIT_FAILURE); ++(*pos); } else return (options_parser_syntax(av[*i])); return (EXIT_SUCCESS); }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { uint8_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; LOG("Entering"); coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (coap_error_code == NO_ERROR) { LOG_ARG("Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u, Content type: %d", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid, message->content_type); LOG_ARG("Payload: %.*s", message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int64_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, COAP_205_CONTENT, message->mid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++); } /* mirror token */ if (message->token_len) { coap_set_header_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_ARG("Blockwise: block request %u (%u/%u) @ %u bytes", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /* handle block1 option */ if (IS_OPTION(message, COAP_OPTION_BLOCK1)) { #ifdef LWM2M_CLIENT_MODE // get server lwm2m_server_t * serverP; serverP = utils_findServer(contextP, fromSessionH); #ifdef LWM2M_BOOTSTRAP if (serverP == NULL) { serverP = utils_findBootstrapServer(contextP, fromSessionH); } #endif if (serverP == NULL) { coap_error_code = COAP_500_INTERNAL_SERVER_ERROR; } else { uint32_t block1_num; uint8_t block1_more; uint16_t block1_size; uint8_t * complete_buffer = NULL; size_t complete_buffer_size; // parse block1 header coap_get_header_block1(message, &block1_num, &block1_more, &block1_size, NULL); LOG_ARG("Blockwise: block1 request NUM %u (SZX %u/ SZX Max%u) MORE %u", block1_num, block1_size, REST_MAX_CHUNK_SIZE, block1_more); // handle block 1 coap_error_code = coap_block1_handler(&serverP->block1Data, message->mid, message->payload, message->payload_len, block1_size, block1_num, block1_more, &complete_buffer, &complete_buffer_size); // if payload is complete, replace it in the coap message. if (coap_error_code == NO_ERROR) { message->payload = complete_buffer; message->payload_len = complete_buffer_size; } else if (coap_error_code == COAP_231_CONTINUE) { block1_size = MIN(block1_size, REST_MAX_CHUNK_SIZE); coap_set_header_block1(response,block1_num, block1_more,block1_size); } } #else coap_error_code = COAP_501_NOT_IMPLEMENTED; #endif } if (coap_error_code == NO_ERROR) { coap_error_code = handle_request(contextP, fromSessionH, message, response); } if (coap_error_code==NO_ERROR) { /* Save original payload pointer for later freeing. Payload in response may be updated. */ uint8_t *payload = response->payload; if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ if (new_offset==block_offset) { LOG_ARG("Blockwise: unaware resource with payload length %u/%u", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("handle_incoming_data(): block_offset >= response->payload_len"); response->code = COAP_402_BAD_OPTION; 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) */ } else { /* resource provides chunk-wise data */ LOG_ARG("Blockwise: blockwise resource, new offset %d", (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) */ } else if (new_offset!=0) { LOG_ARG("Blockwise: no block option for blockwise resource, using block size %u", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(payload); response->payload = NULL; response->payload_len = 0; } else if (coap_error_code != COAP_IGNORE) { if (1 == coap_set_status_code(response, coap_error_code)) { coap_error_code = message_send(contextP, response, fromSessionH); } } } else { /* Responses */ switch (message->type) { case COAP_TYPE_NON: case COAP_TYPE_CON: { bool done = transaction_handleResponse(contextP, fromSessionH, message, response); #ifdef LWM2M_SERVER_MODE if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) && ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT))) { done = observe_handleNotify(contextP, fromSessionH, message, response); } #endif if (!done && message->type == COAP_TYPE_CON ) { coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); coap_error_code = message_send(contextP, response, fromSessionH); } } break; case COAP_TYPE_RST: /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); transaction_handleResponse(contextP, fromSessionH, message, NULL); break; case COAP_TYPE_ACK: transaction_handleResponse(contextP, fromSessionH, message, NULL); break; default: break; } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */
/*----------------------------------------------------------------------------*/ static int coap_receive(void) { coap_error_code = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen()); /* 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; if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen()); if (coap_error_code==NO_ERROR) { /*TODO duplicates suppression, if required by application */ PRINTF(" Parsed: v %u, t %u, oc %u, c %u, mid %u\n", message->version, message->type, message->option_count, message->code, message->mid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", 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, &UIP_IP_BUF->srcipaddr, UIP_UDP_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()); } /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { coap_set_header_token(response, message->token, message->token_len); SET_OPTION(response, COAP_OPTION_TOKEN); } /* 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", block_num, block_size, REST_MAX_CHUNK_SIZE, 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 (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { PRINTF("Block1 NOT IMPLEMENTED\n"); coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; } 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) */ } else { /* resource provides chunk-wise data */ PRINTF("Blockwise: blockwise resource, new offset %ld\n", 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) */ } else if (new_offset!=0) { PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ } /* no errors/hooks */ } /* successful service callback */ /* Serialize response. */ if (coap_error_code==NO_ERROR) { if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0) { coap_error_code = PACKET_SERIALIZATION_ERROR; } } } else { coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoServiceCallbck"; // no a to fit 16 bytes } /* if (service callback) */ } else { coap_error_code = SERVICE_UNAVAILABLE_5_03; coap_error_message = "NoFreeTraBuffer"; } /* if (transaction buffer) */ } else { /* Responses */ if (message->type==COAP_TYPE_ACK) { PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); } transaction = coap_get_transaction_by_mid(message->mid); if (message->type != COAP_TYPE_CON && transaction) { /* 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) */ /* 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(&UIP_IP_BUF->srcipaddr, \ UIP_UDP_BUF->srcport, message); } transaction = NULL; } /* Request or Response */ } /* if (parsed correctly) */ if (coap_error_code==NO_ERROR) { if (transaction) coap_send_transaction(transaction); } else if (coap_error_code==MANUAL_RESPONSE) { PRINTF("Clearing transaction for manual response"); coap_clear_transaction(transaction); } else { PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); coap_clear_transaction(transaction); /* Set to sendable error code. */ if (coap_error_code >= 192) { coap_error_code = INTERNAL_SERVER_ERROR_5_00; } /* Reuse input buffer for error message. */ coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return coap_error_code; }
/*-----------------------------------------------------------------------------------*/ static int handle_incoming_data(void) { int error = NO_ERROR; PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen()); if (uip_newdata()) { PRINTF("receiving UDP datagram from: "); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() ); PRINTBITS(uip_appdata, uip_datalen()); PRINTF("\n"); coap_packet_t message[1]; coap_transaction_t *transaction = NULL; error = coap_parse_message(message, uip_appdata, uip_datalen()); if (error==NO_ERROR) { /*TODO duplicates suppression, if required */ PRINTF(" Parsed: v %u, t %u, oc %u, c %u, tid %u\n", message->version, message->type, message->option_count, message->code, message->tid); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" Payload: %.*s\n", 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->tid, &UIP_IP_BUF->srcipaddr, UIP_UDP_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 */ coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ if (message->type==COAP_TYPE_CON) { /* Reliable CON requests are answered with an ACK. */ coap_init_message(response, COAP_TYPE_ACK, OK_200, message->tid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, OK_200, coap_get_tid()); } /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { coap_set_header_token(response, message->token, message->token_len); SET_OPTION(response, COAP_OPTION_TOKEN); } /* get offset for blockwise transfers */ if (coap_get_header_block(message, &block_num, NULL, &block_size, &block_offset)) { PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } /*------------------------------------------*/ /* call application-specific handler */ /*------------------------------------------*/ if (service_cbk) { service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset); } /*------------------------------------------*/ /* apply blockwise transfers */ if ( IS_OPTION(message, COAP_OPTION_BLOCK) ) { /* 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) { response->code = BAD_REQUEST_400; coap_set_payload(response, (uint8_t*)"Block out of scope", 18); } else { coap_set_header_block(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) */ } else { /* resource provides chunk-wise data */ PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset); coap_set_header_block(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) */ } else if (new_offset!=0) { PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0) { error = PACKET_SERIALIZATION_ERROR; } } else { error = MEMORY_ALLOCATION_ERROR; } } else { /* Responses */ coap_transaction_t *t; if (message->type==COAP_TYPE_ACK) { PRINTF("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { PRINTF(" Token 0x%02X%02X\n", message->token[0], message->token[1]); coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->token, message->token_len); } } if ( (t = coap_get_transaction_by_tid(message->tid)) ) { /* Free transaction memory before callback, as it may create a new transaction. */ restful_response_handler callback = t->callback; void *callback_data = t->callback_data; coap_clear_transaction(t); /* Check if someone registered for the response */ if (callback) { callback(callback_data, message); } } /* if (transaction) */ } } /* if (parsed correctly) */ if (error==NO_ERROR) { if (transaction) coap_send_transaction(transaction); } else { PRINTF("ERROR %u: %s\n", error, error_messages[error]); /* reuse input buffer */ coap_init_message(message, COAP_TYPE_ACK, INTERNAL_SERVER_ERROR_500, message->tid); coap_set_payload(message, (uint8_t *) error_messages[error], strlen(error_messages[error])); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); } } /* if (new data) */ return error; }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { coap_status_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (coap_error_code==NO_ERROR) { LOG(" Parsed: ver %u, type %u, tkl %u, code %u, mid %u\r\n", message->version, message->type, message->token_len, message->code, message->mid); LOG(" Payload: %.*s\r\n\n", message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { 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_header_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("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } coap_error_code = handle_request(contextP, fromSessionH, message, response); if (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { LOG("Block1 NOT IMPLEMENTED\n"); coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; } 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("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("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) */ } else { /* resource provides chunk-wise data */ LOG("Blockwise: blockwise resource, new offset %d\n", 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) */ } else if (new_offset!=0) { LOG("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(response->payload); response->payload = NULL; response->payload_len = 0; } else { coap_error_code = message_send(contextP, response, fromSessionH); } } else { /* Responses */ lwm2m_transaction_t * transaction; if (message->type==COAP_TYPE_ACK) { LOG("Received ACK\n"); } else if (message->type==COAP_TYPE_RST) { LOG("Received RST\n"); /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); } #ifdef LWM2M_SERVER_MODE if (message->code == COAP_204_CHANGED && IS_OPTION(message, COAP_OPTION_OBSERVE)) { handle_observe_notify(contextP, fromSessionH, message); } else #endif { transaction_handle_response(contextP, fromSessionH, message); } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */ else { LOG("Message parsing failed %d\r\n", coap_error_code); } if (coap_error_code != NO_ERROR) { LOG("ERROR %u: %s\n", coap_error_code, coap_error_message); /* Set to sendable error code. */ if (coap_error_code >= 192) { coap_error_code = INTERNAL_SERVER_ERROR_5_00; } /* Reuse input buffer for error message. */ coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid); coap_set_payload(message, coap_error_message, strlen(coap_error_message)); message_send(contextP, message, fromSessionH); } }
/*---------------------------------------------------------------------------*/ 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; }
/***************************************************************************** * udp_Open *****************************************************************************/ void udp_Open( void ) { int i_family; struct addrinfo *p_connect_ai = NULL, *p_bind_ai; int i_if_index = 0; in_addr_t i_if_addr = INADDR_ANY; int i_mtu = 0; char *psz_bind, *psz_string = strdup( psz_udp_src ); char *psz_save = psz_string; int i = 1; /* Parse configuration. */ if ( (psz_bind = strchr( psz_string, '@' )) != NULL ) { *psz_bind++ = '\0'; p_connect_ai = ParseNodeService( psz_string, NULL, 0 ); } else psz_bind = psz_string; p_bind_ai = ParseNodeService( psz_bind, &psz_string, DEFAULT_PORT ); if ( p_bind_ai == NULL ) { msg_Err( NULL, "couldn't parse %s", psz_bind ); exit(EXIT_FAILURE); } i_family = p_bind_ai->ai_family; if ( p_connect_ai != NULL && p_connect_ai->ai_family != i_family ) { msg_Warn( NULL, "invalid connect address" ); freeaddrinfo( p_connect_ai ); p_connect_ai = NULL; } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) b_udp = true; else if ( IS_OPTION("mtu=") ) i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) i_if_index = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("ifaddr=") ) i_if_addr = inet_addr( ARG_OPTION("ifaddr=") ); else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } if ( !i_mtu ) i_mtu = i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; i_block_cnt = (i_mtu - (b_udp ? 0 : RTP_HEADER_SIZE)) / TS_SIZE; /* Do stuff. */ if ( (i_handle = socket( i_family, SOCK_DGRAM, IPPROTO_UDP )) < 0 ) { msg_Err( NULL, "couldn't create socket (%s)", strerror(errno) ); exit(EXIT_FAILURE); } setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof( i ) ); /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid * packet loss caused by scheduling problems */ i = 0x80000; setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *) &i, sizeof( i ) ); if ( bind( i_handle, p_bind_ai->ai_addr, p_bind_ai->ai_addrlen ) < 0 ) { msg_Err( NULL, "couldn't bind (%s)", strerror(errno) ); close( i_handle ); exit(EXIT_FAILURE); } if ( p_connect_ai != NULL ) { uint16_t i_port; if ( i_family == AF_INET6 ) i_port = ((struct sockaddr_in6 *)p_connect_ai->ai_addr)->sin6_port; else i_port = ((struct sockaddr_in *)p_connect_ai->ai_addr)->sin_port; if ( i_port != 0 && connect( i_handle, p_connect_ai->ai_addr, p_connect_ai->ai_addrlen ) < 0 ) msg_Warn( NULL, "couldn't connect socket (%s)", strerror(errno) ); } /* Join the multicast group if the socket is a multicast address */ if ( i_family == AF_INET6 ) { struct sockaddr_in6 *p_addr = (struct sockaddr_in6 *)p_bind_ai->ai_addr; if ( IN6_IS_ADDR_MULTICAST( &p_addr->sin6_addr ) ) { struct ipv6_mreq imr; imr.ipv6mr_multiaddr = p_addr->sin6_addr; imr.ipv6mr_interface = i_if_index; if ( i_if_addr != INADDR_ANY ) msg_Warn( NULL, "ignoring ifaddr option in IPv6" ); if ( setsockopt( i_handle, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ipv6_mreq) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } } else { struct sockaddr_in *p_addr = (struct sockaddr_in *)p_bind_ai->ai_addr; if ( IN_MULTICAST( ntohl(p_addr->sin_addr.s_addr)) ) { if ( p_connect_ai != NULL ) { #ifndef IP_ADD_SOURCE_MEMBERSHIP msg_Err( NULL, "IP_ADD_SOURCE_MEMBERSHIP is unsupported." ); #else /* Source-specific multicast */ struct sockaddr_in *p_src = (struct sockaddr_in *)&p_connect_ai->ai_addr; struct ip_mreq_source imr; imr.imr_multiaddr = p_addr->sin_addr; imr.imr_interface.s_addr = i_if_addr; imr.imr_sourceaddr = p_src->sin_addr; if ( i_if_index ) msg_Warn( NULL, "ignoring ifindex option in SSM" ); if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq_source) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); #endif } else if ( i_if_index ) { /* Linux-specific interface-bound multicast */ struct ip_mreqn imr; imr.imr_multiaddr = p_addr->sin_addr; #if defined(__linux__) imr.imr_address.s_addr = i_if_addr; imr.imr_ifindex = i_if_index; #endif if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreqn) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } else { /* Regular multicast */ struct ip_mreq imr; imr.imr_multiaddr = p_addr->sin_addr; imr.imr_interface.s_addr = i_if_addr; if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq) ) == -1 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } } } freeaddrinfo( p_bind_ai ); if ( p_connect_ai != NULL ) freeaddrinfo( p_connect_ai ); free( psz_save ); msg_Dbg( NULL, "binding socket to %s", psz_udp_src ); }
uint8_t dm_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, coap_packet_t * message, coap_packet_t * response) { uint8_t result; lwm2m_media_type_t format; LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); LOG_URI(uriP); if (IS_OPTION(message, COAP_OPTION_CONTENT_TYPE)) { format = utils_convertMediaType(message->content_type); } else { format = LWM2M_CONTENT_TLV; } if (uriP->objectId == LWM2M_SECURITY_OBJECT_ID) { return COAP_404_NOT_FOUND; } if (serverP->status != STATE_REGISTERED && serverP->status != STATE_REG_UPDATE_NEEDED && serverP->status != STATE_REG_FULL_UPDATE_NEEDED && serverP->status != STATE_REG_UPDATE_PENDING) { return COAP_IGNORE; } // TODO: check ACL switch (message->code) { case COAP_GET: { uint8_t * buffer = NULL; size_t length = 0; int res; if (IS_OPTION(message, COAP_OPTION_OBSERVE)) { lwm2m_data_t * dataP = NULL; int size = 0; result = object_readData(contextP, uriP, &size, &dataP); if (COAP_205_CONTENT == result) { result = observe_handleRequest(contextP, uriP, serverP, size, dataP, message, response); if (COAP_205_CONTENT == result) { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } else { format = LWM2M_CONTENT_TLV; } res = lwm2m_data_serialize(uriP, size, dataP, &format, &buffer); if (res < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; } else { length = (size_t)res; LOG_ARG("Observe Request[/%d/%d/%d]: %.*s\n", uriP->objectId, uriP->instanceId, uriP->resourceId, length, buffer); } } lwm2m_data_free(size, dataP); } } else if (IS_OPTION(message, COAP_OPTION_ACCEPT) && message->accept_num == 1 && message->accept[0] == APPLICATION_LINK_FORMAT) { format = LWM2M_CONTENT_LINK; result = object_discover(contextP, uriP, serverP, &buffer, &length); } else { if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { format = utils_convertMediaType(message->accept[0]); } result = object_read(contextP, uriP, &format, &buffer, &length); } if (COAP_205_CONTENT == result) { coap_set_header_content_type(response, format); coap_set_payload(response, buffer, length); // lwm2m_handle_packet will free buffer } else { lwm2m_free(buffer); } } break; case COAP_POST: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (result == COAP_201_CREATED) { //longest uri is /65535/65535 = 12 + 1 (null) chars char location_path[13] = ""; //instanceId expected if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } if (sprintf(location_path, "/%d/%d", uriP->objectId, uriP->instanceId) < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } coap_set_header_location_path(response, location_path); lwm2m_update_registration(contextP, 0, true); } } else if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = object_execute(contextP, uriP, message->payload, message->payload_len); } } break; case COAP_PUT: { if (IS_OPTION(message, COAP_OPTION_URI_QUERY)) { lwm2m_attributes_t attr; if (0 != prv_readAttributes(message->uri_query, &attr)) { result = COAP_400_BAD_REQUEST; } else { result = observe_setParameters(contextP, uriP, serverP, &attr); } } else if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } else { result = COAP_400_BAD_REQUEST; } } break; case COAP_DELETE: { if (!LWM2M_URI_IS_SET_INSTANCE(uriP) || LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = COAP_400_BAD_REQUEST; } else { result = object_delete(contextP, uriP); if (result == COAP_202_DELETED) { lwm2m_update_registration(contextP, 0, true); } } } break; default: result = COAP_400_BAD_REQUEST; break; } return result; }
/* This function is an adaptation of function coap_receive() from Erbium's er-coap-13-engine.c. * Erbium is Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. */ void lwm2m_handle_packet(lwm2m_context_t * contextP, uint8_t * buffer, int length, void * fromSessionH) { coap_status_t coap_error_code = NO_ERROR; static coap_packet_t message[1]; static coap_packet_t response[1]; coap_error_code = coap_parse_message(message, buffer, (uint16_t)length); if (message[0].uri_path && message[0].uri_path->next && (message[0].uri_path->next->is_static != 0 && message[0].uri_path->next->is_static != 1)) { printf("BLA\n"); } if (coap_error_code == NO_ERROR) { LOG(" Parsed: ver %u, type %u, tkl %u, code %u.%.2u, mid %u\r\n", message->version, message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid); LOG(" Content type: %d\r\n Payload: %.*s\r\n\n", message->content_type, message->payload_len, message->payload); if (message->code >= COAP_GET && message->code <= COAP_DELETE) { uint32_t block_num = 0; uint16_t block_size = REST_MAX_CHUNK_SIZE; uint32_t block_offset = 0; int64_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, COAP_205_CONTENT, message->mid); } else { /* Unreliable NON requests are answered with a NON as well. */ coap_init_message(response, COAP_TYPE_NON, COAP_205_CONTENT, contextP->nextMID++); } /* mirror token */ if (message->token_len) { coap_set_header_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("Blockwise: block request %u (%u/%u) @ %u bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } coap_error_code = handle_request(contextP, fromSessionH, message, response); if (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<COAP_400_BAD_REQUEST && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { LOG("Block1 NOT IMPLEMENTED\n"); coap_error_code = COAP_501_NOT_IMPLEMENTED; coap_error_message = "NoBlock1Support"; } 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("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); if (block_offset >= response->payload_len) { LOG("handle_incoming_data(): block_offset >= response->payload_len\n"); response->code = COAP_402_BAD_OPTION; 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) */ } else { /* resource provides chunk-wise data */ LOG("Blockwise: 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) */ } else if (new_offset!=0) { LOG("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ coap_error_code = message_send(contextP, response, fromSessionH); lwm2m_free(response->payload); response->payload = NULL; response->payload_len = 0; } else if (coap_error_code != COAP_IGNORE) { if (1 == coap_set_status_code(response, coap_error_code)) { coap_error_code = message_send(contextP, response, fromSessionH); } } } else { /* Responses */ switch (message->type) { case COAP_TYPE_NON: case COAP_TYPE_CON: { bool done = transaction_handleResponse(contextP, fromSessionH, message, response); #ifdef LWM2M_SERVER_MODE if (!done && IS_OPTION(message, COAP_OPTION_OBSERVE) && ((message->code == COAP_204_CHANGED) || (message->code == COAP_205_CONTENT))) { done = observe_handleNotify(contextP, fromSessionH, message, response); } #endif if (!done && message->type == COAP_TYPE_CON ) { coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); coap_error_code = message_send(contextP, response, fromSessionH); } } break; case COAP_TYPE_RST: /* Cancel possible subscriptions. */ handle_reset(contextP, fromSessionH, message); transaction_handleResponse(contextP, fromSessionH, message, NULL); break; case COAP_TYPE_ACK: transaction_handleResponse(contextP, fromSessionH, message, NULL); break; default: break; } } /* Request or Response */ coap_free_header(message); } /* if (parsed correctly) */
/** @internal @This parses _uri and opens IPv4 & IPv6 sockets * * @param upipe description structure of the pipe * @param _uri socket URI * @param ttl packets time-to-live * @param bind_port bind port * @param connect_port connect port * @param weight weight (UNUSED) * @param use_tcp Set this to open a tcp socket (instead of udp) * @param use_raw open RAW socket (udp) * @param raw_header user-provided buffer for RAW header (ip+udp) * @return socket fd, or -1 in case of error */ int upipe_udp_open_socket(struct upipe *upipe, const char *_uri, int ttl, uint16_t bind_port, uint16_t connect_port, unsigned int *weight, bool *use_tcp, bool *use_raw, uint8_t *raw_header) { union sockaddru bind_addr, connect_addr; int fd, i; char *uri = strdup(_uri); char *token = uri; char *token2 = NULL; int bind_if_index = 0, connect_if_index = 0; in_addr_t if_addr = INADDR_ANY; in_addr_t src_addr = INADDR_ANY; uint16_t src_port = 4242; int tos = 0; bool b_tcp; bool b_raw; int family; socklen_t sockaddr_len; #if !defined(__APPLE__) && !defined(__native_client__) char *ifname = NULL; #endif if (!uri) return -1; memset(&bind_addr, 0, sizeof(union sockaddru)); memset(&connect_addr, 0, sizeof(union sockaddru)); bind_addr.ss.ss_family = AF_UNSPEC; connect_addr.ss.ss_family = AF_UNSPEC; if (use_tcp == NULL) { use_tcp = &b_tcp; } *use_tcp = false; if (use_raw == NULL) { use_raw = &b_raw; } *use_raw = false; token2 = strrchr(uri, ','); if (token2) { *token2++ = '\0'; if (weight) { *weight = strtoul(token2, NULL, 0); } } else if (weight) { *weight = 1; } token2 = strchr(uri, '/'); if (token2) { *token2 = '\0'; } if (*token == '\0') { free(uri); return -1; } /* Hosts */ if (token[0] != '@') { if (!upipe_udp_parse_node_service(upipe, token, &token, connect_port, &connect_if_index, &connect_addr.ss)) { free(uri); return -1; } /* required on some architectures */ memset(&connect_addr.sin.sin_zero, 0, sizeof(connect_addr.sin.sin_zero)); } if (token[0] == '@') { token++; if (!upipe_udp_parse_node_service(upipe, token, &token, bind_port, &bind_if_index, &bind_addr.ss)) { free(uri); return -1; } /* required on some architectures */ memset(&bind_addr.sin.sin_zero, 0, sizeof(bind_addr.sin.sin_zero)); } if (bind_addr.ss.ss_family == AF_UNSPEC && connect_addr.ss.ss_family == AF_UNSPEC) { free(uri); return -1; } upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); /* Weights and options */ if (token2) { do { *token2++ = '\0'; #define IS_OPTION(option) (!strncasecmp(token2, option, strlen(option))) #define ARG_OPTION(option) (token2 + strlen(option)) if (IS_OPTION("ifindex=")) { bind_if_index = connect_if_index = strtol(ARG_OPTION("ifindex="), NULL, 0); } else if (IS_OPTION("ifaddr=")) { char *option = config_stropt(ARG_OPTION("ifaddr=")); if_addr = inet_addr(option); free( option ); #if !defined(__APPLE__) && !defined(__native_client__) } else if ( IS_OPTION("ifname=") ) { ifname = config_stropt( ARG_OPTION("ifname=") ); if (strlen(ifname) >= IFNAMSIZ) { ifname[IFNAMSIZ-1] = '\0'; } #endif } else if (IS_OPTION("srcaddr=")) { char *option = config_stropt(ARG_OPTION("srcaddr=")); src_addr = inet_addr(option); free(option); *use_raw = true; } else if (IS_OPTION("srcport=")) { src_port = strtol(ARG_OPTION("srcport="), NULL, 0); } else if (IS_OPTION("ttl=")) { ttl = strtol(ARG_OPTION("ttl="), NULL, 0); } else if (IS_OPTION("tos=")) { tos = strtol(ARG_OPTION("tos="), NULL, 0); } else if (IS_OPTION("tcp")) { *use_tcp = true; } else { upipe_warn_va(upipe, "unrecognized option %s", token2); } #undef IS_OPTION #undef ARG_OPTION } while ((token2 = strchr(token2, '/')) != NULL); } if (unlikely(*use_tcp && *use_raw)) { upipe_warn(upipe, "RAW sockets not implemented for tcp"); free(uri); return -1; } free(uri); /* Sanity checks */ if (bind_addr.ss.ss_family != AF_UNSPEC && connect_addr.ss.ss_family != AF_UNSPEC && bind_addr.ss.ss_family != connect_addr.ss.ss_family) { upipe_err(upipe, "incompatible address types"); return -1; } if (bind_addr.ss.ss_family != AF_UNSPEC) { family = bind_addr.ss.ss_family; } else if (connect_addr.ss.ss_family != AF_UNSPEC) { family = connect_addr.ss.ss_family; } else { upipe_err(upipe, "ambiguous address declaration"); return -1; } sockaddr_len = (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); if (bind_if_index && connect_if_index && bind_if_index != connect_if_index) { upipe_err(upipe, "incompatible bind and connect interfaces"); return -1; } if (connect_if_index) bind_if_index = connect_if_index; else connect_if_index = bind_if_index; /* RAW header */ if (*use_raw && raw_header) { upipe_udp_raw_fill_headers(upipe, raw_header, src_addr, connect_addr.sin.sin_addr.s_addr, src_port, ntohs(connect_addr.sin.sin_port), ttl, tos, 0); } /* Socket configuration */ int sock_type = SOCK_DGRAM; if (*use_tcp) sock_type = SOCK_STREAM; if (*use_raw) sock_type = SOCK_RAW; int sock_proto = (*use_raw ? IPPROTO_RAW : 0); if ((fd = socket(family, sock_type, sock_proto)) < 0) { upipe_err_va(upipe, "unable to open socket (%m)"); return -1; } #if !defined(__APPLE__) && !defined(__native_client__) if (*use_raw) { int hincl = 1; if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) { upipe_err_va(upipe, "unable to set IP_HDRINCL"); close(fd); return -1; } } #endif i = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&i, sizeof(i)) == -1) { upipe_err_va(upipe, "unable to set socket (%m)"); close(fd); return -1; } if (family == AF_INET6) { if (bind_if_index && setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (void *)&bind_if_index, sizeof(bind_if_index)) < 0) { upipe_err(upipe, "couldn't set interface index"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } if (bind_addr.ss.ss_family != AF_UNSPEC) { #if !defined(__APPLE__) && !defined(__native_client__) if (IN6_IS_ADDR_MULTICAST(&bind_addr.sin6.sin6_addr)) { struct ipv6_mreq imr; union sockaddru bind_addr_any = bind_addr; bind_addr_any.sin6.sin6_addr = in6addr_any; if (bind(fd, &bind_addr_any.so, sizeof(bind_addr_any)) < 0) { upipe_err(upipe, "couldn't bind"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } imr.ipv6mr_multiaddr = bind_addr.sin6.sin6_addr; imr.ipv6mr_interface = bind_if_index; /* Join Multicast group without source filter */ if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ipv6_mreq)) < 0) { upipe_err(upipe, "couldn't join multicast group"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } else #endif goto normal_bind; } } else if (bind_addr.ss.ss_family != AF_UNSPEC) { normal_bind: if (bind(fd, &bind_addr.so, sockaddr_len) < 0) { upipe_err(upipe, "couldn't bind"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } if (!*use_tcp) { /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to * avoid packet loss caused by scheduling problems */ i = 0x80000; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &i, sizeof(i))) upipe_warn(upipe, "fail to increase receive buffer"); /* Join the multicast group if the socket is a multicast address */ if (bind_addr.ss.ss_family == AF_INET && IN_MULTICAST(ntohl(bind_addr.sin.sin_addr.s_addr))) { #ifndef __native_client__ if (connect_addr.ss.ss_family != AF_UNSPEC) { /* Source-specific multicast */ struct ip_mreq_source imr; imr.imr_multiaddr = bind_addr.sin.sin_addr; imr.imr_interface.s_addr = if_addr; imr.imr_sourceaddr = connect_addr.sin.sin_addr; if (bind_if_index) { upipe_warn(upipe, "ignoring ifindex option in SSM"); } if (setsockopt(fd, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq_source)) < 0) { upipe_err_va(upipe, "couldn't join multicast group (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } else if (bind_if_index) { /* Linux-specific interface-bound multicast */ struct ip_mreqn imr; imr.imr_multiaddr = bind_addr.sin.sin_addr; imr.imr_address.s_addr = if_addr; imr.imr_ifindex = bind_if_index; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreqn)) < 0) { upipe_err_va(upipe, "couldn't join multicast group (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } else #endif { /* Regular multicast */ struct ip_mreq imr; imr.imr_multiaddr = bind_addr.sin.sin_addr; imr.imr_interface.s_addr = if_addr; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq)) < 0) { upipe_err_va(upipe, "couldn't join multicast group (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } #ifdef SO_BINDTODEVICE if (ifname) { /* linux specific, needs root or CAP_NET_RAW */ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname) + 1) < 0) { upipe_err_va(upipe, "couldn't bind to device %s (%m)", ifname); free(ifname); close(fd); return -1; } ubase_clean_str(&ifname); } #endif } } if (connect_addr.ss.ss_family != AF_UNSPEC) { if (connect(fd, &connect_addr.so, sockaddr_len) < 0) { upipe_err_va(upipe, "cannot connect socket (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } if (!*use_tcp) { if (ttl) { if (family == AF_INET && IN_MULTICAST(ntohl(connect_addr.sin.sin_addr.s_addr))) { if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof(ttl)) == -1) { upipe_err_va(upipe, "couldn't set TTL (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } if (family == AF_INET6 && IN6_IS_ADDR_MULTICAST(&connect_addr.sin6.sin6_addr)) { if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof(ttl)) == -1) { upipe_err_va(upipe, "couldn't set TTL (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } } if (tos) { if (setsockopt(fd, IPPROTO_IP, IP_TOS, (void *)&tos, sizeof(tos)) == -1) { upipe_err_va(upipe, "couldn't set TOS (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } } } else if (*use_tcp) { /* Open in listen mode - wait for an incoming connection */ int new_fd; if (listen(fd, 1) < 0) { upipe_err_va(upipe, "couldn't listen (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } while ((new_fd = accept(fd, NULL, NULL)) < 0) { if (errno != EINTR) { upipe_err_va(upipe, "couldn't accept (%m)"); upipe_udp_print_socket(upipe, "socket definition:", &bind_addr, &connect_addr); close(fd); return -1; } } close(fd); return new_fd; } return fd; }
/*---------------------------------------------------------------------------*/ 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; }
bool config_ParseHost( output_config_t *p_config, char *psz_string ) { struct addrinfo *p_ai; int i_mtu; p_config->psz_displayname = strdup( psz_string ); p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT ); if ( p_ai == NULL ) return false; memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); p_config->i_family = p_config->connect_addr.ss_family; if ( p_config->i_family == AF_UNSPEC ) return false; if ( psz_string == NULL || !*psz_string ) goto end; if ( *psz_string == '@' ) { psz_string++; p_ai = ParseNodeService( psz_string, &psz_string, 0 ); if ( p_ai == NULL || p_ai->ai_family != p_config->i_family ) msg_Warn( NULL, "invalid bind address" ); else memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) p_config->i_config |= OUTPUT_UDP; else if ( IS_OPTION("dvb") ) p_config->i_config |= OUTPUT_DVB; else if ( IS_OPTION("epg") ) p_config->i_config |= OUTPUT_EPG; else if ( IS_OPTION("tsid=") ) p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 ); else if ( IS_OPTION("retention=") ) p_config->i_max_retention = strtoll( ARG_OPTION("retention="), NULL, 0 ) * 1000; else if ( IS_OPTION("latency=") ) p_config->i_output_latency = strtoll( ARG_OPTION("latency="), NULL, 0 ) * 1000; else if ( IS_OPTION("ttl=") ) p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 ); else if ( IS_OPTION("tos=") ) p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 ); else if ( IS_OPTION("mtu=") ) p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("srvname=") ) { if ( p_config->psz_service_name ) free( p_config->psz_service_name ); p_config->psz_service_name = config_stropt( ARG_OPTION("srvname=") ); } else if ( IS_OPTION("srvprovider=") ) { if ( !p_config->psz_service_provider ) free( p_config->psz_service_provider ); p_config->psz_service_provider = config_stropt( ARG_OPTION("srvprovider=") ); } else if ( IS_OPTION("ssrc=") ) { in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") ); memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) ); } else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } if ( !p_config->psz_service_provider && psz_provider_name ) p_config->psz_service_provider = strdup( psz_provider_name ); end: i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; if ( !p_config->i_mtu ) p_config->i_mtu = i_mtu; else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE ) { msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu ); p_config->i_mtu = i_mtu; } return true; }
int ddxProcessArgument (int argc, char *argv[], int i) { static Bool s_fBeenHere = FALSE; winScreenInfo *screenInfoPtr = NULL; /* Initialize once */ if (!s_fBeenHere) { #ifdef DDXOSVERRORF /* * This initialises our hook into VErrorF () for catching log messages * that are generated before OsInit () is called. */ OsVendorVErrorFProc = OsVendorVErrorF; #endif s_fBeenHere = TRUE; /* Initialize only if option is not -help */ if (!IS_OPTION("-help") && !IS_OPTION("-h") && !IS_OPTION("--help") && !IS_OPTION("-version") && !IS_OPTION("--version")) { /* Log the version information */ winLogVersionInfo (); /* Log the command line */ winLogCommandLine (argc, argv); /* * Initialize default screen settings. We have to do this before * OsVendorInit () gets called, otherwise we will overwrite * settings changed by parameters such as -fullscreen, etc. */ winErrorFVerb (2, "ddxProcessArgument - Initializing default " "screens\n"); winInitializeScreenDefaults(); } } #if CYGDEBUG winDebug ("ddxProcessArgument - arg: %s\n", argv[i]); #endif /* * Look for the '-help' and similar options */ if (IS_OPTION ("-help") || IS_OPTION("-h") || IS_OPTION("--help")) { /* Reset logfile. We don't need that helpmessage in the logfile */ g_pszLogFile = NULL; g_fNoHelpMessageBox = TRUE; UseMsg(); exit (0); return 1; } if (IS_OPTION ("-version") || IS_OPTION("--version")) { /* Reset logfile. We don't need that versioninfo in the logfile */ g_pszLogFile = NULL; winLogVersionInfo (); exit (0); return 1; } /* * Look for the '-screen scr_num [width height]' argument */ if (IS_OPTION ("-screen")) { int iArgsProcessed = 1; int nScreenNum; int iWidth, iHeight, iX, iY; int iMonitor; #if CYGDEBUG winDebug ("ddxProcessArgument - screen - argc: %d i: %d\n", argc, i); #endif /* Display the usage message if the argument is malformed */ if (i + 1 >= argc) { return 0; } /* Grab screen number */ nScreenNum = atoi (argv[i + 1]); /* Validate the specified screen number */ if (nScreenNum < 0) { ErrorF ("ddxProcessArgument - screen - Invalid screen number %d\n", nScreenNum); UseMsg (); return 0; } /* Initialize default values for any new screens Note that default values can't change after a -screen option is seen, so it's safe to do this for each screen as it is introduced */ winInitializeScreens(nScreenNum+1); /* look for @m where m is monitor number */ if (i + 2 < argc && 1 == sscanf(argv[i + 2], "@%d", (int *) &iMonitor)) { struct GetMonitorInfoData data; if (!QueryMonitor(iMonitor, &data)) { ErrorF ("ddxProcessArgument - screen - " "Querying monitors is not supported on NT4 and Win95\n"); } else if (data.bMonitorSpecifiedExists == TRUE) { winErrorFVerb(2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); iArgsProcessed = 3; g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; g_ScreenInfo[nScreenNum].dwWidth = data.monitorWidth; g_ScreenInfo[nScreenNum].dwHeight = data.monitorHeight; g_ScreenInfo[nScreenNum].dwUserWidth = data.monitorWidth; g_ScreenInfo[nScreenNum].dwUserHeight = data.monitorHeight; g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; } else { /* monitor does not exist, error out */ ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); UseMsg (); exit (0); return 0; } } /* Look for 'WxD' or 'W D' */ else if (i + 2 < argc && 2 == sscanf (argv[i + 2], "%dx%d", (int *) &iWidth, (int *) &iHeight)) { winErrorFVerb (2, "ddxProcessArgument - screen - Found ``WxD'' arg\n"); iArgsProcessed = 3; g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; g_ScreenInfo[nScreenNum].dwWidth = iWidth; g_ScreenInfo[nScreenNum].dwHeight = iHeight; g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; /* Look for WxD+X+Y */ if (2 == sscanf (argv[i + 2], "%*dx%*d+%d+%d", (int *) &iX, (int *) &iY)) { winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X+Y'' arg\n"); g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; g_ScreenInfo[nScreenNum].dwInitialX = iX; g_ScreenInfo[nScreenNum].dwInitialY = iY; /* look for WxD+X+Y@m where m is monitor number. take X,Y to be offsets from monitor's root position */ if (1 == sscanf (argv[i + 2], "%*dx%*d+%*d+%*d@%d", (int *) &iMonitor)) { struct GetMonitorInfoData data; if (!QueryMonitor(iMonitor, &data)) { ErrorF ("ddxProcessArgument - screen - " "Querying monitors is not supported on NT4 and Win95\n"); } else if (data.bMonitorSpecifiedExists == TRUE) { g_ScreenInfo[nScreenNum].dwInitialX += data.monitorOffsetX; g_ScreenInfo[nScreenNum].dwInitialY += data.monitorOffsetY; } else { /* monitor does not exist, error out */ ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); UseMsg (); exit (0); return 0; } } } /* look for WxD@m where m is monitor number */ else if (1 == sscanf(argv[i + 2], "%*dx%*d@%d", (int *) &iMonitor)) { struct GetMonitorInfoData data; if (!QueryMonitor(iMonitor, &data)) { ErrorF ("ddxProcessArgument - screen - " "Querying monitors is not supported on NT4 and Win95\n"); } else if (data.bMonitorSpecifiedExists == TRUE) { winErrorFVerb (2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; g_ScreenInfo[nScreenNum].dwInitialX = data.monitorOffsetX; g_ScreenInfo[nScreenNum].dwInitialY = data.monitorOffsetY; } else { /* monitor does not exist, error out */ ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); UseMsg (); exit (0); return 0; } } } else if (i + 3 < argc && 1 == sscanf (argv[i + 2], "%d", (int *) &iWidth) && 1 == sscanf (argv[i + 3], "%d", (int *) &iHeight)) { winErrorFVerb (2, "ddxProcessArgument - screen - Found ``W D'' arg\n"); iArgsProcessed = 4; g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = TRUE; g_ScreenInfo[nScreenNum].dwWidth = iWidth; g_ScreenInfo[nScreenNum].dwHeight = iHeight; g_ScreenInfo[nScreenNum].dwUserWidth = iWidth; g_ScreenInfo[nScreenNum].dwUserHeight = iHeight; if (i + 5 < argc && 1 == sscanf (argv[i + 4], "%d", (int *) &iX) && 1 == sscanf (argv[i + 5], "%d", (int *) &iY)) { winErrorFVerb (2, "ddxProcessArgument - screen - Found ``X Y'' arg\n"); iArgsProcessed = 6; g_ScreenInfo[nScreenNum].fUserGavePosition = TRUE; g_ScreenInfo[nScreenNum].dwInitialX = iX; g_ScreenInfo[nScreenNum].dwInitialY = iY; } } else { winErrorFVerb (2, "ddxProcessArgument - screen - Did not find size arg. " "dwWidth: %d dwHeight: %d\n", (int) g_ScreenInfo[nScreenNum].dwWidth, (int) g_ScreenInfo[nScreenNum].dwHeight); iArgsProcessed = 2; g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth = FALSE; } /* Calculate the screen width and height in millimeters */ if (g_ScreenInfo[nScreenNum].fUserGaveHeightAndWidth) { g_ScreenInfo[nScreenNum].dwWidth_mm = (g_ScreenInfo[nScreenNum].dwWidth / monitorResolution) * 25.4; g_ScreenInfo[nScreenNum].dwHeight_mm = (g_ScreenInfo[nScreenNum].dwHeight / monitorResolution) * 25.4; } /* Flag that this screen was explicity specified by the user */ g_ScreenInfo[nScreenNum].fExplicitScreen = TRUE; /* * Keep track of the last screen number seen, as parameters seen * before a screen number apply to all screens, whereas parameters * seen after a screen number apply to that screen number only. */ iLastScreen = nScreenNum; return iArgsProcessed; } /* * Is this parameter attached to a screen or global? * * If the parameter is for all screens (appears before * any -screen option), store it in the default screen * info * * If the parameter is for a single screen (appears * after a -screen option), store it in the screen info * for that screen * */ if (iLastScreen == -1) { screenInfoPtr = &defaultScreenInfo; } else { screenInfoPtr = &(g_ScreenInfo[iLastScreen]); } /* * Look for the '-engine n' argument */ if (IS_OPTION ("-engine")) { DWORD dwEngine = 0; CARD8 c8OnBits = 0; /* Display the usage message if the argument is malformed */ if (++i >= argc) { UseMsg (); return 0; } /* Grab the argument */ dwEngine = atoi (argv[i]); /* Count the one bits in the engine argument */ c8OnBits = winCountBits (dwEngine); /* Argument should only have a single bit on */ if (c8OnBits != 1) { UseMsg (); return 0; } screenInfoPtr->dwEnginePreferred = dwEngine; /* Indicate that we have processed the argument */ return 2; } /* * Look for the '-fullscreen' argument */ if (IS_OPTION ("-fullscreen")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = FALSE; #endif screenInfoPtr->fFullScreen = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-lesspointer' argument */ if (IS_OPTION ("-lesspointer")) { screenInfoPtr->fLessPointer = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-nodecoration' argument */ if (IS_OPTION ("-nodecoration")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = FALSE; #endif screenInfoPtr->fDecoration = FALSE; /* Indicate that we have processed this argument */ return 1; } #ifdef XWIN_MULTIWINDOWEXTWM /* * Look for the '-mwextwm' argument */ if (IS_OPTION ("-mwextwm")) { if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = TRUE; screenInfoPtr->fMWExtWM = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-internalwm' argument */ if (IS_OPTION ("-internalwm")) { if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = TRUE; screenInfoPtr->fMWExtWM = TRUE; screenInfoPtr->fInternalWM = TRUE; /* Indicate that we have processed this argument */ return 1; } #endif /* * Look for the '-rootless' argument */ if (IS_OPTION ("-rootless")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = FALSE; #endif screenInfoPtr->fRootless = TRUE; /* Indicate that we have processed this argument */ return 1; } #ifdef XWIN_MULTIWINDOW /* * Look for the '-multiwindow' argument */ if (IS_OPTION ("-multiwindow")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) if (!screenInfoPtr->fMultiMonitorOverride) screenInfoPtr->fMultipleMonitors = TRUE; #endif screenInfoPtr->fMultiWindow = TRUE; /* Indicate that we have processed this argument */ return 1; } #endif /* * Look for the '-multiplemonitors' argument */ if (IS_OPTION ("-multiplemonitors") || IS_OPTION ("-multimonitors")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) screenInfoPtr->fMultiMonitorOverride = TRUE; #endif screenInfoPtr->fMultipleMonitors = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-nomultiplemonitors' argument */ if (IS_OPTION ("-nomultiplemonitors") || IS_OPTION ("-nomultimonitors")) { #if defined(XWIN_MULTIWINDOW) || defined(XWIN_MULTIWINDOWEXTWM) screenInfoPtr->fMultiMonitorOverride = TRUE; #endif screenInfoPtr->fMultipleMonitors = FALSE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-scrollbars' argument */ if (IS_OPTION ("-scrollbars")) { screenInfoPtr->fScrollbars = TRUE; /* Indicate that we have processed this argument */ return 1; } #ifdef XWIN_CLIPBOARD /* * Look for the '-clipboard' argument */ if (IS_OPTION ("-clipboard")) { /* Now the default, we still accept the arg for backwards compatibility */ g_fClipboard = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-noclipboard' argument */ if (IS_OPTION ("-noclipboard")) { g_fClipboard = FALSE; /* Indicate that we have processed this argument */ return 1; } #endif /* * Look for the '-ignoreinput' argument */ if (IS_OPTION ("-ignoreinput")) { screenInfoPtr->fIgnoreInput = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-emulate3buttons' argument */ if (IS_OPTION ("-emulate3buttons")) { int iArgsProcessed = 1; int iE3BTimeout = WIN_DEFAULT_E3B_TIME; /* Grab the optional timeout value */ if (i + 1 < argc && 1 == sscanf (argv[i + 1], "%d", &iE3BTimeout)) { /* Indicate that we have processed the next argument */ iArgsProcessed++; } else { /* * sscanf () won't modify iE3BTimeout if it doesn't find * the specified format; however, I want to be explicit * about setting the default timeout in such cases to * prevent some programs (me) from getting confused. */ iE3BTimeout = WIN_DEFAULT_E3B_TIME; } screenInfoPtr->iE3BTimeout = iE3BTimeout; /* Indicate that we have processed this argument */ return iArgsProcessed; } /* * Look for the '-depth n' argument */ if (IS_OPTION ("-depth")) { DWORD dwBPP = 0; /* Display the usage message if the argument is malformed */ if (++i >= argc) { UseMsg (); return 0; } /* Grab the argument */ dwBPP = atoi (argv[i]); screenInfoPtr->dwBPP = dwBPP; /* Indicate that we have processed the argument */ return 2; } /* * Look for the '-refresh n' argument */ if (IS_OPTION ("-refresh")) { DWORD dwRefreshRate = 0; /* Display the usage message if the argument is malformed */ if (++i >= argc) { UseMsg (); return 0; } /* Grab the argument */ dwRefreshRate = atoi (argv[i]); screenInfoPtr->dwRefreshRate = dwRefreshRate; /* Indicate that we have processed the argument */ return 2; } /* * Look for the '-clipupdates num_boxes' argument */ if (IS_OPTION ("-clipupdates")) { DWORD dwNumBoxes = 0; /* Display the usage message if the argument is malformed */ if (++i >= argc) { UseMsg (); return 0; } /* Grab the argument */ dwNumBoxes = atoi (argv[i]); screenInfoPtr->dwClipUpdatesNBoxes = dwNumBoxes; /* Indicate that we have processed the argument */ return 2; } #ifdef XWIN_EMULATEPSEUDO /* * Look for the '-emulatepseudo' argument */ if (IS_OPTION ("-emulatepseudo")) { screenInfoPtr->fEmulatePseudo = TRUE; /* Indicate that we have processed this argument */ return 1; } #endif /* * Look for the '-nowinkill' argument */ if (IS_OPTION ("-nowinkill")) { screenInfoPtr->fUseWinKillKey = FALSE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-winkill' argument */ if (IS_OPTION ("-winkill")) { screenInfoPtr->fUseWinKillKey = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-nounixkill' argument */ if (IS_OPTION ("-nounixkill")) { screenInfoPtr->fUseUnixKillKey = FALSE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-unixkill' argument */ if (IS_OPTION ("-unixkill")) { screenInfoPtr->fUseUnixKillKey = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-notrayicon' argument */ if (IS_OPTION ("-notrayicon")) { screenInfoPtr->fNoTrayIcon = TRUE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-trayicon' argument */ if (IS_OPTION ("-trayicon")) { screenInfoPtr->fNoTrayIcon = FALSE; /* Indicate that we have processed this argument */ return 1; } /* * Look for the '-fp' argument */ if (IS_OPTION ("-fp")) { CHECK_ARGS (1); g_cmdline.fontPath = argv[++i]; return 0; /* Let DIX parse this again */ } /* * Look for the '-query' argument */ if (IS_OPTION ("-query")) { CHECK_ARGS (1); g_fXdmcpEnabled = TRUE; g_pszQueryHost = argv[++i]; return 0; /* Let DIX parse this again */ } /* * Look for the '-auth' argument */ if (IS_OPTION ("-auth")) { g_fAuthEnabled = TRUE; return 0; /* Let DIX parse this again */ } /* * Look for the '-indirect' or '-broadcast' arguments */ if (IS_OPTION ("-indirect") || IS_OPTION ("-broadcast")) { g_fXdmcpEnabled = TRUE; return 0; /* Let DIX parse this again */ } /* * Look for the '-config' argument */ if (IS_OPTION ("-config") || IS_OPTION ("-xf86config")) { CHECK_ARGS (1); #ifdef XWIN_XF86CONFIG g_cmdline.configFile = argv[++i]; #else winMessageBoxF ("The %s option is not supported in this " "release.\n" "Ignoring this option and continuing.\n", MB_ICONINFORMATION, argv[i]); #endif return 2; } /* * Look for the '-configdir' argument */ if (IS_OPTION ("-configdir")) { CHECK_ARGS (1); #ifdef XWIN_XF86CONFIG g_cmdline.configDir = argv[++i]; #else winMessageBoxF ("The %s option is not supported in this " "release.\n" "Ignoring this option and continuing.\n", MB_ICONINFORMATION, argv[i]); #endif return 2; } /* * Look for the '-keyboard' argument */ if (IS_OPTION ("-keyboard")) { #ifdef XWIN_XF86CONFIG CHECK_ARGS (1); g_cmdline.keyboard = argv[++i]; #else winMessageBoxF ("The -keyboard option is not supported in this " "release.\n" "Ignoring this option and continuing.\n", MB_ICONINFORMATION); #endif return 2; } /* * Look for the '-logfile' argument */ if (IS_OPTION ("-logfile")) { CHECK_ARGS (1); g_pszLogFile = argv[++i]; #ifdef RELOCATE_PROJECTROOT g_fLogFileChanged = TRUE; #endif return 2; } /* * Look for the '-logverbose' argument */ if (IS_OPTION ("-logverbose")) { CHECK_ARGS (1); g_iLogVerbose = atoi(argv[++i]); return 2; } #ifdef XWIN_CLIPBOARD /* * Look for the '-nounicodeclipboard' argument */ if (IS_OPTION ("-nounicodeclipboard")) { g_fUnicodeClipboard = FALSE; /* Indicate that we have processed the argument */ return 1; } #endif if (IS_OPTION ("-xkbrules")) { CHECK_ARGS (1); g_cmdline.xkbRules = argv[++i]; return 2; } if (IS_OPTION ("-xkbmodel")) { CHECK_ARGS (1); g_cmdline.xkbModel = argv[++i]; return 2; } if (IS_OPTION ("-xkblayout")) { CHECK_ARGS (1); g_cmdline.xkbLayout = argv[++i]; return 2; } if (IS_OPTION ("-xkbvariant")) { CHECK_ARGS (1); g_cmdline.xkbVariant = argv[++i]; return 2; } if (IS_OPTION ("-xkboptions")) { CHECK_ARGS (1); g_cmdline.xkbOptions = argv[++i]; return 2; } if (IS_OPTION ("-keyhook")) { g_fKeyboardHookLL = TRUE; return 1; } if (IS_OPTION ("-nokeyhook")) { g_fKeyboardHookLL = FALSE; return 1; } if (IS_OPTION ("-swcursor")) { g_fSoftwareCursor = TRUE; return 1; } if (IS_OPTION ("-silent-dup-error")) { g_fSilentDupError = TRUE; return 1; } if (IS_OPTION("-wgl")) { g_fNativeGl = TRUE; return 1; } if (IS_OPTION("-nowgl")) { g_fNativeGl = FALSE; return 1; } return 0; }
// server CB int request1 (void* transaction_, void* data) { #if COAP_CEU CEU_Transaction* transaction = (CEU_Transaction*) transaction_; #else coap_transaction_t* transaction = (coap_transaction_t*) transaction_; #endif /* Use transaction buffer for response to confirmable request. */ 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_header_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", block_num, block_size, REST_MAX_CHUNK_SIZE, 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 (coap_error_code==NO_ERROR) { /* Apply blockwise transfers. */ if ( IS_OPTION(message, COAP_OPTION_BLOCK1) && response->code<BAD_REQUEST_4_00 && !IS_OPTION(response, COAP_OPTION_BLOCK1) ) { PRINTF("Block1 NOT IMPLEMENTED\n"); coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoBlock1Support"; } 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) */ } else { /* resource provides chunk-wise data */ PRINTF("Blockwise: blockwise resource, new offset %ld\n", 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) */ } else if (new_offset!=0) { PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); } /* if (blockwise request) */ } /* no errors/hooks */ } /* successful service callback */ /* Serialize response. */ if (coap_error_code==NO_ERROR) { if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0) { coap_error_code = PACKET_SERIALIZATION_ERROR; } } } else { coap_error_code = NOT_IMPLEMENTED_5_01; coap_error_message = "NoServiceCallbck"; // no a to fit 16 bytes } /* if (service callback) */ return coap_error_code; }
coap_status_t handle_dm_request(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, void * fromSessionH, coap_packet_t * message, coap_packet_t * response) { coap_status_t result; lwm2m_server_t * serverP = NULL; lwm2m_media_type_t format; #ifdef LWM2M_BOOTSTRAP lwm2m_server_t * bsServerP = NULL; #endif format = prv_convertMediaType(message->content_type); serverP = prv_findServer(contextP, fromSessionH); if (NULL == serverP) { #ifdef LWM2M_BOOTSTRAP bsServerP = utils_findBootstrapServer(contextP, fromSessionH); if (NULL == bsServerP) { // No server found return COAP_IGNORE; } #else return COAP_IGNORE; #endif } #ifdef LWM2M_BOOTSTRAP if (contextP->bsState != BOOTSTRAP_PENDING) { if (NULL != bsServerP) { // server initiated bootstrap? // currently not implemented. return NOT_IMPLEMENTED_5_01; } if ( serverP->status != STATE_REGISTERED && serverP->status != STATE_REG_UPDATE_PENDING) { return COAP_IGNORE; } } else { if (NULL != serverP) { // Request form management server during bootstrap. return UNAUTHORIZED_4_01; } } #endif switch (message->code) { case COAP_GET: { uint8_t * buffer = NULL; size_t length = 0; result = object_read(contextP, uriP, &format, &buffer, &length); if (COAP_205_CONTENT == result) { if (IS_OPTION(message, COAP_OPTION_OBSERVE)) { result = handle_observe_request(contextP, uriP, serverP, message, response); } if (COAP_205_CONTENT == result) { coap_set_header_content_type(response, format); coap_set_payload(response, buffer, length); // lwm2m_handle_packet will free buffer } else { lwm2m_free(buffer); } } } break; case COAP_POST: { #ifdef LWM2M_BOOTSTRAP /* no POST during bootstrap */ if (contextP->bsState == BOOTSTRAP_PENDING) return METHOD_NOT_ALLOWED_4_05; #endif if (!LWM2M_URI_IS_SET_INSTANCE(uriP)) { lwm2m_media_type_t format; format = prv_convertMediaType(message->content_type); result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (result == COAP_201_CREATED) { //longest uri is /65535/65535 = 12 + 1 (null) chars char location_path[13] = ""; //instanceId expected if ((uriP->flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } if (sprintf(location_path, "/%d/%d", uriP->objectId, uriP->instanceId) < 0) { result = COAP_500_INTERNAL_SERVER_ERROR; break; } coap_set_header_location_path(response, location_path); } } else if (!LWM2M_URI_IS_SET_RESOURCE(uriP)) { if (object_isInstanceNew(contextP, uriP->objectId, uriP->instanceId)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); } else { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } } else { result = object_execute(contextP, uriP, message->payload, message->payload_len); } } break; case COAP_PUT: { if (LWM2M_URI_IS_SET_INSTANCE(uriP)) { #ifdef LWM2M_BOOTSTRAP if (contextP->bsState == BOOTSTRAP_PENDING && object_isInstanceNew(contextP, uriP->objectId, uriP->instanceId)) { result = object_create(contextP, uriP, format, message->payload, message->payload_len); if (COAP_201_CREATED == result) { result = COAP_204_CHANGED; } } else #endif { result = object_write(contextP, uriP, format, message->payload, message->payload_len); } } else { result = BAD_REQUEST_4_00; } } break; case COAP_DELETE: { if (LWM2M_URI_IS_SET_INSTANCE(uriP) && !LWM2M_URI_IS_SET_RESOURCE(uriP)) { result = object_delete(contextP, uriP); } else { result = BAD_REQUEST_4_00; } } break; default: result = BAD_REQUEST_4_00; break; } return result; }
static bool config_ParseHost( output_config_t *p_config, char *psz_string ) { struct addrinfo *p_ai; int i_mtu; p_config->psz_displayname = strdup( psz_string ); p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT ); if ( p_ai == NULL ) return false; memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); p_config->i_family = p_config->connect_addr.ss_family; if ( p_config->i_family == AF_UNSPEC ) return false; if ( psz_string == NULL || !*psz_string ) goto end; if ( *psz_string == '@' ) { psz_string++; p_ai = ParseNodeService( psz_string, &psz_string, 0 ); if ( p_ai == NULL || p_ai->ai_family != p_config->i_family ) msg_Warn( NULL, "invalid bind address" ); else memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) p_config->i_config |= OUTPUT_UDP; else if ( IS_OPTION("dvb") ) p_config->i_config |= OUTPUT_DVB; else if ( IS_OPTION("epg") ) p_config->i_config |= OUTPUT_EPG; else if ( IS_OPTION("tsid=") ) p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 ); else if ( IS_OPTION("retention=") ) p_config->i_max_retention = strtoll( ARG_OPTION("retention="), NULL, 0 ) * 1000; else if ( IS_OPTION("latency=") ) p_config->i_output_latency = strtoll( ARG_OPTION("latency="), NULL, 0 ) * 1000; else if ( IS_OPTION("ttl=") ) p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 ); else if ( IS_OPTION("tos=") ) p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 ); else if ( IS_OPTION("mtu=") ) p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("networkid=") ) p_config->i_network_id = strtol( ARG_OPTION("networkid="), NULL, 0 ); else if ( IS_OPTION("networkname=") ) { config_strdvb( &p_config->network_name, ARG_OPTION("networkname=") ); } else if ( IS_OPTION("srvname=") ) { config_strdvb( &p_config->service_name, ARG_OPTION("srvname=") ); } else if ( IS_OPTION("srvprovider=") ) { config_strdvb( &p_config->provider_name, ARG_OPTION("srvprovider=") ); } else if ( IS_OPTION("srcaddr=") ) { if ( p_config->i_family != AF_INET ) { msg_Err( NULL, "RAW sockets currently implemented for ipv4 only"); return false; } free( p_config->psz_srcaddr ); p_config->psz_srcaddr = config_stropt( ARG_OPTION("srcaddr=") ); p_config->i_config |= OUTPUT_RAW; } else if ( IS_OPTION("srcport=") ) p_config->i_srcport = strtol( ARG_OPTION("srcport="), NULL, 0 ); else if ( IS_OPTION("ssrc=") ) { in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") ); memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) ); } else if ( IS_OPTION("pidmap=") ) { char *str1; char *saveptr = NULL; char *tok = NULL; int i, i_newpid; for (i = 0, str1 = config_stropt( (ARG_OPTION("pidmap="))); i < N_MAP_PIDS; i++, str1 = NULL) { tok = strtok_r(str1, ",", &saveptr); if ( !tok ) break; i_newpid = strtoul(tok, NULL, 0); p_config->pi_confpids[i] = i_newpid; } p_config->b_do_remap = true; } else if ( IS_OPTION("newsid=") ) p_config->i_new_sid = strtol( ARG_OPTION("newsid="), NULL, 0 ); else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } end: i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; if ( !p_config->i_mtu ) p_config->i_mtu = i_mtu; else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE ) { msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu ); p_config->i_mtu = i_mtu; } return true; }
coap_status_t observe_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, int size, lwm2m_data_t * dataP, coap_packet_t * message, coap_packet_t * response) { lwm2m_watcher_t * watcherP; uint32_t count; LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); LOG_URI(uriP); coap_get_header_observe(message, &count); switch (count) { case 0: if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; if (message->token_len == 0) return COAP_400_BAD_REQUEST; watcherP = prv_getWatcher(contextP, uriP, serverP); if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; watcherP->tokenLen = message->token_len; memcpy(watcherP->token, message->token, message->token_len); watcherP->active = true; watcherP->lastTime = lwm2m_gettime(); if (IS_OPTION(message, COAP_OPTION_ACCEPT)) { watcherP->format = utils_convertMediaType(message->accept[0]); } else { watcherP->format = LWM2M_CONTENT_TLV; } if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &(watcherP->lastValue.asInteger))) return COAP_500_INTERNAL_SERVER_ERROR; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &(watcherP->lastValue.asFloat))) return COAP_500_INTERNAL_SERVER_ERROR; break; default: break; } } coap_set_header_observe(response, watcherP->counter++); return COAP_205_CONTENT; case 1: // cancellation observe_cancel(contextP, LWM2M_MAX_ID, serverP->sessionH); return COAP_205_CONTENT; default: return COAP_400_BAD_REQUEST; } }