====== Jednoduchá adresářová služba ====== ===== Popis použitého aplikačního protokolu ===== Protokol adresářové služby je velice triviální a inspiroval se fenoménem dnešního internetu -- lolcats(([[http://icanhascheezburger.com/|Lolcats ‘n’ Funny Pictures – I Can Has Cheezburger?]], [[http://speaklolspeak.com|The Definitive Lolcats Glossary – Speak Lol Speak]])). Nejlépe bude předvést si jej na ukázce: ^ ./server 10000 ^ ./client -h localhost -p 10000 -NSF -l xkalab00 ^ | | ICANHAS NSF WHERE LOGIN xkalab00 KTHX | | Jan;Kalab;FIT;\r\n | | | \r\n | | Jak vidno, klient pouze zašle požadavek začínající klíčovým slovem ICANHAS. Následuje seznam sloupců, které klient požaduje (NSF). Další je klíčové slovo WHERE a po něm následujicí dvojice klíčové slovo pro vyhledání (NAME, SURNAME, LOGIN, FACULTY) a hodnota. Požavek ukončuje klíčové slovo KTHX. Tento požadavek server zpracuje, a začne vracet řádky adresáře. Nakonec zprávu uzavře znaky \r\n, čímž vznikne čtvěřice \r\n\r\n na kterou klient zareguje ukončením spojení a vypsáním přijatého adresáře. ===== README ===== +------------------------------+ | Jednoducha adresarova sluzba | +------------------------------+ Autor: Jan Kalab SERVER ------ Server spustite prikazem ./server xxx kde xxx znaci cislo portu na kterem bude server poslouchat. Toto cislo musi byt vetsi nez 1024. Na jakekoliv chyby Vas server upozorni. Server ocekava v adresari ze ktereho byl spusten soubor ipk_database.txt ze ktereho muze cist. V tomto souboru musi byt stredniky oddeleny seznam jmen, prijmeni, loginu a fakult ve stejnem poradi a formatu v jakem bylo vzorove zadani (vcetne ukoncovani radku pomoci CRLF). Pokud toto nebude dodrzeno, neni zarucena funkcnost serveru Server nelze ukoncit jinak nez zaslanim patricneho signalu (nejlepe 15 SIGTERM). KLIENT ------ Klient se spousti prikazem ./client -h xxx -p yyy kde xxx je adresa na kterou se ma klient pripojit a yyy cislo portu na ktery se ma pripojit. Cislo portu musi byt vetsi nez 1024, ale na to vas klient upozorni. Dale by mely nasledovat nektere z vyhledavacich parametru -n -s -l -f pro jmeno, prijmeni, login a fakultu. Pokud nebude zadano zadne vyhledavaci kriterium, dojde i tak k odeslani dotazu na server, ktery vrati prazdnou (ci nesmyslnou) odpoved. Dale je mozno zadat ktere sloupce chcete vratit, k tomu slouzi parametr -NSLF, u ktereho lze nektera pismena vynechat. Neni-li tento parametr zadan vubec, budou vypsany vsechny sloupce. Po spusteni klienta s patricnymi parametry se spoji se serverem a na standardni vystup vypise pozadovana data z adresare. ===== server.c ===== #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { if (argc != 2) { fprintf(stderr, "D'oh! Spatny pocet parametru! Ocekava se jeden, a to cislo portu.\n"); return 1; } unsigned int port = atoi(argv[1]); if (port <= 1024) { fprintf(stderr, "D'oh! Na vyhrazenem portu odmitam bezet!\n"); return 1; } FILE *file; file = fopen("ipk_database.txt", "r"); if (file == NULL) { fprintf(stderr, "D'oh! Nedokazu otevrit soubor ipk_database.txt!\n"); return 1; } if (fseek(file, 0, SEEK_END)) { fprintf(stderr, "D'oh! Nedokazu zjistit velikost souboru ipk_database.txt!\n"); return 1; } unsigned long filesize = ftell(file); fseek(file, 0, SEEK_SET); char* database = malloc(filesize * sizeof(char)); if (database == NULL) { fprintf(stderr, "D'oh! Chyba alokace pameti!\n"); return 1; } unsigned int items = 0; for (unsigned long i = 0; i < filesize; i++) { database[i] = fgetc(file); if (database[i] == '\n') { items++; } } fclose(file); char *line[items]; char *login[items]; char *name[items]; char *surname[items]; char *faculty[items]; line[0] = strtok(database, ";"); login[0] = strtok(NULL, ";"); surname[0] = strtok(NULL, ";"); name[0] = strtok(NULL, ";"); faculty[0] = strtok(NULL, ";\r\n"); for (unsigned int i = 1; i < items; i++) { line[i] = strtok(NULL, ";"); login[i] = strtok(NULL, ";"); surname[i] = strtok(NULL, ";"); name[i] = strtok(NULL, ";"); faculty[i] = strtok(NULL, ";\r\n"); } struct sockaddr_in myaddr; struct sockaddr_in remoteaddr; int listener = socket(AF_INET, SOCK_STREAM, 0); if (listener == -1) { fprintf(stderr, "D'oh! Rozbita zasuvka!"); return 1; } myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); myaddr.sin_port = htons(port); memset(&(myaddr.sin_zero), '\0', 8); if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) { fprintf(stderr, "D'oh! Nepovedlo se zasunout zasuvku!\n"); return 1; } if (listen(listener, 10) == -1) { fprintf(stderr, "D'oh! Server je nahluchly.\n"); return 1; } printf("Server @ %d\n", port); socklen_t addrlen = sizeof(listener); signal(SIGCHLD, SIG_IGN); while (1) { int newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen); if (newfd == -1) { fprintf(stderr, "D'oh! Neprijimame...\n"); } else { int pid = fork(); if (pid == 0) { //printf("INCOMING!\n"); //cteni unsigned int allocated = 1; unsigned int dumped = 0; char* request = malloc(allocated * sizeof(char)); while (!strstr(request, "KTHX")) { read(newfd, request + dumped++, 1); if (dumped >= allocated) { allocated *= 2; request = realloc(request, allocated); if (!request) { fprintf(stderr, "D'OH! Realloc fail, buy me more memory!\n"); return 1; } } } //printf("%s\n", request); char* columns = strstr(request, "ICANHAS ") + strlen("ICANHAS "); columns = strtok(columns, " "); //printf("\n%s\n", columns); char* filters = columns + strlen(columns) + strlen(" WHERE "); //printf("%s", filters); char* filter[10]; filter[0] = strtok(filters, " "); //printf("Filter0: %s\n", filter[0]); if (strstr(filter[0], "KTHX")) { fprintf(stderr, "D'oh! Zadny vyhledavaci filtr\n"); write(newfd, "\r\n\r\n", 4); free(request); exit(1); } for (short i = 1; i < 10; i++) { filter[i] = strtok(NULL, " "); if (strstr(filter[i], "KTHX")) { //printf("Konec filtru\n"); break; } } char* namefilter = NULL; char* surnamefilter = NULL; char* loginfilter = NULL; char* facultyfilter = NULL; for (short i = 0; i < 10; i++) { if (strstr(filter[i], "KTHX")) { //printf("Konec filtru\n"); break; } if (!strcmp(filter[i], "NAME")) { namefilter = filter[++i]; continue; } if (!strcmp(filter[i], "SURNAME")) { surnamefilter = filter[++i]; continue; } if (!strcmp(filter[i], "LOGIN")) { loginfilter = filter[++i]; continue; } if (!strcmp(filter[i], "FACULTY")) { facultyfilter = filter[++i]; continue; } } /* printf("Columns: %s\n", columns); printf("Name: %s\n", namefilter); printf("Surname: %s\n", surnamefilter); printf("Login: %s\n", loginfilter); printf("Faculty: %s\n", facultyfilter); */ //Filtrovani short mask[items]; for (unsigned int i = 0; i < items; i++) { mask[i] = 1; } for (unsigned int i = 0; i < items; i++) { if (mask[i] == 1) { if (namefilter) { if (strcmp(name[i], namefilter)) { mask[i] = 0; } } if (surnamefilter) { if (strcmp(surname[i], surnamefilter)) { mask[i] = 0; } } if (loginfilter) { if (strcmp(login[i], loginfilter)) { mask[i] = 0; } } if (facultyfilter) { if (strcmp(faculty[i], facultyfilter)) { mask[i] = 0; } } } } //Odpoved for (unsigned int i = 0; i < items; i++) { if (mask[i] == 1) { if (strstr(columns, "N")) { //printf("N"); write(newfd, name[i], strlen(name[i])); write(newfd, ";", 1); } if (strstr(columns, "S")) { //printf("S"); write(newfd, surname[i], strlen(surname[i])); write(newfd, ";", 1); } if (strstr(columns, "L")) { //printf("L"); write(newfd, login[i], strlen(login[i])); write(newfd, ";", 1); } if (strstr(columns, "F")) { //printf("F"); write(newfd, faculty[i], strlen(faculty[i])); write(newfd, ";", 1); } //printf("\n"); write(newfd, "\r\n", 2); } } write(newfd, "\r\n", 2); /* write(newfd, name[0], strlen(name[0])); write(newfd, ";", 1); write(newfd, surname[0], strlen(surname[0])); write(newfd, ";", 1); write(newfd, login[0], strlen(login[0])); write(newfd, ";", 1); write(newfd, faculty[0], strlen(faculty[0])); write(newfd, ";", 1); write(newfd, "\r\n", 2); */ //printf("\n"); write(newfd, "\r\n\r\n", 4); free(request); exit(0); } } } /* printf("%s, %s, %s, %s, %s\n", line[0], login[0], name[0], surname[0], faculty[0]); printf("%s, %s, %s, %s, %s\n", line[items-1], login[items-1], name[items-1], surname[items-1], faculty[items-1]); printf("Polozek: %d\n", items); */ free(database); return 0; } ===== client.c ===== #include #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { if (argc < 5) { fprintf(stderr, "D'oh! Prilis malo parametru! Chce to aspon -h host -p port\n"); return 1; } //Init char* host = NULL; unsigned int port = 0; char* columns = NULL; char* name = NULL; char* surname = NULL; char* login = NULL; char* faculty = NULL; //Parsovani vstupu for (unsigned short i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0) { host = argv[++i]; continue; } if (strcmp(argv[i], "-p") == 0) { port = atoi(argv[++i]); continue; } if (strstr(argv[i], "-N") || strstr(argv[i], "-S") || strstr(argv[i], "-L") || strstr(argv[i], "-F")) { columns = argv[i] + 1; continue; } if (strcmp(argv[i], "-n") == 0) { name = argv[++i]; continue; } if (strcmp(argv[i], "-s") == 0) { surname = argv[++i]; continue; } if (strcmp(argv[i], "-l") == 0) { login = argv[++i]; continue; } if (strcmp(argv[i], "-f") == 0) { faculty = argv[++i]; continue; } fprintf(stderr, "D'oh! Neznamy parametr %s!\n", argv[i]); return 1; } //Mozne chyby if (host == NULL) { fprintf(stderr, "D'oh! Nerekl jsi mi kam se pripojit!\n"); return 1; } if (port <= 1024) { fprintf(stderr, "D'oh! Na vyhrazenem (nebo nezadanem) portu odmitam bezet!\n"); return 1; } if (columns != NULL) { if (strlen(columns) > 4) { fprintf(stderr, "D'oh! Prilis mnoho sloupcu!\n"); return 1; } else { for (unsigned short i = 0; i < 4; i++) { if (columns[i] == '\0') { break; } if (columns[i] != 'N' && columns[i] != 'S' && columns[i] != 'L' && columns[i] != 'F') { fprintf(stderr, "D'oh! Spatne definovane sloupce!\n"); return 1; } } } } else { columns = "NSLF"; } //Vypis /* printf("Client @ %s:%d\n", host, port); printf("Columns: %s\n", columns); printf("Name: %s\n", name); printf("Surname: %s\n", surname); printf("Login: %s\n", login); printf("Faculty: %s\n", faculty); */ int socketfd = socket(PF_INET, SOCK_STREAM, 0); if (socketfd == -1) { fprintf(stderr, "D'oh! Rozbita zasuvka!\n"); return 1; } struct sockaddr_in stSockAddr; bzero(&stSockAddr, sizeof(stSockAddr)); stSockAddr.sin_family = AF_INET; stSockAddr.sin_port = htons(port); struct hostent *hoststruct; if ((hoststruct = gethostbyname(host)) == NULL) { fprintf(stderr, "D'OH! Unknown host.\n"); return 1; } memcpy(&stSockAddr.sin_addr, hoststruct->h_addr, hoststruct->h_length); //adresa if (connect(socketfd, (struct sockaddr*) &stSockAddr, sizeof(stSockAddr)) == -1) { fprintf(stderr, "D'oh! Server is dead!\n"); return 1; } //pozadavek unsigned int filters = 0; if (name) { filters += strlen(" NAME ") + strlen(name); } if (surname) { filters += strlen(" SURNAME ") + strlen(surname); } if (login) { filters += strlen(" LOGIN ") + strlen(login); } if (faculty) { filters += strlen(" FACULTY ") + strlen(faculty); } char* request = malloc((strlen("ICANHAS ") + strlen(columns) + strlen(" WHERE") + filters + strlen(" KTHX")) * sizeof(char)); if (!request) { fprintf(stderr, "D'OH! Malloc fail, buy more RAM!\n"); return 1; } request[0] = '\0'; strcat(request, "ICANHAS "); strcat(request, columns); strcat(request, " WHERE"); if (name) { strcat(request, " NAME "); strcat(request, name); } if (surname) { strcat(request, " SURNAME "); strcat(request, surname); } if (login) { strcat(request, " LOGIN "); strcat(request, login); } if (faculty) { strcat(request, " FACULTY "); strcat(request, faculty); } strcat(request, " KTHX"); //printf("Request: %s\n", request); if (write(socketfd, request, strlen(request)) <= 0) { fprintf(stderr, "D'oh! Nedokazu psat do zasuvky!\n"); return 1; } free(request); //Odpoved //printf("Answer:\n"); unsigned int allocated = 1; unsigned int dumped = 0; char* answer = malloc(allocated * sizeof(char)); while (!strstr(answer, "\r\n\r\n")) { read(socketfd, answer + dumped++, 1); if (dumped >= allocated) { allocated *= 2; answer = realloc(answer, allocated); if (answer == NULL) { fprintf(stderr, "D'OH! Realloc fail, buy me more memory!\n"); return 1; } } } printf("%s", answer); free(answer); //printf("Everything went just fine.\n"); shutdown(socketfd, 2); close(socketfd); return 0; }