Skip to content

Instantly share code, notes, and snippets.

@felis-ron-silvestris
Forked from metadaddy/server.c
Created July 23, 2012 21:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felis-ron-silvestris/3166380 to your computer and use it in GitHub Desktop.
Save felis-ron-silvestris/3166380 to your computer and use it in GitHub Desktop.
sendfile
#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