-
-
Save felis-ron-silvestris/3166380 to your computer and use it in GitHub Desktop.
sendfile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <sys/sendfile.h> | |
#include <stdio.h> | |
#include <netinet/in.h> | |
#include <signal.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include <string.h> | |
#define _GNU_SOURCE | |
#include <fcntl.h> | |
#include <sys/uio.h> | |
#include <limits.h> | |
#include <features.h> | |
#ifndef _MAX_SIZE_ | |
#define _MAX_SIZE_ 80 | |
#endif /* _MAX_SIZE_ */ | |
#ifndef _SERVER_PORT_ | |
#define _SERVER_PORT_ 9734 | |
#endif /* _SERVER_PORT_ */ | |
#ifndef _USER_PRESENT_ | |
#define _USER_PRESENT_ 1 | |
#endif /* _USER_PRESENT_ */ | |
#ifndef _USER_NOT_PRESENT_ | |
#define _USER_NOT_PRESENT_ -1 | |
#endif /* _USER_NOT_PRESENT_ */ | |
#ifndef SPLICE_F_MOVE | |
#define SPLICE_F_MOVE 0x01 | |
#endif | |
#ifndef SPLICE_F_NONBLOCK | |
#define SPLICE_F_NONBLOCK 0x02 | |
#endif | |
#ifndef SPLICE_F_MORE | |
#define SPLICE_F_MORE 0x04 | |
#endif | |
#ifndef SPLICE_F_GIFT | |
#define SPLICE_F_GIFT 0x08 | |
#endif | |
#ifndef MIN | |
#define MIN(x, y) ((x) < (y) ? (x) : (y)) | |
#endif /* MIN */ | |
int err_num; | |
char username_string[15]; | |
struct sockaddr_in server_address; | |
struct sockaddr_in client_address; | |
/* get username from the client */ | |
void get_usrname_credentials(int sock_fd, int c_len); | |
void receive_mail(char *filename, int sock_fd); | |
/* receive file */ | |
ssize_t do_recvfile(int output_fd, int sock_fd, off_t offset, size_t count); | |
/* check if the username is present */ | |
int check_username_credentials(char *username); | |
int main(int argc, char **argv) | |
{ | |
int backlog = 5; | |
/* server socket file descriptor */ | |
int server_socket_fd; | |
/* client socket file descriptor */ | |
int client_socket_fd; | |
int server_length; | |
int client_length; | |
int rc; | |
int on = 1; | |
server_socket_fd = socket(AF_INET, SOCK_STREAM, 0); | |
if (server_socket_fd < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"socket\" error: %s\n", strerror(err_num)); | |
exit(EXIT_FAILURE); | |
} | |
/* allow socket descriptor to be reusable */ | |
rc = setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); | |
/* checking for "setsockopt" errors */ | |
if (rc < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"setsockopt\" error: %s\n", strerror(err_num)); | |
close(server_socket_fd); | |
exit(EXIT_FAILURE); | |
} | |
/* init server info */ | |
memset(&server_address, 0, sizeof(server_address)); | |
server_address.sin_family = AF_INET; | |
server_address.sin_addr.s_addr = htonl(INADDR_ANY); | |
server_address.sin_port = htons(_SERVER_PORT_); | |
server_length = sizeof(server_address); | |
/* bind (checking for errors) */ | |
if ((bind(server_socket_fd, (struct sockaddr *)&server_address, server_length)) < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"bind\" error: %s\n", strerror(err_num)); | |
close(server_socket_fd); | |
exit(EXIT_FAILURE); | |
} | |
/* listen (checking for errors) */ | |
if ((listen(server_socket_fd, backlog)) < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"listen\" error: %s\n", strerror(err_num)); | |
close(server_socket_fd); | |
exit(EXIT_FAILURE); | |
} | |
signal(SIGCHLD, SIG_IGN); | |
for (;;) | |
{ | |
char ch; | |
(void)fprintf(stdout, "\nServer waiting\n"); | |
/* accept the connection */ | |
client_length = sizeof(client_address); | |
client_socket_fd = accept(server_socket_fd, (struct sockaddr *)&client_address, &client_length); | |
/* checking for "accept" errors */ | |
if (client_socket_fd < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"accept\" error: %s\n", strerror(err_num)); | |
exit(EXIT_FAILURE); | |
} | |
(void)fprintf(stdout, "\nAccept completed successfully\n"); | |
/* fork to create a process for this client */ | |
if (fork() == 0) | |
{ | |
/* receive e-mail */ | |
receive_mail("mail_rc", client_socket_fd); | |
//get_usrname_credentials(client_socket_fd, client_length); | |
/* five seconds delay */ | |
sleep(5); | |
/* | |
(void)fprintf(stdout, "Username from client: %s\n", username_string); | |
if ((check_username_credentials(username_string)) < 0) | |
{ (void)fprintf(stderr, "Utente non presente\n"); exit(0); } | |
*/ | |
exit(0); | |
} | |
else | |
{ close(client_socket_fd); } | |
} | |
return 0; | |
} | |
/* check if the username is present */ | |
int check_username_credentials(char *username) | |
{ | |
if (!(strcmp(username, "root"))) | |
{ return (1); } | |
else | |
{ return (-1); } | |
} | |
void get_usrname_credentials(int sock_fd, int c_len) | |
{ | |
struct msghdr username_cred; | |
struct iovec iov; | |
username_cred.msg_name = &client_address; | |
username_cred.msg_namelen = c_len; | |
username_cred.msg_iov = &iov; | |
username_cred.msg_iovlen = 1; | |
username_cred.msg_iov->iov_base = username_string; | |
username_cred.msg_iov->iov_len = 15; | |
username_cred.msg_control = 0; | |
username_cred.msg_controllen = 0; | |
username_cred.msg_flags = 0; | |
recvmsg(sock_fd, &username_cred, 0); | |
close(sock_fd); | |
} | |
/* receive e-mail */ | |
void receive_mail(char *filename, int sock_fd) | |
{ | |
/* file descriptor for destination file */ | |
int destination_fd; | |
/* byte offset used by sendfile */ | |
off_t offset = 0; | |
size_t total_bytes_sent = 0; | |
struct stat stat_buf; | |
struct stat info_src; | |
/* open destination file */ | |
destination_fd = open(filename, O_WRONLY | O_CREAT); | |
/* checking for "open" errors */ | |
if (destination_fd < 0) | |
{ exit(EXIT_FAILURE); } | |
fstat(destination_fd, &stat_buf); | |
(void)fprintf(stdout, "File size: %jd\n", (intmax_t)stat_buf.st_size); | |
/* receive file */ | |
total_bytes_sent = do_recvfile(destination_fd, sock_fd, offset, 18 /* DUNNO WHAT TO DO HERE */); | |
(void)fprintf(stdout, "Total bytes sent: %d\n", total_bytes_sent); | |
close(destination_fd); | |
} | |
/* receive file */ | |
ssize_t do_recvfile(int output_fd, int sock_fd, off_t offset, size_t count) | |
{ | |
ssize_t bytes; | |
ssize_t bytes_sent; | |
ssize_t bytes_in_pipe; | |
size_t total_bytes_sent = 0; | |
/* pipe */ | |
static int pipefd[2]; | |
/* setup the pipe */ | |
if (pipe(pipefd) < 0) | |
{ | |
err_num = errno; | |
(void)fprintf(stderr, "\"pipe\" error:%s\n", strerror(err_num)); | |
exit(EXIT_FAILURE); | |
} | |
/* splice the data from "sock_fd" into the pipe */ | |
while (total_bytes_sent < count) | |
{ | |
if ((bytes_sent = splice(sock_fd, NULL, pipefd[1], NULL, MIN(count - total_bytes_sent, 16384), SPLICE_F_MORE | SPLICE_F_MOVE)) <= 0) | |
{ | |
if (errno == EINTR || errno == EAGAIN) | |
{ continue; } | |
err_num = errno; | |
(void)fprintf(stderr, "\"splice\" error (bytes_sent): %s\n", strerror(err_num)); | |
return (-1); | |
} | |
bytes_in_pipe = bytes_sent; | |
while (bytes_in_pipe > 0) | |
{ | |
if ((bytes = splice(pipefd[0], NULL, output_fd, &offset, bytes_in_pipe, SPLICE_F_MORE | SPLICE_F_MOVE)) <= 0) | |
{ | |
if (errno == EINTR || errno == EAGAIN) | |
{ continue; } | |
err_num = errno; | |
(void)fprintf(stderr, "\"splice\" error (bytes): %s\n", strerror(err_num)); | |
return (-1); | |
} | |
bytes_in_pipe -= bytes; | |
} | |
total_bytes_sent += bytes_sent; | |
} | |
return (total_bytes_sent); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment