/* * AWS IoT Over-the-air Update v3.3.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file ota_os_posix.c * @brief Example implementation of the OTA OS Functional Interface for POSIX. */ /* Standard Includes.*/ #include <stdlib.h> #include <string.h> #include <time.h> /* MISRA rule 21.5 prohibits the use of signal.h because of undefined behavior. However, this * implementation is on POSIX, which has well defined behavior. We're using the timer functionality * from POSIX so we deviate from this rule. */ /* coverity[misra_c_2012_rule_21_5_violation] */ #include <signal.h> #include <errno.h> /* Posix includes. */ #include <sys/types.h> #include <sys/stat.h> #include <mqueue.h> /* OTA OS POSIX Interface Includes.*/ #include "ota_os_posix.h" /* OTA Library include. */ #include "ota_private.h" /* OTA Event queue attributes.*/ #define OTA_QUEUE_NAME "/otaqueue" #define MAX_MESSAGES 10 #define MAX_MSG_SIZE sizeof( OtaEventMsg_t ) static void requestTimerCallback( union sigval arg ); static void selfTestTimerCallback( union sigval arg ); static OtaTimerCallback_t otaTimerCallback; /* OTA Event queue attributes.*/ static mqd_t otaEventQueue; /* OTA Timer handles.*/ static timer_t otaTimers[ OtaNumOfTimers ]; static timer_t * pOtaTimers[ OtaNumOfTimers ] = { 0 }; /* OTA Timer callbacks.*/ static void ( * timerCallback[ OtaNumOfTimers ] )( union sigval arg ) = { requestTimerCallback, selfTestTimerCallback }; OtaOsStatus_t Posix_OtaInitEvent( OtaEventContext_t * pEventCtx ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; struct mq_attr attr; ( void ) pEventCtx; /* Unlink the event queue.*/ ( void ) mq_unlink( OTA_QUEUE_NAME ); /* Initialize queue attributes.*/ attr.mq_flags = 0; attr.mq_maxmsg = MAX_MESSAGES; attr.mq_msgsize = ( long ) MAX_MSG_SIZE; attr.mq_curmsgs = 0; /* Open the event queue.*/ errno = 0; /* MISRA rule 10.1 requires bitwise operand to be unsigned type. However, O_CREAT and O_RDWR * flags are from standard linux header, and this is the normal way of using them. Hence we * silence the warning here. */ /* coverity[misra_c_2012_rule_10_1_violation] */ otaEventQueue = mq_open( OTA_QUEUE_NAME, O_CREAT | O_RDWR, S_IRWXU, &attr ); if( otaEventQueue == -1 ) { otaOsStatus = OtaOsEventQueueCreateFailed; LogError( ( "Failed to create OTA Event Queue: " "mq_open returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Event Queue created." ) ); } return otaOsStatus; } OtaOsStatus_t Posix_OtaSendEvent( OtaEventContext_t * pEventCtx, const void * pEventMsg, unsigned int timeout ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; ( void ) pEventCtx; ( void ) timeout; /* Send the event to OTA event queue.*/ errno = 0; if( mq_send( otaEventQueue, pEventMsg, MAX_MSG_SIZE, 0 ) == -1 ) { otaOsStatus = OtaOsEventQueueSendFailed; LogError( ( "Failed to send event to OTA Event Queue: " "mq_send returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Event Sent." ) ); } return otaOsStatus; } OtaOsStatus_t Posix_OtaReceiveEvent( OtaEventContext_t * pEventCtx, void * pEventMsg, uint32_t timeout ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; char * pDst = pEventMsg; char buff[ MAX_MSG_SIZE ]; ( void ) pEventCtx; ( void ) timeout; /* Receive the next event from OTA event queue.*/ errno = 0; if( mq_receive( otaEventQueue, buff, sizeof( buff ), NULL ) == -1 ) { otaOsStatus = OtaOsEventQueueReceiveFailed; LogError( ( "Failed to receive OTA Event: " "mq_reqeive returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Event received." ) ); /* copy the data from local buffer.*/ ( void ) memcpy( pDst, buff, MAX_MSG_SIZE ); } return otaOsStatus; } OtaOsStatus_t Posix_OtaDeinitEvent( OtaEventContext_t * pEventCtx ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; ( void ) pEventCtx; /* Remove the event queue.*/ errno = 0; if( mq_unlink( OTA_QUEUE_NAME ) == -1 ) { otaOsStatus = OtaOsEventQueueDeleteFailed; LogError( ( "Failed to delete OTA Event queue: " "mq_unlink returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Event queue deleted." ) ); } return otaOsStatus; } static void selfTestTimerCallback( union sigval arg ) { ( void ) arg; LogDebug( ( "Self-test expired within %ums\r\n", otaconfigSELF_TEST_RESPONSE_WAIT_MS ) ); if( otaTimerCallback != NULL ) { otaTimerCallback( OtaSelfTestTimer ); } else { LogWarn( ( "Self-test timer event unhandled.\r\n" ) ); } } static void requestTimerCallback( union sigval arg ) { ( void ) arg; LogDebug( ( "Request timer expired in %ums \r\n", otaconfigFILE_REQUEST_WAIT_MS ) ); if( otaTimerCallback != NULL ) { otaTimerCallback( OtaRequestTimer ); } else { LogWarn( ( "Request timer event unhandled.\r\n" ) ); } } OtaOsStatus_t Posix_OtaStartTimer( OtaTimerId_t otaTimerId, const char * const pTimerName, const uint32_t timeout, OtaTimerCallback_t callback ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; /* Create the timer structures. */ struct sigevent sgEvent; struct itimerspec timerAttr; ( void ) pTimerName; /* clear everything in the structures. */ ( void ) memset( &sgEvent, 0, sizeof( struct sigevent ) ); ( void ) memset( &timerAttr, 0, sizeof( struct itimerspec ) ); /* Set attributes. */ sgEvent.sigev_notify = SIGEV_THREAD; sgEvent.sigev_value.sival_ptr = ( void * ) otaTimers[ otaTimerId ]; sgEvent.sigev_notify_function = timerCallback[ otaTimerId ]; /* Set OTA lib callback. */ otaTimerCallback = callback; /* Set timeout attributes.*/ timerAttr.it_value.tv_sec = ( time_t ) timeout / 1000; /* Create timer if required.*/ if( pOtaTimers[ otaTimerId ] == NULL ) { errno = 0; if( timer_create( CLOCK_REALTIME, &sgEvent, &otaTimers[ otaTimerId ] ) == -1 ) { otaOsStatus = OtaOsTimerCreateFailed; LogError( ( "Failed to create OTA timer: " "timer_create returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { pOtaTimers[ otaTimerId ] = &otaTimers[ otaTimerId ]; } } /* Set timeout.*/ if( pOtaTimers[ otaTimerId ] != NULL ) { errno = 0; if( timer_settime( otaTimers[ otaTimerId ], 0, &timerAttr, NULL ) == -1 ) { otaOsStatus = OtaOsTimerStartFailed; LogError( ( "Failed to set OTA timer timeout: " "timer_settime returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Timer started." ) ); } } return otaOsStatus; } OtaOsStatus_t Posix_OtaStopTimer( OtaTimerId_t otaTimerId ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; /* Create the timer structures. */ struct itimerspec timerAttr; /* clear everything in the structures. */ ( void ) memset( &timerAttr, 0, sizeof( struct itimerspec ) ); /* Clear the timeout. */ timerAttr.it_value.tv_sec = 0; if( pOtaTimers[ otaTimerId ] != NULL ) { /* Stop the timer*/ errno = 0; if( timer_settime( otaTimers[ otaTimerId ], 0, &timerAttr, NULL ) == -1 ) { otaOsStatus = OtaOsTimerStopFailed; LogError( ( "Failed to stop OTA timer: " "timer_settime returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Timer Stopped for Timerid=%i.", otaTimerId ) ); } } else { LogDebug( ( "OTA Timer handle NULL for Timerid=%i, can't stop.", otaTimerId ) ); otaOsStatus = OtaOsTimerStopFailed; } return otaOsStatus; } OtaOsStatus_t Posix_OtaDeleteTimer( OtaTimerId_t otaTimerId ) { OtaOsStatus_t otaOsStatus = OtaOsSuccess; if( pOtaTimers[ otaTimerId ] != NULL ) { /* Delete the timer*/ errno = 0; if( timer_delete( otaTimers[ otaTimerId ] ) == -1 ) { otaOsStatus = OtaOsTimerDeleteFailed; LogError( ( "Failed to delete OTA timer: " "timer_delete returned error: " "OtaOsStatus_t=%i " ",errno=%s", otaOsStatus, strerror( errno ) ) ); } else { LogDebug( ( "OTA Timer deleted." ) ); pOtaTimers[ otaTimerId ] = NULL; } } else { LogWarn( ( "OTA Timer handle NULL for Timerid=%i, can't delete.", otaTimerId ) ); otaOsStatus = OtaOsTimerDeleteFailed; } return otaOsStatus; } void * STDC_Malloc( size_t size ) { /* Use standard C malloc.*/ /* MISRA rule 21.3 prohibits the use of malloc and free from stdlib.h because of undefined * behavior. The design for our OTA library is to let user choose whether they want to pass * buffers to us or not. Dynamic allocation is used only when they do not provide these buffers. * Further, we have unit tests with memory, and address sanitizer enabled to ensure we're not * leaking or free memory that's not dynamically allocated. */ /* coverity[misra_c_2012_rule_21_3_violation]. */ return malloc( size ); } void STDC_Free( void * ptr ) { /* Use standard C free.*/ /* See explanation in STDC_Malloc. */ /* coverity[misra_c_2012_rule_21_3_violation]. */ free( ptr ); }