get,debug,help done. net_get/net_send in libft manage data transfer

This commit is contained in:
Jack Halford 2017-04-05 00:45:10 +02:00
parent 2772d8d0b3
commit ebb2a5cefc
16 changed files with 396 additions and 196 deletions

View file

@ -29,18 +29,23 @@ INC_DIR = includes/
OBJ_DIR = objs/ OBJ_DIR = objs/
SERVER_OBJ = $(OBJ_DIR)server.o 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 = \ SRC_BASE = \
cli_do_debug.c\
cli_do_get.c\
cli_do_help.c\
cli_do_local.c\
cli_output.c\
client.c\ client.c\
ftp.c\ console_msg.c\
ftp_cmd.c\ req_init.c\
serv_do_get.c\
server.c server.c
SRCS = $(addprefix $(SRC_DIR), $(SRC_BASE)) SRCS = $(addprefix $(SRC_DIR), $(SRC_BASE))
OBJS = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o)) OBJS = $(addprefix $(OBJ_DIR), $(SRC_BASE:.c=.o))
OBJS := $(filter-out $(SERVER_OBJ), $(OBJS)) OBJS := $(filter-out $(SERVER_OBJ) $(CLIENT_OBJ), $(OBJS))
OBJS := $(filter-out $(CLIENT_OBJ), $(OBJS))
NB = $(words $(SRC_BASE)) NB = $(words $(SRC_BASE))
INDEX = 0 INDEX = 0

View file

@ -1 +0,0 @@
jhalford

View file

@ -15,33 +15,57 @@
# define FTP_SERVER_USAGE "%s <port>" # define FTP_SERVER_USAGE "%s <port>"
# define FTP_CLIENT_USAGE "%s <addr> <port>" # define FTP_CLIENT_USAGE "%s <addr> <port>"
# define FTP_BUF 1024
# define FTP_READ_BUF 1024 # define MAXLINE 256
# define FTP_REPLY_BUF 1024 # define MAXSIZE 512
# include "libft.h" # include "libft.h"
# include <sys/socket.h>
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <signal.h>
# include <stdio.h> # include <stdio.h>
# include <readline/readline.h> # include <readline/readline.h>
typedef struct s_ftp_reply t_ftp_reply; # include <sys/mman.h>
struct s_ftp_reply typedef struct s_cmd_map t_cmd_map;
struct s_cmd_map
{ {
int code; char *key;
char *data; 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); extern char **g_av;
int ftp_spawn(int cs); extern int g_debug;
int ftp_cmd(char *cmd, t_ftp_reply *reply); 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 #endif

@ -1 +1 @@
Subproject commit 83fa039e360fc16134f1068c30dd4eb1e1c62d8c Subproject commit 61ecc913bbc31dafab3fff2386e1cbfffd34596a

26
ftp/srcs/cli_do_debug.c Normal file
View file

@ -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);
}

44
ftp/srcs/cli_do_get.c Normal file
View file

@ -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 <file>"));
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);
}

26
ftp/srcs/cli_do_help.c Normal file
View file

@ -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);
}

28
ftp/srcs/cli_do_local.c Normal file
View file

@ -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);
}

7
ftp/srcs/cli_output.c Normal file
View file

@ -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);
}

View file

@ -12,74 +12,71 @@
#include "ft_p.h" #include "ft_p.h"
int create_client(char *addr, int port) int g_debug = 0;
{
int sock;
struct protoent *proto;
struct sockaddr_in sin;
if (!(proto = getprotobyname("tcp"))) int g_debug;
return (-1); t_cmd_map g_cli_cmd[] =
sock = socket(PF_INET, SOCK_STREAM, proto->p_proto); {
sin.sin_family = AF_INET; {"?", cli_do_help, "print local help information"},
sin.sin_port = htons(port); {"l", cli_do_local, "execute a local command"},
sin.sin_addr.s_addr = inet_addr(addr); {"debug", cli_do_debug, "toggle/set debugging mode"},
if (connect(sock, (const struct sockaddr *)&sin, sizeof(sin)) < 0) {"get", cli_do_get, "receive file"},
return (-1); {"quit", NULL, "terminate ftp session and exit"},
return (sock); {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; char *input;
ft_putchar('\n'); t_cmd_map *cmd;
signal(SIGINT, SIG_DFL); char **av;
kill(SIGINT, getpid());
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 main(int ac, char **av)
{ {
int port; int port;
int sock; int sock;
char buf[FTP_READ_BUF];
char *input;
pid_t pid;
pid_t client_pid;
int status;
client_pid = getpid();
if (ac != 3) if (ac != 3)
ft_usage(FTP_CLIENT_USAGE, av[0]); ft_usage(FTP_CLIENT_USAGE, av[0]);
port = ft_atoi(av[2]); 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]); perror(av[0]);
return (1); return (1);
} }
signal(SIGINT, SIG_IGN); do_client(sock);
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);
}
close(sock); close(sock);
return (0); return (0);
} }

22
ftp/srcs/console_msg.c Normal file
View file

@ -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);
}

View file

@ -1,64 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ft_p.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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);
}

View file

@ -1,39 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ftp_cmd.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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);
}

19
ftp/srcs/req_init.c Normal file
View file

@ -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);
}

56
ftp/srcs/serv_do_get.c Normal file
View file

@ -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);
}

View file

@ -14,24 +14,74 @@
#define FTP_SERVER_USAGE "%s <port>" #define FTP_SERVER_USAGE "%s <port>"
char **g_av = NULL; char **g_av = NULL;
t_itof g_ftp_cmd[] =
int create_server(int port)
{ {
int sock; {REQUEST_FILE, serv_do_get},
struct protoent *proto; {0, 0},
struct sockaddr_in sin; };
if (!(proto = getprotobyname("tcp"))) int ftp_cmd(int sock, int req)
return (-1); {
sock = socket(PF_INET, SOCK_STREAM, proto->p_proto); int i;
sin.sin_family = AF_INET; int msg_ok;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = htonl(INADDR_ANY); i = -1;
if (bind(sock, (const struct sockaddr *)&sin, sizeof(sin)) < 0) msg_ok = htons(CMD_SUPPORTED);
return (-1); while (g_ftp_cmd[++i].id)
listen(sock, 2); {
return (sock); 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) int main(int ac, char **av)
@ -43,11 +93,11 @@ int main(int ac, char **av)
if (ac != 2) if (ac != 2)
ft_usage(FTP_SERVER_USAGE, av[0]); ft_usage(FTP_SERVER_USAGE, av[0]);
port = ft_atoi(av[1]); 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]); perror(av[0]);
return (1); return (1);
} }
ftp_daemon(sock);
return (0); return (0);
} }