/** * @file GoAccelerator.c * * @internal * Copyright (C) 2016-2021 by LMI Technologies Inc. * Licensed under the MIT License. * Redistributed files must retain the above copyright notice. */ #include #include #include #if defined(K_WINDOWS) #include // added for global mutex checking mechanism in function GoAccelerator_Init() HANDLE globalMutexApi = NULL; // store handle to mutex for API level locking #endif kBeginClassEx(Go, GoAccelerator) kAddVMethod(GoAccelerator, kObject, VRelease) kEndClassEx() GoFx(kStatus) GoAccelerator_Construct(GoAccelerator* accelerator, kAlloc allocator) { #if defined(K_WINDOWS) kAlloc alloc = kAlloc_Fallback(allocator); kStatus status; kCheck(kAlloc_GetObject(alloc, kTypeOf(GoAccelerator), accelerator)); if (!kSuccess(status = GoAccelerator_Init(*accelerator, kTypeOf(GoAccelerator), alloc))) { kAlloc_FreeRef(alloc, accelerator); } return status; #else return kERROR_UNIMPLEMENTED; // Currently only supported on Windows #endif } GoFx(kStatus) GoAccelerator_Init(GoAccelerator accelerator, kType type, kAlloc alloc) { kObjR(GoAccelerator, accelerator); kText256 libPath = { 0 }; kStatus exception; kCheck(kObject_Init(accelerator, type, alloc)); kZero(obj->serverLib); kZero(obj->gsLibAssembly); kZero(obj->gsLibConstruct); kZero(obj->serverConstruct); kZero(obj->serverSetIpAddress); kZero(obj->serverIpAddress); kZero(obj->serverSetControlPort); kZero(obj->serverControlPort); kZero(obj->serverSetHealthPort); kZero(obj->serverHealthPort); kZero(obj->serverSetUpgradePort); kZero(obj->serverUpgradePort); kZero(obj->serverSetWebPort); kZero(obj->serverWebPort); kZero(obj->serverSetPrivateDataPort); kZero(obj->serverPrivateDataPort); kZero(obj->serverSetPublicDataPort); kZero(obj->serverPublicDataPort); kZero(obj->serverStart); kZero(obj->serverStop); kZero(obj->serverSetAcceleratorUpdateHandler); kZero(obj->server); obj->isRunning = kFALSE; kZero(obj->attachedSensorAddress); obj->attachedSensor = kNULL; kTry { // get server library path kTest(kPath_LibraryName(GS_REMOTE_APP_LIB_NAME, libPath, kCountOf(libPath))); kTest(kDynamicLib_Construct(&obj->serverLib, libPath, alloc)); kTest(kDynamicLib_FindFunction(obj->serverLib, GSA_ASM_CONSTRUCT_FX, (kFunction*)&obj->gsLibConstruct)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_CONSTRUCT_FX, (kFunction*)&obj->serverConstruct)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_IP_ADDRESS_FX, (kFunction*)&obj->serverSetIpAddress)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_IP_ADDRESS_FX, (kFunction*)&obj->serverIpAddress)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_CONTROL_PORT_FX, (kFunction*)&obj->serverSetControlPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_CONTROL_PORT_FX, (kFunction*)&obj->serverControlPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_HEALTH_PORT_FX, (kFunction*)&obj->serverSetHealthPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_HEALTH_PORT_FX, (kFunction*)&obj->serverHealthPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_UPGRADE_PORT_FX, (kFunction*)&obj->serverSetUpgradePort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_UPGRADE_PORT_FX, (kFunction*)&obj->serverUpgradePort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_WEB_PORT_FX, (kFunction*)&obj->serverSetWebPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_WEB_PORT_FX, (kFunction*)&obj->serverWebPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_PRIVATE_DATA_PORT_FX, (kFunction*)&obj->serverSetPrivateDataPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_PRIVATE_DATA_PORT_FX, (kFunction*)&obj->serverPrivateDataPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_PUBLIC_DATA_PORT_FX, (kFunction*)&obj->serverSetPublicDataPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_PUBLIC_DATA_PORT_FX, (kFunction*)&obj->serverPublicDataPort)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_START_FX, (kFunction*)&obj->serverStart)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_STOP_FX, (kFunction*)&obj->serverStop)); kTest(kDynamicLib_FindFunction(obj->serverLib, GS_REMOTE_APP_SET_ACCELERATOR_UPDATE_HANDLER_FX, (kFunction*)&obj->serverSetAcceleratorUpdateHandler)); // Construct the GsLib assembly kTest(obj->gsLibConstruct(&obj->gsLibAssembly)); // Construct the accelerator server kTest(obj->serverConstruct(&obj->server, alloc)); } kCatch(&exception) { kDestroyRef(&obj->server); kDestroyRef(&obj->gsLibAssembly); kDestroyRef(&obj->serverLib); kEndCatch(exception); } return kOK; } GoFx(kStatus) GoAccelerator_VRelease(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); kDestroyRef(&obj->attachedSensor); kDestroyRef(&obj->server); kDestroyRef(&obj->gsLibAssembly); kDestroyRef(&obj->serverLib); return kObject_VRelease(accelerator); } GoFx(kStatus) GoAccelerator_Start(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); obj->isRunning = kTRUE; return kOK; } GoFx(kStatus) GoAccelerator_Attach(GoAccelerator accelerator, GoSensor sensor) { kObj(GoAccelerator, accelerator); kSize i = 0; k32u id = GoSensor_Id(sensor); kBool useStdPorts = kTRUE; kStatus exception; GoState state = GO_STATE_OFFLINE; k64u start; if (kIsNull(sensor)) { return kERROR; } // ensure the sensor is not already attached else if (GoAccelerator_IsAttached(accelerator, sensor)) { return kERROR_ALREADY_EXISTS; } // already attached to another sensor else if (kNULL != obj->attachedSensor) { return kERROR_BUSY; } // ensure the sensor is disconnected kCheck(GoSensor_Disconnect(sensor)); #if defined(K_WINDOWS) { // Mutex name needs to match GoEmulateApp/Program.cs if ((globalMutexApi = CreateMutexA(NULL, TRUE, "Global/GocatorPortMutex-0")) != NULL) { DWORD result = GetLastError(); if (result != 0) { CloseHandle(globalMutexApi); globalMutexApi = NULL; //useStdPorts = kFALSE; } } } #endif kTry { // get the sensor's address obj->attachedSensorAddress = *GoSensor_AddressInfo(sensor); if (!useStdPorts) { kTest(GoAccelerator_SetControlPort(accelerator, kIP_PORT_ANY)); kTest(GoAccelerator_SetUpgradePort(accelerator, kIP_PORT_ANY)); kTest(GoAccelerator_SetPrivateDataPort(accelerator, kIP_PORT_ANY)); kTest(GoAccelerator_SetPublicDataPort(accelerator, kIP_PORT_ANY)); kTest(GoAccelerator_SetHealthPort(accelerator, kIP_PORT_ANY)); } // start accelerating this sensor kTest(obj->serverStart(obj->server, id)); // store the sensor details kTest(kShareRef(&obj->attachedSensor, sensor)); // update the control port GoSensor_SetControlPort(sensor, GoAccelerator_ControlPort(accelerator)); // update the upgrade port GoSensor_SetUpgradePort(sensor, GoAccelerator_UpgradePort(accelerator)); // update the data port GoSensor_SetDataPort(sensor, GoAccelerator_PublicDataPort(accelerator)); // update the health port GoSensor_SetHealthPort(sensor, GoAccelerator_HealthPort(accelerator)); // Update the sensor address to point to the local PC // TODO: this is a workaround in lieu of a proper wait for discovery update. // Should remove when proper fix is done. e.g. some way to invalidate old // discovery info, and then wait for new updates. // Directly modifying the value by pointer is also bad form. GoSensor_AddressInfo(sensor)->address = kIpAddress_LoopbackV4(); start = kTimer_Now(); while (ACCELERATOR_START_TIMEOUT >= (kTimer_Now()-start) && GO_STATE_ONLINE != (state = GoSensor_State(obj->attachedSensor))) { kThread_Sleep(10 * 1000); //10ms sleep } if (GO_STATE_ONLINE != state) { kTest(kERROR_TIMEOUT); } } kCatch(&exception) { #if defined(K_WINDOWS) // this clears the global mutexes if the actual attachment fails if (globalMutexApi != NULL) { CloseHandle(globalMutexApi); globalMutexApi = NULL; } #endif kEndCatch(exception); } // the parent system needs to be updated too //kCheck(GoSensor_RefreshSystem(sensor)); return kOK; } GoFx(kStatus) GoAccelerator_Detach(GoAccelerator accelerator, GoSensor sensor) { kObj(GoAccelerator, accelerator); kSize i = 0; kSize itemIndex = kSIZE_NULL; k32u id = GoSensor_Id(sensor); GoAddressInfo* address = kNULL; GoControl control = kNULL; if (!GoAccelerator_IsAttached(accelerator, sensor)) { return kERROR_NOT_FOUND; } // ensure the sensor is disconnected kCheck(GoSensor_Disconnect(sensor)); // stop the server // Note - this should only stop the server for the sensor at hand, // but it only works for 1 sensor right now kCheck(obj->serverStop(obj->server)); // update the control channel to point to the sensor control = GoSensor_Control(sensor); kCheck(GoControl_SetRemoteAddress(control, obj->attachedSensorAddress.address)); // update the sensor address to point to the sensor address = GoSensor_AddressInfo(sensor); *address = obj->attachedSensorAddress; // detach the sensor from the accelerator kCheck(kDestroyRef(&obj->attachedSensor)); #if defined(K_WINDOWS) // clear the global mutexes if (globalMutexApi != NULL) { CloseHandle(globalMutexApi); globalMutexApi = NULL; } #endif return kOK; } GoFx(GoSensor) GoAccelerator_Sensor(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->attachedSensor; } GoFx(kStatus) GoAccelerator_Stop(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); obj->isRunning = kFALSE; return kOK; } GoFx(kBool) GoAccelerator_IsRunning(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->isRunning; } GoFx(kBool) GoAccelerator_IsAttached(GoAccelerator accelerator, GoSensor sensor) { kObj(GoAccelerator, accelerator); if (kIsNull(obj->attachedSensor) || kIsNull(sensor)) { return kFALSE; } else if (GoSensor_Id(sensor) == GoSensor_Id(obj->attachedSensor)) { return kTRUE; } return kFALSE; } GoFx(kStatus) GoAccelerator_SetAcceleratorUpdateHandler(GoAccelerator accelerator, kCallbackFx function, kPointer receiver) { kObj(GoAccelerator, accelerator); return obj->serverSetAcceleratorUpdateHandler(obj->server, function, receiver); } GoFx(kStatus) GoAccelerator_SetIpAddress(GoAccelerator accelerator, kIpAddress address) { kObj(GoAccelerator, accelerator); return obj->serverSetIpAddress(obj->server, address); } GoFx(kIpAddress) GoAccelerator_IpAddress(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverIpAddress(obj->server); } GoFx(kStatus) GoAccelerator_SetControlPort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetControlPort(obj->server, port); } GoFx(k32u) GoAccelerator_ControlPort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverControlPort(obj->server); } GoFx(kStatus) GoAccelerator_SetHealthPort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetHealthPort(obj->server, port); } GoFx(k32u) GoAccelerator_HealthPort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverHealthPort(obj->server); } GoFx(kStatus) GoAccelerator_SetUpgradePort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetUpgradePort(obj->server, port); } GoFx(k32u) GoAccelerator_UpgradePort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverUpgradePort(obj->server); } GoFx(kStatus) GoAccelerator_SetWebPort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetWebPort(obj->server, port); } GoFx(k32u) GoAccelerator_WebPort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverWebPort(obj->server); } GoFx(kStatus) GoAccelerator_SetPrivateDataPort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetPrivateDataPort(obj->server, port); } GoFx(k32u) GoAccelerator_PrivateDataPort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverPrivateDataPort(obj->server); } GoFx(kStatus) GoAccelerator_SetPublicDataPort(GoAccelerator accelerator, k32u port) { kObj(GoAccelerator, accelerator); return obj->serverSetPublicDataPort(obj->server, port); } GoFx(k32u) GoAccelerator_PublicDataPort(GoAccelerator accelerator) { kObj(GoAccelerator, accelerator); return obj->serverPublicDataPort(obj->server); }