added client/server sources

This commit is contained in:
Jack Halford 2017-11-08 17:23:37 +01:00
parent 21f1af7011
commit 5b370b6a43
14 changed files with 625 additions and 0 deletions

20
ftp/srcs/client/cli_ls.c Normal file
View file

@ -0,0 +1,20 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_ls.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/08 13:43:10 by jhalford #+# #+# */
/* Updated: 2017/11/08 13:50:20 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_client.h"
int cli_ls(int sock, char **av)
{
(void)sock;
(void)av;
return (0);
}

90
ftp/srcs/client/client.c Normal file
View file

@ -0,0 +1,90 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* client.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/04/02 19:18:31 by jhalford #+# #+# */
/* Updated: 2017/11/08 15:12:12 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_client.h"
int g_debug = 0;
int g_debug;
t_cmd_map g_cli_cmd[] =
{
{"ls", cli_ls, "list contents of remote directory"},
/* {"cd", cli_do_cd, "change remote working directory"}, */
/* {"get", cli_do_get, "receive file"}, */
/* {"put", cli_do_put, "send one file"}, */
/* {"pwd", cli_do_sh, "print working directory on remote machine"}, */
/* {"quit", NULL, "terminate ftp session and exit"}, */
/* {"?", cli_do_help, "print local help information"}, */
/* {"l", cli_do_local, "execute a local command"}, */
/* {"debug", cli_do_debug, "toggle/set debugging mode"}, */
{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);
}
int do_client(int sock)
{
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)
{
(void)sock;
(cmd->f)(sock, av);
}
else
return (0);
ft_sstrfree(av);
}
ft_strdel(&input);
}
}
int main(int ac, char **av)
{
int port;
int sock;
if (ac != 3)
ft_usage(FTP_CLIENT_USAGE, av[0]);
port = ft_atoi(av[2]);
if ((sock = create_client(av[1], port, "tcp")) < 0)
{
perror(av[0]);
return (1);
}
do_client(sock);
close(sock);
return (0);
}

25
ftp/srcs/server/cmd_cwd.c Normal file
View file

