/ src / server.cpp
server.cpp
  1  /**
  2   * @file server.cpp
  3   * @author Rene Ceska xceska06 (xceska06@stud.fit.vutbr.cz)
  4   * @date 2023-11-19
  5   */
  6  #include "inc/server.h"
  7  
  8  // Writes which child died
  9  void SigCatcher(int n) {
 10    int pid = wait3(NULL, WNOHANG, NULL);
 11    printf("Child %d died.\n", pid);
 12  }
 13  // global variable for signal handlers
 14  int childSocket = 0;
 15  int communicationSocket;
 16  std::vector<int> children = {};
 17  
 18  /**
 19   * @brief signal handler for main process, when SIGINT is received, it kills all
 20   * children and closes the socket
 21   *
 22   * @param n
 23   */
 24  void SigIntCatcher(int n) {
 25    printf("Killing children.\n");
 26    for (long unsigned int i = 0; i < children.size(); i++) {
 27      kill(children[i], SIGQUIT);
 28    }
 29    close(communicationSocket);
 30    printf("Closing.\n");
 31    exit(0);
 32  }
 33  
 34  /**
 35   * @brief signal handler for child process, when SIGQUIT is received, it closes
 36   * the socket and exits
 37   *
 38   * @param n
 39   */
 40  void SigQuitCatcher(int n) {
 41    sendNoticeOfDisconnection(childSocket, BER_LDAP_UNAVAILABLE);
 42    printf("Dying. %d\n", childSocket);
 43    close(childSocket);
 44    exit(0);
 45  }
 46  
 47  // makro for destroying berBindResponse object
 48  #define CLEANUP_SERVER delete ((BerSequenceObject *)berBindResponse);
 49  
 50  /**
 51   * @brief Ldap server, This part was inspired by the example from stubs demo tcp
 52   * server
 53   * https://git.fit.vutbr.cz/NESFIT/IPK-Projekty/src/branch/master/Stubs/cpp/DemoTcp
 54   * by Vladimir Vesely Ph.D.
 55   *
 56   * @param port port to listen on
 57   * @param dbPath path to database file
 58   * @return int
 59   */
 60  int ldapServer(int port, char *dbPath) {
 61    int returnCode;
 62    // starting main socket
 63    if ((communicationSocket = socket(PF_INET6, SOCK_STREAM, 0)) < 0) {
 64      perror("socket() failed");
 65      exit(EXIT_FAILURE);
 66    }
 67    // setting options for main socket
 68    const int enable = 1;
 69    const int disable = 0;
 70    returnCode = setsockopt(communicationSocket, IPPROTO_IPV6, IPV6_V6ONLY,
 71                            &disable, sizeof(int));
 72  
 73    if (returnCode < 0) {
 74      perror("setsockopt() failed");
 75      close(communicationSocket);
 76      exit(1);
 77    }
 78    returnCode = setsockopt(communicationSocket, SOL_SOCKET, SO_REUSEADDR,
 79                            &enable, sizeof(int));
 80    if (returnCode < 0) {
 81      perror("setsockopt() failed");
 82      close(communicationSocket);
 83      exit(1);
 84    }
 85    returnCode = setsockopt(communicationSocket, SOL_SOCKET, SO_REUSEPORT,
 86                            &enable, sizeof(int));
 87    if (returnCode < 0) {
 88      perror("setsockopt() failed");
 89      close(communicationSocket);
 90      exit(1);
 91    }
 92  
 93    // setting up main socket
 94    struct sockaddr_in6 sa = {0};
 95    struct sockaddr_in6 clientSA = {0};
 96    char str[INET6_ADDRSTRLEN];
 97    socklen_t ClientSALen = sizeof(clientSA);
 98    memset(&sa, 0, sizeof(sa));
 99    sa.sin6_family = AF_INET6;
100    sa.sin6_addr = in6addr_any;
101    sa.sin6_port = htons(port);
102    if ((returnCode =
103             bind(communicationSocket, (struct sockaddr *)&sa, sizeof(sa))) < 0) {
104      perror("bind() failed");
105      exit(EXIT_FAILURE);
106    }
107    if ((returnCode = listen(communicationSocket, 1)) < 0) {
108      perror("listen() failed");
109      exit(EXIT_FAILURE);
110    }
111    // setup signal handlers
112    //user kills server
113    signal(SIGINT, SigIntCatcher);
114    // child dies
115    signal(SIGCHLD, SigCatcher);
116    //server kills child
117    signal(SIGQUIT, SigQuitCatcher);
118  
119    // main loop
120    while (1) {
121      // seting up child socket
122      childSocket =
123          accept(communicationSocket, (struct sockaddr *)&clientSA, &ClientSALen);
124      returnCode = fcntl(communicationSocket, F_SETFD, FD_CLOEXEC);
125      if (returnCode < 0) {
126        perror("ERROR: fcntl");
127        exit(EXIT_FAILURE);
128      }
129      if (childSocket <= 0)
130        continue;
131  
132      // spliting into child process and parent process
133      int pid = fork();
134      if (pid < 0) {
135        perror("fork() failed");
136        exit(EXIT_FAILURE);
137      }
138  
139      if (pid == 0) // new process to maintain client's requests:
140      {
141        int childPid = getpid();
142        close(communicationSocket); // closing for child process
143        printf("New ldap connection (maintained by %d):\n", childPid);
144        if (inet_ntop(AF_INET6, &clientSA.sin6_addr, str, sizeof(str))) {
145          printf("%d:Client address:%s\n", childPid, str);
146          printf("%d:Client port: %d\n", childPid, ntohs(clientSA.sin6_port));
147        }
148  
149        // load envelope
150        int err = 0;
151        std::vector<unsigned char> envelope;
152        while (1) {
153          envelope.clear();
154          int lenghtOfEnvelope = loadEnvelope(envelope, childSocket);
155          if (lenghtOfEnvelope == -1) {
156            printf("connection closed\n");
157            close(childSocket);
158            exit(0);
159          }
160          printf("%d: received message\n", childPid);
161  
162          std::vector<unsigned char>::iterator envelopeTagPointer =
163              envelope.begin();
164  
165          GoIntoTag(envelopeTagPointer, &err, envelope.end());
166          CHECK_ERR(err, "error going into tag");
167          SkipTags(envelopeTagPointer, 1, &err, envelope.end());
168          CHECK_ERR(err, "error skipping tags");
169          BerObject *EnvelopeObject =
170              ParseBerObject(envelope.begin(), &err, envelope.end());
171          switch (envelopeTagPointer[0]) {
172          case 0x63:
173            printf("search request\n");
174            searchRequestHandler(EnvelopeObject, childSocket, dbPath);
175            delete EnvelopeObject;
176            break;
177          case 0x62: // unbind request
178            printf("%d: Connection closed\n", childPid);
179            close(childSocket);
180            delete EnvelopeObject;
181            exit(0);
182            break;
183          case 0x60: { // bind request
184            // send bind response
185            BerObject *berBindResponse =
186                CreateBindResponse(EnvelopeObject, BER_LDAP_SUCCESS);
187            std::vector<unsigned char> bindResponse =
188                berBindResponse->getBerRepresentation();
189            // check for correct auth method
190            BerUndefinedObject *authMethod =
191                (BerUndefinedObject *)((BerSequenceObject *)((BerSequenceObject *)
192                                                                 EnvelopeObject)
193                                           ->objects[1])
194                    ->objects[2];
195            std::vector<unsigned char> authMethodValue =
196                authMethod->getBerRepresentation();
197  
198            if (authMethodValue[0] != 0x80 && authMethodValue[1] != 0x00) {
199              printf("invalid auth method\n");
200              BerObject *berBindResponse = CreateBindResponse(
201                  EnvelopeObject, BER_LDAP_AUTH_METHOD_NOT_SUPPORTED);
202              std::vector<unsigned char> bindResponse =
203                  berBindResponse->getBerRepresentation();
204              send(childSocket, &bindResponse[0], bindResponse.size(),
205                   MSG_NOSIGNAL);
206              delete EnvelopeObject;
207              close(childSocket);
208              exit(0);
209            }
210  
211            send(childSocket, &bindResponse[0], bindResponse.size(),
212                 MSG_NOSIGNAL);
213            delete EnvelopeObject;
214            break;
215          }
216          default:
217            printf("unknown request\n");
218            delete EnvelopeObject;
219            close(childSocket);
220            exit(0);
221            break;
222          }
223        }
224  
225        printf("%d: Connection closed\n", childPid);
226  
227        close(childSocket);
228        exit(0);
229      } else {
230        children.push_back(pid);
231        close(childSocket);
232      }
233    }
234  }