/* Realizarea unui cat de pe o masina la distanta, folosind * un server TFTP (implementat prin UDP-socket) */ #include #include #include #include #include #include #include extern int errno; #define ERR(S,N) {fprintf(stderr,"\n%d\n\ APEL: rcat NumeMasina NumeFisier \n",N);\ perror(S);exit(N);} #define PORT_TFTP 69 /* portul de acces TFTP */ #define BSIZE 600 /* Dimensiunea buffer-ului de date */ #define MODE "octet" #define OP_RRQ 1 #define OP_DATA 3 #define OP_ACK 4 #define OP_ERROR 5 main (argc, argv) int argc; char *argv[]; { int sock; /* Descriptorul de socket */ struct sockaddr_in server; /* Adresa serverului */ struct sockaddr_in client; /* Adresa clientului */ struct hostent *host; /* Informatia de pe hostul server */ char buffer[BSIZE], *p; int len_addr, contor; if (argc != 3) ERR ("argumente", 1); /* creaza o datagram socket */ sock = socket (AF_INET, SOCK_DGRAM, 0); client.sin_family = AF_INET; client.sin_addr.s_addr = htonl (INADDR_ANY); client.sin_port = 0; /* sistemul alege portul */ if (bind (sock, (struct sockaddr *) &client, sizeof client) < 0) ERR ("bind", 2); /* Da adresa severului */ host = gethostbyname (argv[1]); if (host == NULL) ERR (argv[1], 3); server.sin_family = AF_INET; memcpy (&server.sin_addr.s_addr, host->h_addr, host->h_length); server.sin_port = htons (PORT_TFTP); /* Construieste un pachet TFTP READ REQUEST */ *(short *) buffer = htons (OP_RRQ); /* Codul operatiei, * in ordinea de pe retea */ p = buffer + 2; strcpy (p, argv[2]); /* Numele fisierului */ p += strlen (argv[2]) + 1; /* Pastreaza zeroul terminal */ strcpy (p, MODE); /* Modul */ p += strlen (MODE) + 1; /* Pastreaza zeroul terminal */ /* Emite READ REQUEST spre serverul TFTP. Lungimea este * calculata din diferenta de pointeri */ if (sendto (sock, buffer, p - buffer, 0, (struct sockaddr *) &server, sizeof (server)) < 0) ERR ("sendto RRQ", 4); /* Cicleaza si colecteaza pachetele de date de la server, * pana cand soseste un pachet scurt. Acesta va indica EOF */ do { len_addr = sizeof (server); if ((contor = recvfrom (sock, buffer, BSIZE, 0, (struct sockaddr *) &server, &len_addr)) < 0) ERR ("recvfrom", 5); if (ntohs (*(short *) buffer) == OP_ERROR) { ERR ("recvfrom OP_ERROR", 6); } /* Ignora codul de eroare si da doar un mesaj */ else { /* A gasit un bloc bun, pe care-l scrie la iesirea standard */ write (1, buffer + 4, contor - 4); /* X */ /* Emite un pachet ACK. Numarul de bloc pentru care * se doreste ACK este deja in buffer, asa ca trebuie * pus doar codul de operatie si trimisi inapoi * primii patru octeti. Trebuie remarcat faptul ca * ACK este emis la numarul de port de la care * serverul a trimis datele, nu de la portul 69. * Adresa ceruta este deja in structura server, * in urma apelului recvfrom */ *(short *) buffer = htons (OP_ACK); if (sendto (sock, buffer, 4, 0, (struct sockaddr *) &server, sizeof (server)) < 0) ERR ("sendto ACK", 7); } } while (contor == 516); } /* Programul 3.11 Sursa fisierului rcat.c */