/*! * \file core.c * * \author Christos Choutouridis AEM:8997 */ #include #include #include #include #include #include "core.h" pthread_mutex_t lock_msgList; //! Helper API //! @{ #define _ADHOC_SUBNET(A, B, C, D) (((A)<<24) | ((B)<<16) | ((C)<<8) | (D)) device_t addr2device (uint32_t in_addr) { device_t dev = { .id = (in_addr & 0x000000FF) + ((in_addr >> 8) & 0x000000FF) * 100, .next = NULL }; return dev; } uint32_t device2addr (const device_t* dev) { uint32_t add = _adhoc_subnet; add |= (dev->id % 100) & 0x000000FF; add |= ((dev->id / 100) & 0x000000FF) << 8; return add; } device_t ip2device (devIP_t* ip) { device_t dev = { .id = ip->C*100 + ip->D, .next = NULL }; return dev; } devIP_t device2ip (const device_t* dev) { devIP_t ip = { .A=0, .B=0, .C=dev->id/100, .D=dev->id%100 }; return ip; } devIP_t addr2ip (uint32_t in_addr) { devIP_t ip = { .A=0, .B=0, .C=(in_addr >> 8) & 0x000000FF, .D=in_addr & 0x000000FF }; return ip; } //! @} //! cMsg_t API //! @{ /*! * Parse an incoming message * * @param cMsg Pointer to cMsg object to store the parsed data * @param rawMsg Pointer to raw message * @param size The size f raw message buffer * @return The status of the operation * @arg MSG_OK Success * @arg MSG_ERROR Parse failure, incoming message format error */ status_t cMsg_parse (cMsg_t* cMsg, char_t* rawMsg, size_t size) { // Check message integrity if (size > MSG_TEXT_SIZE) return MSG_ERROR; int d =0; for (size_t i =0; rawMsg[i] && imsg, rawMsg); // Parse message char_t del[2] = {MSG_DELIMITER, '\0'}; char_t* tok; tok = strtok (cMsg->msg, del); cMsg->from = atoi (tok); tok = strtok(NULL, del); cMsg->to = atoi (tok); tok = strtok(NULL, del); cMsg->ts = atoll (tok); tok = strtok(NULL, del); cMsg->text = tok - cMsg->msg; return MSG_OK; } /*! getter for cMsg_t member fromAEM */ uint32_t cMsg_getFrom(cMsg_t* cMsg) { return cMsg->from; } /*! getter for cMsg_t member toAEM */ uint32_t cMsg_getTo(cMsg_t* cMsg) { return cMsg->to; } /*! getter for cMsg_t member fromAEM */ uint64_t cMsg_getTs(cMsg_t* cMsg) { return cMsg->ts; } /*! getter for payload text member */ char_t* cMsg_getText(cMsg_t* cMsg) { return (char_t*)& cMsg->msg[cMsg->text]; } /*! * Predicate to check core message equality * @param m1 Pointer to message 1 * @param m2 Pointer to message 2 * @return Equality result (true, false) */ bool cMsg_equal (cMsg_t* m1, cMsg_t* m2) { if (m1->from != m2->from) return false; if (m1->to != m2->to) return false; if (m1->ts != m2->ts) return false; if (strncmp (cMsg_getText(m1), cMsg_getText(m2), sizeof(m1->msg))) return false; return true; } //! @} /*! * Create a message list for our application. */ msgList_t msgList; //! msgList API //! @{ /*! Macro helper to saturate increased values */ #define _top_saturate(test, apply, value) do { \ if (test >= value) apply = value; \ } while (0) /*! Macro helper to saturate decreased values */ #define _btm_saturate(test, apply, value) do { \ if (test < value) apply = value; \ while (0) /*! * @brief msgList iterator pre-increment in the msg_t direction * * This iterator force a ring buffer behavior. This function takes pointer * to iterator to alter but return the altered value so it can be directly * used in expressions * * @param it Pointer to iterator to increase * @return The iterator values */ static mIter_t _preInc(mIter_t* it) { if (++*it >= MSG_LIST_SIZE) *it = 0; return *it; } /*! * @brief msgList iterator pre-decrement in the msg_t direction * * This iterator force a ring buffer behavior. This function takes pointer * to iterator to alter but return the altered value so it can be directly * used in expressions * * @param it Pointer to iterator to decrease * @return The iterator values */ static mIter_t _preDec(mIter_t* it) { if (--*it < 0) *it = MSG_LIST_SIZE; return *it; } /*! * @brief Access devices in the device_t direction. * * This function returns the first device on the recipient list if there is one. * * @param this The msgList object to work with * @param it The iterator value [msg_t direction] * @return Pointer to first device on the list, or NULL if the list is empty */ static device_t* devList_get (msgList_t* this, mIter_t it) { device_t* d = this->m[it].recipients; return (d) ? d->next : NULL; } /*! * Iterate through device list. * * This function return the next device on the recipient list if there is one. * [device direction] * * @param d Pointer to current device * @return Pointer to next device on the list, or NULL if the list is empty */ //static device_t* devList_getNext (device_t* d) { // return (d) ? d->next : NULL; //} /*! * @brief Adds a new device on the recipients list * * @param this The msgList object to work with * @param it The iterator value [msg_t direction] * @param dev Pointer to device to add [device direction] * @return The status of the operation * @arg MSG_OK Success * @arg MSG_ERROR memory allocation error */ status_t devList_add (msgList_t* this, mIter_t it, device_t* dev) { pthread_mutex_lock (&lock_msgList); device_t* last = devList_get (this, it); while (last && last->next) last = last->next; last = (device_t*)malloc (sizeof(device_t)); *last = *dev; pthread_mutex_unlock (&lock_msgList); return (last) ? MSG_OK : MSG_ERROR; } /*! * Frees up all allocated memory in a device list. * * @param this The msgList object to work with * @param it The iterator value [msg_t direction] */ static void devList_free (msgList_t* this, mIter_t it) { device_t* last = devList_get (this, it); while (last) { device_t* next = last->next; free(last); last = next; } } status_t msgList_init (msgList_t* msgList) { if (pthread_mutex_init(&lock_msgList, NULL) != 0) { fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ ); return MSG_ERROR; } memset((void*)msgList, 0, sizeof(msgList_t)); msgList->last =-1; return MSG_OK; } /*! * Searches for a message in the message list. * * @param this The msgList object to work with * @param msg Pointer to message to search * @return Iterator to message if found, or -1 if not */ mIter_t msgList_find (msgList_t* this, msg_t* msg) { pthread_mutex_lock (&lock_msgList); mIter_t it =this->last; // get iterator // search from end to start to find msg, return on success for (size_t i=0 ; i < this->size ; ++i) { if (cMsg_equal (&this->m[it].cMsg, &msg->cMsg)) { pthread_mutex_unlock (&lock_msgList); return it; } _preDec(&it); // We start from the end as we think, its more possible // to find msg in the recent messages. } pthread_mutex_unlock (&lock_msgList); return (mIter_t)-1; // fail to find } /*! * Add a new message in the message list * * @param this The msgList object to work with * @param msg Pointer to message */ void msgList_add (msgList_t* this, msg_t* msg) { pthread_mutex_lock (&lock_msgList); devList_free (this, _preInc(&this->last)); // free up possible previous recipients list this->m[this->last] = *msg; // store data pthread_mutex_unlock (&lock_msgList); _top_saturate(++this->size, this->size, MSG_LIST_SIZE); // count the items } //! @} static char_t* _frm_msg_io = "dev=%d, message: from=%d, to=%d, timestamp=%lld, text=%s"; static char_t* _frm_msg_new = "new message: from=%d, to=%d, timestamp=%lld, text=%s"; pthread_mutex_t lock_stderr; pthread_mutex_t lock_stdout; status_t log_init (void) { if (pthread_mutex_init(&lock_stderr, NULL) != 0) { fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ ); return MSG_ERROR; } if (pthread_mutex_init(&lock_stdout, NULL) != 0) { fprintf (stderr, "Error %s: mutex init has failed\n", __FUNCTION__ ); return MSG_ERROR; } return MSG_OK; } void log_msg_io (msg_t* msg) { if (settings.outLevel >= OUTLEVEL_1) { char_t head[16]; strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head)); head[16] = 0; pthread_mutex_lock(&lock_stdout); fprintf (stdout, _frm_msg_io, msg->sender.id, cMsg_getFrom (&msg->cMsg), cMsg_getTo (&msg->cMsg), cMsg_getTs (&msg->cMsg), head ); fflush(stdout); pthread_mutex_unlock(&lock_stdout); } } void log_msg_new (msg_t* msg) { if (settings.outLevel >= OUTLEVEL_1) { char_t head[16]; strncpy (head, cMsg_getText(&msg->cMsg), sizeof(head)); head[16] = 0; pthread_mutex_lock(&lock_stdout); fprintf (stdout, _frm_msg_new, cMsg_getFrom (&msg->cMsg), cMsg_getTo (&msg->cMsg), cMsg_getTs (&msg->cMsg), head ); fflush(stdout); pthread_mutex_unlock(&lock_stdout); } } void log_debug (const char *fmt, ...) { if (settings.outLevel >= OUTLEVEL_2) { va_list ap; va_start(ap, fmt); pthread_mutex_lock(&lock_stdout); vfprintf (stdout, fmt, ap); fflush(stdout); pthread_mutex_unlock(&lock_stdout); va_end(ap); } } void log_error (const char *fmt, ...) { va_list ap; va_start(ap, fmt); pthread_mutex_lock(&lock_stderr); vfprintf (stderr, fmt, ap); fflush(stderr); pthread_mutex_unlock(&lock_stderr); va_end(ap); }