Commit 8580363c authored by captainwong's avatar captainwong

update server_demo

parent e4c9168c
...@@ -8,43 +8,44 @@ ...@@ -8,43 +8,44 @@
#define ioctl ioctlsocket #define ioctl ioctlsocket
#define socklen_t int #define socklen_t int
#define close closesocket #define close closesocket
#else // linux #else // linux
#include <unistd.h> #include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SOCKET int #define SOCKET int
#define INVALID_SOCKET -1 #define INVALID_SOCKET -1
#endif #endif
#define DISABLE_JLIB_LOG2 #define DISABLE_JLIB_LOG2
#include <string.h>
#include <mutex>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include <mutex>
#include <string.h>
#include "../../ademco.h"
#include "../../ademco.h"
void op_usage() { void op_usage() {
printf("Press A for Arm, D for Disarm, E for Emergency, Q for Quit\n"); printf("Press A for Arm, D for Disarm, E for Emergency, Q for Quit\n");
} }
void usage(const char* name) { void usage(const char* name) {
printf("Usage: %s listening_port\n", name); printf("Usage: %s listening_port\n", name);
op_usage(); op_usage();
} }
constexpr size_t BUFF_SIZE = 4096; constexpr size_t BUFF_SIZE = 4096;
struct Buffer { struct Buffer {
size_t rpos; size_t rpos;
size_t wpos; size_t wpos;
char buff[BUFF_SIZE]; char buff[BUFF_SIZE];
Buffer() { clear(); } Buffer() { clear(); }
void clear() { memset(this, 0, sizeof(Buffer)); } void clear() { memset(this, 0, sizeof(Buffer)); }
}; };
SOCKET clientSock = INVALID_SOCKET; SOCKET clientSock = INVALID_SOCKET;
...@@ -57,261 +58,280 @@ std::vector<ademco_event_t> evntsWaiting4Send = {}; ...@@ -57,261 +58,280 @@ std::vector<ademco_event_t> evntsWaiting4Send = {};
char pwd[1024] = {}; char pwd[1024] = {};
int setNonBlocking(SOCKET socket) { int setNonBlocking(SOCKET socket) {
u_long lngMode = 1; u_long lngMode = 1;
int ret = ioctl(socket, FIONBIO, (u_long*)&lngMode); int ret = ioctl(socket, FIONBIO, (u_long*)&lngMode);
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "ioctl failed %d\n", ret); fprintf(stderr, "ioctl failed %d\n", ret);
return ret; return ret;
} }
return ret; return ret;
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
usage(argv[0]); usage(argv[0]);
#ifdef _WIN32 #ifdef _WIN32
WSADATA wsaData; WSADATA wsaData;
int err = WSAStartup(MAKEWORD(1, 1), &wsaData); int err = WSAStartup(MAKEWORD(1, 1), &wsaData);
if (err != 0) { if (err != 0) {
printf("init wsa failed %d\n", err); printf("init wsa failed %d\n", err);
abort(); abort();
} }
#endif #endif
int port = 12345; int port = 12345;
if (argc > 1) { if (argc > 1) {
port = atoi(argv[1]); port = atoi(argv[1]);
} }
struct sockaddr_in sAddrIn; struct sockaddr_in sAddrIn;
memset(&sAddrIn, 0, sizeof(sAddrIn)); memset(&sAddrIn, 0, sizeof(sAddrIn));
sAddrIn.sin_family = AF_INET; sAddrIn.sin_family = AF_INET;
sAddrIn.sin_port = htons(static_cast<u_short>(port)); sAddrIn.sin_port = htons(static_cast<u_short>(port));
sAddrIn.sin_addr.s_addr = INADDR_ANY; sAddrIn.sin_addr.s_addr = INADDR_ANY;
auto serverSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); auto serverSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int ret = setNonBlocking(serverSock); int ret = setNonBlocking(serverSock);
if (ret != 0) { if (ret != 0) {
return ret; return ret;
} }
ret = bind(serverSock, (struct sockaddr*)&sAddrIn, sizeof(sAddrIn)); ret = bind(serverSock, (struct sockaddr*)&sAddrIn, sizeof(sAddrIn));
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "bind failed %d\n", ret); fprintf(stderr, "bind failed %d\n", ret);
return ret; return ret;
} }
ret = listen(serverSock, SOMAXCONN); ret = listen(serverSock, SOMAXCONN);
if (ret != 0) { if (ret != 0) {
fprintf(stderr, "listen failed %d\n", ret); fprintf(stderr, "listen failed %d\n", ret);
return ret; return ret;
} }
printf("Listening on %s:%d\n", inet_ntoa(sAddrIn.sin_addr), ntohs(sAddrIn.sin_port)); printf("Listening on %s:%d\n", inet_ntoa(sAddrIn.sin_addr), ntohs(sAddrIn.sin_port));
auto do_accept = [&serverSock]() { auto do_accept = [&serverSock]() {
if (clientSock != INVALID_SOCKET) { return; } if (clientSock != INVALID_SOCKET) {
return;
struct sockaddr_in sForeignAddrIn; }
socklen_t nLength = sizeof(struct sockaddr_in);
struct sockaddr_in sForeignAddrIn;
fd_set rfd; socklen_t nLength = sizeof(struct sockaddr_in);
FD_ZERO(&rfd);
FD_SET(serverSock, &rfd); fd_set rfd;
timeval timeout = { 1, 0 }; FD_ZERO(&rfd);
int nfds = select((int)(serverSock + 1), &rfd, (fd_set*)0, (fd_set*)0, &timeout); FD_SET(serverSock, &rfd);
printf("do_accept, select ret=%d\n", nfds); timeval timeout = {1, 0};
if (nfds > 0) { int nfds = select((int)(serverSock + 1), &rfd, (fd_set*)0, (fd_set*)0, &timeout);
FD_CLR(serverSock, &rfd); printf("do_accept, select ret=%d\n", nfds);
clientSock = accept(serverSock, (struct sockaddr*)&sForeignAddrIn, &nLength); if (nfds > 0) {
int ret = setNonBlocking(clientSock); FD_CLR(serverSock, &rfd);
if (ret != 0) { clientSock = accept(serverSock, (struct sockaddr*)&sForeignAddrIn, &nLength);
exit(0); int ret = setNonBlocking(clientSock);
} if (ret != 0) {
printf("Got connection from %s:%d, fd=%d\n", inet_ntoa(sForeignAddrIn.sin_addr), sForeignAddrIn.sin_port, (int)clientSock); exit(0);
} }
}; printf("Got connection from %s:%d, fd=%d\n", inet_ntoa(sForeignAddrIn.sin_addr), sForeignAddrIn.sin_port, (int)clientSock);
}
auto do_handle = []() -> ademco_parse_result_t { };
ademco_packet_t pkt; size_t cb = 0;
ademco_parse_result_t result = ademco_parse_packet(clientBuffer.buff + clientBuffer.rpos, auto do_handle = []() -> ademco_parse_result_t {
clientBuffer.wpos - clientBuffer.rpos, ademco_packet_t pkt;
&pkt, size_t cb = 0;
&cb, ademco_parse_result_t result = ademco_parse_packet(clientBuffer.buff + clientBuffer.rpos,
nullptr); clientBuffer.wpos - clientBuffer.rpos,
&pkt,
switch (result) { &cb,
case ademco_parse_result_t::ADEMCO_PARSE_RESULT_OK: nullptr);
{
clientBuffer.rpos += cb; switch (result) {
//printf("id=%s\n", ap.id_.data()); case ademco_parse_result_t::ADEMCO_PARSE_RESULT_OK: {
printf("C:"); ademco_print(pkt.raw, pkt.raw_len); clientBuffer.rpos += cb;
switch (pkt.id) { // printf("id=%s\n", ap.id_.data());
case AID_ACK: printf("C:");
// success ademco_print(pkt.raw, pkt.raw_len);
break; switch (pkt.id) {
case AID_ACK:
case AID_NULL: // reply ack // success
{ break;
char ack[1024];
size_t len = ademco_make_ack_packet(ack, sizeof(ack), pkt.seq, pkt.acct, 0); case AID_NULL: // reply ack
printf("S:"); ademco_print(ack, len); {
send(clientSock, (const char*)ack, len, 0); char ack[1024];
break; size_t len = ademco_make_ack_packet(ack, sizeof(ack), pkt.seq, pkt.acct, 0);
} printf("S:");
ademco_print(ack, len);
case AID_HB: // event report send(clientSock, (const char*)ack, len, 0);
case AID_ADM_CID: break;
{ }
clientAcct = pkt.acct;
clientAdemcoId = pkt.dat.ademco_id; case AID_HB: // event report
// handle event case AID_ADM_CID: {
clientAcct = pkt.acct;
// reply ack clientAdemcoId = pkt.dat.ademco_id;
{
char ack[1024]; // reply ack
int len = ademco_make_ack_packet(ack, sizeof(ack), pkt.seq, pkt.acct, 0); {
printf("S:"); ademco_print(ack, len); char ack[1024];
send(clientSock, (const char*)ack, len, 0); int len = ademco_make_ack_packet(ack, sizeof(ack), pkt.seq, pkt.acct, 0);
} printf("S:");
ademco_print(ack, len);
break; send(clientSock, (const char*)ack, len, 0);
} }
default: // handle event
break; switch (pkt.dat.ademco_event) {
} case EVENT_BURGLAR: // 盗警
break; case EVENT_FIRE: // 火警
} // case ...
printf("zone %03d triggered %s\n", pkt.dat.zone, ademco_event_to_string(pkt.dat.ademco_event));
case ademco_parse_result_t::ADEMCO_PARSE_RESULT_NOT_ENOUGH: break;
// do nothing }
break;
break;
case ademco_parse_result_t::ADEMCO_PARSE_RESULT_ERROR: }
default:
// error handle, e.g. clear buff default:
clientBuffer.clear(); break;
break; }
} break;
}
return result;
}; case ademco_parse_result_t::ADEMCO_PARSE_RESULT_NOT_ENOUGH:
// do nothing
auto do_read = [&do_handle]() { break;
if (clientSock == INVALID_SOCKET) return;
case ademco_parse_result_t::ADEMCO_PARSE_RESULT_ERROR:
timeval tv = { 0, 1000000 }; default:
fd_set fd_read; // error handle, e.g. clear buff
FD_ZERO(&fd_read); clientBuffer.clear();
FD_SET(clientSock, &fd_read); break;
int nfds = select(int(clientSock + 1), &fd_read, (fd_set*)0, (fd_set*)0, &tv); }
if (nfds <= 0) {
return; return result;
} };
int bRead = FD_ISSET(clientSock, &fd_read); auto do_read = [&do_handle]() {
if (!bRead) { return; } if (clientSock == INVALID_SOCKET) return;
char* temp = clientBuffer.buff + clientBuffer.wpos; timeval tv = {0, 1000000};
size_t dwLenToRead = BUFF_SIZE - clientBuffer.wpos; fd_set fd_read;
int bytes_transfered = recv(clientSock, (char*)temp, (int)dwLenToRead, 0); FD_ZERO(&fd_read);
FD_SET(clientSock, &fd_read);
if (-1 == bytes_transfered) { int nfds = select(int(clientSock + 1), &fd_read, (fd_set*)0, (fd_set*)0, &tv);
if (EAGAIN == errno) { if (nfds <= 0) {
return; return;
} }
}
int bRead = FD_ISSET(clientSock, &fd_read);
if (bytes_transfered <= 0) { if (!bRead) {
printf("Client %d offline\n", (int)clientSock); return;
close(clientSock); clientSock = INVALID_SOCKET; }
clientBuffer.clear();
} else { char* temp = clientBuffer.buff + clientBuffer.wpos;
clientBuffer.wpos += bytes_transfered; size_t dwLenToRead = BUFF_SIZE - clientBuffer.wpos;
auto result = do_handle(); int bytes_transfered = recv(clientSock, (char*)temp, (int)dwLenToRead, 0);
while (1) {
size_t bytes_not_commited = clientBuffer.wpos - clientBuffer.rpos; if (-1 == bytes_transfered) {
if (bytes_not_commited == 0) { if (EAGAIN == errno) {
if (clientBuffer.wpos == BUFF_SIZE) { return;
clientBuffer.clear(); }
} }
break;
} if (bytes_transfered <= 0) {
printf("Client %d offline\n", (int)clientSock);
if (clientBuffer.wpos == BUFF_SIZE) { close(clientSock);
memmove(clientBuffer.buff, clientBuffer.buff + clientBuffer.rpos, bytes_not_commited); clientSock = INVALID_SOCKET;
memset(clientBuffer.buff + bytes_not_commited, 0, BUFF_SIZE - bytes_not_commited); clientBuffer.clear();
clientBuffer.wpos -= clientBuffer.rpos; clientBuffer.rpos = 0; } else {
result = do_handle(); clientBuffer.wpos += bytes_transfered;
} else { auto result = do_handle();
result = do_handle(); while (1) {
} size_t bytes_not_commited = clientBuffer.wpos - clientBuffer.rpos;
if (bytes_not_commited == 0) {
if (result == ademco_parse_result_t::ADEMCO_PARSE_RESULT_NOT_ENOUGH) { break; } if (clientBuffer.wpos == BUFF_SIZE) {
} clientBuffer.clear();
} }
}; break;
}
bool running = true;
if (clientBuffer.wpos == BUFF_SIZE) {
std::thread worker([&running, &serverSock, &do_accept, &do_read]() { memmove(clientBuffer.buff, clientBuffer.buff + clientBuffer.rpos, bytes_not_commited);
while (running) { memset(clientBuffer.buff + bytes_not_commited, 0, BUFF_SIZE - bytes_not_commited);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); clientBuffer.wpos -= clientBuffer.rpos;
do_accept(); clientBuffer.rpos = 0;
do_read(); result = do_handle();
} else {
if (clientSock != INVALID_SOCKET && !evntsWaiting4Send.empty()) { result = do_handle();
std::lock_guard<std::mutex> lg(mutex); }
char buf[1024];
for (auto e : evntsWaiting4Send) { if (result == ademco_parse_result_t::ADEMCO_PARSE_RESULT_NOT_ENOUGH) {
if (e == EVENT_DISARM) { break;
ademco_xdata_t xdata; }
ademco_make_xdata(&xdata, ADEMCO_XDATA_LENGTH_FMT_TWO_HEX, ADEMCO_XDATA_TRANSFORM_AS_IS, pwd, 6); }
int len = ademco_make_hb_packet(buf, sizeof(buf), 1, clientAcct.c_str(), clientAdemcoId, e, 0, 0, &xdata); }
printf("S:"); ademco_print(buf, len); };
send(clientSock, (const char*)buf, len, 0);
} else { bool running = true;
int len = ademco_make_hb_packet(buf, sizeof(buf), 1, clientAcct.c_str(), clientAdemcoId, e, 0, 0, nullptr);
printf("S:"); ademco_print(buf, len); std::thread worker([&running, &serverSock, &do_accept, &do_read]() {
send(clientSock, (const char*)buf, len, 0); while (running) {
} std::this_thread::sleep_for(std::chrono::milliseconds(100));
do_accept();
} do_read();
evntsWaiting4Send.clear();
} if (clientSock != INVALID_SOCKET && !evntsWaiting4Send.empty()) {
} std::lock_guard<std::mutex> lg(mutex);
}); char buf[1024];
for (auto e : evntsWaiting4Send) {
while (1) { if (e == EVENT_DISARM) {
std::this_thread::sleep_for(std::chrono::milliseconds(200)); ademco_xdata_t xdata;
ademco_make_xdata(&xdata, ADEMCO_XDATA_LENGTH_FMT_TWO_HEX, ADEMCO_XDATA_TRANSFORM_AS_IS, pwd, 6);
int cmd = getc(stdin); int len = ademco_make_hb_packet(buf, sizeof(buf), 1, clientAcct.c_str(), clientAdemcoId, e, 0, 0, &xdata);
printf("S:");
if (cmd == 'a' || cmd == 'A') { ademco_print(buf, len);
std::lock_guard<std::mutex> lg(mutex); send(clientSock, (const char*)buf, len, 0);
evntsWaiting4Send.push_back(EVENT_ARM_AWAY); } else {
} else if (cmd == 'd' || cmd == 'D') { int len = ademco_make_hb_packet(buf, sizeof(buf), 1, clientAcct.c_str(), clientAdemcoId, e, 0, 0, nullptr);
int ret = 0; printf("S:");
do { ademco_print(buf, len);
printf("Input 6 digit password:"); send(clientSock, (const char*)buf, len, 0);
ret = scanf("%s", pwd); }
} while (ret != 1 || strlen(pwd) != 6); }
std::lock_guard<std::mutex> lg(mutex); evntsWaiting4Send.clear();
evntsWaiting4Send.push_back(EVENT_DISARM); }
} else if (cmd == 'e' || cmd == 'E') { }
std::lock_guard<std::mutex> lg(mutex); });
evntsWaiting4Send.push_back(EVENT_EMERGENCY);
} else if (cmd == '\r' || cmd == '\n') { while (1) {
} else if (cmd == 'q' || cmd == 'Q') { std::this_thread::sleep_for(std::chrono::milliseconds(200));
running = false;
worker.join(); int cmd = getc(stdin);
break;
} else { if (cmd == 'a' || cmd == 'A') {
op_usage(); std::lock_guard<std::mutex> lg(mutex);
} evntsWaiting4Send.push_back(EVENT_ARM_AWAY);
} } else if (cmd == 'd' || cmd == 'D') {
int ret = 0;
close(serverSock); do {
printf("Bye!"); printf("Input 6 digit password:");
ret = scanf("%s", pwd);
} while (ret != 1 || strlen(pwd) != 6);
std::lock_guard<std::mutex> lg(mutex);
evntsWaiting4Send.push_back(EVENT_DISARM);
} else if (cmd == 'e' || cmd == 'E') {
std::lock_guard<std::mutex> lg(mutex);
evntsWaiting4Send.push_back(EVENT_EMERGENCY);
} else if (cmd == '\r' || cmd == '\n') {
} else if (cmd == 'q' || cmd == 'Q') {
running = false;
worker.join();
break;
} else {
op_usage();
}
}
close(serverSock);
printf("Bye!");
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment