// Handler called when the server posts a "finished" message to /bs static int BootStrapPost(void * ctxt, AddressType * addr, const char * path, const char * query, ContentType contentType, const char * requestContent, size_t requestContentLen, char * responseContent, size_t * responseContentLen, int * responseCode) { Lwm2mContextType * context = (Lwm2mContextType *)ctxt; Lwm2mBootStrapState state = Lwm2mCore_GetBootstrapState(context); *responseContentLen = 0; // no content Lwm2m_Debug("POST to /bs\n"); if (state == Lwm2mBootStrapState_BootStrapFinishPending) { Lwm2m_Info("Bootstrap finished\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); Lwm2mCore_UpdateAllServers(context, Lwm2mRegistrationState_Register); *responseCode = AwaResult_SuccessChanged; } else if ((state == Lwm2mBootStrapState_BootStrapPending) || (state == Lwm2mBootStrapState_ClientHoldOff)) { Lwm2m_Info("Server initiated bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); Lwm2mCore_UpdateAllServers(context, Lwm2mRegistrationState_Register); *responseCode = AwaResult_SuccessChanged; } else { *responseCode = AwaResult_BadRequest; } return 0; }
int coap_Destroy(void) { Lwm2m_Info("Close port: \n"); // TODO - remove if (networkSocket) NetworkSocket_Free(&networkSocket); // TODO - close any open sessions // coap_free_context(coapContext); // DestroyLists(); return 0; }
static void HandleBootstrapResponse(void * ctxt, AddressType* address, const char * responsePath, int responseCode, ContentType contentType, char * payload, size_t payloadLen) { Lwm2mContextType * context = ctxt; if (responseCode == AwaResult_SuccessChanged) { Lwm2m_Info("Waiting for bootstrap to finish\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFinishPending); Lwm2mCore_SetLastBootStrapUpdate(context, Lwm2mCore_GetTickCountMs()); } else { Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFailed); } }
bool DTLS_Decrypt(NetworkAddress * sourceAddress, uint8_t * encrypted, int encryptedLength, uint8_t * decryptBuffer, int decryptBufferLength, int * decryptedLength, void *context) { bool result = false; DTLS_Session * session = GetSession(sourceAddress); if (session) { session->Buffer = encrypted; session->BufferLength = encryptedLength; if (session->SessionEstablished) { *decryptedLength = gnutls_read(session->Session, decryptBuffer, decryptBufferLength); result = (*decryptedLength > 0); if (!result) { FreeSession(session); session = NULL; } } else { *decryptedLength = 0; session->SessionEstablished = (gnutls_handshake(session->Session) == GNUTLS_E_SUCCESS); if (session->SessionEstablished) Lwm2m_Info("Session established"); } } if (!session) { int index; for (index = 0;index < MAX_DTLS_SESSIONS; index++) { if (!sessions[index].Session) { SetupNewSession(index, sourceAddress, false); sessions[index].UserContext = context; gnutls_transport_set_push_function(sessions[index].Session, SSLSendCallBack); sessions[index].Buffer = encrypted; sessions[index].BufferLength = encryptedLength; sessions[index].SessionEstablished = (gnutls_handshake(sessions[index].Session) == GNUTLS_E_SUCCESS); break; } } } return result; }
/* * The bootstrap interface is used to optionally configure a LWM2M Client so that it can successfully register with a LWM2M Server. * The client bootstrap operation is performed by sending a CoAP POST request to the LWM2M Bootstrap Server at the /bs path including * the Endpoint Client Name as a query string parameter. * * In client-initiated bootstrap, when the Bootstrap Server receives Request Bootstrap operation, the Bootstrap Server performs Write * and/or Delete operation. In server initiated bootstrap, the Bootstrap Server performs Write operation. * The Write or Delete operation targets to an Object Instance or a Resource. The Write and Delete operation can be sent multiple times. * Only in Bootstrap Interface, Delete operation MAY target to “/” URI to delete all the existing Object Instances except * LWM2M Bootstrap Server Account in the LWM2M Client for initializing before LWM2M Bootstrap Server sends Write operation(s) * to the LWM2M Client. Different from „Write“ operation in Device Management and Service Enablement interface, the LWM2M Client MUST write * the value included in the payload regardless of an existence of the targeting Object Instance or Resource. */ static void SendBootStrapRequest(Lwm2mContextType * context, int shortServerID) { char * uriPath = "/bs"; char uriQuery[128]; char buffer[128]; char serverPath[128]; char uri[1024]; Lwm2mCore_GetEndPointClientName(context, buffer, sizeof(buffer)); sprintf(uriQuery, "?ep=%s", buffer); Lwm2m_GetServerURI(context, shortServerID, serverPath, sizeof(serverPath)); sprintf(uri, "%s%s%s", serverPath, uriPath, uriQuery); Lwm2m_Info("Bootstrap with %s\n", uri); coap_PostRequest(context, uri, ContentType_None, NULL, 0, HandleBootstrapResponse); }
bool DTLS_Encrypt(NetworkAddress * destAddress, uint8_t * plainText, int plainTextLength, uint8_t * encryptedBuffer, int encryptedBufferLength, int * encryptedLength, void *context) { bool result = false; DTLS_Session * session = GetSession(destAddress); if (session) { if (session->SessionEstablished) { gnutls_transport_set_push_function(session->Session, EncryptCallBack); session->Buffer = encryptedBuffer; session->BufferLength = encryptedBufferLength; int written = gnutls_write(session->Session, plainText, plainTextLength); if (written >= 0) { *encryptedLength = encryptedBufferLength - session->BufferLength; result = (*encryptedLength > 0); } } else { session->UserContext = context; gnutls_transport_set_push_function(session->Session, SSLSendCallBack); session->SessionEstablished = (gnutls_handshake(session->Session) == GNUTLS_E_SUCCESS); if (session->SessionEstablished) Lwm2m_Info("DTLS Session established\n"); } } else { int index; for (index = 0;index < MAX_DTLS_SESSIONS; index++) { if (!sessions[index].Session) { SetupNewSession(index, destAddress, true); sessions[index].UserContext = context; gnutls_transport_set_push_function(sessions[index].Session, SSLSendCallBack); sessions[index].SessionEstablished = (gnutls_handshake(sessions[index].Session) == GNUTLS_E_SUCCESS); break; } } } return result; }
CoapInfo * coap_Init(const char * ipAddress, int port, bool secure, int logLevel) { Lwm2m_Info("Bind port: %d\n", port); memset(CurrentTransaction, 0, sizeof(CurrentTransaction)); memset(Observations, 0, sizeof(Observations)); coap_init_transactions(); coap_set_service_callback(coap_HandleRequest); DTLS_Init(); if (secure) networkSocket = NetworkSocket_New(NetworkSocketType_UDP | NetworkSocketType_Secure, port); else networkSocket = NetworkSocket_New(NetworkSocketType_UDP, port); if (networkSocket) { if (NetworkSocket_StartListening(networkSocket)) { coapInfo.fd = NetworkSocket_GetFileDescriptor(networkSocket); } } return &coapInfo; }
/* The LWM2M Client MUST follow the procedure specified as below when attempting to bootstrap a LWM2M Device: * 1. If the LWM2M Device has Smartcard, the LWM2M Client tries to obtain Bootstrap Information * from the Smartcard using the Bootstrap from Smartcard mode. * 2. If the LWM2M Client is not configured using the Bootstrap from Smartcard mode, the LWM2M * Client tries to obtain the Bootstrap Information by using Factory Bootstrap mode. * 3. If the LWM2M Client has any LWM2M Server Object Instances from the previous steps, the LWM2M * Client tries to register to the LWM2M Server(s) configured in the LWM2M Server Object Instance(s). * 4. If LWM2M Client fails to register to all the LWM2M Servers or the Client doesn’t have any * LWM2M Server Object Instances, and the LWM2M Client hasn’t received a Server Initiated Bootstrap * within the ClientHoldOffTime, the LWM2M Client performs the Client Initiated Bootstrap. */ void Lwm2m_UpdateBootStrapState(Lwm2mContextType * context) { uint32_t now = Lwm2mCore_GetTickCountMs(); uint32_t clientHoldOff; enum { SERVER_BOOTSTRAP = 0 }; switch (Lwm2mCore_GetBootstrapState(context)) { case Lwm2mBootStrapState_NotBootStrapped: // First attempt smart card bootstrap. if (BootStrapFromSmartCard(context)) { Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); } // If that fails try and use the factory information. else if (BootStrapFromFactory(context)) { Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapped); } // If that fails wait for the client hold off time, for a server initiated bootstrap. else { Lwm2m_Info("Try existing server entries\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_CheckExisting); } Lwm2mCore_UpdateAllServers(context, Lwm2mRegistrationState_Register); Lwm2mCore_SetLastBootStrapUpdate(context, now); break; case Lwm2mBootStrapState_CheckExisting: // Pass control to Registration process, if this fails then we will // drop into the ClientHoldOff State break; case Lwm2mBootStrapState_ClientHoldOff: // Wait for server initiated bootstrap. // Only one bootstrap server is supported. // If the hold off timer has expired, then request a boot strap. Lwm2m_GetClientHoldOff(context, SERVER_BOOTSTRAP, &clientHoldOff); if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= (clientHoldOff * 1000)) { Lwm2m_Info("Hold Off expired - attempt client-initiated bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapPending); SendBootStrapRequest(context, SERVER_BOOTSTRAP); Lwm2mCore_SetLastBootStrapUpdate(context, now); } break; case Lwm2mBootStrapState_BootStrapPending: if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= BOOTSTRAP_TIMEOUT) { Lwm2m_Error("No response to client initiated bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFailed); Lwm2mCore_SetLastBootStrapUpdate(context, now); } break; case Lwm2mBootStrapState_BootStrapFinishPending: // The 2015/07/07 LWM2M draft requires that the server sends a bootstrap finished to the clients /bs endpoint, // however for now lets just wait up to 15 seconds and then move to BootStrapped state. if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= BOOTSTRAP_FINISHED_TIMEOUT) { Lwm2m_Warning("No bootstrap finished after 15 seconds, retrying...\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_BootStrapFailed); } break; case Lwm2mBootStrapState_BootStrapped: break; case Lwm2mBootStrapState_BootStrapFailed: // If the hold off timer has expired, then request a boot strap. Lwm2m_GetClientHoldOff(context, SERVER_BOOTSTRAP, &clientHoldOff); if (now - Lwm2mCore_GetLastBootStrapUpdate(context) >= (clientHoldOff * 1000)) { Lwm2m_Warning("HoldOff Expired - Re-attempt bootstrap\n"); Lwm2mCore_SetBootstrapState(context, Lwm2mBootStrapState_NotBootStrapped); } break; default: Lwm2m_Error("Unhandled bootstrap state %d\n", Lwm2mCore_GetBootstrapState(context)); } }
static int Lwm2mServer_Start(Options * options) { int xmlFd; int result = 0; if (options->Daemonise) { Daemonise(options->Verbose); } else { signal(SIGINT, Lwm2m_CtrlCSignalHandler); } signal(SIGTERM, Lwm2m_CtrlCSignalHandler); // open log files here if (options->LogFile != NULL) { errno = 0; logFile = fopen(options->LogFile, "at"); if (logFile != NULL) { Lwm2m_SetOutput(logFile); // redirect stdout dup2(fileno(logFile), STDOUT_FILENO); } else { Lwm2m_Error("Failed to open log file %s: %s\n", options->LogFile, strerror(errno)); } } if (options->Version) { Lwm2m_Printf(0, "%s\n", version); goto error_close_log; } Lwm2m_SetLogLevel((options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); Lwm2m_PrintBanner(); if (options->Verbose) { PrintOptions(options); } Lwm2m_Info("Awa LWM2M Server, version %s\n", version); Lwm2m_Info(" Process ID : %d\n", getpid()); Lwm2m_Info(" DTLS library : %s\n", DTLS_LibraryName); Lwm2m_Info(" CoAP library : %s\n", coap_LibraryName); Lwm2m_Info(" CoAP port : %d\n", options->CoapPort); Lwm2m_Info(" Secure : %s\n", options->Secure ? "true": "false"); Lwm2m_Info(" IPC port : %d\n", options->IpcPort); Lwm2m_Info(" Address family : IPv%d\n", options->AddressFamily == AF_INET ? 4 : 6); if (options->InterfaceName != NULL) { Lwm2m_Info("LWM2M server - Using interface %s [IPv%d]\n", options->InterfaceName, options->AddressFamily == AF_INET? 4 : 6); } else if (strcmp(DEFAULT_IP_ADDRESS, options->IPAddress) != 0) { Lwm2m_Info("LWM2M server - IP Address %s\n", options->IPAddress); } char ipAddress[NI_MAXHOST]; if (options->InterfaceName != NULL) { if (Lwm2mCore_GetIPAddressFromInterface(options->InterfaceName, options->AddressFamily, ipAddress, sizeof(ipAddress)) != 0) { result = 1; goto error_close_log; } Lwm2m_Info("LWM2M server - Interface Address %s\n", ipAddress); } else { strncpy(ipAddress, options->IPAddress, NI_MAXHOST); ipAddress[NI_MAXHOST - 1] = '\0'; // Defensive } CoapInfo * coap = coap_Init(ipAddress, options->CoapPort, options->Secure, (options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); if (coap == NULL) { printf("Unable to map address to network interface\n"); result = 1; goto error_close_log; } if (options->Secure) { coap_SetCertificate(serverCert, sizeof(serverCert), CertificateFormat_PEM); coap_SetPSK(pskIdentity, pskKey, sizeof(pskKey)); } Lwm2mContextType * context = Lwm2mCore_Init(NULL, options->ContentType); // NULL, don't map coap with objectStore // must happen after coap_Init() Lwm2m_RegisterObjectTypes(context); // listen for UDP packets on port 12345 for now. xmlFd = xmlif_init(context, options->IpcPort); if (xmlFd < 0) { result = 1; goto error_destroy; } xmlif_RegisterHandlers(); // wait for messages on both the "IPC" and coap interfaces while (!quit) { int loop_result; struct pollfd fds[2]; int nfds = 2; int timeout; fds[0].fd = coap->fd; fds[0].events = POLLIN; fds[1].fd = xmlFd; fds[1].events = POLLIN; timeout = Lwm2mCore_Process(context); loop_result = poll(fds, nfds, timeout); if (loop_result < 0) { if (errno == EINTR) { continue; } perror("poll:"); break; } else if (loop_result > 0) { if (fds[0].revents == POLLIN) { coap_HandleMessage(); } if (fds[1].revents == POLLIN) { xmlif_process(fds[1].fd); } } coap_Process(); } Lwm2m_Debug("Exit triggered\n"); error_destroy: xmlif_destroy(xmlFd); Lwm2mCore_Destroy(context); coap_Destroy(); error_close_log: Lwm2m_Info("Server exiting\n"); if (logFile != NULL) { fclose(logFile); } return result; }
static int Lwm2mClient_Start(Options * options) { FILE * logFile = NULL; uint8_t * loadedClientCert = NULL; int result = 0; uint8_t * key = NULL; if (options->Daemonise) { Daemonise(options->Verbose); } else { signal(SIGINT, Lwm2m_CtrlCSignalHandler); } signal(SIGTERM, Lwm2m_CtrlCSignalHandler); if (options->LogFile) { errno = 0; logFile = fopen(options->LogFile, "at"); if (logFile != NULL) { Lwm2m_SetOutput(logFile); // redirect stdout dup2(fileno(logFile), STDOUT_FILENO); } else { Lwm2m_Error("Failed to open log file %s: %s\n", options->LogFile, strerror(errno)); } } if (options->Version) { Lwm2m_Printf(0, "%s\n", version); goto error_close_log; } srandom((int)time(NULL)*getpid()); if (options->CoapPort == 0) { options->CoapPort = 6000 + (rand() % 32768); } Lwm2m_SetLogLevel((options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); Lwm2m_PrintBanner(); if (options->Verbose) { PrintOptions(options); } Lwm2m_Info("Awa LWM2M Client, version %s\n", version); Lwm2m_Info(" Process ID : %d\n", getpid()); Lwm2m_Info(" Endpoint name : \'%s\'\n", options->EndPointName); Lwm2m_Info(" DTLS library : %s\n", DTLS_LibraryName); Lwm2m_Info(" CoAP library : %s\n", coap_LibraryName); Lwm2m_Info(" CoAP port : %d\n", options->CoapPort); Lwm2m_Info(" IPC port : %d\n", options->IpcPort); Lwm2m_Info(" Address family : IPv%d\n", options->AddressFamily == AF_INET ? 4 : 6); Lwm2mCore_SetDefaultContentType(options->DefaultContentType); CoapInfo * coap = coap_Init((options->AddressFamily == AF_INET) ? "0.0.0.0" : "::", options->CoapPort, false /* not a server */, (options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); if (coap == NULL) { Lwm2m_Error("Failed to initialise CoAP on port %d\n", options->CoapPort); result = 1; goto error_close_log; } // always set key if (options->CertificateFile) { loadedClientCert = LoadCertificateFile(options->CertificateFile); } else coap_SetCertificate(clientCert, sizeof(clientCert), AwaCertificateFormat_PEM); if (options->PskIdentity && options->PskKey) { int hexKeyLength = strlen(options->PskKey); int keyLength = hexKeyLength / 2; key = (uint8_t *)malloc(keyLength); if (key) { char * value = options->PskKey; int index; for (index = 0; index < keyLength; index++) { key[index] = HexToByte(value); value += 2; } coap_SetPSK(options->PskIdentity, key, keyLength); } else coap_SetPSK(pskIdentity, pskKey, sizeof(pskKey)); } else coap_SetPSK(pskIdentity, pskKey, sizeof(pskKey)); // if required read the bootstrap information from a file const BootstrapInfo * factoryBootstrapInfo; if (options->FactoryBootstrapFile != NULL) { factoryBootstrapInfo = BootstrapInformation_ReadConfigFile(options->FactoryBootstrapFile); if (factoryBootstrapInfo == NULL) { Lwm2m_Error("Factory Bootstrap configuration file load failed\n"); result = 1; goto error_coap; } else { Lwm2m_Info("Factory Bootstrap:\n"); Lwm2m_Info("Server Configuration\n"); Lwm2m_Info("====================\n"); BootstrapInformation_Dump(factoryBootstrapInfo); } } else { factoryBootstrapInfo = NULL; } Lwm2mContextType * context = Lwm2mCore_Init(coap, options->EndPointName); // Must happen after coap_Init(). RegisterObjects(context, options); if (factoryBootstrapInfo != NULL) { Lwm2mCore_SetFactoryBootstrap(context, factoryBootstrapInfo); } // bootstrap information has been loaded, no need to hang onto this anymore BootstrapInformation_DeleteBootstrapInfo(factoryBootstrapInfo); // load any specified objDef files if (LoadObjectDefinitionsFromFiles(context, options->ObjDefsFiles, options->NumObjDefsFiles) != 0) { goto error_core; } // Listen for UDP packets on IPC port int xmlFd = xmlif_init(context, options->IpcPort); if (xmlFd < 0) { Lwm2m_Error("Failed to initialise XML interface on port %d\n", options->IpcPort); result = 1; goto error_core; } xmlif_RegisterHandlers(); // Wait for messages on both the IPC and CoAP interfaces while (!quit) { int loop_result; struct pollfd fds[2]; int nfds = 2; int timeout; fds[0].fd = coap->fd; fds[0].events = POLLIN; fds[1].fd = xmlFd; fds[1].events = POLLIN; timeout = Lwm2mCore_Process(context); loop_result = poll(fds, nfds, timeout); if (loop_result < 0) { if (errno == EINTR) { continue; } perror("poll:"); break; } else if (loop_result > 0) { if (fds[0].revents == POLLIN) { coap_HandleMessage(); } if (fds[1].revents == POLLIN) { xmlif_process(fds[1].fd); } } coap_Process(); } Lwm2m_Debug("Exit triggered\n"); xmlif_DestroyExecuteHandlers(); xmlif_destroy(xmlFd); error_core: Lwm2mCore_Destroy(context); error_coap: coap_Destroy(); error_close_log: free(loadedClientCert); free(key); Lwm2m_Info("Client exiting\n"); if (logFile) { fclose(logFile); } return result; }
static int Bootstrap_Start(Options * options) { int result = 0; if (options->Daemonise) { Daemonise(options->Verbose); } else { signal(SIGINT, CtrlCSignalHandler); } signal(SIGTERM, CtrlCSignalHandler); // open log files here if (options->LogFile) { errno = 0; logFile = fopen(options->LogFile, "at"); if (logFile != NULL) { Lwm2m_SetOutput(logFile); // redirect stdout dup2(fileno(logFile), STDOUT_FILENO); } else { Lwm2m_Error("Failed to open log file %s: %s\n", options->LogFile, strerror(errno)); } } if (options->Version) { Lwm2m_Printf(0, "%s\n", version); goto error_close_log; } Lwm2m_SetLogLevel((options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); Lwm2m_PrintBanner(); if (options->Verbose) { PrintOptions(options); } Lwm2m_Info("Awa LWM2M Bootstrap Server, version %s\n", version); Lwm2m_Info(" Process ID : %d\n", getpid()); Lwm2m_Info(" CoAP port : %d\n", options->Port); if (options->InterfaceName != NULL) { Lwm2m_Info(" Interface : %s [IPv%d]\n", options->InterfaceName, options->AddressFamily == AF_INET? 4 : 6); } else if (strcmp(DEFAULT_IP_ADDRESS, options->IPAddress) != 0) { Lwm2m_Info(" IP Address : %s\n", options->IPAddress); } char ipAddress[NI_MAXHOST]; if (options->InterfaceName != NULL) { if (Lwm2mCore_GetIPAddressFromInterface(options->InterfaceName, options->AddressFamily, ipAddress, sizeof(ipAddress)) != 0) { result = 1; goto error_close_log; } Lwm2m_Info(" Interface Addr : %s\n", ipAddress); } else { strncpy(ipAddress, options->IPAddress, NI_MAXHOST); ipAddress[NI_MAXHOST - 1] = '\0'; // Defensive } CoapInfo * coap = coap_Init(ipAddress, options->Port, (options->Verbose) ? DebugLevel_Debug : DebugLevel_Info); if (coap == NULL) { printf("Unable to map address to network interface\n"); result = 1; goto error_close_log; } Lwm2mContextType * context = Lwm2mCore_Init(coap); // must happen after coap_Init() Lwm2m_RegisterObjectTypes(context); if (!Lwm2mBootstrap_BootStrapInit(context, options->Config, options->ConfigCount)) { printf("Failed to initialise boostrap\n"); result = 1; goto error_destroy; } // wait for messages on both the "IPC" and coap interfaces while (!quit) { int loop_result; struct pollfd fds[1]; int nfds = 1; int timeout; fds[0].fd = coap->fd; fds[0].events = POLLIN; timeout = Lwm2mCore_Process(context); loop_result = poll(fds, nfds, timeout); if (loop_result < 0) { if (errno == EINTR) { continue; } perror("poll:"); break; } else if (loop_result > 0) { if (fds[0].revents == POLLIN) { coap_HandleMessage(); } } coap_Process(); } Lwm2m_Debug("Exit triggered\n"); error_destroy: Lwm2mBootstrap_Destroy(); Lwm2mCore_Destroy(context); coap_Destroy(); error_close_log: Lwm2m_Info("Bootstrap Server exiting\n"); if (logFile != NULL) { fclose(logFile); } return result; }
void coap_createCoapRequest(coap_method_t method, const char * uri, ContentType contentType, ObserveState observeState, const char * payload, int payloadLen, TransactionCallback callback, void * context) { coap_packet_t request; char path[MAX_COAP_PATH] = { 0 }; char query[128] = { 0 }; coap_transaction_t *transaction; NetworkAddress * remoteAddress = NetworkAddress_New(uri, strlen(uri)); coap_getPathQueryFromURI(uri, path, query); Lwm2m_Info("Coap request: %s\n", uri); //Lwm2m_Debug("Coap request path: %s\n", path); //Lwm2m_Debug("Coap request query: %s\n", query); coap_init_message(&request, COAP_TYPE_CON, method, coap_get_mid()); coap_set_header_uri_path(&request, path); if (strlen(query) > 0) coap_set_header_uri_query(&request, query); // TODO - REVIEW: Erbium must copy path/query from request - else mem out of scope if (contentType != ContentType_None) { if ((method == COAP_POST) || (method == COAP_PUT)) { coap_set_header_content_format(&request, contentType); coap_set_payload(&request, payload, payloadLen); } else { coap_set_header_accept(&request, contentType); } } if (method == COAP_GET) { if (observeState == ObserveState_Establish) { coap_set_header_observe(&request, 0); int token = addObserve(remoteAddress, path, callback, context); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } else if (observeState == ObserveState_Cancel) { coap_set_header_observe(&request, 1); int token = removeObserve(remoteAddress, path); if (token != 0) coap_set_token(&request, (const uint8_t *) &token, sizeof(token)); } } if (CurrentTransaction[CurrentTransactionIndex].TransactionUsed && CurrentTransaction[CurrentTransactionIndex].TransactionPtr) { Lwm2m_Warning("Canceled previous transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_clear_transaction(&CurrentTransaction[CurrentTransactionIndex].TransactionPtr); } //if ((transaction = coap_new_transaction(request.mid, remote_ipaddr, uip_htons(remote_port)))) if ((transaction = coap_new_transaction(networkSocket, request.mid, remoteAddress))) { transaction->callback = coap_CoapRequestCallback; memcpy(CurrentTransaction[CurrentTransactionIndex].Path, path, MAX_COAP_PATH); CurrentTransaction[CurrentTransactionIndex].Callback = callback; CurrentTransaction[CurrentTransactionIndex].Context = context; CurrentTransaction[CurrentTransactionIndex].TransactionUsed = true; CurrentTransaction[CurrentTransactionIndex].TransactionPtr = transaction; NetworkAddress_SetAddressType(remoteAddress, &CurrentTransaction[CurrentTransactionIndex].Address); transaction->callback_data = &CurrentTransaction[CurrentTransactionIndex]; transaction->packet_len = coap_serialize_message(&request, transaction->packet); Lwm2m_Debug("Sending transaction [%d]: %p\n", CurrentTransactionIndex, CurrentTransaction[CurrentTransactionIndex].TransactionPtr); coap_send_transaction(transaction); CurrentTransactionIndex++; if (CurrentTransactionIndex >= MAX_COAP_TRANSACTIONS) { CurrentTransactionIndex = 0; } } }