/* ***************************************** */ /* Laboration 2 i Datakommunikation 2 */ /* RPC-lib */ /* ***************************************** */ /* s_stub.c */ /* Ansvarar för att operationer utförs */ /* utförs på rätt sätt i servern */ /* ***************************************** */ /* Christian Ohlsson, di7chro@cse.kau.se */ /* Stefan Sonesson, di7stes@cse.kau.se */ /* ***************************************** */ #include "header.h" /* Globala variabler */ int data_sockfd; /* Den socket som data färdas på */ msg myMsg; /* Meddelandet som funktionerna fyller i */ /* ============================================== printsin() Skriver ut information om klienten ============================================== */ printsin(struct sockaddr_in *sin, char *m1, char *m2 ) { struct hostent *gethostbyaddr(), *h; printf ("%s %s\n", m1, m2); printf ("Family %d addr %x port %d\n", sin -> sin_family, ntohl(sin -> sin_addr.s_addr), ntohs(sin -> sin_port)); h = gethostbyaddr((char *)&sin->sin_addr, sizeof(int), AF_INET); printf ("Symbolic host name <%s>\n",h->h_name); } /* ============================================== rem_open() Öppnar en fil och fyller i data såsom längd och fildeskriptor i strukten. ============================================== */ void rem_open() { int fd; struct stat st; if((fd = open(myMsg.path, O_CREAT|O_RDWR|O_APPEND, PERMS)) < 0) { myMsg.op = OPN; /* Skicka fel till klient */ return; } fstat(fd, &st); myMsg.length = st.st_size; myMsg.op = OPP; /* Operationen gick bra */ myMsg.fd = fd; } /* ============================================== rem_read() Läser data ur en fil tills EOF tecknet nås och dessa tecken stoppas i en buffer, som slutligen returneras ============================================== */ char *rem_read() { char *buf; int fd; lseek(myMsg.fd, 0, SEEK_SET); buf = (char*)malloc(myMsg.length); if((read(myMsg.fd, buf, myMsg.length)) < 0) myMsg.op = RDN; /* Skicka fel till klient */ else myMsg.op = RDP; /* Operationen gick bra */ return buf; } /* ============================================== rem_write() Skriver tecken till fil ============================================== */ void rem_write() { if((write(myMsg.fd, myMsg.data, myMsg.length)) < 0) myMsg.op = WRN; /* Skicka fel till klient */ else myMsg.op = WRP; /* Operationen gick bra */ } /* ============================================== rem_delete() Tar bort en fil mha unlink, som egentligen räknar ner antalet länkar till en fil ============================================== */ int rem_delete() { if((unlink(myMsg.path)) < 0) { myMsg.op = DLN; /* Skicka fel till klient */ return 0; } else { myMsg.op = DLP; /* Operationen gick bra */ return 1; } } /* ============================================== rem_close() Stänger en fil. Returnerar svar om hur det gick ============================================== */ int rem_close() { if((close(myMsg.fd)) < 0) { myMsg.op = CLN; /* Skicka fel till klient */ return 0; } else { myMsg.op = CLP; /* Operationen gick bra */ return 1; } } /* ============================================== rem_exit() Stänger datasocketen vid fel. Avslutar programmet ============================================== */ void rem_exit() { puts("Quitting"); close(data_sockfd); exit(0); } /* ============================================== main() Sköter uppkoppling och lyssnar efter klienter ============================================== */ main() { int listener, client_length, length, val, again; char *bytes; struct sockaddr_in srvr_addr, client_addr; signal(SIGCHLD, SIG_IGN); signal(SIGINT, rem_exit); /* Skapa en socket som lyssnar efter uppkopplingar */ if((listener = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) { perror("server: can't open stream socket"); exit(0); } /* Nolla ut strukten */ bzero((char *) &srvr_addr, sizeof(srvr_addr)); srvr_addr.sin_family = AF_INET; srvr_addr.sin_addr.s_addr = htons(INADDR_ANY); srvr_addr.sin_port = PORT; /* Bind ett namn till socketen */ if(bind(listener, (struct sockaddr *)&srvr_addr, sizeof(srvr_addr)) < 0) { perror("server: can't bind local address"); exit(0); } length = sizeof(srvr_addr); while(TRUE) { /* Hämta namnet på socketen */ if(getsockname(listener, (struct sockaddr *)&srvr_addr, &length) < 0) { perror("server: can't get sockname"); exit(0); } printf("Port number %d\n", ntohs(srvr_addr.sin_port)); /* Lyssna efter uppkopplingar */ listen(listener, MAXCONNECTED); client_length = sizeof(client_addr); /* Acceptera den nya uppkopplingen */ if ((data_sockfd=accept(listener, (struct sockaddr *)&client_addr, &length)) < 0) { perror("server: accept error"); exit(0); } /*printsin(&client_addr,"\nRSTREAM", "accepted connection from");*/ again=1; while(again) { /* Läs data från socketen */ if((read(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); switch(myMsg.op) { case OP: /* Klienten vill öppna en fil */ rem_open(); if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); break; case RD: /* Klienten vill läsa från en fil */ bytes = rem_read(); if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); if((write(data_sockfd, bytes, myMsg.length)) < 0) rem_exit(); break; case WR: /* Klienten vill skriva till en fil */ if((myMsg.data = (char*)malloc(myMsg.length)) == NULL) { myMsg.op = WRN; /* Om minne inte kunde allokeras */ if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); } if((read(data_sockfd, myMsg.data, myMsg.length)) < 0) rem_exit(); rem_write(); if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); free(myMsg.data); break; case DEL:/* Klienten vill ta bort en fil */ val = rem_delete(); if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); if(val == 1) { close(data_sockfd); again=0; } break; case CL: /* Klienten vill stänga en fil */ val = rem_close(); if((write(data_sockfd, &myMsg, sizeof(myMsg))) < 0) rem_exit(); if(val == 1) { close(data_sockfd); again=0; } break; default: break; } } } }