/* * Dinko Korunic, kreator@fly.srk.fer.hr, 36355514 * Sun Nov 18 23:33:48 CET 2001 * * Potrebno je napravit jednostavni echo klijent i posluzitelj koristeci * UDP protokol. Drugim rijecima, server ceka na odred/enom pristupu i sve * sto mu pristigne na taj pristup vraca nazad klijentu. S druge strane, * klijent cita sa tipkovnice liniju po liniju, te svaku liniju salje * posluzitelju, a potom ocekuje odgovor posluzitelja. Klijent mora * ispisati odgovor. U trenutku kada se upise "kraj" kao jedina rijec u * liniji klijent salje posluzitelju tu rijec, a posluzitelj nakon * odgovora prekida rad. U trenutku primitka odgovora od posluzitelja i * klijent prekida rad. Argument klijentu je IP adresa na kojoj se nalazi * posluzitelj te pristup na kojem posluzitelj ceka. Argument posluzitelju * je pristup na kojemu ce cekati pakete od klijenta. */ /* * Dodao sam i IPv6 podrsku za UDP echo (uz standardni IPv4). Program se * nalazi kompletan u jednoj datoteci, s time da iz argv[0] saznaje da li * je klijent ili posluzitelj * -kre */ #include #include #include #include #include #include #include #include #include #include #include #include #define POSLUZITELJ "./posluzitelj" /* ime posluzitelja */ #define KLIJENT "./klijent" /* ime klijenta */ #define KRAJ "kraj\n" /* kontrolna rijec za kraj transmisije */ #define MAXLINE 4096 /* velicina UDP receive buffera */ /* polje error poruka za printhelp() */ static const char *help[] = { "Posluzitelj se poziva sa:\n./posluzitelj \n" /* 0 */ "pri cemu je port cijeli broj 1024:65535.\n", "Klijent se poziva sa:\n./klijent \n" /* 1 */ "pri cemu je IP adresa posluzitelja,\n" "a port cijeli broj 1024:65535.\n", "Nije pozvan niti klijent niti posluzitelj.\n" /* 2 */ "Ispravna sintaksa je:\n" "./posluzitelj ili ./klijent .\n", "Drugi labos iz Mreza racunala, " __DATE__ "\n" /* 3 */ }; /* ispisivanje samih error poruka prema internim kodovima */ int printhelp(int helpno) { return fprintf(stderr, "%s", help[helpno]); } /* myerrorhandler() -> evolucija perror() i exit() u jednu funkciju sa * vracanjem odgovarajucih error poruka sistemu */ void merror(char *errmsg, int lineno) { fprintf(stderr, "Greska u liniji %d: ", lineno); perror(errmsg); exit(errno); } /* petlja koja radi mrezni setup te slusa i radi dg_echo() nazad * posiljatelju, ma tko god on bio :-) */ void dolisten(const char *strport) { #ifndef IPV6 struct sockaddr_in recv_addr, sender_addr; int len = sizeof(struct sockaddr_in); #else struct sockaddr_in6 recv_addr, sender_addr; int len = sizeof(struct sockaddr_in6); #endif /* IPV6 */ int port = 0, socketfd, rc = 0; char buf[MAXLINE]; int len2 = sizeof(buf), len3 = sizeof(KRAJ); /* trazimo integer port iz stringa */ port = atoi(strport); memset(&recv_addr, 0, len); /* obrisi sve */ /* napunimo recv_addr strukturu zeljenim podacima */ #ifndef IPV6 recv_addr.sin_family = AF_INET; /* AF_INET */ recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* svi interfaceovi */ recv_addr.sin_port = htons(port); /* i na kojem portu */ #else recv_addr.sin6_family = AF_INET6; /* AF_INET6 */ recv_addr.sin6_addr = in6addr_any; /* svi interfaceovi */ recv_addr.sin6_port = htons(port); /* i na kojem portu */ #endif /* IPV6 */ /* otvorimo socket ako je moguce, i to za udp/17 protokol */ #ifndef IPV6 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) merror("Greska u otvaranju socketa", __LINE__); #else if ((socketfd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) merror("Greska u otvaranju socketa", __LINE__); #endif /* IPV6 */ /* povezivanje imena i socketa */ if (bind(socketfd, (struct sockaddr*)&recv_addr, len) == -1) merror("Greska u povezivanju imena i socketa", __LINE__); /* jedna mala beskonacna petlja - iskreno, ja bih radije jos cekao * podatke sa socketa pomocu select() ili poll() petlje, no kako nam je * socket blocking tipa, nema potrebe */ for (;;) { if ((rc = recvfrom(socketfd, buf, len2, 0, (struct sockaddr*)&sender_addr, &len)) == -1) merror("Greska u primanju paketa", __LINE__); /* okej, a sad posalji sve sto si primio */ if (sendto(socketfd, buf, rc, 0, (struct sockaddr*)&sender_addr, len) == -1) merror("Greska u slanju paketa", __LINE__); if (!strncmp(KRAJ, buf, len3)) break; } } void doconnect(const char *straddr, const char *strport) { struct hostent *hp = NULL; #ifndef IPV6 struct in_addr ip; struct sockaddr_in server_addr; int len = sizeof(struct sockaddr_in); #else struct in6_addr ip; struct sockaddr_in6 server_addr; int len = sizeof(struct sockaddr_in6); #endif /* IPV6 */ char buf[MAXLINE]; int socketfd, rc = 0, port = 0; int len2 = sizeof(buf), len3 = sizeof(KRAJ); #ifndef IPV6 /* pokusaj dobiti binary adresu iz stringa */ #ifndef SOLARIS if (inet_aton(straddr, &ip) == 0) #else if ((ip.s_addr = inet_addr(straddr)) == -1) #endif { /* ako to ne ide, pokusaj ga dobiti iz imena */ hp = gethostbyname(straddr); if (hp != NULL) memcpy(&ip.s_addr, hp->h_addr_list[0], hp->h_length); else merror("Nepoznata adresa", __LINE__); } #else if (inet_pton(AF_INET6, straddr, &ip) <= 0) { hp = gethostbyname2(straddr, AF_INET6); if (hp != NULL) memcpy(&ip, hp->h_addr_list[0], sizeof(ip.s6_addr)); else merror("Nepoznata adresa", __LINE__); } #endif /* IPV6 */ /* trazimo integer port iz stringa */ port = atoi(strport); memset(&server_addr, 0, len); /* obrisi sve */ #ifndef IPV6 /* napunimo recv_addr strukturu zeljenim podacima */ server_addr.sin_family = AF_INET; /* AF_INET */ server_addr.sin_addr.s_addr = ip.s_addr; /* salji udaljenom stroju */ server_addr.sin_port = htons(port); /* i na kojem portu */ #else server_addr.sin6_family = AF_INET6; /* AF_INET */ server_addr.sin6_addr = ip; /* salji udaljenom stroju */ server_addr.sin6_port = htons(port); /* i na kojem portu */ #endif /* IPV6 */ /* otvorimo socket ako je moguce, i to za udp/17 protokol */ #ifndef IPV6 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) merror("Greska u otvaranju socketa", __LINE__); #else if ((socketfd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) merror("Greska u otvaranju socketa", __LINE__); #endif /* IPV6 */ for (;;) { fputs("Unesi niz> ", stdout); fgets(buf, len2, stdin); /* okej, a sad posalji sve sto si primio */ if ((rc = sendto(socketfd, buf, len2, 0, (struct sockaddr*)&server_addr, len)) == -1) merror("Greska u slanju paketa", __LINE__); if (recvfrom(socketfd, buf, rc, 0, (struct sockaddr*)&server_addr, &len) == -1) merror("Greska u primanju paketa", __LINE__); fputs("Dobiveno nazad> ", stdout); fputs(buf, stdout); if (!strncmp(KRAJ, buf, len3)) break; } } int main(int argc, char **argv) { /*intro tekst */ printhelp(3); /* provjeri da li je pozvan posluzitelj.. */ if (!strncmp(argv[0], POSLUZITELJ, strlen(KLIJENT))) (argc != 2) ? printhelp(0) : dolisten(argv[1]); else /* ..ili klijent */ if (!strncmp(argv[0], KLIJENT, strlen(KLIJENT))) (argc != 3) ? printhelp(1) : doconnect(argv[1], argv[2]); else /* ili je greska! */ printhelp(2), exit(EXIT_FAILURE); return EXIT_SUCCESS; }