X Tutup
/* * Copyright (c) 2019, Mathias Küsel * MIT License */ #include namespace node_snap7 { static uv_async_t event_async_g; static uv_async_t rw_async_g; static uv_mutex_t mutex_rw; static uv_mutex_t mutex_event; static uv_sem_t sem_rw; static std::deque event_list_g; static struct rw_event_baton_t { int Sender; int Operation; TS7Tag Tag; void *pUsrData; } rw_event_baton_g; void S7API EventCallBack(void *usrPtr, PSrvEvent PEvent, int Size) { uv_mutex_lock(&mutex_event); event_list_g.push_back(*PEvent); uv_mutex_unlock(&mutex_event); uv_async_send(&event_async_g); } int S7API RWAreaCallBack(void *usrPtr, int Sender, int Operation, PS7Tag PTag , void *pUsrData ) { uv_mutex_lock(&mutex_rw); rw_event_baton_g.Sender = Sender; rw_event_baton_g.Operation = Operation; rw_event_baton_g.Tag = *PTag; rw_event_baton_g.pUsrData = pUsrData; uv_async_send(&rw_async_g); uv_sem_wait(&sem_rw); uv_mutex_unlock(&mutex_rw); return 0; } Nan::Persistent S7Server::constructor; NAN_MODULE_INIT(S7Server::Init) { Nan::HandleScope scope; v8::Local tpl; tpl = Nan::New(S7Server::New); v8::Local name = Nan::New("S7Server") .ToLocalChecked(); tpl->SetClassName(name); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Setup the prototype Nan::SetPrototypeMethod( tpl , "Start" , S7Server::Start); Nan::SetPrototypeMethod( tpl , "StartTo" , S7Server::StartTo); Nan::SetPrototypeMethod( tpl , "Stop" , S7Server::Stop); Nan::SetPrototypeMethod( tpl , "SetParam" , S7Server::SetParam); Nan::SetPrototypeMethod( tpl , "GetParam" , S7Server::GetParam); Nan::SetPrototypeMethod( tpl , "SetResourceless" , S7Server::SetResourceless); Nan::SetPrototypeMethod( tpl , "RegisterArea" , S7Server::RegisterArea); Nan::SetPrototypeMethod( tpl , "UnregisterArea" , S7Server::UnregisterArea); Nan::SetPrototypeMethod( tpl , "LockArea" , S7Server::LockArea); Nan::SetPrototypeMethod( tpl , "UnlockArea" , S7Server::UnlockArea); Nan::SetPrototypeMethod( tpl , "SetArea" , S7Server::SetArea); Nan::SetPrototypeMethod( tpl , "GetArea" , S7Server::GetArea); Nan::SetPrototypeMethod( tpl , "SetEventMask" , S7Server::SetEventsMask); Nan::SetPrototypeMethod( tpl , "GetEventsMask" , S7Server::GetEventsMask); Nan::SetPrototypeMethod( tpl , "ErrorText" , S7Server::ErrorText); Nan::SetPrototypeMethod( tpl , "LastError" , S7Server::LastError); Nan::SetPrototypeMethod( tpl , "EventText" , S7Server::EventText); Nan::SetPrototypeMethod( tpl , "ServerStatus" , S7Server::ServerStatus); Nan::SetPrototypeMethod( tpl , "ClientsCount" , S7Server::ClientsCount); Nan::SetPrototypeMethod( tpl , "GetCpuStatus" , S7Server::GetCpuStatus); Nan::SetPrototypeMethod( tpl , "SetCpuStatus" , S7Server::SetCpuStatus); // Error codes Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvCannotStart").ToLocalChecked() , Nan::New(errSrvCannotStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvDBNullPointer").ToLocalChecked() , Nan::New(errSrvDBNullPointer) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvAreaAlreadyExists").ToLocalChecked() , Nan::New(errSrvAreaAlreadyExists) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvUnknownArea").ToLocalChecked() , Nan::New(errSrvUnknownArea) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvInvalidParams").ToLocalChecked() , Nan::New(errSrvInvalidParams) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvTooManyDB").ToLocalChecked() , Nan::New(errSrvTooManyDB) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvInvalidParamNumber").ToLocalChecked() , Nan::New(errSrvInvalidParamNumber) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("errSrvCannotChangeParam").ToLocalChecked() , Nan::New(errSrvCannotChangeParam) , v8::ReadOnly); // Server area IDs Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaPE").ToLocalChecked() , Nan::New(srvAreaPE) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaPA").ToLocalChecked() , Nan::New(srvAreaPA) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaMK").ToLocalChecked() , Nan::New(srvAreaMK) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaCT").ToLocalChecked() , Nan::New(srvAreaCT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaTM").ToLocalChecked() , Nan::New(srvAreaTM) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("srvAreaDB").ToLocalChecked() , Nan::New(srvAreaDB) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("operationWrite").ToLocalChecked() , Nan::New(OperationWrite) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("operationRead").ToLocalChecked() , Nan::New(OperationRead) , v8::ReadOnly); // TCP server event codes Nan::SetPrototypeTemplate( tpl , Nan::New("evcServerStarted").ToLocalChecked() , Nan::New(evcServerStarted) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcServerStopped").ToLocalChecked() , Nan::New(evcServerStopped) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcListenerCannotStart").ToLocalChecked() , Nan::New(evcListenerCannotStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientAdded").ToLocalChecked() , Nan::New(evcClientAdded) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientRejected").ToLocalChecked() , Nan::New(evcClientRejected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientNoRoom").ToLocalChecked() , Nan::New(evcClientNoRoom) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientException").ToLocalChecked() , Nan::New(evcClientException) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientDisconnected").ToLocalChecked() , Nan::New(evcClientDisconnected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientTerminated").ToLocalChecked() , Nan::New(evcClientTerminated) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClientsDropped").ToLocalChecked() , Nan::New(evcClientsDropped) , v8::ReadOnly); // S7 server event codes Nan::SetPrototypeTemplate( tpl , Nan::New("evcPDUincoming").ToLocalChecked() , Nan::New(evcPDUincoming) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDataRead").ToLocalChecked() , Nan::New(evcDataRead) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDataWrite").ToLocalChecked() , Nan::New(evcDataWrite) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcNegotiatePDU").ToLocalChecked() , Nan::New(evcNegotiatePDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcReadSZL").ToLocalChecked() , Nan::New(evcReadSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcClock").ToLocalChecked() , Nan::New(evcClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcUpload").ToLocalChecked() , Nan::New(evcUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDownload").ToLocalChecked() , Nan::New(evcDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcDirectory").ToLocalChecked() , Nan::New(evcDirectory) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcSecurity").ToLocalChecked() , Nan::New(evcSecurity) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcControl").ToLocalChecked() , Nan::New(evcControl) , v8::ReadOnly); // Masks to enable/disable all events Nan::SetPrototypeTemplate( tpl , Nan::New("evcAll").ToLocalChecked() , Nan::New(evcAll) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evcNone").ToLocalChecked() , Nan::New(evcNone) , v8::ReadOnly); // Event subcodes Nan::SetPrototypeTemplate( tpl , Nan::New("evsUnknown").ToLocalChecked() , Nan::New(evsUnknown) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartUpload").ToLocalChecked() , Nan::New(evsStartUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartDownload").ToLocalChecked() , Nan::New(evsStartDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetBlockList").ToLocalChecked() , Nan::New(evsGetBlockList) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsStartListBoT").ToLocalChecked() , Nan::New(evsStartListBoT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsListBoT").ToLocalChecked() , Nan::New(evsListBoT) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetBlockInfo").ToLocalChecked() , Nan::New(evsGetBlockInfo) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsGetClock").ToLocalChecked() , Nan::New(evsGetClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsSetClock").ToLocalChecked() , Nan::New(evsSetClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsSetPassword").ToLocalChecked() , Nan::New(evsSetPassword) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evsClrPassword").ToLocalChecked() , Nan::New(evsClrPassword) , v8::ReadOnly); // Event params : functions group Nan::SetPrototypeTemplate( tpl , Nan::New("grProgrammer").ToLocalChecked() , Nan::New(grProgrammer) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grCyclicData").ToLocalChecked() , Nan::New(grCyclicData) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grBlocksInfo").ToLocalChecked() , Nan::New(grBlocksInfo) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grSZL").ToLocalChecked() , Nan::New(grSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grPassword").ToLocalChecked() , Nan::New(grPassword) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grBSend").ToLocalChecked() , Nan::New(grBSend) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grClock").ToLocalChecked() , Nan::New(grClock) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("grSecurity").ToLocalChecked() , Nan::New(grSecurity) , v8::ReadOnly); // Event params : control codes Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlUnknown").ToLocalChecked() , Nan::New(CodeControlUnknown) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlColdStart").ToLocalChecked() , Nan::New(CodeControlColdStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlWarmStart").ToLocalChecked() , Nan::New(CodeControlWarmStart) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlStop").ToLocalChecked() , Nan::New(CodeControlStop) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlCompress").ToLocalChecked() , Nan::New(CodeControlCompress) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlCpyRamRom").ToLocalChecked() , Nan::New(CodeControlCpyRamRom) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("CodeControlInsDel").ToLocalChecked() , Nan::New(CodeControlInsDel) , v8::ReadOnly); // Event results Nan::SetPrototypeTemplate( tpl , Nan::New("evrNoError").ToLocalChecked() , Nan::New(evrNoError) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrFragmentRejected").ToLocalChecked() , Nan::New(evrFragmentRejected) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrMalformedPDU").ToLocalChecked() , Nan::New(evrMalformedPDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrSparseBytes").ToLocalChecked() , Nan::New(evrSparseBytes) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotHandlePDU").ToLocalChecked() , Nan::New(evrCannotHandlePDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrNotImplemented").ToLocalChecked() , Nan::New(evrNotImplemented) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrException").ToLocalChecked() , Nan::New(evrErrException) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrAreaNotFound").ToLocalChecked() , Nan::New(evrErrAreaNotFound) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrOutOfRange").ToLocalChecked() , Nan::New(evrErrOutOfRange) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrOverPDU").ToLocalChecked() , Nan::New(evrErrOverPDU) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrErrTransportSize").ToLocalChecked() , Nan::New(evrErrTransportSize) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrInvalidGroupUData").ToLocalChecked() , Nan::New(evrInvalidGroupUData) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrInvalidSZL").ToLocalChecked() , Nan::New(evrInvalidSZL) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrDataSizeMismatch").ToLocalChecked() , Nan::New(evrDataSizeMismatch) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotUpload").ToLocalChecked() , Nan::New(evrCannotUpload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrCannotDownload").ToLocalChecked() , Nan::New(evrCannotDownload) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrUploadInvalidID").ToLocalChecked() , Nan::New(evrUploadInvalidID) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("evrResNotFound").ToLocalChecked() , Nan::New(evrResNotFound) , v8::ReadOnly); // Server parameter Nan::SetPrototypeTemplate( tpl , Nan::New("LocalPort").ToLocalChecked() , Nan::New(p_u16_LocalPort) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("WorkInterval").ToLocalChecked() , Nan::New(p_i32_WorkInterval) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("PDURequest").ToLocalChecked() , Nan::New(p_i32_PDURequest) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("MaxClients").ToLocalChecked() , Nan::New(p_i32_MaxClients) , v8::ReadOnly); // CPU status codes Nan::SetPrototypeTemplate( tpl , Nan::New("S7CpuStatusUnknown").ToLocalChecked() , Nan::New(S7CpuStatusUnknown) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("S7CpuStatusRun").ToLocalChecked() , Nan::New(S7CpuStatusRun) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("S7CpuStatusStop").ToLocalChecked() , Nan::New(S7CpuStatusStop) , v8::ReadOnly); // Server status codes Nan::SetPrototypeTemplate( tpl , Nan::New("SrvStopped").ToLocalChecked() , Nan::New(0) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("SrvRunning").ToLocalChecked() , Nan::New(1) , v8::ReadOnly); Nan::SetPrototypeTemplate( tpl , Nan::New("SrvError").ToLocalChecked() , Nan::New(2) , v8::ReadOnly); constructor.Reset(tpl); Nan::Set(target, name, Nan::GetFunction(tpl).ToLocalChecked()); } NAN_METHOD(S7Server::New) { if (info.IsConstructCall()) { S7Server *s7Server = new S7Server(info.This()); s7Server->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } else { v8::Local constructorHandle; constructorHandle = Nan::New(constructor); info.GetReturnValue().Set( Nan::NewInstance(Nan::GetFunction(constructorHandle).ToLocalChecked()).ToLocalChecked()); } } S7Server::S7Server(v8::Local resource) : async_resource("S7Server:emit", resource) { lastError = 0; snap7Server = new TS7Server(); event_async_g.data = rw_async_g.data = this; uv_async_init(uv_default_loop(), &event_async_g, S7Server::HandleEvent); uv_async_init(uv_default_loop(), &rw_async_g, S7Server::HandleReadWriteEvent); uv_unref(reinterpret_cast(&event_async_g)); uv_unref(reinterpret_cast(&rw_async_g)); uv_mutex_init(&mutex); uv_mutex_init(&mutex_rw); uv_mutex_init(&mutex_event); uv_sem_init(&sem_rw, 0); snap7Server->SetEventsCallback(&EventCallBack, NULL); } S7Server::~S7Server() { snap7Server->Stop(); delete snap7Server; constructor.Reset(); uv_close(reinterpret_cast(&event_async_g), 0); uv_close(reinterpret_cast(&rw_async_g), 0); uv_sem_destroy(&sem_rw); uv_mutex_destroy(&mutex_event); uv_mutex_destroy(&mutex_rw); uv_mutex_destroy(&mutex); } int S7Server::GetByteCountFromWordLen(int WordLen) { switch (WordLen) { case S7WLBit: case S7WLByte: return 1; case S7WLWord: case S7WLCounter: case S7WLTimer: return 2; case S7WLReal: case S7WLDWord: return 4; default: return 0; } } NAN_METHOD(S7Server::RWBufferCallback) { Nan::HandleScope scope; if (rw_event_baton_g.Operation == OperationRead) { if (!node::Buffer::HasInstance(info[0])) { return Nan::ThrowTypeError("Wrong argument"); } int byteCount, size; byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen); size = byteCount * rw_event_baton_g.Tag.Size; if (node::Buffer::Length(info[0].As()) < size) { return Nan::ThrowTypeError("Buffer length too small"); } memcpy( rw_event_baton_g.pUsrData , node::Buffer::Data(info[0].As()) , size); } uv_sem_post(&sem_rw); } #if NODE_VERSION_AT_LEAST(0, 11, 13) void S7Server::HandleEvent(uv_async_t* handle) { #else void S7Server::HandleEvent(uv_async_t* handle, int status) { #endif Nan::HandleScope scope; S7Server *s7server = static_cast(handle->data); uv_mutex_lock(&mutex_event); while (!event_list_g.empty()) { PSrvEvent Event = &event_list_g.front(); in_addr sin; sin.s_addr = Event->EvtSender; double time = static_cast(Event->EvtTime * 1000); v8::Local event_obj = Nan::New(); Nan::Set(event_obj, Nan::New("EvtTime").ToLocalChecked() , Nan::New(time).ToLocalChecked()); Nan::Set(event_obj, Nan::New("EvtSender").ToLocalChecked() , Nan::New(inet_ntoa(sin)).ToLocalChecked()); Nan::Set(event_obj, Nan::New("EvtCode").ToLocalChecked() , Nan::New(Event->EvtCode)); Nan::Set(event_obj, Nan::New("EvtRetCode").ToLocalChecked() , Nan::New(Event->EvtRetCode)); Nan::Set(event_obj, Nan::New("EvtParam1").ToLocalChecked() , Nan::New(Event->EvtParam1)); Nan::Set(event_obj, Nan::New("EvtParam2").ToLocalChecked() , Nan::New(Event->EvtParam2)); Nan::Set(event_obj, Nan::New("EvtParam3").ToLocalChecked() , Nan::New(Event->EvtParam3)); Nan::Set(event_obj, Nan::New("EvtParam4").ToLocalChecked() , Nan::New(Event->EvtParam4)); v8::Local argv[2] = { Nan::New("event").ToLocalChecked(), event_obj }; s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 2, argv); event_list_g.pop_front(); } uv_mutex_unlock(&mutex_event); } #if NODE_VERSION_AT_LEAST(0, 11, 13) void S7Server::HandleReadWriteEvent(uv_async_t* handle) { #else void S7Server::HandleReadWriteEvent(uv_async_t* handle, int status) { #endif Nan::HandleScope scope; S7Server *s7server = static_cast(handle->data); in_addr sin; sin.s_addr = rw_event_baton_g.Sender; v8::Local rw_tag_obj = Nan::New(); Nan::Set(rw_tag_obj, Nan::New("Area").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Area)); Nan::Set(rw_tag_obj, Nan::New("DBNumber").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.DBNumber)); Nan::Set(rw_tag_obj, Nan::New("Start").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Start)); Nan::Set(rw_tag_obj, Nan::New("Size").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.Size)); Nan::Set(rw_tag_obj, Nan::New("WordLen").ToLocalChecked() , Nan::New(rw_event_baton_g.Tag.WordLen)); int byteCount, size; byteCount = S7Server::GetByteCountFromWordLen(rw_event_baton_g.Tag.WordLen); size = byteCount * rw_event_baton_g.Tag.Size; v8::Local buffer; if (rw_event_baton_g.Operation == OperationWrite) { buffer = Nan::CopyBuffer( static_cast(rw_event_baton_g.pUsrData), size).ToLocalChecked(); } else { buffer = Nan::NewBuffer(size).ToLocalChecked(); memset(node::Buffer::Data(buffer), 0, size); } v8::Local argv[6] = { Nan::New("readWrite").ToLocalChecked(), Nan::New(inet_ntoa(sin)).ToLocalChecked(), Nan::New(rw_event_baton_g.Operation), rw_tag_obj, buffer, Nan::New(S7Server::RWBufferCallback) }; s7server->async_resource.runInAsyncScope(s7server->handle(), "emit", 6, argv); } void IOWorkerServer::Execute() { uv_mutex_lock(&s7server->mutex); switch (caller) { case STARTTO: ret = s7server->snap7Server->StartTo( **static_cast(pData)); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } break; case START: ret = s7server->snap7Server->Start(); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } break; case STOP: ret = s7server->snap7Server->Stop(); if (ret == 0) { uv_unref(reinterpret_cast(&event_async_g)); } break; } uv_mutex_unlock(&s7server->mutex); } void IOWorkerServer::HandleOKCallback() { Nan::HandleScope scope; v8::Local argv1[1]; v8::Local argv2[2]; if (ret == 0) { argv2[0] = argv1[0] = Nan::Null(); } else { argv2[0] = argv1[0] = Nan::New(ret); } switch (caller) { case STARTTO: delete static_cast(pData); callback->Call(1, argv1, async_resource); break; case START: case STOP: callback->Call(1, argv1, async_resource); break; } } NAN_METHOD(S7Server::Start) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int ret = s7server->snap7Server->Start(); if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, START)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::StartTo) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (info.Length() < 1) { return Nan::ThrowTypeError("Wrong number of arguments"); } if (!info[0]->IsString()) { return Nan::ThrowTypeError("Wrong arguments"); } Nan::Utf8String *address = new Nan::Utf8String(info[0]); if (!info[1]->IsFunction()) { int ret = s7server->snap7Server->StartTo(**address); delete address; if (ret == 0) { uv_ref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[1].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, STARTTO , address)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::Stop) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsFunction()) { int ret = s7server->snap7Server->Stop(); if (ret == 0) { uv_unref(reinterpret_cast(&event_async_g)); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } else { Nan::Callback *callback = new Nan::Callback(info[0].As()); Nan::AsyncQueueWorker(new IOWorkerServer(callback, s7server, STOP)); info.GetReturnValue().SetUndefined(); } } NAN_METHOD(S7Server::SetResourceless) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsBoolean()) { return Nan::ThrowTypeError("Wrong arguments"); } bool resourceless = Nan::To(info[0]).FromJust(); int ret; if (resourceless) { ret = s7server->snap7Server->SetRWAreaCallback(&RWAreaCallBack, NULL); } else { ret = s7server->snap7Server->SetRWAreaCallback(NULL, NULL); } s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::GetParam) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int pData; int ret = s7server->snap7Server->GetParam(Nan::To(info[0]).FromJust() , &pData); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::SetParam) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!(info[0]->IsInt32() || info[1]->IsInt32())) { return Nan::ThrowTypeError("Wrong arguments"); } int pData = Nan::To(info[1]).FromJust(); int ret = s7server->snap7Server->SetParam(Nan::To(info[0]).FromJust(), &pData); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::GetEventsMask) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->GetEventsMask(); info.GetReturnValue().Set(Nan::New(ret)); } NAN_METHOD(S7Server::SetEventsMask) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsUint32()) { return Nan::ThrowTypeError("Wrong arguments"); } s7server->snap7Server->SetEventsMask(Nan::To(info[0]).FromJust()); info.GetReturnValue().SetUndefined(); } NAN_METHOD(S7Server::RegisterArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index; char *pBuffer; size_t len; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32() || !node::Buffer::HasInstance(info[2])) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else if (!node::Buffer::HasInstance(info[1])) { return Nan::ThrowTypeError("Wrong arguments"); } else { index = 0; len = node::Buffer::Length(info[1].As()); pBuffer = node::Buffer::Data(info[1].As()); } if (len > 0xFFFF) { return Nan::ThrowRangeError("Max area buffer size is 65535"); } word size = static_cast(len); char *data = new char[size]; memcpy(data, pBuffer, size); int ret = s7server->snap7Server->RegisterArea(area, index, data, size); s7server->lastError = ret; if (ret == 0) { s7server->area2buffer[area][index].pBuffer = data; s7server->area2buffer[area][index].size = size; } else { delete[] data; } info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::UnregisterArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->UnregisterArea(area, index); s7server->lastError = ret; if (ret == 0) { delete[] s7server->area2buffer[area][index].pBuffer; s7server->area2buffer[area].erase(index); } info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::SetArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int area = Nan::To(info[0]).FromJust(); if (!s7server->area2buffer.count(area)) { return Nan::ThrowError("Unknown area"); } int index; char *pBuffer; size_t len; if (area == srvAreaDB) { if (!info[1]->IsInt32() || !node::Buffer::HasInstance(info[2])) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); if (!s7server->area2buffer[area].count(index)) { return Nan::ThrowError("DB index not found"); } len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else { index = 0; if (node::Buffer::HasInstance(info[1])) { len = node::Buffer::Length(info[1].As()); pBuffer = node::Buffer::Data(info[1].As()); } else if (node::Buffer::HasInstance(info[2])) { len = node::Buffer::Length(info[2].As()); pBuffer = node::Buffer::Data(info[2].As()); } else { return Nan::ThrowTypeError("Wrong arguments"); } } if (len != s7server->area2buffer[area][index].size) { return Nan::ThrowError("Wrong buffer length"); } s7server->snap7Server->LockArea(area, index); memcpy( s7server->area2buffer[area][index].pBuffer , pBuffer, s7server->area2buffer[area][index].size); s7server->snap7Server->UnlockArea(area, index); info.GetReturnValue().SetUndefined(); } NAN_METHOD(S7Server::GetArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (!s7server->area2buffer.count(area)) { return Nan::ThrowError("Unknown area"); } if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); if (!s7server->area2buffer[area].count(index)) { return Nan::ThrowError("DB index not found"); } } s7server->snap7Server->LockArea(area, index); v8::Local buffer = Nan::CopyBuffer( s7server->area2buffer[area][index].pBuffer , s7server->area2buffer[area][index].size).ToLocalChecked(); s7server->snap7Server->UnlockArea(area, index); info.GetReturnValue().Set(buffer); } NAN_METHOD(S7Server::LockArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->LockArea(area, index); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::UnlockArea) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int index = 0; int area = Nan::To(info[0]).FromJust(); if (area == srvAreaDB) { if (!info[1]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } index = Nan::To(info[1]).FromJust(); } int ret = s7server->snap7Server->UnlockArea(area, index); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::ServerStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->ServerStatus(); if ((ret == 0) || (ret == 1) || (ret == 2)) { s7server->lastError = 0; info.GetReturnValue().Set(Nan::New(ret)); } else { s7server->lastError = ret; info.GetReturnValue().Set(Nan::False()); } } NAN_METHOD(S7Server::ClientsCount) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->ClientsCount(); info.GetReturnValue().Set(Nan::New(ret)); } NAN_METHOD(S7Server::GetCpuStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); int ret = s7server->snap7Server->GetCpuStatus(); if ((ret == S7CpuStatusUnknown) || (ret == S7CpuStatusStop) || (ret == S7CpuStatusRun)) { s7server->lastError = 0; info.GetReturnValue().Set(Nan::New(ret)); } else { s7server->lastError = ret; info.GetReturnValue().Set(Nan::False()); } } NAN_METHOD(S7Server::SetCpuStatus) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } int ret = s7server->snap7Server->SetCpuStatus(Nan::To(info[0]).FromJust()); s7server->lastError = ret; info.GetReturnValue().Set(Nan::New(ret == 0)); } NAN_METHOD(S7Server::ErrorText) { if (!info[0]->IsInt32()) { return Nan::ThrowTypeError("Wrong arguments"); } info.GetReturnValue().Set(Nan::New( SrvErrorText(Nan::To(info[0]).FromJust()).c_str()).ToLocalChecked()); } NAN_METHOD(S7Server::EventText) { TSrvEvent SrvEvent; if (!info[0]->IsObject()) { return Nan::ThrowTypeError("Wrong arguments"); } v8::Local event_obj = v8::Local::Cast(info[0]); if (!Nan::Has(event_obj, Nan::New("EvtTime").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtSender").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtCode").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam1").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam2").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam3").ToLocalChecked()).FromJust() || !Nan::Has(event_obj, Nan::New("EvtParam4").ToLocalChecked()).FromJust()) { return Nan::ThrowTypeError("Wrong argument structure"); } if (!Nan::Get(event_obj, Nan::New("EvtTime").ToLocalChecked()).ToLocalChecked()->IsDate() || !Nan::Get(event_obj, Nan::New("EvtSender").ToLocalChecked()).ToLocalChecked()->IsString() || !Nan::Get(event_obj, Nan::New("EvtCode").ToLocalChecked()).ToLocalChecked()->IsUint32() || !Nan::Get(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam1").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam2").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam3").ToLocalChecked()).ToLocalChecked()->IsInt32() || !Nan::Get(event_obj, Nan::New("EvtParam4").ToLocalChecked()).ToLocalChecked()->IsInt32()) { return Nan::ThrowTypeError("Wrong argument types"); } Nan::Utf8String *remAddress = new Nan::Utf8String( Nan::Get( event_obj , Nan::New("EvtSender").ToLocalChecked()).ToLocalChecked()); SrvEvent.EvtTime = static_cast(Nan::To(v8::Local::Cast(Nan::Get(event_obj, Nan::New("EvtTime").ToLocalChecked()).ToLocalChecked())).FromJust() / 1000); SrvEvent.EvtSender = inet_addr(**remAddress); SrvEvent.EvtCode = Nan::To(Nan::Get(event_obj, Nan::New("EvtCode").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtRetCode = Nan::To(Nan::Get(event_obj, Nan::New("EvtRetCode").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam1 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam1").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam2 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam2").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam3 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam3").ToLocalChecked()).ToLocalChecked()).FromJust(); SrvEvent.EvtParam4 = Nan::To(Nan::Get(event_obj, Nan::New("EvtParam4").ToLocalChecked()).ToLocalChecked()).FromJust(); delete remAddress; info.GetReturnValue().Set(Nan::New( SrvEventText(&SrvEvent).c_str()).ToLocalChecked()); } NAN_METHOD(S7Server::LastError) { S7Server *s7server = ObjectWrap::Unwrap(info.Holder()); info.GetReturnValue().Set(Nan::New(s7server->lastError)); } } // namespace node_snap7
X Tutup