#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "jsockets.h"
int servidor(short puerto);
int cliente(const char *host, short puerto, const char *archivo);
ssize_t reeead(int socket, void *buf, size_t n);
uint32_t transmitir(int fd_from, int fd_to, uint32_t total);
void entierra_hijos(int senal);
int atender_cliente(int socket_cliente);
int main(int argc, char *argv[]) {
if (argc > 1) {
if (!strcmp("servidor", argv[1])) {
return servidor((short)atoi(argv[2]));
} else if (!strcmp("cliente", argv[1])) {
return cliente(argv[2], (short)atoi(argv[3]), argv[4]);
}
} else {
printf("Uso: %s {servidor PUERTO | cliente SERVIDOR PUERTO ARCHIVO}\n", argv[0]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int cliente(const char *host, short puerto, const char *archivo) {
struct stat st; int socket, fd, ok; uint32_t size;
if (stat(archivo, &st)) {
perror(NULL);
return 2;
}
socket = j_socket(); if (j_connect(socket, host, puerto)) {
printf("No se pudo conectar a %s:%i\n", host, puerto);
return 3;
}
printf("Transmitiendo nombre de archivo: %s\n", archivo);
write(socket, archivo, sizeof(*archivo) * (strlen(archivo) + 1)); printf("Transmitiendo tamaño: %u\n", (unsigned int)st.st_size);
size = htonl(st.st_size);
write(socket, &size, sizeof(size)); fd = open(archivo, O_RDONLY); ok = EXIT_SUCCESS;
if (transmitir(fd, socket, st.st_size) != st.st_size) {
printf("Error en la transmisión.\n");
ok = EXIT_FAILURE;
}
close(fd); close(socket); return ok;
}
void entierra_hijos(int senal) {
int status;
wait(&status);
}
int servidor(short puerto) {
int socket, socket_cliente;
socket = j_socket(); if (j_bind(socket, puerto)) {
printf("No se pudo bind al puerto %i\n", puerto);
return 2;
}
signal(SIGCHLD, entierra_hijos);
printf("Escuchando en el puerto %i...\n", puerto);
do {
while ((socket_cliente = j_accept(socket)) >= 0) {
printf("Conexión aceptada.\n");
switch (fork()) {
case 0: { int ok;
close(socket);
ok = atender_cliente(socket_cliente);
close(socket_cliente);
exit(ok);
}
case -1:
break;
default: close(socket_cliente);
}
}
} while (errno == EINTR);
return EXIT_FAILURE;
}
uint32_t transmitir(int fd_from, int fd_to, uint32_t total) {
char buf[1024];
uint32_t transmitido = 0;
while (transmitido < total) {
size_t leido, leer = total - transmitido;
if (leer > sizeof(buf) / sizeof(*buf)) {
leer = sizeof(buf) / sizeof(*buf);
}
leido = reeead(fd_from, buf, leer);
if (leido != leer) {
return transmitido;
}
if (write(fd_to, buf, leido) != leido) {
perror(NULL);
return transmitido;
}
transmitido += leido;
printf("#");
}
printf("\n");
return transmitido;
}
ssize_t reeead(int socket, void *buf, size_t n) {
size_t bcount = 0, br;
while(bcount < n) {
if((br = read(socket, buf, n - bcount)) > 0) {
bcount += br;
buf = ((char *)buf) + br;
} else if (br < 0) {
break;
}
}
if (br < 0)
return -1;
return bcount;
}
int atender_cliente(int socket_cliente) {
int ok, fd_archivo;
char nombre_archivo[512 + 1];
uint32_t largo_nombre_archivo = 0, size;
while (
largo_nombre_archivo < sizeof(nombre_archivo) / sizeof(*nombre_archivo) - 1 &&
(largo_nombre_archivo == 0 || nombre_archivo[largo_nombre_archivo - 1] != '\0')
) {
reeead(socket_cliente, nombre_archivo + largo_nombre_archivo, sizeof(*nombre_archivo));
++largo_nombre_archivo;
}
nombre_archivo[largo_nombre_archivo] = '\0';
printf("Recibiendo archivo: %s\n", nombre_archivo);
reeead(socket_cliente, &size, sizeof(size)); size = ntohl(size);
printf("Recibiendo Tamaño: %u\n", (unsigned int)size);
fd_archivo = open(nombre_archivo, O_WRONLY | O_CREAT);
if (fd_archivo < 0) {
perror(NULL);
return EXIT_FAILURE;
}
ok = EXIT_SUCCESS;
if (transmitir(socket_cliente, fd_archivo, size) != size) {
printf("Error en la recepción.\n");
ok = EXIT_FAILURE;
}
close(fd_archivo); return ok;
}