Subversion Repositories oidinfo_api

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. // **************************************************
  2. // ** OID CSV Lookup Server 1.1                    **
  3. // ** (c) 2016-2019 ViaThinkSoft, Daniel Marschall **
  4. // **************************************************
  5.  
  6. // todo: log verbosity + datetime
  7. // todo: publish at codelib
  8. // todo: server hat sich einfach so beendet... "read: connection reset by peer"
  9. // todo: 2019-02-24 service was booted together with the system, and i got "0 OIDs loaded". why???
  10. // todo: create vnag monitor that checks if this service is OK
  11.  
  12. #include "oid_lookup_srv.h"
  13.  
  14. unordered_set<string> lines;
  15.  
  16. int loadfile(const string &filename) {
  17.         int cnt = 0;
  18.  
  19.         ifstream infile(filename);
  20.         string line;
  21.         while (getline(infile, line)) {
  22.                 lines.insert(line);
  23.                 ++cnt;
  24.         }
  25.         infile.close();
  26.  
  27.         fprintf(stdout, "Loaded %d OIDs from %s\n", cnt, filename.c_str());
  28.  
  29.         return cnt;
  30. }
  31.  
  32. bool stringAvailable(const string &str) {
  33.         return lines.find(str) != lines.end();
  34. }
  35.  
  36. // Template of this code: http://www.gnu.org/software/libc/manual/html_node/Server-Example.html
  37. //                        http://www.gnu.org/software/libc/manual/html_node/Inet-Example.html#Inet-Example
  38.  
  39. struct con_descriptor {
  40.         time_t              last_activity;
  41.         struct sockaddr_in  clientname;
  42.         int                 queries;
  43.         time_t              connect_ts;
  44. };
  45.  
  46. con_descriptor cons[FD_SETSIZE];
  47.  
  48. int read_from_client(int filedes) {
  49.         char buffer[MAXMSG];
  50.         int nbytes;
  51.  
  52.         nbytes = read(filedes, buffer, MAXMSG);
  53.         if (nbytes < 0) {
  54.                 /* Read error. */
  55.                 //perror("read");
  56.                 //exit(EXIT_FAILURE);
  57.                 return -1;
  58.         } else if (nbytes == 0) {
  59.                 /* End-of-file. */
  60.                 return -1;
  61.         } else {
  62.                 /* Data read. */
  63.  
  64.                 for (int i=0; i<MAXMSG; ++i) {
  65.                         if ((buffer[i] == 13) || (buffer[i] == 10)) buffer[i] = 0;
  66.                 }
  67.  
  68.                 if (strcmp(buffer, "bye") == 0) {
  69.                         fprintf(stdout, "%s:%d[%d] Client said good bye.\n", inet_ntoa(cons[filedes].clientname.sin_addr), ntohs(cons[filedes].clientname.sin_port), filedes);
  70.                         return -1;
  71.                 } else {
  72.                         cons[filedes].queries++;
  73.  
  74.                         // fprintf(stdout, "%s:%d[%d] Query #%d: %s\n", inet_ntoa(cons[filedes].clientname.sin_addr), ntohs(cons[filedes].clientname.sin_port), filedes, cons[filedes].queries, buffer);
  75.  
  76.                         if (stringAvailable(buffer)) {
  77.                                 write(filedes, "1\n", 2);
  78.                         } else {
  79.                                 write(filedes, "0\n", 2);
  80.                         }
  81.                         return 0;
  82.                 }
  83.         }
  84. }
  85.  
  86. int fd_set_isset_count(const fd_set &my_fd_set) {
  87.         int cnt = 0;
  88.         for (int fd = 0; fd < FD_SETSIZE; ++fd) {
  89.                 if (FD_ISSET(fd, &my_fd_set)) {
  90.                         ++cnt;
  91.                 }
  92.         }
  93.         return cnt;
  94. }
  95.  
  96. int loadCSVs() {
  97.         return loadfile("oid_table.csv");
  98. }
  99.  
  100. void initConsArray() {
  101.         for (int i=0; i<FD_SETSIZE; ++i) {
  102.                 cons[i].last_activity = 0;
  103.                 memset(&cons[i].clientname, 0, sizeof(sockaddr_in));
  104.                 cons[i].queries = 0;
  105.         }
  106. }
  107.  
  108. int make_socket(uint16_t port) {
  109.         int sock;
  110.         struct sockaddr_in name;
  111.  
  112.         /* Create the socket. */
  113.         sock = socket(PF_INET, SOCK_STREAM, 0);
  114.         if (sock < 0) {
  115.                 perror("socket");
  116.                 exit(EXIT_FAILURE);
  117.         }
  118.  
  119.         int enable = 1;
  120.         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
  121.                 fprintf(stderr, "ERROR: setsockopt(SO_REUSEADDR) failed");
  122.                 exit(EXIT_FAILURE);
  123.         }
  124.  
  125.         /* Give the socket a name. */
  126.         name.sin_family = AF_INET;
  127.         name.sin_port = htons (port);
  128.         name.sin_addr.s_addr = htonl (INADDR_ANY);
  129.         if (bind (sock, (struct sockaddr *) &name, sizeof(name)) < 0) {
  130.                 perror("bind");
  131.                 exit(EXIT_FAILURE);
  132.         }
  133.  
  134.         return sock;
  135. }
  136.  
  137. int main(void) {
  138. //      extern int make_socket(uint16_t port);
  139.         int sock;
  140.         fd_set active_fd_set, read_fd_set;
  141.  
  142.         fprintf(stdout, "OID CSV Lookup Server 1.0 (c)2016-2019 ViaThinkSoft\n");
  143.         fprintf(stdout, "Listening at port: %d\n", PORT);
  144.         fprintf(stdout, "Max connections: %d\n", FD_SETSIZE);
  145.  
  146.         initConsArray();
  147.  
  148.         int loadedOIDs = loadCSVs();
  149.         time_t csvLoad = time(NULL);
  150.  
  151.         /* Create the socket and set it up to accept connections. */
  152.         sock = make_socket(PORT);
  153.         if (listen(sock, 1) < 0) {
  154.                 perror("listen");
  155.                 exit(EXIT_FAILURE);
  156.         }
  157.  
  158.         /* Initialize the set of active sockets. */
  159.         FD_ZERO(&active_fd_set);
  160.         FD_SET(sock, &active_fd_set);
  161.  
  162.         while (1) {
  163.                 /* Block until input arrives on one or more active sockets. */
  164.                 read_fd_set = active_fd_set;
  165.  
  166.                 struct timeval tv;
  167.                 tv.tv_sec = 1;
  168.                 tv.tv_usec = 0;  // Not init'ing this can cause strange errors
  169.  
  170.                 int retval = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tv);
  171.  
  172.                 if (retval < 0) {
  173.                         perror("select");
  174.                         exit(EXIT_FAILURE);
  175.                 } else if (retval == 0) {
  176.                         // fprintf(stdout, "Nothing received\n");
  177.                 } else {
  178.                         /* Service all the sockets with input pending. */
  179.                         for (int i=0; i < FD_SETSIZE; ++i) {
  180.                                 if (FD_ISSET (i, &read_fd_set)) {
  181.                                         if (i == sock) {
  182.                                                 /* Connection request on original socket. */
  183.                                                 int new_fd;
  184.                                                 struct sockaddr_in clientname;
  185.                                                 socklen_t size = sizeof(clientname);
  186.                                                 new_fd = accept(sock, (struct sockaddr *) &clientname, &size);
  187.                                                 if (new_fd < 0) {
  188.                                                         perror("accept");
  189.                                                         exit(EXIT_FAILURE);
  190.                                                 }
  191.                                                 FD_SET(new_fd, &active_fd_set);
  192.  
  193.                                                 cons[new_fd].clientname = clientname;
  194.                                                 cons[new_fd].connect_ts = time(NULL);
  195.  
  196.                                                 if (loadedOIDs == 0) {
  197.                                                         loadedOIDs = loadCSVs();
  198.                                                         if (loadedOIDs == 0) {
  199.                                                                 fprintf(stderr, "%s:%d[%d] Service temporarily unavailable (OID list empty)\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
  200.                                                                 close(new_fd);
  201.                                                                 FD_CLR(new_fd, &active_fd_set);
  202.                                                         }
  203.                                                 }
  204.  
  205.                                                 if (fd_set_isset_count(active_fd_set)-1 > MAX_CONNECTIONS) { // -1 is because we need to exclude the listening socket (i=sock) which is not a connected client
  206.                                                         fprintf(stderr, "%s:%d[%d] Rejected because too many connections are open\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
  207.                                                         close(new_fd);
  208.                                                         FD_CLR(new_fd, &active_fd_set);
  209.                                                 } else {
  210.                                                         fprintf(stdout, "%s:%d[%d] Connected\n", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), new_fd);
  211.                                                 }
  212.  
  213.                                                 cons[new_fd].last_activity = time(NULL);
  214.                                                 cons[new_fd].queries = 0;
  215.                                         } else {
  216.                                                 /* Data arriving on an already-connected socket. */
  217.                                                 cons[i].last_activity = time(NULL);
  218.                                                 if (read_from_client(i) < 0) {
  219.                                                         fprintf(stdout, "%s:%d[%d] Connection closed after %d queries in %lu seconds.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i, cons[i].queries, time(NULL)-cons[i].connect_ts);
  220.                                                         close(i);
  221.                                                         FD_CLR(i, &active_fd_set);
  222.                                                 }
  223.                                         }
  224.                                 }
  225.                         }
  226.                 }
  227.  
  228.                 /* Check if we need to reload the CSV */
  229.                 if (time(NULL)-csvLoad >= CSVRELOADINTERVAL) {
  230.                         loadCSVs();
  231.                         csvLoad = time(NULL);
  232.                 }
  233.  
  234.                 /* Check if we can close connections due to timeout */
  235.                 for (int i=0; i < FD_SETSIZE; ++i) {
  236.                         if (FD_ISSET(i, &active_fd_set)) {
  237.                                 if (i == sock) continue;
  238.                                 if (time(NULL)-cons[i].last_activity >= CONNECTION_TIMEOUT) {
  239.                                         fprintf(stdout, "%s:%d[%d] Connection timeout.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i);
  240.                                         fprintf(stdout, "%s:%d[%d] Connection closed after %d queries in %lu seconds.\n", inet_ntoa(cons[i].clientname.sin_addr), ntohs(cons[i].clientname.sin_port), i, cons[i].queries, time(NULL)-cons[i].connect_ts);
  241.                                         close(i);
  242.                                         FD_CLR(i, &active_fd_set);
  243.                                 }
  244.                         }
  245.                 }
  246.         }
  247. }
  248.