@ -0,0 +1,25 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_cwd.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/02 13:36:24 by jhalford #+# #+# */
/* Updated: 2017/11/02 15:24:00 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_cwd(t_ftp *ftp, char **av)
{
if (chdir(av[1]))
{
console_msg(1, "chdir(%s) failed errno=%i", av[1], errno);
ftp_ret(ftp, "550 file not found");
}
else
ftp_ret(ftp, "200 success");
return (1);
}

View file

@ -0,0 +1,31 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_list.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/01 19:22:12 by jhalford #+# #+# */
/* Updated: 2017/11/08 17:19:24 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_list(t_ftp *ftp, char **av)
{
pid_t pid;
int status;
if (dconn_open(ftp) < 0)
return (-1);
if ((pid = fork()) < 0)
perror("fork");
else if (pid == 0)
{
dup2(ftp->d_sock, 1);
execl("/bin/ls", "ls", "-lA", av[1], NULL);
}
waitpid(pid, &status, 0);
return (dconn_close(ftp));
}

View file

@ -0,0 +1,48 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_pasv.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/08 13:54:57 by jhalford #+# #+# */
/* Updated: 2017/11/08 17:15:09 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_pasv(t_ftp *ftp, char **av)
{
uint16_t port;
int sock;
struct sockaddr_in sin;
(void)av;
return (ftp_ret(ftp, "502 not implemented"));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
port = 35000;
while (++port < USHRT_MAX)
{
sin.sin_port = htons(port);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (bind(sock, (const struct sockaddr *)&sin,
sizeof(struct sockaddr_in)) == 0
&& listen(sock, 3) == 0)
{
ftp->data_state = DATA_PASV;
ftp->dconn.sock = sock;
console_msg(1, "listening on %i (PASV)", port);
return (ftp_ret(ftp, "227 %i,%i,%i,%i,%i,%i",
(ntohl(sin.sin_addr.s_addr) >> (8*3)) & 0xff,
(ntohl(sin.sin_addr.s_addr) >> (8*2)) & 0xff,
(ntohl(sin.sin_addr.s_addr) >> (8*1)) & 0xff,
(ntohl(sin.sin_addr.s_addr) >> (8*0)) & 0xff,
(ntohs(sin.sin_port) >> (8*1)) & 0xff,
(ntohs(sin.sin_port) >> (8*0)) & 0xff
));
}
}
return (ftp_ret(ftp, "500 couldn't find local port"));
}

View file

@ -0,0 +1,39 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_port.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/01 18:42:50 by jhalford #+# #+# */
/* Updated: 2017/11/08 17:17:44 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_port(t_ftp *ftp, char **av)
{
char **hostport;
char buf[INET_ADDRSTRLEN];
if (!av[1])
return (ftp_ret(ftp, "501 syntax error in parameter"));
if (ftp->data_state == DATA_PASV)
close(ftp->dconn.sock);
hostport = ft_strsplit(av[1], ',');
ftp->dconn.sin.sin_family = AF_INET;
ftp->dconn.sin.sin_port = htons(256 * ft_atoi(hostport[4])
+ ft_atoi(hostport[5]));
ftp->dconn.sin.sin_addr.s_addr =
htonl(
256 * 256 * 256 * ft_atoi(hostport[0])
+ 256 * 256 * ft_atoi(hostport[1])
+ 256 * ft_atoi(hostport[2])
+ ft_atoi(hostport[3]));
ftp->data_state = DATA_ACTV;
console_msg(1, "remote dconn @ %s:%i",
inet_ntop(AF_INET, &ftp->dconn.sin.sin_addr, buf, sizeof(struct sockaddr_in)),
ntohs(ftp->dconn.sin.sin_port));
return (ftp_ret(ftp, "200 ip/port ok"));
}

23
ftp/srcs/server/cmd_pwd.c Normal file
View file

@ -0,0 +1,23 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* pwd.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/01 17:39:01 by jhalford #+# #+# */
/* Updated: 2017/11/02 14:18:58 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_pwd(t_ftp *ftp, char **av)
{
char path[200];
(void)av;
getcwd(path, 200);
ftp_ret(ftp, "257 \"%s\"", path);
return (0);
}

View file

@ -0,0 +1,22 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_quit.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/02 15:20:58 by jhalford #+# #+# */
/* Updated: 2017/11/02 15:31:17 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_quit(t_ftp *ftp, char **av)
{
(void)av;
close(ftp->cmd_sock);
ftp->cmd_sock = 0;
ftp_ret(ftp, "221 service closing control connection");
return (1);
}

View file

@ -0,0 +1,42 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_retr.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/02 15:32:28 by jhalford #+# #+# */
/* Updated: 2017/11/08 15:12:28 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_retr(t_ftp *ftp, char **av)
{
int sock;
int fd;
struct stat buf;
char *file;
int i;
char **split;
sock = dconn_open(ftp);
if ((fd = open(av[1], O_RDONLY)) < 0 || fstat(fd, &buf) < 0)
return (ftp_ret(ftp, "550 file not found / no access"));
if (buf.st_size)
{
if ((file = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0))
== MAP_FAILED)
return (ftp_ret(ftp, "550 mmap failed"));
split = ft_strsplit(file, '\n');
i = -1;
while (split[++i])
ftp_send(sock, split[i]);
ft_sstrfree(split);
munmap(file, buf.st_size);
}
ftp_ret(ftp, "226 closing dataconn");
close(sock);
return (0);
}

View file

@ -0,0 +1,33 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_stor.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/02 16:01:54 by jhalford #+# #+# */
/* Updated: 2017/11/08 17:09:21 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_stor(t_ftp *ftp, char **av)
{
int sock;
int fd;
char *msg;
sock = dconn_open(ftp);
if ((fd = open(av[1], O_WRONLY | O_CREAT, 0644)) < 0)
return (ftp_ret(ftp, "550 couldn't open/create file"));
while (1)
{
if (ftp_recv(sock, &msg))
break ;
write(fd, msg, ft_strlen(msg));
ft_strdel(&msg);
}
dconn_close(ftp);
return (0);
}

View file

@ -0,0 +1,30 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_file.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/01 18:14:51 by jhalford #+# #+# */
/* Updated: 2017/11/02 15:49:12 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_type(t_ftp *ftp, char **av)
{
if (!av[1])
ftp_ret(ftp, "501 syntax error in parameter");
if (av[1][0] == 'A')
{
ftp_ret(ftp, "200 type A ok");
}
else if (av[1][0] == 'I')
{
ftp_ret(ftp, "200 type A ok");
}
else
ftp_ret(ftp, "500 parameter unrecognized");
return (1);
}

View file

@ -0,0 +1,29 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* cmd_user.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/02 14:20:46 by jhalford #+# #+# */
/* Updated: 2017/11/08 15:14:02 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
int cmd_user(t_ftp *ftp, char **av)
{
ft_strcpy(ftp->username, av[1]);
ft_strcpy(ftp->path, REPOPATH);
ft_strcat(ftp->path, av[1]);
if (mkdir(ftp->path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0
&& chdir(ftp->path) < 0)
return (ftp_ret(ftp, "530 mkdir/chdir"));
if (getcwd(ftp->path, 100) < 0)
return (ftp_ret(ftp, "530 getcwd"));
ftp_ret(ftp, "230 user '%s' logged in, proceed", ftp->username);
console_msg(1, "logon: %s@ftp://%s", ftp->username, ftp->path);
ftp->log_state = LOG_YES;
return (0);
}

69
ftp/srcs/server/dconn.c Normal file
View file

@ -0,0 +1,69 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* dconn.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/11/08 14:55:15 by jhalford #+# #+# */
/* Updated: 2017/11/08 17:22:37 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
static int dconn_open_actv(t_ftp *ftp)
{
int sock;
ftp_ret(ftp, "150 about to open data connection");
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connect(sock, (struct sockaddr*)&ftp->dconn.sin,
sizeof(struct sockaddr_in)) < 0)
{
ftp_ret(ftp, "425 can't open data conn");
return(-1);
}
ftp->d_sock = sock;
return (0);
}
static int dconn_open_pasv(t_ftp *ftp)
{
int sock;
ftp_ret(ftp, "150 about to accept");
if ((sock = accept(ftp->dconn.sock, NULL, NULL)) < 0)
{
ftp_ret(ftp, "425 can't open data conn");
return(-1);
}
ftp->d_sock = sock;
return (0);
}
int dconn_open(t_ftp *ftp)
{
if (ftp->d_sock)
{
ftp_ret(ftp, "125 data connection already open; transfer starting");
return (0);
}
else if (ftp->data_state == DATA_ACTV)
return (dconn_open_actv(ftp));
else if (ftp->data_state == DATA_PASV)
return (dconn_open_pasv(ftp));
else
{
console_msg(1, "dconn_open() called but no dconn available");
return (-1);
}
}
int dconn_close(t_ftp *ftp)
{
return (ftp_ret(ftp, "226 closing dataconn"));
close(ftp->d_sock);
ftp->d_sock = 0;
return (0);
}

124
ftp/srcs/server/server.c Normal file
View file

@ -0,0 +1,124 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* server.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: jhalford <jack@crans.org> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2017/04/02 15:02:48 by jhalford #+# #+# */
/* Updated: 2017/11/08 16:39:15 by jhalford ### ########.fr */
/* */
/* ************************************************************************** */
#include "ftp_server.h"
#define FTP_SERVER_USAGE "%s <port>"
char **g_av = NULL;
char g_rootdir[PATH_MAX];
t_ftp_cmd g_ftp_cmd[] =
{
{"USER", cmd_user, 0},
{"QUIT", cmd_quit, 0},
{"RETR", cmd_retr, LOG_YES},
{"STOR", cmd_stor, LOG_YES},
{"CWD", cmd_cwd, LOG_YES},
{"PASV", cmd_pasv, LOG_YES},
{"PORT", cmd_port, LOG_YES},
{"PWD", cmd_pwd, LOG_YES},
{"TYPE", cmd_type, LOG_YES},
{"LIST", cmd_list, LOG_YES},
{0, 0, 0},
};
int g_debug = 2;
int ftp_cmd(t_ftp *ftp)
{
int i;
char *msg;
char **av;
ftp_recv(ftp->cmd_sock, &msg);
i = -1;
while (g_ftp_cmd[++i].name)
{
if (ft_strncmp(msg, g_ftp_cmd[i].name,
ft_strlen(g_ftp_cmd[i].name)) == 0)
{
if (ftp->log_state < g_ftp_cmd[i].statelock)
{
return (ftp_ret(ftp, "530 not logged in"));
}
if (!(g_ftp_cmd[i].f))
break ;
else
{
av = ft_strsplit(msg, ' ');
return (g_ftp_cmd[i].f(ftp, av));
ft_sstrfree(av);
}
return (0);
}
}
ftp_ret(ftp, "502 command not implemented");
ft_strdel(&msg);
return (1);
}
int ftp_spawn(int sock)
{
t_ftp ftp;
ftp.cmd_sock = sock;
ftp.log_state = LOG_NONE;
ftp.d_sock = 0;
ftp.data_state = 0;
ftp_ret(&ftp, "220 ready for user");
while (ftp.cmd_sock)
ftp_cmd(&ftp);
close(ftp.cmd_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 port;
int sock;
g_av = av;
getcwd(g_rootdir, PATH_MAX);
if (ac != 2)
ft_usage(FTP_SERVER_USAGE, av[0]);
port = ft_atoi(av[1]);
if ((sock = create_server(port, 3, "tcp")) < 0
|| ftp_daemon(sock) < 0)
{
perror(av[0]);
return (1);
}
return (0);
}