Uživatelské nástroje

Nástroje pro tento web


pitel:ipk:projekt2

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 – lolcats1). 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 <[email protected]>

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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
 
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
 
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;
}
/var/www/wiki/data/pages/pitel/ipk/projekt2.txt · Poslední úprava: 30. 12. 2022, 13.43:01 autor: 127.0.0.1