Nothing Special   »   [go: up one dir, main page]

MPS

Download as pdf or txt
Download as pdf or txt
You are on page 1of 4

/*

** CSSE2310/CSSE7231 - Sample Server


** Accept connections on a given port, read text from connection
** turn it into upper case, send it back.
** Multi-process and multi-threaded versions of this server will
** be created in class.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>

// Listens on given port. Returns listening socket (or exits on failure)


int open_listen(const char* port)
{
struct addrinfo* ai = 0;
struct addrinfo hints;

memset(&hints, 0, sizeof(struct addrinfo));


hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // listen on all IP addresses

int err;
if ((err = getaddrinfo(NULL, port, &hints, &ai))) {
freeaddrinfo(ai);
fprintf(stderr, "%s\n", gai_strerror(err));
return 1; // Could not determine address
}

// Create a socket and bind it to a port


int listenfd = socket(AF_INET, SOCK_STREAM, 0); // 0=default protocol (TCP)

// Allow address (port number) to be reused immediately


int optVal = 1;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(int))
< 0) {
perror("Error setting socket option");
exit(1);
}
if (bind(listenfd, ai->ai_addr, sizeof(struct sockaddr)) < 0) {
perror("Binding");
return 3;
}

if (listen(listenfd, 10) < 0) { // Up to 10 connection requests can queue


perror("Listen");
return 4;
}

// Have listening socket - return it


return listenfd;
}

// Function to capitalise a string (in place)


char* capitalise(char* buffer, int len)
{
int i;

for (i = 0; i < len; i++) {


buffer[i] = (char)toupper((int)buffer[i]);
}
return buffer;
}

void process_connections(int fdServer)


{
int fd;
struct sockaddr_in fromAddr;
socklen_t fromAddrSize;
char buffer[1024];
ssize_t numBytesRead;

// Repeatedly accept connections and process data (capitalise)


while (1) {
fromAddrSize = sizeof(struct sockaddr_in);
// Block, waiting for a new connection. (fromAddr will be populated
// with address of client)
fd = accept(fdServer, (struct sockaddr*)&fromAddr, &fromAddrSize);
if (fd < 0) {
perror("Error accepting connection");
exit(1);
}

// Turn our client address into a hostname and print out both
// the address and hostname as well as the port number
char hostname[NI_MAXHOST];
int error = getnameinfo((struct sockaddr*)&fromAddr, fromAddrSize,
hostname, NI_MAXHOST, NULL, 0, 0);
if (error) {
fprintf(stderr, "Error getting hostname: %s\n",
gai_strerror(error));
} else {
printf("Accepted connection from %s (%s), port %d\n",
inet_ntoa(fromAddr.sin_addr), hostname,
ntohs(fromAddr.sin_port));
}

// Send a welcome message to our client


dprintf(fd, "Welcome\n");
//
// Create child
pid_t pid = fork();
if (pid == 0) {
// Child
close(fdServer);
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
close(fd);
execlp("tr", "tr", "a-z", "A-Z", NULL);
// Should never get here
exit(99);
} else if (pid < 0) {
perror("fork");
exit(1);
} else {
// Parent
close(fd);
}
}
}

void child_sig_handler(int sig)


{
pid_t pid;
int status;

while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {


printf("Child done: %d\n", pid);
fflush(stdout);
}
}

int main(int argc, char* argv[])


{
if (argc != 2) {
fprintf(stderr, "Usage: %s port-num\n", argv[0]);
exit(1);
}

int portnum = atoi(argv[1]);


if (portnum < 1024 || portnum > 65535) {
fprintf(stderr, "Invalid port number: %s\n", argv[1]);
exit(1);
}

// Set up signal handler


struct sigaction sa;
sa.sa_handler = child_sig_handler;
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
sigaction(SIGCHLD, &sa, NULL);

const char* port = argv[1];


int fdServer = open_listen(port);
process_connections(fdServer);

return 0;
}

You might also like