/* Servidor para el ejemplo de sendfile. uso: server [puerto] Copyright (C) 2003 Jeff Tranter. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int port = 1234; /* número de puerto a utilizar */ int sock; /* indicador del socket */ int desc; /* indicador del archivo para el socket */ int fd; /* indicador del archivo a enviar */ struct sockaddr_in addr; /* parámetros del socket para bind */ struct sockaddr_in addr1; /* parámetros del socket para accept */ int addrlen; /* argumento para accept */ struct stat stat_buf; /* argumentos para fstat */ off_t offset = 0; /* offset del archivo */ char filename[PATH_MAX]; /* nombre del archivo a enviar */ int rc; /* mantiene el código de regreso de las llamadas de sistema */ /* verifica los argumentos de la línea de comando, manejando un número de puerto opcional */ if (argc == 2) { port = atoi(argv[1]); if (port <= 0) { fprintf(stderr, "puerto inválido: %s\n", argv[1]); exit(1); } } else if (argc != 1) { fprintf(stderr, "uso: %s [puerto]\n", argv[0]); exit(1); } /* crear un socket de Internet */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { fprintf(stderr, "no se pudo crear el socket: %s\n", strerror(errno)); exit(1); } /* llenar la estructura del socket */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); /* enlazar el socket al puerto */ rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); if (rc == -1) { fprintf(stderr, "no se pudo abrir el socket: %s\n", strerror(errno)); exit(1); } /* leer el socket para conexiones de los clientes */ rc = listen(sock, 1); if (rc == -1) { fprintf(stderr, "no se puede leer el socket: %s\n", strerror(errno)); exit(1); } while (1) { /* esperar la conexión de un cliente */ desc = accept(sock, (struct sockaddr *) &addr1, &addrlen); if (desc == -1) { fprintf(stderr, "accept failed: %s\n", strerror(errno)); exit(1); } /* leer el nombre de archivo del cliente */ rc = recv(desc, filename, sizeof(filename), 0); if (rc == -1) { fprintf(stderr, "recv failed: %s\n", strerror(errno)); exit(1); } /* terminar en null y quitar cualquier \r y \n del nombre de archivo */ filename[rc] = '\0'; if (filename[strlen(filename)-1] == '\n') filename[strlen(filename)-1] = '\0'; if (filename[strlen(filename)-1] == '\r') filename[strlen(filename)-1] = '\0'; /* terminar la ejecución del servidor si el nombre de archivo es "quit" */ if (strcmp(filename, "quit") == 0) { fprintf(stderr, "se recibió el comando quit, apagando el servidor\n"); break; } fprintf(stderr, "se recibió petición para enviar el archivo %s\n", filename); /* abrir el archivo que va a enviarse */ fd = open(filename, O_RDONLY); if (fd == -1) { fprintf(stderr, "no se pudo abrir '%s': %s\n", filename, strerror(errno)); exit(1); } /* obtener el tamaño del archivo que se va a enviar */ fstat(fd, &stat_buf); /* copiar el archivo usando sendfile */ offset = 0; rc = sendfile (desc, fd, &offset, stat_buf.st_size); if (rc == -1) { fprintf(stderr, "error de sendfile: %s\n", strerror(errno)); exit(1); } if (rc != stat_buf.st_size) { fprintf(stderr, "transferencia incompleta de sendfile: %d of %d bytes\n", rc, (int)stat_buf.st_size); exit(1); } /* cerrar el indicador del archivo enviado */ close(fd); /* cerrar el indicador del socket */ close(desc); } /* cerrar el socket */ close(sock); return 0; }