void AJ_Initialize(void) { AJ_GUID localGuid; if (!initialized) { initialized = TRUE; AJ_NVRAM_Init(); /* * This will seed the random number generator */ AJ_RandBytes(NULL, 0); /* * This will initialize credentials if needed */ AJ_GetLocalGUID(&localGuid); /* * Clear the Routing Node black list */ AJ_InitRoutingNodeBlacklist(); AJ_InitRoutingNodeResponselist(); } }
AJ_Status AJ_FindBusAndConnect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout) { AJ_Status status; AJ_Service service; AJ_Time connectionTimer; int32_t connectionTime; uint8_t finished = FALSE; bus->isAuthenticated = FALSE; bus->isProbeRequired = TRUE; AJ_InfoPrintf(("AJ_FindBusAndConnect(bus=0x%p, serviceName=\"%s\", timeout=%d, selection timeout=%d.)\n", bus, serviceName, timeout, selectionTimeout)); // Clear the bus struct memset(bus, 0, sizeof(AJ_BusAttachment)); // Clear stale name->GUID mappings AJ_GUID_ClearNameMap(); // Discover a daemon or service to connect to if (!serviceName) { serviceName = daemonService; } while (finished == FALSE) { finished = TRUE; connectionTime = (int32_t) timeout; #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #else AJ_InitTimer(&connectionTimer); printf("AJ_FindBusAndConnect(): Connection timer started\n"); status = AJ_Discover(serviceName, &service, timeout, selectionTimeout);//aj_disco.c if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): AJ_Discover status=%s\n", AJ_StatusText(status)); goto ExitConnect; } #endif // this calls into platform code that will decide whether to use UDP or TCP, based on what is available printf("TCP connection started \n"); status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status)); goto ExitConnect; } status = AJ_Authenticate(bus); if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status)); #if ((!AJ_CONNECT_LOCALHOST) && (!defined(ARDUINO)) && (!defined(AJ_SERIAL_CONNECTION))) printf("AJ_FindBusAndConnect(): Blacklisting routing node\n"); // какие-то махинации с данными AddRoutingNodeToBlacklist(&service); // try again finished = FALSE; connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); // select a new node from the response list while (connectionTime > 0) { // махинация с данными status = AJ_SelectRoutingNodeFromResponseList(&service); if (status == AJ_ERR_END_OF_DATA) { status = AJ_ERR_TIMEOUT; //AJ_InfoPrintf(("Exhausted all the retries from the response list\n")); finished = FALSE; break; } printf("Retrying with a new selection from the routing node response list\n"); status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status)); goto ExitConnect; } status = AJ_Authenticate(bus); if (status == AJ_OK) { finished = TRUE; break; } else { connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); } } #endif } if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status)); goto ExitConnect; } status = SetSignalRules(bus); if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): SetSignalRules status=%s\n", AJ_StatusText(status)); goto ExitConnect; } AJ_InitRoutingNodeResponselist(); } ExitConnect: AJ_InitRoutingNodeResponselist(); if (status != AJ_OK) { printf("AJ_FindBusAndConnect(): status=%s\n", AJ_StatusText(status)); //закрываем соединение AJ_Disconnect(bus); } return status; }
// TODO: deprecate this function; replace it with AJ_FindBusAndConnect AJ_Status AJ_Connect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout) { AJ_Status status; AJ_Service service; bus->isAuthenticated = FALSE; AJ_InfoPrintf(("AJ_Connect(bus=0x%p, serviceName=\"%s\", timeout=%d, selectionTimeout=%d.)\n", bus, serviceName, timeout, selectionTimeout)); // Clear the bus struct memset(bus, 0, sizeof(AJ_BusAttachment)); // Clear stale name->GUID mappings AJ_GUID_ClearNameMap(); // Discover a daemon or service to connect to if (!serviceName) { serviceName = daemonService; } #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #else status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #endif status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = AJ_Authenticate(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = SetSignalRules(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): SetSignalRules status=%s\n", AJ_StatusText(status))); goto ExitConnect; } ExitConnect: if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); } AJ_InitRoutingNodeResponselist(); return status; }
AJ_Status AJ_SelectRoutingNodeFromResponseList(AJ_Service* service) { /* * The selection involves choosing the router with the * highest protocol version and the lowest service priority * (inverse of static rank/score). */ uint8_t i = 1; uint8_t selectedIndex = 0; uint32_t runningSum = 0; uint8_t skip = 0; uint32_t priority_idx = 0; uint32_t priority_srv = 0; uint32_t rand32 = 0; if (RNResponseList[0].ipv4 || RNResponseList[0].ipv4Udp) { service->ipv4 = RNResponseList[0].ipv4; service->ipv4port = RNResponseList[0].ipv4port; service->ipv4Udp = RNResponseList[0].ipv4Udp; service->ipv4portUdp = RNResponseList[0].ipv4portUdp; service->pv = RNResponseList[0].pv; service->addrTypes = RNResponseList[0].addrTypes; service->priority = RNResponseList[0].priority; runningSum = service->priority; skip = RNAttemptsList[0]; if (skip) { AJ_InfoPrintf(("Index 0 was previously selected\n")); } for (; i < AJ_ROUTING_NODE_RESPONSELIST_SIZE; ++i) { if (RNResponseList[i].ipv4 || RNResponseList[i].ipv4Udp) { if (RNAttemptsList[i]) { AJ_InfoPrintf(("Index %d was previously selected\n", i)); continue; } if (skip) { service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; selectedIndex = i; runningSum = service->priority; skip = 0; continue; } if (RNResponseList[i].pv < service->pv) { continue; } if (RNResponseList[i].pv > service->pv || (RNResponseList[i].pv == service->pv && RNResponseList[i].priority < service->priority)) { service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; runningSum = service->priority; selectedIndex = i; AJ_InfoPrintf(("Tentatively selecting routing node %x (pv = %d, port = %d, priority = %d).\n", service->ipv4, service->pv, service->ipv4port, service->priority)); } else if (RNResponseList[i].priority == service->priority) { /* * Randomly select one of out of all the routing nodes with the same * protocol version and priority with each node given an equal chance * of being selected. To select from a pair of nodes, the first node's * priority is used as its associated sum, while the sum of the two * priorities under consideration is used as the second node's * associated sum. A uniform random number up to the sum of the two * priorities (inclusive) is chosen and the first node whose associated * sum is greater than or equal to the random number is selected. */ rand32 = 0; AJ_RandBytes((uint8_t*)&rand32, sizeof(rand32)); priority_idx = RNResponseList[i].priority + runningSum; priority_srv = runningSum; runningSum = priority_idx; rand32 %= (runningSum + 1); AJ_InfoPrintf(("P_idx is %u and P_srv is %u and random is %u\n", priority_idx, priority_srv, rand32)); if (rand32 > priority_srv) { AJ_InfoPrintf(("Picking index %d on this round\n", i)); service->ipv4 = RNResponseList[i].ipv4; service->ipv4port = RNResponseList[i].ipv4port; service->ipv4Udp = RNResponseList[i].ipv4Udp; service->ipv4portUdp = RNResponseList[i].ipv4portUdp; service->pv = RNResponseList[i].pv; service->addrTypes = RNResponseList[i].addrTypes; service->priority = RNResponseList[i].priority; selectedIndex = i; AJ_InfoPrintf(("Tentatively selecting routing node 0x%x (pv = %d, port = %d, priority = %d).\n", service->ipv4, service->pv, service->ipv4port, service->priority)); } } } else { // break early if list isn't full break; } } } else { AJ_InitRoutingNodeResponselist(); return AJ_ERR_TIMEOUT; } if (skip) { AJ_InfoPrintf(("All entries in the response list have been previously selected\n")); return AJ_ERR_END_OF_DATA; } RNAttemptsList[selectedIndex] = 1; AJ_InfoPrintf(("Selected routing node 0x%x (pv = %d, port = %d, priority = %d) out of %d responses in the list.\n", service->ipv4, service->pv, service->ipv4port, service->priority, RNResponseListIndex)); return AJ_OK; }
AJ_Status AJ_FindBusAndConnect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout) { AJ_Status status; AJ_Service service; AJ_Time connectionTimer; int32_t connectionTime; uint8_t finished = FALSE; #ifdef AJ_SERIAL_CONNECTION AJ_Time start, now; AJ_InitTimer(&start); #endif AJ_InfoPrintf(("AJ_FindBusAndConnect(bus=0x%p, serviceName=\"%s\", timeout=%d, selection timeout=%d.)\n", bus, serviceName, timeout, selectionTimeout)); /* * Clear the bus struct */ memset(bus, 0, sizeof(AJ_BusAttachment)); bus->isProbeRequired = TRUE; /* * Clear stale name->GUID mappings */ AJ_GUID_ClearNameMap(); /* * Discover a daemon or service to connect to */ if (!serviceName) { serviceName = daemonService; } while (finished == FALSE) { finished = TRUE; connectionTime = (int32_t) timeout; #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #elif defined(ARDUINO) service.ipv4port = 9955; service.ipv4 = 0x6501A8C0; // 192.168.1.101 service.addrTypes = AJ_ADDR_TCP4; AJ_InitTimer(&connectionTimer); AJ_InfoPrintf(("AJ_FindBusAndConnect(): Connection timer started\n")); status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #elif defined(AJ_SERIAL_CONNECTION) // don't bother with discovery, we are connected to a daemon. // however, take this opportunity to bring up the serial connection status = AJ_Serial_Up(); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Serial_Up status=%s\n", AJ_StatusText(status))); } #else AJ_InitTimer(&connectionTimer); AJ_InfoPrintf(("AJ_FindBusAndConnect(): Connection timer started\n")); status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #endif // this calls into platform code that will decide whether to use UDP or TCP, based on what is available status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #ifdef AJ_SERIAL_CONNECTION // run the state machine for long enough to (hopefully) do the SLAP handshake do { AJ_StateMachine(); AJ_InitTimer(&now); } while (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE && AJ_GetTimeDifference(&now, &start) < timeout); if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Failed to establish active SLAP connection in %u msec\n", timeout)); AJ_SerialShutdown(); return AJ_ERR_TIMEOUT; } #endif status = AJ_Authenticate(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); #if !AJ_CONNECT_LOCALHOST && !defined(ARDUINO) && !defined(AJ_SERIAL_CONNECTION) if ((status == AJ_ERR_ACCESS_ROUTING_NODE) || (status == AJ_ERR_OLD_VERSION)) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Blacklisting routing node\n")); AddRoutingNodeToBlacklist(&service, AJ_ADDR_TCP4); } AJ_Disconnect(bus); // try again finished = FALSE; connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); // select a new node from the response list while (connectionTime > 0) { status = AJ_SelectRoutingNodeFromResponseList(&service); if (status == AJ_ERR_END_OF_DATA) { status = AJ_ERR_TIMEOUT; AJ_InfoPrintf(("Exhausted all the retries from the response list\n")); finished = FALSE; break; } AJ_InfoPrintf(("Retrying with a new selection from the routing node response list\n")); status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = AJ_Authenticate(bus); if (status == AJ_OK) { finished = TRUE; break; } if ((status == AJ_ERR_ACCESS_ROUTING_NODE) || (status == AJ_ERR_OLD_VERSION)) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): Blacklisting another routing node\n")); AddRoutingNodeToBlacklist(&service, AJ_ADDR_TCP4); } AJ_Disconnect(bus); connectionTime -= AJ_GetElapsedTime(&connectionTimer, FALSE); } #endif } if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = SetSignalRules(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): SetSignalRules status=%s\n", AJ_StatusText(status))); goto ExitConnect; } AJ_InitRoutingNodeResponselist(); } ExitConnect: AJ_InitRoutingNodeResponselist(); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_FindBusAndConnect(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); } return status; }
// TODO: deprecate this function; replace it with AJ_FindBusAndConnect AJ_Status AJ_Connect(AJ_BusAttachment* bus, const char* serviceName, uint32_t timeout) { AJ_Status status; AJ_Service service; bus->isAuthenticated = FALSE; #ifdef AJ_SERIAL_CONNECTION AJ_Time start, now; AJ_InitTimer(&start); #endif AJ_InfoPrintf(("AJ_Connect(bus=0x%p, serviceName=\"%s\", timeout=%d, selectionTimeout=%d.)\n", bus, serviceName, timeout, selectionTimeout)); /* * Clear the bus struct */ memset(bus, 0, sizeof(AJ_BusAttachment)); /* * Clear stale name->GUID mappings */ AJ_GUID_ClearNameMap(); #if !(defined(ARDUINO) || defined(__linux) || defined(_WIN32) || defined(__MACH__)) /* * Get an IP address. We don't want to break this older version * of AJ_Connect, so acquire an IP if we don't already have one. * * This does not work on non-embedded platforms! */ { uint32_t ip, mask, gw; status = AJ_AcquireIPAddress(&ip, &mask, &gw, AJ_DHCP_TIMEOUT); if (status != AJ_OK) { AJ_ErrPrintf(("AJ_Net_Up(): AJ_AcquireIPAddress Failed\n")); } } #endif /* * Discover a daemon or service to connect to */ if (!serviceName) { serviceName = daemonService; } #if AJ_CONNECT_LOCALHOST service.ipv4port = 9955; #if HOST_IS_LITTLE_ENDIAN service.ipv4 = 0x0100007F; // 127.0.0.1 #endif #if HOST_IS_BIG_ENDIAN service.ipv4 = 0x7f000001; // 127.0.0.1 #endif service.addrTypes = AJ_ADDR_TCP4; #elif defined(ARDUINO) service.ipv4port = 9955; service.ipv4 = 0x6501A8C0; // 192.168.1.101 service.addrTypes = AJ_ADDR_TCP4; status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #elif defined(AJ_SERIAL_CONNECTION) // don't bother with discovery, we are connected to a daemon. // however, take this opportunity to bring up the serial connection // in a way that depends on the target status = AJ_Serial_Up(); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Serial_Up status=%s\n", AJ_StatusText(status))); } #else status = AJ_Discover(serviceName, &service, timeout, selectionTimeout); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Discover status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #endif status = AJ_Net_Connect(bus, &service); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Net_Connect status=%s\n", AJ_StatusText(status))); goto ExitConnect; } #ifdef AJ_SERIAL_CONNECTION // run the state machine for long enough to (hopefully) do the SLAP handshake do { AJ_StateMachine(); AJ_InitTimer(&now); } while (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE && AJ_GetTimeDifference(&now, &start) < timeout); if (AJ_SerialLinkParams.linkState != AJ_LINK_ACTIVE) { AJ_InfoPrintf(("Failed to establish active SLAP connection in %u msec\n", timeout)); AJ_SerialShutdown(); return AJ_ERR_TIMEOUT; } #endif status = AJ_Authenticate(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): AJ_Authenticate status=%s\n", AJ_StatusText(status))); goto ExitConnect; } status = SetSignalRules(bus); if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): SetSignalRules status=%s\n", AJ_StatusText(status))); goto ExitConnect; } ExitConnect: if (status != AJ_OK) { AJ_InfoPrintf(("AJ_Connect(): status=%s\n", AJ_StatusText(status))); AJ_Disconnect(bus); } AJ_InitRoutingNodeResponselist(); return status; }