From ebb2a5cefca3320a0400a44205a91b4b82774375 Mon Sep 17 00:00:00 2001 From: Jack Halford Date: Wed, 5 Apr 2017 00:45:10 +0200 Subject: [PATCH] get,debug,help done. net_get/net_send in libft manage data transfer --- ftp/Makefile | 15 ++++--- ftp/auteur | 1 - ftp/includes/ft_p.h | 60 +++++++++++++++++-------- ftp/libft | 2 +- ftp/srcs/cli_do_debug.c | 26 +++++++++++ ftp/srcs/cli_do_get.c | 44 +++++++++++++++++++ ftp/srcs/cli_do_help.c | 26 +++++++++++ ftp/srcs/cli_do_local.c | 28 ++++++++++++ ftp/srcs/cli_output.c | 7 +++ ftp/srcs/client.c | 97 ++++++++++++++++++++--------------------- ftp/srcs/console_msg.c | 22 ++++++++++ ftp/srcs/ftp.c | 64 --------------------------- ftp/srcs/ftp_cmd.c | 39 ----------------- ftp/srcs/req_init.c | 19 ++++++++ ftp/srcs/serv_do_get.c | 56 ++++++++++++++++++++++++ ftp/srcs/server.c | 86 ++++++++++++++++++++++++++++-------- 16 files changed, 396 insertions(+), 196 deletions(-) delete mode 100644 ftp/auteur create mode 100644 ftp/srcs/cli_do_debug.c create mode 100644 ftp/srcs/cli_do_get.c create mode 100644 ftp/srcs/cli_do_help.c create mode 100644 ftp/srcs/cli_do_local.c create mode 100644 ftp/srcs/cli_output.c create mode 100644 ftp/srcs/console_msg.c delete mode 100644 ftp/srcs/ftp.c delete mode 100644 ftp/srcs/ftp_cmd.c create mode 100644 ftp/srcs/req_init.c create mode 100644 ftp/srcs/serv_do_get.c diff --git a/ftp/Makefile b/ftp/Makefile index 695a33b0..7624ce99 100644 --- a/ftp/Makefile +++ b/ftp/Makefile @@ -29,18 +29,23 @@ INC_DIR = includes/ OBJ_DIR = objs/ SERVER_OBJ = $(OBJ_DIR)server.o -CLIENT_OBJ = $(OBJ_DIR)client.o +CLIENT_OBJ = $(OBJ_DIR)client.o $(OBJ_DIR)cli_do_help.o SRC_BASE = \ +cli_do_debug.c\ +cli_do_get.c\ +cli_do_help.c\ +cli_do_local.c\ +cli_output.c\ client.c\ -ftp.c\ -ftp_cmd.c\ +console_msg.c\ +req_init.c\ +serv_do_get.c\ server.c SRCS = $(addprefix $(SRC_DIR), $(SRC_BASE)) OBJS = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o)) -OBJS := $(filter-out $(SERVER_OBJ), $(OBJS)) -OBJS := $(filter-out $(CLIENT_OBJ), $(OBJS)) +OBJS := $(filter-out $(SERVER_OBJ) $(CLIENT_OBJ), $(OBJS)) NB = $(words $(SRC_BASE)) INDEX = 0 diff --git a/ftp/auteur b/ftp/auteur deleted file mode 100644 index b0e9923f..00000000 --- a/ftp/auteur +++ /dev/null @@ -1 +0,0 @@ -jhalford diff --git a/ftp/includes/ft_p.h b/ftp/includes/ft_p.h index 910ebd38..1e128b73 100644 --- a/ftp/includes/ft_p.h +++ b/ftp/includes/ft_p.h @@ -15,33 +15,57 @@ # define FTP_SERVER_USAGE "%s " # define FTP_CLIENT_USAGE "%s " -# define FTP_BUF 1024 -# define FTP_READ_BUF 1024 -# define FTP_REPLY_BUF 1024 + +# define MAXLINE 256 +# define MAXSIZE 512 # include "libft.h" -# include -# include -# include -# include - -# include - # include # include -typedef struct s_ftp_reply t_ftp_reply; +# include -struct s_ftp_reply +typedef struct s_cmd_map t_cmd_map; + +struct s_cmd_map { - int code; - char *data; + char *key; + int (*f)(); + char *help; }; -extern char **g_av; +enum e_ftp +{ + REQUEST_FILE = 100, + CMD_NOT_SUPPORTED = 150, + CMD_SUPPORTED = 160, + FILENAME_OK = 700, + NO_SUCH_FILE, + TRANSFER_START, + ABORT = 800, + ERR_READ, + ERR_STAT, + ERR_MMAP, +}; -int ftp_daemon(int sock); -int ftp_spawn(int cs); -int ftp_cmd(char *cmd, t_ftp_reply *reply); +extern char **g_av; +extern int g_debug; +extern t_cmd_map g_cli_cmd[]; + +int ftp_daemon(int sock); +int ftp_spawn(int sock); +int ftp_cmd(int sock, int req); + +int serv_do_get(int sock); + +int console_msg(int level, char *str, ...); +t_cmd_map *get_cmd(char *cmd); +int cli_output(int req, char *name, char *msg); +int cli_do_help(int sock, char **av); +int cli_do_debug(int sock, char **av); +int cli_do_get(int sock, char **av); +int cli_do_local(int sock, char **av); + +int req_init(int sock, int req, char *name); #endif diff --git a/ftp/libft b/ftp/libft index 83fa039e..61ecc913 160000 --- a/ftp/libft +++ b/ftp/libft @@ -1 +1 @@ -Subproject commit 83fa039e360fc16134f1068c30dd4eb1e1c62d8c +Subproject commit 61ecc913bbc31dafab3fff2386e1cbfffd34596a diff --git a/ftp/srcs/cli_do_debug.c b/ftp/srcs/cli_do_debug.c new file mode 100644 index 00000000..e739d531 --- /dev/null +++ b/ftp/srcs/cli_do_debug.c @@ -0,0 +1,26 @@ +#include "ft_p.h" + +int g_debug; + +int cli_do_debug(int sock, char **av) +{ + (void)sock; + if (av[1] && av[2]) + return (console_msg(-1, "usage: debug [ on | off | level ]")); + if (!av[1]) + g_debug = !g_debug; + else if (ft_strcmp(av[1], "on") == 0) + g_debug = 1; + else if (ft_strcmp(av[1], "off") == 0) + g_debug = 0; + else if (ft_stris(av[1], ft_isdigit)) + g_debug = ft_atoi(av[1]); + else + { + console_msg(-1, "%s: bad debugging value", av[1]); + return (1); + } + console_msg(0, "Debugging %s (g_debug = %i)", + g_debug ? "on" : "off", g_debug); + return (0); +} diff --git a/ftp/srcs/cli_do_get.c b/ftp/srcs/cli_do_get.c new file mode 100644 index 00000000..6035f1c2 --- /dev/null +++ b/ftp/srcs/cli_do_get.c @@ -0,0 +1,44 @@ +#include "ft_p.h" + +int cli_do_get(int sock, char **av) +{ + int rep; + int num_blks; + int num_last_blk; + int i; + int fd; + + (void)av; + if (!av[1] || av[2]) + return (console_msg(-1, "usage: get ")); + if (req_init(sock, REQUEST_FILE, "PORT")) + return (1); + write(sock, av[1], ft_strlen(av[1])); + read(sock, (char*)&rep, sizeof(rep)); + if (ntohs(rep) != FILENAME_OK) + { + cli_output(REQUEST_FILE, "PORT", "no such file"); + return (1); + } + rep = htons(TRANSFER_START); + if ((fd = open_new(av[1], O_WRONLY | O_TRUNC | O_APPEND)) < 0) + rep = htons(ABORT); + write(sock, (char*)&rep, sizeof(rep)); + if (rep != htons(TRANSFER_START)) + return (1); + net_get(sock, (char*)&num_blks, sizeof(num_blks)); + net_get(sock, (char*)&num_last_blk, sizeof(num_last_blk)); + num_blks = ntohs(num_blks); + num_last_blk = ntohs(num_last_blk); + if (g_debug > 3) + { + console_msg(3, "received num_blks=[%i]", num_blks); + console_msg(3, "received num_last_blk=[%i]", num_last_blk); + } + i = -1; + while (++i < num_blks) + net_get_fd(sock, fd, MAXSIZE); + if (num_last_blk) + net_get_fd(sock, fd, MAXSIZE); + return (0); +} diff --git a/ftp/srcs/cli_do_help.c b/ftp/srcs/cli_do_help.c new file mode 100644 index 00000000..aeb2bfd0 --- /dev/null +++ b/ftp/srcs/cli_do_help.c @@ -0,0 +1,26 @@ +#include "ft_p.h" + +int cli_do_help(int sock, char **av) +{ + int i; + t_cmd_map *cmd; + + (void)sock; + (void)av; + i = 0; + while (av[++i]) + { + if (!(cmd = get_cmd(av[i]))) + console_msg(-1, "?Invalid ? command `%s'", av[i]); + else + console_msg(0, "%s\t%s", cmd->key, cmd->help); + } + if (i == 1) + { + console_msg(0, "Commands are:"); + i = -1; + while (g_cli_cmd[++i].key) + console_msg(0, "%s\n", g_cli_cmd[i].key); + } + return (0); +} diff --git a/ftp/srcs/cli_do_local.c b/ftp/srcs/cli_do_local.c new file mode 100644 index 00000000..699ba9f1 --- /dev/null +++ b/ftp/srcs/cli_do_local.c @@ -0,0 +1,28 @@ +#include "ft_p.h" + +char **environ; + +int cli_do_local(int sock, char **av) +{ + pid_t pid; + char *cmd[4]; + + (void)sock; + av++; + if ((pid = fork()) < 0) + return (1); + if (pid == 0) + { + cmd[0] = "/bin/sh"; + cmd[1] = "-c"; + cmd[2] = ft_sstrcat(av, ' '); + cmd[3] = NULL; + console_msg(3, "inside pid cmd=[%s]", cmd[2]); + execve(cmd[0], cmd, environ); + console_msg(3, "execve(2) error: %s", strerror(errno)); + exit(42); + } + console_msg(3, "waiting for local command"); + waitpid(pid, NULL, 0); + return (0); +} diff --git a/ftp/srcs/cli_output.c b/ftp/srcs/cli_output.c new file mode 100644 index 00000000..35d29caf --- /dev/null +++ b/ftp/srcs/cli_output.c @@ -0,0 +1,7 @@ +#include "ft_p.h" + +int cli_output(int req, char *name, char *msg) +{ + ft_printf("%i %s %s\n", req, name, msg); + return (0); +} diff --git a/ftp/srcs/client.c b/ftp/srcs/client.c index 27988d76..ec59b314 100644 --- a/ftp/srcs/client.c +++ b/ftp/srcs/client.c @@ -12,74 +12,71 @@ #include "ft_p.h" -int create_client(char *addr, int port) -{ - int sock; - struct protoent *proto; - struct sockaddr_in sin; +int g_debug = 0; - if (!(proto = getprotobyname("tcp"))) - return (-1); - sock = socket(PF_INET, SOCK_STREAM, proto->p_proto); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = inet_addr(addr); - if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) < 0) - return (-1); - return (sock); +int g_debug; +t_cmd_map g_cli_cmd[] = +{ + {"?", cli_do_help, "print local help information"}, + {"l", cli_do_local, "execute a local command"}, + {"debug", cli_do_debug, "toggle/set debugging mode"}, + {"get", cli_do_get, "receive file"}, + {"quit", NULL, "terminate ftp session and exit"}, + {0, 0, 0}, +}; + +t_cmd_map *get_cmd(char *cmd) +{ + int i; + + i = -1; + while (g_cli_cmd[++i].key) + { + if (ft_strcmp(g_cli_cmd[i].key, cmd) == 0) + return (&g_cli_cmd[i]); + } + return (NULL); } -void sigint_nl(int signo) +int do_client(int sock) { - (void)signo; - ft_putchar('\n'); - signal(SIGINT, SIG_DFL); - kill(SIGINT, getpid()); + char *input; + t_cmd_map *cmd; + char **av; + + while (1) + { + if (!(input = readline("ft_p> "))) + return (1); + if (*input) + { + av = ft_split_whitespaces(input); + if (!(cmd = get_cmd(av[0]))) + console_msg(-1, "?Invalid command"); + else if (cmd->f) + (cmd->f)(sock, av); + else + return (0); + ft_sstrfree(av); + } + ft_strdel(&input); + } } int main(int ac, char **av) { int port; int sock; - char buf[FTP_READ_BUF]; - char *input; - pid_t pid; - pid_t client_pid; - int status; - client_pid = getpid(); if (ac != 3) ft_usage(FTP_CLIENT_USAGE, av[0]); port = ft_atoi(av[2]); - if ((sock = create_client(av[1], port)) < 0) + if ((sock = create_client(av[1], port, "tcp")) < 0) { perror(av[0]); return (1); } - signal(SIGINT, SIG_IGN); - while (1) - { - if ((pid = fork()) < 0) - exit(1); - if (pid == 0) - { - signal(SIGINT, sigint_nl); - if (!(input = readline("ft_p> "))) - exit(1); - if (*input) - { - write(sock, input, ft_strlen(input)); - read(sock, buf, FTP_READ_BUF); - write(1, buf, ft_strlen(buf)); - } - ft_strdel(&input); - tcsetpgrp(STDIN, client_pid); - exit(0); - } - waitpid(pid, &status, 0); - if (WEXITSTATUS(status) == 1) - return (1); - } + do_client(sock); close(sock); return (0); } diff --git a/ftp/srcs/console_msg.c b/ftp/srcs/console_msg.c new file mode 100644 index 00000000..423d7343 --- /dev/null +++ b/ftp/srcs/console_msg.c @@ -0,0 +1,22 @@ +#include "ft_p.h" + +int g_debug; + +int console_msg(int level, char *str, ...) +{ + va_list ap; + + va_start(ap, str); + if (g_debug >= level) + { + if (level == -1) + ft_printf("{red}"); + if (level == 0) + ft_printf("{blu}"); + else + ft_printf("{mag}"); + ft_vdprintf(1, str, ap); + ft_printf("{eoc}\n"); + } + return (level); +} diff --git a/ftp/srcs/ftp.c b/ftp/srcs/ftp.c deleted file mode 100644 index 0098217b..00000000 --- a/ftp/srcs/ftp.c +++ /dev/null @@ -1,64 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* ft_p.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: jhalford +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2017/04/03 16:08:44 by jhalford #+# #+# */ -/* Updated: 2017/04/03 18:24:24 by jhalford ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "ft_p.h" - -char **g_av; - -int ftp_reply(int sock, t_ftp_reply *reply) -{ - write(sock, reply->data, ft_strlen(reply->data)); - return (0); -} - -int ftp_spawn(int cs) -{ - int r; - char buf[1024]; - t_ftp_reply reply; - - ft_printf("{yel}{inv}%i {gre} new connection {eoc}\n", getpid()); - while ((r = read(cs, buf, FTP_BUF)) > 0) - { - buf[r] = 0; - ft_printf("{yel}{inv}%i {eoc} received %i bytes: [%s]\n", getpid(), r, buf); - ft_bzero(&reply, sizeof(reply)); - ftp_cmd(buf, &reply); - ftp_reply(cs, &reply); - } - ft_printf("{yel}{inv}%i {red} end of connection {eoc}\n", getpid()); - close(cs); - return (0); -} - -int ftp_daemon(int sock) -{ - int cs; - struct sockaddr_in csin; - socklen_t cslen; - pid_t pid; - - while (1) - { - cs = accept(sock, (struct sockaddr*)&csin, &cslen); - if ((pid = fork()) < 0) - { - perror(g_av[0]); - return (1); - } - if (pid == 0) - exit(ftp_spawn(cs)); - close(cs); - } - close(sock); - return (0); -} diff --git a/ftp/srcs/ftp_cmd.c b/ftp/srcs/ftp_cmd.c deleted file mode 100644 index 08af8e47..00000000 --- a/ftp/srcs/ftp_cmd.c +++ /dev/null @@ -1,39 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* ftp_cmd.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: jhalford +#+ +:+ +#+ */ -/* +#+#+#+#+#+ +#+ */ -/* Created: 2017/04/03 16:42:58 by jhalford #+# #+# */ -/* Updated: 2017/04/03 18:42:32 by jhalford ### ########.fr */ -/* */ -/* ************************************************************************** */ - -#include "ft_p.h" - -t_stof g_ftp_cmdlist[] = -{ - {"ls", NULL}, - {0, 0}, -}; - -int ftp_cmd(char *cmd, t_ftp_reply *reply) -{ - char **av; - int i; - - reply->code = 0; - av = ft_split_whitespaces(cmd); - i = -1; - while (g_ftp_cmdlist[++i].key) - { - if (ft_strcmp(g_ftp_cmdlist[i].key, av[0]) == 0) - { - ft_asprintf(&reply->data, "%s: Valid command !!!\n", av[0]); - return (0); - } - } - ft_asprintf(&reply->data, "%s: ?Invalid command\n", av[0]); - return (0); -} diff --git a/ftp/srcs/req_init.c b/ftp/srcs/req_init.c new file mode 100644 index 00000000..f2494583 --- /dev/null +++ b/ftp/srcs/req_init.c @@ -0,0 +1,19 @@ +#include "ft_p.h" + +int req_init(int sock, int req, char *name) +{ + int rep; + int net_req; + + net_req = htons(req); + write(sock, (char*)&net_req, sizeof(net_req)); + read(sock, (char*)&rep, sizeof(rep)); + rep = ntohs(rep); + if (rep == CMD_SUPPORTED) + cli_output(req, name, "command succesful"); + else if (rep == CMD_NOT_SUPPORTED) + cli_output(req, name, "command not supported"); + else + cli_output(req, name, "unexpected response"); + return (rep == CMD_SUPPORTED ? 0 : 1); +} diff --git a/ftp/srcs/serv_do_get.c b/ftp/srcs/serv_do_get.c new file mode 100644 index 00000000..42db2137 --- /dev/null +++ b/ftp/srcs/serv_do_get.c @@ -0,0 +1,56 @@ +#include "ft_p.h" + +int serv_do_get(int sock) +{ + char fname[MAXLINE]; + int req; + int rep; + int fd; + struct stat stat; + char *file; + int num_blks; + int num_last_blk; + int i; + + DG("%i file requested", REQUEST_FILE); + ft_bzero(&fname, MAXLINE); + rep = htons(FILENAME_OK); + file = NULL; + if (read(sock, fname, MAXLINE) < 0) + rep = htons(ERR_READ); + else if ((fd = open(fname, O_RDONLY)) < 0) + rep = htons(NO_SUCH_FILE); + else if ((fstat(fd, &stat)) < 0) + rep = htons(ERR_STAT); + else if ((file = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) + == MAP_FAILED) + rep = htons(ERR_MMAP); + write(sock, (char*)&rep, sizeof(rep)); + + if (ntohs(rep) != FILENAME_OK) + return (1); + if (read(sock, (char*)&req, sizeof(req)) < 0) + rep = htons(ERR_READ); + DG("start transfer command, %d, received", ntohs(req)); + + num_blks = htons(stat.st_size / MAXSIZE + 1); + num_last_blk = htons(stat.st_size % MAXSIZE); + DG("telling client file has [%i] blocks", ntohs(num_blks)); + if (net_send(sock, (char*)&num_blks, sizeof(num_blks))) + DG("ACK not received on num_blks"); + DG("telling client last block has [%i] bytes", ntohs(num_last_blk)); + if (net_send(sock, (char*)&num_last_blk, sizeof(num_blks))) + DG("ACK not received on size of last block"); + + num_blks = ntohs(num_blks); + num_last_blk = ntohs(num_last_blk); + i = -1; + while (++i < num_blks) + net_send(sock, file + i * MAXSIZE, MAXSIZE); + if (num_last_blk) + net_send(sock, file + i * MAXSIZE, MAXSIZE); + + if (file && munmap(file, stat.st_size) < 0) + rep = htons(ERR_MMAP); + return (0); +} diff --git a/ftp/srcs/server.c b/ftp/srcs/server.c index c3ccb8d2..be3d790e 100644 --- a/ftp/srcs/server.c +++ b/ftp/srcs/server.c @@ -14,24 +14,74 @@ #define FTP_SERVER_USAGE "%s " -char **g_av = NULL; - -int create_server(int port) +char **g_av = NULL; +t_itof g_ftp_cmd[] = { - int sock; - struct protoent *proto; - struct sockaddr_in sin; + {REQUEST_FILE, serv_do_get}, + {0, 0}, +}; - if (!(proto = getprotobyname("tcp"))) - return (-1); - sock = socket(PF_INET, SOCK_STREAM, proto->p_proto); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(sock, (const struct sockaddr *)&sin, sizeof(sin)) < 0) - return (-1); - listen(sock, 2); - return (sock); +int ftp_cmd(int sock, int req) +{ + int i; + int msg_ok; + + i = -1; + msg_ok = htons(CMD_SUPPORTED); + while (g_ftp_cmd[++i].id) + { + if (g_ftp_cmd[i].id == req) + { + if (!(g_ftp_cmd[i].f)) + break ; + write(sock, (char *)&msg_ok, sizeof(msg_ok)); + (g_ftp_cmd[i].f)(sock); + return (0); + } + } + msg_ok = htons(CMD_NOT_SUPPORTED); + write(sock, (char *)&msg_ok, sizeof(msg_ok)); + return (1); +} + +int ftp_spawn(int sock) +{ + int req; + int r; + + DG("new connection"); + while ((r = read(sock, (char*)&req, sizeof(req))) > 0) + { + req = ntohs(req); + DG("request code [%i]", req); + ftp_cmd(sock, req); + } + DG("end of connection"); + close(sock); + return (0); +} + +int ftp_daemon(int sock) +{ + int cs; + struct sockaddr_in csin; + socklen_t cslen; + pid_t pid; + + while (1) + { + cs = accept(sock, (struct sockaddr*)&csin, &cslen); + if ((pid = fork()) < 0) + return (-1); + if (pid == 0) + { + close(sock); + exit(ftp_spawn(cs)); + } + close(cs); + } + close(sock); + return (0); } int main(int ac, char **av) @@ -43,11 +93,11 @@ int main(int ac, char **av) if (ac != 2) ft_usage(FTP_SERVER_USAGE, av[0]); port = ft_atoi(av[1]); - if ((sock = create_server(port)) < 0) + if ((sock = create_server(port, 3, "tcp")) < 0 + || ftp_daemon(sock) < 0) { perror(av[0]); return (1); } - ftp_daemon(sock); return (0); }