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 }