From e24dd44fe979d4b976ac3e9aaa1e201a2aea5c01 Mon Sep 17 00:00:00 2001 From: Andrew Elder Date: Fri, 21 Sep 2012 14:06:35 -0400 Subject: [PATCH] mrpd: Windows build module --- daemons/mrpd/mrpw.c | 957 ++++++++++++++++++++++++++++++++++++++++++++++++++++ daemons/mrpd/que.c | 96 ++++++ daemons/mrpd/que.h | 70 ++++ 3 files changed, 1123 insertions(+) create mode 100644 daemons/mrpd/mrpw.c create mode 100644 daemons/mrpd/que.c create mode 100644 daemons/mrpd/que.h diff --git a/daemons/mrpd/mrpw.c b/daemons/mrpd/mrpw.c new file mode 100644 index 0000000..3ba873f --- /dev/null +++ b/daemons/mrpd/mrpw.c @@ -0,0 +1,957 @@ +/****************************************************************************** + + Copyright (c) 2012, Intel Corporation + Copyright (c) 2012, AudioScience, Inc + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ +/* + * Main code for Windows implementation of MRP/MMRP/MVRP/MSRP + */ + +#include +#include + +#include +#include +#include + +#include "mrpd.h" +#include "mrp.h" +#include "mvrp.h" +#include "msrp.h" +#include "mmrp.h" + +#include "que.h" + +#define TIME_PERIOD_100_MILLISECONDS 100 +#define NETIF_TIMEOUT (-2) + +/* local structs */ +struct wtimer { + int running; + int elapsed; + unsigned int count; + unsigned int interval; + unsigned int start_time; +}; + +struct netif { + //pcap version + pcap_if_t *alldevs; + pcap_if_t *d; + uint8_t mac[6]; + int inum; + int i; + int error; + pcap_t *pcap_interface; + char errbuf[PCAP_ERRBUF_SIZE]; + struct bpf_program fcode; + struct pcap_pkthdr *header; + const u_char *ethernet_frame; + uint8_t tx_frame[1500]; // ethernet frame used to send packets +}; + +enum { + pkt_event_wpcap, + pkt_event_localhost, + pkt_event_wpcap_timeout, + pkt_event_localhost_timeout, + app_event_kill_all, + loop_time_tick +}; + +/* global mgmt parameters */ +int daemonize; +int mmrp_enable; +int mvrp_enable; +int msrp_enable; +int logging_enable; +int mrpd_port; +HANDLE pkt_events[6]; +HANDLE sem_kill_wpcap_thread; +HANDLE sem_kill_localhost_thread; +struct que_def *que_wpcap; +struct que_def *que_localhost; + + +//char *net_interface; +int interface_fd; + + +/* state machine controls */ +int periodic_enable; +int registration; + +/* if registration is FIXED or FORBIDDEN + * updates from MRP are discarded, and + * only IN and JOININ messages are sent + */ + +int participant; + +/* if participant role is 'SILENT' (or non-participant) + * applicant doesn't send any messages - configured per-attribute + */ + +#define VERSION_STR "0.0" + +static const char *version_str = + "mrpw v" VERSION_STR "\n" "Copyright (c) 2012, AudioScience Inc\n"; + +unsigned char STATION_ADDR[] = { 0x00, 0x88, 0x77, 0x66, 0x55, 0x44 }; + +/* global variables */ +SOCKET control_socket; +extern SOCKET mmrp_socket; +extern SOCKET mvrp_socket; +extern SOCKET msrp_socket; +struct netif *net_if; + +HTIMER periodic_timer; +HTIMER gc_timer; +HTIMER timer_check_tick; + +extern struct mmrp_database *MMRP_db; +extern struct mvrp_database *MVRP_db; +extern struct msrp_database *MSRP_db; + +struct netif *netif_open( int timeout_ms ) +{ + int inum=0; + int i=0, total_interfaces=0; + struct netif *netif; + IP_ADAPTER_INFO *AdapterInfo; + IP_ADAPTER_INFO *Current; + ULONG AIS; + DWORD status; + + + netif = (struct netif *)calloc(1, sizeof(struct netif)); + + /* Retrieve the device list on the local machine */ + if (pcap_findalldevs(&netif->alldevs, netif->errbuf) == -1) + { + printf("Error finding interfaces\n"); + goto error_return; + } + + /* Print the list */ + for(netif->d=netif->alldevs; netif->d; netif->d=netif->d->next) + { + /*printf("%d. %s", ++i, d->name);*/ + printf("%d", ++i); + if (netif->d->description) + printf(" (%-70s)\n", netif->d->description); + else + printf(" (No description available)\n"); + } + total_interfaces = i; + + if(i==0) + { + printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); + goto error_return; + } + + printf("Enter the interface number (1-%d):",i ); + scanf_s("%d", &inum); + + if(inum < 1 || inum > i) + { + printf("\nInterface number out of range.\n"); + /* Free the device list */ + pcap_freealldevs(netif->alldevs); + goto error_return; + } + + /* Jump to the selected adapter */ + for(netif->d=netif->alldevs, i=0; i< inum-1 ;netif->d=netif->d->next, i++); + + /* Open the device */ + if ( (netif->pcap_interface= pcap_open_live(netif->d->name, // name of the device + 65536, // portion of the packet to capture + // 65536 guarantees that the whole packet will be captured on all the link layers + 1, // promiscuous mode + timeout_ms, // read timeout in ms + netif->errbuf // error buffer + ) ) == NULL) + { + fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", netif->d->name); + /* Free the device list */ + pcap_freealldevs(netif->alldevs); + goto error_return; + } + + /* lookup ip address */ + AdapterInfo = (IP_ADAPTER_INFO *)calloc(total_interfaces, sizeof(IP_ADAPTER_INFO)); + AIS = sizeof(IP_ADAPTER_INFO) * total_interfaces; + status = GetAdaptersInfo(AdapterInfo, &AIS); + if (status != ERROR_SUCCESS) { + fprintf(stderr,"\nError, GetAdaptersInfo() call in netif_win32_pcap.c failed\n"); + free(AdapterInfo); + goto error_return; + } + + for(Current = AdapterInfo; Current != NULL; Current = Current->Next) { + if(strstr(netif->d->name, Current->AdapterName) != 0){ + uint32_t my_ip; + ULONG len; + uint8_t tmp[16]; + + my_ip = inet_addr(Current->IpAddressList.IpAddress.String); + len = sizeof(tmp); + SendARP(my_ip ,INADDR_ANY, tmp, &len); + memcpy(netif->mac, &tmp[0], sizeof(netif->mac)); + } + } + free(AdapterInfo); + return netif; + +error_return: + free(netif); + return NULL; +} + +int netif_close( struct netif *net_if ) +{ + /* At this point, we don't need any more the device list. Free it */ + pcap_freealldevs(net_if->alldevs); + pcap_close(net_if->pcap_interface); + free(net_if); + return(0); +} + +int netif_set_capture_ethertype( struct netif *net_if, uint16_t *ethertype, uint32_t count) +{ + struct bpf_program fcode; + char ethertype_string[512]; + char ethertype_single[64]; + unsigned int i; + + ethertype_string[0] = 0; + for (i = 0; i < count; i++){ + sprintf( ethertype_single, "ether proto 0x%04x", ethertype[i]); + strcat(ethertype_string, ethertype_single); + if ( (i + 1) < count) + strcat(ethertype_string, " or "); + } + + // compile a filter + if (pcap_compile(net_if->pcap_interface, &fcode, ethertype_string, 1, 0) < 0) { + fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n"); + /* Free the device list */ + pcap_freealldevs(net_if->alldevs); + return -1; + } + + //set the filter + if (pcap_setfilter(net_if->pcap_interface, &fcode) < 0) { + fprintf(stderr,"\nError setting the filter.\n"); + /* Free the device list */ + pcap_freealldevs(net_if->alldevs); + return -1; + } + + return(0); +} + +int netif_capture_frame( struct netif *net_if, uint8_t **frame, uint16_t *length ) +{ + struct pcap_pkthdr *header; + int error=0; + + *length = 0; + error = pcap_next_ex( net_if->pcap_interface, &header, frame); + if(error > 0 ) { + *length = (uint16_t)header->len; + return(1); + } else { + return(NETIF_TIMEOUT); + } +} + +int netif_send_frame( struct netif *net_if, uint8_t *frame, uint16_t length ) +{ + //printf("TX frame: %d bytes\n", length); + if (pcap_sendpacket(net_if->pcap_interface, frame, length ) != 0){ + fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(net_if->pcap_interface)); + return -1; + } + return(0); +} + +struct netif_thread_data { + uint8_t *frame; + uint16_t length; +}; + +DWORD WINAPI netif_thread( LPVOID lpParam ) +{ + int status; + struct netif_thread_data d; + + while (WaitForSingleObject(sem_kill_wpcap_thread, 0)){ + status = netif_capture_frame(net_if, &d.frame, &d.length); + if (status > 0) { + que_push(que_wpcap, &d); + } else { + if ( !SetEvent(pkt_events[pkt_event_wpcap_timeout]) ) { + printf("SetEvent pkt_event_wpcap_timeout failed (%d)\n", GetLastError()); + return 1; + } + } + } + return 0; +} + +static int clock_monotonic_in_ms_init = 0; +static LARGE_INTEGER clock_monotonic_freq; + +unsigned int clock_monotonic_in_ms(void) +{ + LARGE_INTEGER count; + QueryPerformanceCounter(&count); + if (!clock_monotonic_in_ms_init) { + QueryPerformanceFrequency(&clock_monotonic_freq); + clock_monotonic_in_ms_init = 1; + } + return (unsigned int)((double)count.QuadPart * 1000.0 / + (double)clock_monotonic_freq.QuadPart); +} + +HTIMER mrpd_timer_create(void) +{ + return (struct wtimer *)calloc(1,sizeof(struct wtimer)); +} + +void mrpd_timer_close(HTIMER t) +{ + if (t) + free(t); +} + +int mrpd_timer_start_interval( + HTIMER timerfd, + unsigned long value_ms, + unsigned long interval_ms) +{ + struct wtimer *t = (struct wtimer *)timerfd; + t->running = TRUE; + t->elapsed = FALSE; + t->count = value_ms; + t->interval = interval_ms; + t->start_time = clock_monotonic_in_ms(); + return 0; +} +int mrpd_timer_start( + HTIMER timerfd, + unsigned long value_ms) +{ + return mrpd_timer_start_interval(timerfd, value_ms, 0); +} + +int mrpd_timer_restart( HTIMER timerfd) +{ + struct wtimer *t = (struct wtimer *)timerfd; + if (t->interval) { + t->start_time = t->start_time + t->interval; + t->running = TRUE; + t->elapsed = FALSE; + } + return 0; +} + +int mrpd_timer_stop(HTIMER timerfd) +{ + struct wtimer *t = (struct wtimer *)timerfd; + t->running = FALSE; + t->elapsed = FALSE; + return 0; +} + +int mrpd_timer_timeout( + HTIMER timerfd) +{ + struct wtimer *t = (struct wtimer *)timerfd; + if (t->running && !t->elapsed) { + unsigned int elapsed_ms; + unsigned int current_time = clock_monotonic_in_ms(); + elapsed_ms = current_time - t->start_time; + if( elapsed_ms > t->count) { + t->elapsed = TRUE; + } + } + return t->elapsed; +} + +int gctimer_start() +{ + /* reclaim memory every 30 minutes */ + return mrpd_timer_start(gc_timer, 30 * 60 *1000); +} + +int periodictimer_start() +{ + /* periodictimer has expired. (10.7.5.23) + * PeriodicTransmission state machine generates periodic events + * period is one-per-sec + */ + return mrpd_timer_start_interval(periodic_timer, 1000, 1000); +} + +int periodictimer_stop() +{ + /* periodictimer has expired. (10.7.5.23) + * PeriodicTransmission state machine generates periodic events + * period is one-per-sec + */ + return mrpd_timer_stop(periodic_timer); +} + + +int mrpd_init_timers(struct mrp_database *mrp_db) +{ + mrp_db->join_timer = mrpd_timer_create(); + mrp_db->lv_timer = mrpd_timer_create(); + mrp_db->lva_timer = mrpd_timer_create(); + + if (NULL == mrp_db->join_timer) + goto out; + if (NULL == mrp_db->lv_timer) + goto out; + if (NULL == mrp_db->lva_timer) + goto out; + return 0; + out: + mrpd_timer_close(mrp_db->join_timer); + mrpd_timer_close(mrp_db->lv_timer); + mrpd_timer_close(mrp_db->lva_timer); + + return -1; +} + +int init_timers(void) +{ + /* + * primarily whether to schedule the periodic timer as the + * rest are self-scheduling as a side-effect of state transitions + * of the various attributes + */ + + periodic_timer = mrpd_timer_create(); + gc_timer = mrpd_timer_create(); + + if (NULL == periodic_timer) + goto out; + if (NULL == gc_timer) + goto out; + + gctimer_start(); + + if (periodic_enable) + periodictimer_start(); + + return 0; + out: + return -1; +} + +//sockaddr + +int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client) +{ + + char respbuf[8]; + /* + * Inbound/output commands from/to a client: + * + * When sent from a client, indicates an operation on the + * internal attribute databases. When sent by the daemon to + * a client, indicates an event such as a new attribute arrival, + * or a leaveall timer to force clients to re-advertise continued + * interest in an attribute. + * + * BYE Client detaches from daemon + * + * M+? - JOIN_MT a MAC address or service declaration + * M++ JOIN_IN a MAC Address (XXX: MMRP doesn't use 'New' though?) + * M-- - LV a MAC address or service declaration + * V+? - JOIN_MT a VID (VLAN ID) + * V++ - JOIN_IN a VID (VLAN ID) + * V-- - LV a VID (VLAN ID) + * S+? - JOIN_MT a Stream + * S++ - JOIN_IN a Stream + * S-- - LV a Stream + * + * Outbound messages + * ERC - error, unrecognized command + * ERP - error, unrecognized parameter + * ERI - error, internal + * OK+ - success + * + * Registrar Commands + * + * M?? - query MMRP Registrar MAC Address database + * V?? - query MVRP Registrar VID database + * S?? - query MSRP Registrar database + * + * Registrar Responses (to ?? commands) + * + * MIN - Registered + * MMT - Registered, Empty + * MLV - Registered, Leaving + * MNE - New attribute notification + * MJO - JOIN attribute notification + * MLV - LEAVE attribute notification + * VIN - Registered + * VMT - Registered, Empty + * VLV - Registered, Leaving + * SIN - Registered + * SMT - Registered, Empty + * SLV - Registered, Leaving + * + */ + + memset(respbuf, 0, sizeof(respbuf)); + + if (logging_enable) + printf("CMD:%s from CLNT %d\n", buf, client->sin_port); + + if (buflen < 3) { + printf("buflen = %d!\b", buflen); + + return -1; + } + + switch (buf[0]) { + case 'M': + return mmrp_recv_cmd(buf, buflen, client); + break; + case 'V': + return mvrp_recv_cmd(buf, buflen, client); + break; + case 'S': + return msrp_recv_cmd(buf, buflen, client); + break; + case 'B': + mmrp_bye(client); + mvrp_bye(client); + msrp_bye(client); + break; + default: + printf("unrecognized command %s\n", buf); + snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf); + mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf)); + return -1; + break; + } + + return 0; +} + +static uint8_t *last_pdu_buffer; +static int last_pdu_buffer_size; + +int mrpd_recvmsgbuf(SOCKET sock, char **buf) +{ + + *buf = (char *)malloc(MAX_FRAME_SIZE); + if (NULL == *buf) + return -1; + + memcpy(*buf, last_pdu_buffer, last_pdu_buffer_size); + return last_pdu_buffer_size; +} + +int mrpd_send_ctl_msg( + struct sockaddr_in *client_addr, + char *notify_data, + int notify_len +) +{ + + int rc; + + if (INVALID_SOCKET == control_socket) + return 0; + + printf("mrpd_send_ctl_msg :%s\n", notify_data); + rc = sendto(control_socket, notify_data, notify_len, + 0, (struct sockaddr *)client_addr, sizeof(struct sockaddr)); + return rc; +} + +int mrpd_close_socket(SOCKET sock) +{ + return closesocket(sock); +} + +size_t mrpd_send(SOCKET sockfd, const void *buf, size_t len, int flags) +{ + if (pcap_sendpacket(net_if->pcap_interface, buf, len ) != 0){ + fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(net_if->pcap_interface)); + return -1; + } + return len; +} + + +int mrpd_init_protocol_socket(uint16_t etype, SOCKET *sock, unsigned char *multicast_addr) +{ + *sock = 0x1234; + return 0; +} + + +int init_local_ctl(void) +{ + struct sockaddr_in addr; + SOCKET sock_fd = INVALID_SOCKET; + int rc; + u_long iMode=1; + DWORD iResult; + int timeout = 100; // ms + + sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd == INVALID_SOCKET) + goto out; + + iResult = setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)); + if (iResult != NO_ERROR) + goto out; + iResult = setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, + (void *)&timeout, sizeof(timeout)); + if (iResult != NO_ERROR) + goto out; + + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(mrpd_port); + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + rc = bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)); + + if (rc == SOCKET_ERROR) + goto out; + + control_socket = sock_fd; + + return 0; + out: + if (sock_fd != INVALID_SOCKET) + closesocket(sock_fd); + + return -1; +} + + +struct ctl_thread_params { + char *msgbuf; + struct sockaddr client_addr; + int bytes; +}; + +DWORD WINAPI ctl_thread( LPVOID lpParam ) +{ + struct ctl_thread_params s; + int client_len; + + while (WaitForSingleObject(sem_kill_localhost_thread, 0)){ + client_len = sizeof(struct sockaddr); + s.msgbuf = (char *)malloc (MAX_MRPD_CMDSZ); + s.bytes = recvfrom(control_socket, s.msgbuf, MAX_MRPD_CMDSZ, 0, &s.client_addr, &client_len); + if (s.bytes > 0) { + que_push(que_localhost, &s); + } else { + free(s.msgbuf); + if ( !SetEvent(pkt_events[pkt_event_localhost_timeout]) ) { + printf("SetEvent pkt_event_localhost_timeout failed (%d)\n", GetLastError()); + return 1; + } + } + } + return 0; +} + +int mrpd_reclaim() +{ + + /* + * if the local applications have neither registered interest + * by joining, and the remote node has quit advertising the attribute + * and allowing it to go into the MT state, delete the attribute + */ + + mmrp_reclaim(); + mvrp_reclaim(); + msrp_reclaim(); + + gctimer_start(); + + return 0; + +} + +HANDLE kill_packet_capture; + +void process_events(void) +{ + HANDLE hThread1, hThread2; + DWORD dwThreadID1, dwThreadID2; + uint16_t length=0; + uint8_t *payload; + uint16_t protocol; + uint8_t *proto; + struct avb_avtpdu *avtpdu=NULL; + uint64_t src_mac_address=0; + struct ctl_thread_params localhost_pkt; + struct netif_thread_data wpcap_pkt; + int i; + + timer_check_tick = mrpd_timer_create(); + mrpd_timer_start_interval(timer_check_tick, 100, 100); + + que_wpcap = que_new(256, sizeof(struct netif_thread_data) ); + que_localhost = que_new(256, sizeof(struct ctl_thread_params) ); + + sem_kill_wpcap_thread = CreateSemaphore(NULL, 0, 32767, NULL); + sem_kill_localhost_thread = CreateSemaphore(NULL, 0, 32767, NULL); + for (i = pkt_event_wpcap_timeout; i <= loop_time_tick; i++) { + pkt_events[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (pkt_events[i] == NULL) { + fprintf(stderr, "CreateEvent error: %d\n", GetLastError() ); + ExitProcess(0); + } + } + pkt_events[pkt_event_wpcap] = que_data_available_object(que_wpcap); + pkt_events[pkt_event_localhost] = que_data_available_object(que_localhost); + + + // Create threads + hThread1 = CreateThread( + NULL, // default security attributes + 0, // default stack size + (LPTHREAD_START_ROUTINE)netif_thread, + NULL, // no thread function arguments + 0, // default creation flags + &dwThreadID1); // receive thread identifier + + if( hThread1 == NULL ) { + fprintf(stderr,"CreateThread error: %d\n", GetLastError()); + ExitProcess(0); + } + + hThread2 = CreateThread( + NULL, // default security attributes + 0, // default stack size + (LPTHREAD_START_ROUTINE) ctl_thread, + NULL, // no thread function arguments + 0, // default creation flags + &dwThreadID2); // receive thread identifier + + if( hThread1 == NULL ) { + fprintf(stderr,"CreateThread error: %d\n", GetLastError()); + ExitProcess(0); + } + + while(1) { + DWORD dwEvent = WaitForMultipleObjects( + sizeof(pkt_events)/sizeof(HANDLE), + pkt_events, + FALSE, + 100); /* 100ms wait */ + + /* special exit case */ + if (WAIT_OBJECT_0 + app_event_kill_all == dwEvent) + break; + + switch (dwEvent) { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + loop_time_tick: + /* timeout - run protocols */ + if (mrpd_timer_timeout(MMRP_db->mrp_db.lva_timer)) + mmrp_event(MRP_EVENT_LVATIMER, NULL); + if (mrpd_timer_timeout(MMRP_db->mrp_db.lv_timer)) + mmrp_event(MRP_EVENT_LVTIMER, NULL); + if (mrpd_timer_timeout(MMRP_db->mrp_db.join_timer)) + mmrp_event(MRP_EVENT_TX, NULL); + + if (mrpd_timer_timeout(MVRP_db->mrp_db.lva_timer)) + mvrp_event(MRP_EVENT_LVATIMER, NULL); + if (mrpd_timer_timeout(MVRP_db->mrp_db.lv_timer)) + mvrp_event(MRP_EVENT_LVTIMER, NULL); + if (mrpd_timer_timeout(MVRP_db->mrp_db.join_timer)) + mvrp_event(MRP_EVENT_TX, NULL); + + if (mrpd_timer_timeout(MSRP_db->mrp_db.lva_timer)) + msrp_event(MRP_EVENT_LVATIMER, NULL); + if (mrpd_timer_timeout(MSRP_db->mrp_db.lv_timer)) + msrp_event(MRP_EVENT_LVTIMER, NULL); + if (mrpd_timer_timeout(MSRP_db->mrp_db.join_timer)) + msrp_event(MRP_EVENT_TX, NULL); + + if (mrpd_timer_timeout(periodic_timer)) { + //printf("mrpd_timer_timeout(periodic_timer)\n"); + mmrp_event(MRP_EVENT_PERIODIC, NULL); + mvrp_event(MRP_EVENT_PERIODIC, NULL); + msrp_event(MRP_EVENT_PERIODIC, NULL); + mrpd_timer_restart(periodic_timer); + } + if (mrpd_timer_timeout(gc_timer)) { + mrpd_reclaim(); + } + mrpd_timer_restart(timer_check_tick); + break; + + case WAIT_OBJECT_0 + pkt_event_wpcap: + printf("pkt_event_wpcap\n"); + que_pop_nowait(que_wpcap, &wpcap_pkt); + proto = &wpcap_pkt.frame[12]; + protocol = (uint16_t)proto[0] << 8 | (uint16_t)proto[1]; + payload = proto + 2; + + last_pdu_buffer = wpcap_pkt.frame; + last_pdu_buffer_size = wpcap_pkt.length; + + switch(protocol){ + case MVRP_ETYPE: + mvrp_recv_msg(); + break; + + case MMRP_ETYPE: + mmrp_recv_msg(); + break; + + case MSRP_ETYPE: + msrp_recv_msg(); + break; + } + if (mrpd_timer_timeout(&timer_check_tick)) { + if ( !SetEvent(pkt_events[loop_time_tick]) ) { + printf("SetEvent loop_time_tick failed (%d)\n", GetLastError()); + exit(-1); + } + } + break; + + case WAIT_OBJECT_0 + pkt_event_wpcap_timeout: + //printf("pkt_event_wpcap_timeout\n"); + break; + + case WAIT_OBJECT_0 + pkt_event_localhost: + printf("pkt_event_localhost\n"); + que_pop_nowait(que_localhost, &localhost_pkt); + process_ctl_msg(localhost_pkt.msgbuf, + localhost_pkt.bytes, + (struct sockaddr_in *)&localhost_pkt.client_addr); + if (mrpd_timer_timeout(&timer_check_tick)) { + if ( !SetEvent(pkt_events[loop_time_tick]) ) { + printf("SetEvent loop_time_tick failed (%d)\n", GetLastError()); + exit(-1); + } + } + break; + + case WAIT_OBJECT_0 + pkt_event_localhost_timeout: + //printf("pkt_event_localhost_timeout\n"); + break; + + default: + printf("Unknown event %d\n", dwEvent); + } + } +} + +int main(int argc, char *argv[]) +{ + uint16_t ether_types[4]; + WSADATA wsa_data; + int rc; + + mrpd_port = MRPD_PORT_DEFAULT; + mmrp_enable = 1; + mvrp_enable = 1; + msrp_enable = 1; + periodic_enable = 1; + logging_enable = 1; + + WSAStartup(MAKEWORD(1,1), &wsa_data); + + /* open our network interface and set the capture ethertype to MRP types */ + net_if = netif_open(TIME_PERIOD_100_MILLISECONDS); // time out is 100ms + if(!net_if) { + fprintf(stderr,"ERROR - opening network interface\n"); + exit(-1); + } + + ether_types[0] = MVRP_ETYPE; + ether_types[1] = MMRP_ETYPE; + ether_types[2] = MSRP_ETYPE; + if( netif_set_capture_ethertype( net_if, ether_types, 3 )) { + fprintf(stderr,"ERROR - setting netif capture ethertype\n"); + exit(-1); + } + + rc = mrp_init(); + if (rc) + goto out; + + rc = init_local_ctl(); + if (rc) + goto out; + + rc = mmrp_init(mmrp_enable); + if (rc) + goto out; + + rc = mvrp_init(mvrp_enable); + if (rc) + goto out; + + rc = msrp_init(msrp_enable); + if (rc) + goto out; + + rc = init_timers(); + if (rc) + goto out; + + process_events(); + out: + if (rc) + printf("Error starting. Run as sudo?\n"); + + WSACleanup(); + return rc; + + +} \ No newline at end of file diff --git a/daemons/mrpd/que.c b/daemons/mrpd/que.c new file mode 100644 index 0000000..214b724 --- /dev/null +++ b/daemons/mrpd/que.c @@ -0,0 +1,96 @@ +/****************************************************************************** + + Copyright (c) 2012, AudioScience, Inc + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +/* + * Queue messages in a thread safe way between threads. + */ + +#include "que.h" + +struct que_def *que_new(int entry_count, int entry_size) +{ + struct que_def *q; + + q = (struct que_def *)calloc(1, sizeof(struct que_def)); + if (!q) + return q; + q->buffer = (uint8_t *)calloc(entry_count, entry_size); + if (!q->buffer) { + free (q); + return NULL; + } + q->entry_count = entry_count; + q->entry_size = entry_size; + q->space_avail = CreateSemaphore(NULL, q->entry_count, q->entry_count, NULL); + q->data_avail = CreateSemaphore(NULL, 0, q->entry_count, NULL); + InitializeCriticalSection(&q->mutex); + + return q; +} + +void que_delete(struct que_def *q) +{ + if (q->buffer) + free(q->buffer); + free(q); +} + +void que_push(struct que_def *q, void *d) +{ + WaitForSingleObject(q->space_avail, INFINITE); + EnterCriticalSection(&q->mutex); + memcpy(&q->buffer[q->in_pos * q->entry_size], d, q->entry_size); + q->in_pos = (q->in_pos + 1) % q->entry_count; + LeaveCriticalSection(&q->mutex); + ReleaseSemaphore(q->data_avail, 1, NULL); +} + +void que_pop_nowait(struct que_def *q, void *d) +{ + EnterCriticalSection(&q->mutex); + memcpy(d, &q->buffer[q->out_pos * q->entry_size], q->entry_size); + q->out_pos = (q->out_pos + 1) % q->entry_count; + LeaveCriticalSection(&q->mutex); + ReleaseSemaphore(q->space_avail, 1, NULL); +} + +void que_pop_wait(struct que_def *q, void *d) +{ + WaitForSingleObject(q->data_avail, INFINITE); + que_pop_nowait(q, d); +} + +HANDLE que_data_available_object(struct que_def *q) +{ + return q->data_avail; +} diff --git a/daemons/mrpd/que.h b/daemons/mrpd/que.h new file mode 100644 index 0000000..26376f9 --- /dev/null +++ b/daemons/mrpd/que.h @@ -0,0 +1,70 @@ +/****************************************************************************** + + Copyright (c) 2012, AudioScience, Inc + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +/* + * Windwos specific - queue messages in a thread safe way between threads. + */ + +#ifndef _QUE_H_ +#define _QUE_H_ + +#include // for uint8_t etc +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct que_def { + HANDLE space_avail; // at least one slot empty + HANDLE data_avail; // at least one slot full + CRITICAL_SECTION mutex; // protect buffer, in_pos, out_pos + + uint8_t *buffer; + int in_pos; + int out_pos; + int entry_count; + int entry_size; +}; + +struct que_def *que_new(int count, int entry_size); +void que_delete(struct que_def *q); +void que_push(struct que_def *q, void *d); +void que_pop_nowait(struct que_def *q, void *d); +void que_pop_wait(struct que_def *q, void *d); +HANDLE que_data_available_object(struct que_def *q); + +#ifdef __cplusplus +} +#endif +#endif -- 2.7.4