/** ****************************************************************************** * @file mico_mdns.c * @author William Xu * @version V1.0.0 * @date 05-May-2014 * @brief This header contains function called by mdns protocol operation ****************************************************************************** * UNPUBLISHED PROPRIETARY SOURCE CODE * Copyright (c) 2016 MXCHIP Inc. * * The contents of this file may not be disclosed to third parties, copied or * duplicated in any form, in whole or in part, without the prior written * permission of MXCHIP Corporation. ****************************************************************************** */ #include "mico_mdns.h" #include "StringUtils.h" #include "SocketUtils.h" /** "224.0.0.251" */ #define INADDR_MULTICAST_MDNS ((uint32_t)0xE00000FBUL) static int mDNS_fd = -1; static bool bonjour_instance = false; typedef struct { char* hostname; char* instance_name; char* service_name; char* txt_att; char instance_name_suffix[4]; WiFi_Interface interface; uint32_t ttl; uint16_t port; uint8_t count_down; mdns_record_state_t state; } dns_sd_service_record_t; #define APP_Available_Offset 0 #define Support_TLV_Config_Offset 2 #define Problem_Detected_Offset 0 #define Not_Configured_Offset 1 #define SERVICE_QUERY_NAME "_services._dns-sd._udp.local." //#define mdns_utils_log(M, ...) custom_log("mDNS Utils", M, ##__VA_ARGS__) //#define mdns_utils_log_trace() custom_log_trace("mDNS Utils") #define mdns_utils_log(M, ...) #define mdns_utils_log_trace() static dns_sd_service_record_t available_services[ MAX_RECORD_COUNT ]; static uint8_t available_service_count = MAX_RECORD_COUNT; static int dns_get_next_question( dns_message_iterator_t* iter, dns_question_t* q, dns_name_t* name ); static int dns_compare_name_to_string( dns_name_t* name, const char* string ); static int dns_create_message( dns_message_iterator_t* message, uint16_t size ); static void dns_write_header( dns_message_iterator_t* iter, uint16_t id, uint16_t flags, uint16_t question_count, uint16_t answer_count, uint16_t authorative_count ); static void dns_write_record( dns_message_iterator_t* iter, const char* name, uint16_t record_class, uint16_t record_type, uint32_t ttl, uint8_t* rdata ); static void mdns_send_message(int fd, dns_message_iterator_t* message ); static void dns_free_message( dns_message_iterator_t* message ); static void mdns_process_query(int fd, dns_name_t* name, dns_question_t* question, dns_message_iterator_t* source ); static void dns_write_record( dns_message_iterator_t* iter, const char* name, uint16_t record_class, uint16_t record_type, uint32_t ttl, uint8_t* rdata ); static void dns_write_uint16( dns_message_iterator_t* iter, uint16_t data ); static void dns_write_uint32( dns_message_iterator_t* iter, uint32_t data ); static void dns_write_bytes( dns_message_iterator_t* iter, uint8_t* data, uint16_t length ); static uint16_t dns_read_uint16( dns_message_iterator_t* iter ); static void dns_skip_name( dns_message_iterator_t* iter ); static void dns_write_name( dns_message_iterator_t* iter, const char* src ); static OSStatus start_bonjour_service(void); static mico_mutex_t bonjour_mutex = NULL; static mico_semaphore_t update_state_sem = NULL; static int update_state_fd = 0; static mico_thread_t mfi_bonjour_thread_handler; static void _bonjour_thread(uint32_t arg); void process_dns_questions(int fd, dns_message_iterator_t* iter ) { dns_name_t name; dns_question_t question; dns_message_iterator_t response; IPStatusTypedef para; int a = 0; int question_processed; uint32_t myip; memset( &response, 0, sizeof(dns_message_iterator_t) ); for ( a = 0; a < htons(iter->header->question_count); ++a ) { if (iter->iter > iter->end) break; if(dns_get_next_question( iter, &question, &name )==0) break; question_processed = 0; switch ( question.question_type ){ case RR_TYPE_PTR: if ( available_services != NULL ){ // Check if its a query for all available services if ( dns_compare_name_to_string( &name, SERVICE_QUERY_NAME ) ){ int b = 0; if(dns_create_message( &response, 512 )) { dns_write_header(&response, iter->header->id, 0x8400, 0, available_service_count, 0 ); for ( b = 0; b < available_service_count; ++b ){ dns_write_record( &response, SERVICE_QUERY_NAME, RR_CLASS_IN, RR_TYPE_PTR, 1500, (uint8_t*) available_services[b].service_name ); } mdns_send_message(fd, &response ); dns_free_message( &response ); question_processed = 1; } } // else check if its one of our records else { int b = 0; for ( b = 0; b < available_service_count; ++b ){ //printf("UDP multicast test: Recv a SERVICE Detail request: %s.\r\n", name); if ( dns_compare_name_to_string( &name, available_services[b].service_name )){ if( available_services[b].state != RECORD_NORMAL ) continue; micoWlanGetIPStatus(¶, available_services[b].interface); myip = inet_addr(para.ip); if( myip == 0 || myip == 0xFFFFFFFF) continue; // Send the PTR, TXT, SRV and A records if(dns_create_message( &response, 512 )){ dns_write_header( &response, iter->header->id, 0x8400, 0, 4, 0 ); //dns_write_record( &response, MFi_SERVICE_QUERY_NAME, RR_CLASS_IN, RR_TYPE_PTR, 1500, (u8*) available_services[b].service_name ); dns_write_record( &response, available_services[b].service_name, RR_CLASS_IN, RR_TYPE_PTR, available_services[b].ttl, (uint8_t*) available_services[b].instance_name ); dns_write_record( &response, available_services[b].instance_name, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_TXT, available_services[b].ttl, (uint8_t*) available_services[b].txt_att ); dns_write_record( &response, available_services[b].instance_name, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_SRV, available_services[b].ttl, (uint8_t*) &available_services[b]); dns_write_record( &response, available_services[b].hostname, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_A, available_services[b].ttl, (uint8_t*) &myip); mdns_send_message(fd, &response ); dns_free_message( &response ); question_processed = 1; } } } } } break; } if (!question_processed ){ mdns_process_query(fd, &name, &question, iter); } } } static void mdns_process_query(int fd, dns_name_t* name, dns_question_t* question, dns_message_iterator_t* source ) { dns_message_iterator_t response; IPStatusTypedef para; uint32_t myip; int b = 0; memset( &response, 0, sizeof(dns_message_iterator_t) ); switch ( question->question_type ) { case RR_QTYPE_ANY: case RR_TYPE_A: for ( b = 0; b < available_service_count; ++b ){ if ( dns_compare_name_to_string( name, available_services[b].hostname ) ){ micoWlanGetIPStatus(¶, available_services[b].interface); myip = inet_addr(para.ip); if( myip == 0 || myip == 0xFFFFFFFF) continue; if(dns_create_message( &response, 256 )){ dns_write_header( &response, source->header->id, 0x8400, 0, 1, 0 ); dns_write_record( &response, available_services[b].hostname, RR_CLASS_IN | RR_CACHE_FLUSH, RR_TYPE_A, available_services[b].ttl, (uint8_t *)&myip); mdns_send_message(fd, &response ); dns_free_message( &response ); return; } } } default: break;; } } static int dns_get_next_question( dns_message_iterator_t* iter, dns_question_t* q, dns_name_t* name ) { // Set the name pointers and then skip it name->start_of_name = (uint8_t*) iter->iter; name->start_of_packet = (uint8_t*) iter->header; dns_skip_name( iter ); if (iter->iter > iter->end) return 0; // Read the type and class q->question_type = dns_read_uint16( iter ); q->question_class = dns_read_uint16( iter ); return 1; } static int dns_compare_name_to_string( dns_name_t* name, const char* string ) { uint8_t section_length; int finished = 0; int result = 1; uint8_t* buffer = name->start_of_name; char *temp; while ( !finished ) { // Check if the name is compressed. If so, find the uncompressed version while ( (uint8_t)(*buffer) & 0xC0 ) { uint16_t offset = ( *buffer++ ) << 8; offset += *buffer; offset &= 0x3FFF; buffer = name->start_of_packet + offset; } // Compare section section_length = *( buffer++ ); temp = malloc(section_length+1); temp[section_length] = 0; memcpy(temp, buffer, section_length ); free(temp); if ( strncmp( (char*) buffer, string, section_length ) ) { result = 0; finished = 1; } string += section_length + 1; buffer += section_length; // Check if we've finished comparing if ( *buffer == 0 || *string == 0 ) { finished = 1; // Check if one of the strings has more data if ( *buffer != 0 || *string != 0 ) { result = 0; } } } return result; } static int dns_create_message( dns_message_iterator_t* message, uint16_t size ) { message->header = (dns_message_header_t*) malloc( size ); if ( message->header == NULL ) { return 0; } message->iter = (uint8_t *) message->header + sizeof(dns_message_header_t); return 1; } static void dns_free_message( dns_message_iterator_t* message ) { free(message->header); message->header = NULL; } static void dns_write_string( dns_message_iterator_t* iter, const char* src ) { uint8_t* segment_length_pointer; uint8_t segment_length; while ( *src != 0 && (uint8_t)(*src) != 0xC0) { /* Remember where we need to store the segment length and reset the counter*/ segment_length_pointer = iter->iter++; segment_length = 0; /* Copy bytes until '.' or end of string*/ while ( *src != '.' && *src != 0 && (uint8_t)(*src) != 0xC0) { if (*src == '/') src++; // skip '/' *iter->iter++ = *src++; ++segment_length; } /* Store the length of the segment*/ *segment_length_pointer = segment_length; /* Check if we stopped because of a '.', if so, skip it*/ if ( *src == '.' ) { ++src; } } if ( (uint8_t)(*src) == 0xC0) { // compress name *iter->iter++ = *src++; *iter->iter++ = *src++; } else { /* Add the ending null */ *iter->iter++ = 0; } } static void dns_write_header( dns_message_iterator_t* iter, uint16_t id, uint16_t flags, uint16_t question_count, uint16_t answer_count, uint16_t authorative_count ) { memset( iter->header, 0, sizeof(dns_message_header_t) ); iter->header->id = htons(id); iter->header->flags = htons(flags); iter->header->question_count = htons(question_count); iter->header->name_server_count = htons(authorative_count); iter->header->answer_count = htons(answer_count); } static void dns_write_record( dns_message_iterator_t* iter, const char* name, uint16_t record_class, uint16_t record_type, uint32_t ttl, uint8_t* rdata ) { uint8_t* rd_length; uint8_t* temp_ptr; /* Write the name, type, class, TTL*/ dns_write_name ( iter, name ); dns_write_uint16( iter, record_type ); dns_write_uint16( iter, record_class ); dns_write_uint32( iter, ttl ); /* Keep track of where we store the rdata length*/ rd_length = iter->iter; iter->iter += 2; temp_ptr = iter->iter; switch ( record_type ) { case RR_TYPE_A: dns_write_bytes( iter, rdata, 4 ); break; case RR_TYPE_PTR: case RR_TYPE_TXT: dns_write_name( iter, (const char*) rdata ); break; case RR_TYPE_SRV: /* Set priority and weight to 0*/ dns_write_uint16( iter, 0 ); dns_write_uint16( iter, 0 ); /* Write the port*/ dns_write_uint16( iter, ( (dns_sd_service_record_t*) rdata )->port ); /* Write the hostname*/ dns_write_string( iter, ( (dns_sd_service_record_t*) rdata )->hostname ); break; default: break; } // Write the rdata length rd_length[0] = ( iter->iter - temp_ptr ) >> 8; rd_length[1] = ( iter->iter - temp_ptr ) & 0xFF; } static void mdns_send_message(int fd, dns_message_iterator_t* message ) { struct sockaddr_in addr; // printf("enter send message\r\n"); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_MULTICAST_MDNS); addr.sin_port = htons(5353); sendto(fd, message->header, message->iter - (uint8_t*)message->header, 0, (struct sockaddr *)&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); addr.sin_port = htons(INADDR_BROADCAST); sendto(fd, message->header, message->iter - (uint8_t*)message->header, 0, (struct sockaddr *)&addr, sizeof(addr)); } static void dns_write_uint16( dns_message_iterator_t* iter, uint16_t data ) { // We cannot assume the u8 alignment of iter->iter so we can't just typecast and assign iter->iter[0] = data >> 8; iter->iter[1] = data & 0xFF; iter->iter += 2; } static void dns_write_uint32( dns_message_iterator_t* iter, uint32_t data ) { iter->iter[0] = data >> 24; iter->iter[1] = data >> 16; iter->iter[2] = data >> 8; iter->iter[3] = data & 0xFF; iter->iter += 4; } static void dns_write_bytes( dns_message_iterator_t* iter, uint8_t* data, uint16_t length ) { int a = 0; for ( a = 0; a < length; ++a ) { iter->iter[a] = data[a]; } iter->iter += length; } static uint16_t dns_read_uint16( dns_message_iterator_t* iter ) { uint16_t temp = (uint16_t) ( *iter->iter++ ) << 8; temp += (uint16_t) ( *iter->iter++ ); return temp; } static void dns_skip_name( dns_message_iterator_t* iter ) { while ( *iter->iter != 0 ) { // Check if the name is compressed if ( *iter->iter & 0xC0 ) { iter->iter += 1; // Normally this should be 2, but we have a ++ outside the while loop break; } else { iter->iter += (uint32_t) *iter->iter + 1; } if (iter->iter > iter->end) break; } // Skip the null u8 ++iter->iter; } static void dns_write_name( dns_message_iterator_t* iter, const char* src ) { dns_write_string( iter, src ); } static bool is_service_match ( dns_sd_service_record_t *record, char *service_name, WiFi_Interface interface ) { if( record->state == RECORD_REMOVED || record->state == RECORD_REMOVE ) return false; if( ( service_name == NULL || strcmp( record->service_name, service_name ) == 0 ) && record->interface == interface ) return true; return false; } static int find_record_by_service ( char *service_name, WiFi_Interface interface ) { int i; uint32_t insert_index = 0xFF; for ( i = 0; i < available_service_count; i++ ){ if( is_service_match ( &available_services[i], service_name, interface ) ){ insert_index = i; break; } } return insert_index; } static int find_empty_record ( void ) { int i; uint32_t insert_index = 0xFF; for ( i = 0; i < available_service_count; i++ ){ if( available_services[i].state == RECORD_REMOVED ){ insert_index = i; break; } } return insert_index; } static mico_thread_t _bonjour_announce_handler = NULL; void _bonjour_send_anounce_thread(uint32_t arg) { uint32_t insert_index = 0xFF; UNUSED_PARAMETER( arg ); while(1){ insert_index = 0xFF; for ( int i = 0; i < available_service_count; i++ ){ if( available_services[i].state != RECORD_REMOVED && available_services[i].count_down != 0 ){ insert_index = i; break; } } if( insert_index == 0xFF ) goto exit; mdns_utils_log( "sem trigger" ); mico_rtos_set_semaphore( &update_state_sem ); mico_thread_msleep(200); } exit: _bonjour_announce_handler = NULL; mico_rtos_delete_thread( NULL ); return; } static void _clean_record_resource( dns_sd_service_record_t *record ) { if(record->service_name) { free(record->service_name); record->service_name = NULL; } if(record->hostname){ free(record->hostname); record->hostname = NULL; } if(record->instance_name){ free(record->instance_name); record->instance_name = NULL; } if(record->txt_att){ free(record->txt_att); record->txt_att = NULL; } } OSStatus mdns_add_record( mdns_init_t init, WiFi_Interface interface, uint32_t time_to_live ) { int len; OSStatus err = kNoErr; uint32_t insert_index = 0xFF; if( bonjour_instance == false ){ err = start_bonjour_service( ); require_noerr(err, exit); } insert_index = find_record_by_service ( init.service_name, interface ); if( insert_index == 0xFF) insert_index = find_empty_record ( ); require_action( insert_index < available_service_count, exit, err = kNoResourcesErr); mico_rtos_lock_mutex( &bonjour_mutex ); _clean_record_resource( &available_services[insert_index] ); available_services[insert_index].interface = interface; available_services[insert_index].service_name = (char*)__strdup(init.service_name); available_services[insert_index].hostname = (char*)__strdup(init.host_name); len = strlen(init.instance_name); available_services[insert_index].instance_name = (char*)malloc(len+3);//// 0xc00c+\0 memcpy(available_services[insert_index].instance_name, init.instance_name, len); available_services[insert_index].instance_name[len]= 0xc0; available_services[insert_index].instance_name[len+1]= 0x0c; available_services[insert_index].instance_name[len+2]= 0; available_services[insert_index].txt_att = (char*)__strdup(init.txt_record); available_services[insert_index].port = init.service_port; available_services[insert_index].state = RECORD_UPDATE; available_services[insert_index].count_down = 5; available_services[insert_index].ttl = time_to_live; if( _bonjour_announce_handler == NULL) mico_rtos_create_thread( &_bonjour_announce_handler, MICO_APPLICATION_PRIORITY, "Bonjour Announce", _bonjour_send_anounce_thread, 0x400, 0 ); mico_rtos_unlock_mutex( &bonjour_mutex ); exit: return err; } void mdns_update_txt_record( char *service_name, WiFi_Interface interface, char *txt_record ) { uint32_t insert_index = 0xFF; if( bonjour_instance == false ) return; insert_index = find_record_by_service ( service_name, interface ); if( insert_index == 0xFF ) return; mico_rtos_lock_mutex( &bonjour_mutex ); if(available_services[insert_index].txt_att) free(available_services[insert_index].txt_att); available_services[insert_index].txt_att = (char*)__strdup(txt_record); available_services[insert_index].state = RECORD_UPDATE; available_services[insert_index].count_down = 5; if( _bonjour_announce_handler == NULL) mico_rtos_create_thread( &_bonjour_announce_handler, MICO_APPLICATION_PRIORITY, "Bonjour Announce", _bonjour_send_anounce_thread, 0x400, 0 ); mico_rtos_unlock_mutex( &bonjour_mutex ); } void mdns_suspend_record( char *service_name, WiFi_Interface interface, bool will_remove ) { int i; uint32_t insert_index = 0xFF; mdns_utils_log( "Suspend %s@%d", service_name == NULL ? "null" : service_name, interface); if( bonjour_instance == false ) return; mico_rtos_lock_mutex( &bonjour_mutex ); for ( i = 0; i < available_service_count; i++ ){ if( is_service_match ( &available_services[i], service_name, interface ) == false) continue; mdns_utils_log( "Find index %d to suspend", i); if( will_remove == true ) available_services[i].state = RECORD_REMOVE; else{ if( available_services[i].state != RECORD_REMOVE ) available_services[i].state = RECORD_SUSPEND; } available_services[i].count_down = 5; insert_index = i; } if( insert_index == 0xFF ) goto exit; if( _bonjour_announce_handler == NULL) mico_rtos_create_thread( &_bonjour_announce_handler, MICO_APPLICATION_PRIORITY, "Bonjour Announce", _bonjour_send_anounce_thread, 0x400, 0 ); exit: mico_rtos_unlock_mutex( &bonjour_mutex ); return; } void mdns_resume_record( char *service_name, WiFi_Interface interface ) { int i; uint32_t insert_index = 0xFF; if( bonjour_instance == false ) return; mico_rtos_lock_mutex( &bonjour_mutex ); for ( i = 0; i < available_service_count && is_service_match( &available_services[i], service_name, interface ); i++ ){ available_services[i].state = RECORD_UPDATE; available_services[i].count_down = 5; insert_index = i; } if( insert_index == 0xFF ) goto exit; if( _bonjour_announce_handler == NULL) mico_rtos_create_thread( &_bonjour_announce_handler, MICO_APPLICATION_PRIORITY, "Bonjour Announce", _bonjour_send_anounce_thread, 0x400, 0 ); exit: mico_rtos_unlock_mutex( &bonjour_mutex ); return; } mdns_record_state_t mdns_get_record_status( char *service_name, WiFi_Interface interface) { uint32_t insert_index = find_record_by_service( service_name, interface ); if( insert_index == 0xFF ) return RECORD_REMOVED; return available_services[insert_index].state; } void mdns_handler(int fd, uint8_t* pkt, int pkt_len) { dns_message_iterator_t iter; iter.header = (dns_message_header_t*) pkt; iter.iter = (uint8_t*) iter.header + sizeof(dns_message_header_t); iter.end = pkt+pkt_len; // Check if the message is a response (otherwise its a query) if ( ntohs(iter.header->flags) & DNS_MESSAGE_IS_A_RESPONSE ) { } else { process_dns_questions(fd, &iter ); } } void bonjour_send_record(int record_index) { dns_message_iterator_t response; uint32_t myip; IPStatusTypedef para; int ttl = 0; /* Send service and a ttl > 0 for a working record*/ if( available_services[record_index].state == RECORD_NORMAL || available_services[record_index].state == RECORD_UPDATE ){ ttl = available_services[record_index].ttl; if(dns_create_message( &response, 512 )) { dns_write_header(&response, 0x0, 0x8400, 0, 1, 0 ); dns_write_record( &response, SERVICE_QUERY_NAME, RR_CLASS_IN, RR_TYPE_PTR, 1500, (uint8_t*) available_services[record_index].service_name ); mdns_send_message(mDNS_fd, &response ); dns_free_message( &response ); } } micoWlanGetIPStatus(¶, available_services[record_index].interface); myip = inet_addr(para.ip); if( myip == 0 || myip == 0xFFFFFFFF) return; if(dns_create_message( &response, 512 )){ mdns_utils_log( "TTL = %d", ttl); micoWlanGetIPStatus(¶, available_services[record_index].interface); dns_write_header( &response, 0x0, 0x8400, 0, 4, 0 ); dns_write_record( &response, available_services[record_index].service_name, RR_CLASS_IN, RR_TYPE_PTR, ttl, (uint8_t*) available_services[record_index].instance_name ); dns_write_record( &response, available_services[record_index].instance_name, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_TXT, ttl, (uint8_t*) available_services[record_index].txt_att ); dns_write_record( &response, available_services[record_index].instance_name, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_SRV, ttl, (uint8_t*) &available_services[record_index]); dns_write_record( &response, available_services[record_index].hostname, RR_CACHE_FLUSH|RR_CLASS_IN, RR_TYPE_A, ttl, (uint8_t*) &myip); mdns_send_message(mDNS_fd, &response ); dns_free_message( &response ); } } void BonjourNotify_WifiStatusHandler( WiFiEvent event, void *arg ) { UNUSED_PARAMETER(arg); switch (event) { case NOTIFY_STATION_UP: mdns_resume_record( NULL, Station ); break; case NOTIFY_STATION_DOWN: mdns_suspend_record( NULL, Station, false ); break; case NOTIFY_AP_UP: mdns_resume_record( NULL, Soft_AP ); break; case NOTIFY_AP_DOWN: mdns_suspend_record( NULL, Soft_AP, false ); break; default: break; } return; } void BonjourNotify_SYSWillPoerOffHandler( void *arg ) { UNUSED_PARAMETER(arg); mdns_suspend_record( NULL, Station, true ); mdns_suspend_record( NULL, Soft_AP, true ); } uint8_t *buf = NULL; static OSStatus start_bonjour_service(void) { OSStatus err = kNoErr; struct sockaddr_in addr; ip_mreq mreq_opt; if(bonjour_mutex == NULL) mico_rtos_init_mutex( &bonjour_mutex ); if(update_state_sem == NULL) mico_rtos_init_semaphore( &update_state_sem, 1 ); update_state_fd = mico_create_event_fd( update_state_sem ); memset( available_services, 0x0, sizeof( available_services ) ); buf = malloc(1500); require_action(buf, exit, err =kNoMemoryErr); mDNS_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); require_action(IsValidSocket( mDNS_fd ), exit, err = kNoResourcesErr ); mreq_opt.imr_multiaddr.s_addr = htonl(INADDR_MULTICAST_MDNS); mreq_opt.imr_interface.s_addr = htonl(INADDR_ANY); setsockopt(mDNS_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq_opt, sizeof(ip_mreq)); addr.sin_family = AF_INET; addr.sin_port = htons(5353); addr.sin_addr.s_addr = INADDR_ANY; err = bind(mDNS_fd, (struct sockaddr *)&addr, sizeof(addr)); require_noerr(err, exit); err = mico_system_notify_register( mico_notify_WIFI_STATUS_CHANGED, (void *)BonjourNotify_WifiStatusHandler, NULL ); require_noerr( err, exit ); err = mico_system_notify_register( mico_notify_SYS_WILL_POWER_OFF, (void *)BonjourNotify_SYSWillPoerOffHandler, NULL ); require_noerr( err, exit ); err = mico_rtos_create_thread(&mfi_bonjour_thread_handler, MICO_APPLICATION_PRIORITY, "Bonjour", _bonjour_thread, 0x500, 0 ); require_noerr(err, exit); bonjour_instance = true; exit: return err; } void _bonjour_thread(uint32_t arg) { int i, con = -1; struct timeval t; fd_set readfds; struct sockaddr_in addr; socklen_t addrLen; //OSStatus err = kNoErr; UNUSED_PARAMETER( arg ); t.tv_sec = 1; t.tv_usec = 0; while(1) { /*Check status on erery sockets on bonjour query */ FD_ZERO(&readfds); FD_SET(mDNS_fd, &readfds); FD_SET(update_state_fd, &readfds); select( Max( mDNS_fd, update_state_fd )+ 1, &readfds, NULL, NULL, &t ); if ( FD_ISSET( update_state_fd, &readfds ) ){ mdns_utils_log( "sem recved" ); mico_rtos_get_semaphore( &update_state_sem, 0 ); mico_rtos_lock_mutex( &bonjour_mutex ); for ( i = 0; i < available_service_count; i++ ){ switch ( available_services[i].state ){ case RECORD_REMOVE: mdns_utils_log( "Remove record %d", i ); bonjour_send_record( i ); available_services[i].count_down--; if( available_services[i].count_down == 0){ _clean_record_resource( &available_services[i] ); available_services[i].state = RECORD_REMOVED; } break; case RECORD_SUSPEND: if( available_services[i].count_down ){ mdns_utils_log( "Suspend record %d", i ); bonjour_send_record( i ); if( available_services[i].count_down ) available_services[i].count_down--; } break; case RECORD_UPDATE: mdns_utils_log( "Update record %d, cd: %d", i, available_services[i].count_down ); bonjour_send_record( i ); available_services[i].count_down--; if( available_services[i].count_down == 0) available_services[i].state = RECORD_NORMAL; break; default: break; } } mico_rtos_unlock_mutex( &bonjour_mutex ); } /*Read data from udp and send data back */ if (FD_ISSET(mDNS_fd, &readfds)) { con = recvfrom(mDNS_fd, buf, 1500, 0, (struct sockaddr *)&addr, &addrLen); mico_rtos_lock_mutex( &bonjour_mutex ); mdns_handler(mDNS_fd, (uint8_t *)buf, con); mico_rtos_unlock_mutex( &bonjour_mutex ); } } //mdns_utils_log("Exit: mDNS thread exit with err = %d", err); //SocketClose( &mDNS_fd ); //if(buf) free(buf); //mico_rtos_delete_thread(NULL); }