Initial release of SilverMUD:
Features Added: - Server capable of receiving and sending messages to up to 64 clients. - Client capable of sending and receiving messages from the server, multi-threaded. - Text effect library with one effect. Features Changed: - None, initial release. Features Removed: - None, initial release.
This commit is contained in:
commit
618b2144e3
|
@ -0,0 +1,19 @@
|
||||||
|
clientsrc = $(wildcard src/misc/*.c) \
|
||||||
|
src/SilverMUDClient.c
|
||||||
|
clientobj = $(clientsrc:.c=.o)
|
||||||
|
serversrc = $(wildcard src/misc/*.c) \
|
||||||
|
src/SilverMUDServer.c
|
||||||
|
serverobj = $(serversrc:.c=.o)
|
||||||
|
CLIENTLDFLAGS= -lpthread
|
||||||
|
|
||||||
|
SilverMUDClient: $(clientobj)
|
||||||
|
gcc -o $@ $^ $(CLIENTLDFLAGS)
|
||||||
|
|
||||||
|
SilverMUDServer: $(serverobj)
|
||||||
|
gcc -o $@ $^
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(clientobj) $(serverobj) SilverMUDClient SilverMUDServer
|
||||||
|
|
||||||
|
all: SilverMUDClient SilverMUDServer
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include "misc/texteffects.h"
|
||||||
|
#define MAX 1024
|
||||||
|
#define PORT 5000
|
||||||
|
#define SA struct sockaddr
|
||||||
|
|
||||||
|
void * messageSender(void * sockfd)
|
||||||
|
{
|
||||||
|
char sendBuffer[MAX];
|
||||||
|
int characterindex;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
bzero(sendBuffer, MAX);
|
||||||
|
printf("COMM-LINK> ");
|
||||||
|
fgets(sendBuffer, MAX, stdin);
|
||||||
|
if(sendBuffer[0] != '\n');
|
||||||
|
{
|
||||||
|
write((long)sockfd, sendBuffer, MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * messageReceiver(void * sockfd)
|
||||||
|
{
|
||||||
|
char receiveBuffer[MAX];
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
read((long)sockfd, receiveBuffer, MAX);
|
||||||
|
slowprint("\nUSER-MESSAGE: ", 8000);
|
||||||
|
slowprint(receiveBuffer, 8000);
|
||||||
|
slowprint("\nCOMM-LINK (CONT.)> ", 8000);
|
||||||
|
bzero(receiveBuffer, MAX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sockfd, connfd;
|
||||||
|
struct sockaddr_in servaddr, cli;
|
||||||
|
pthread_t messagingThread;
|
||||||
|
|
||||||
|
// Give me a socket, and make sure it's working:
|
||||||
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sockfd == -1)
|
||||||
|
{
|
||||||
|
printf("Socket creation failed.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slowprint("Socket successfully created.\n", 8000);
|
||||||
|
}
|
||||||
|
bzero(&servaddr, sizeof(servaddr));
|
||||||
|
|
||||||
|
// Set our IP Address and port. Default to localhost for testing:
|
||||||
|
servaddr.sin_family = AF_INET;
|
||||||
|
if (argc == 1)
|
||||||
|
{
|
||||||
|
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
|
||||||
|
}
|
||||||
|
servaddr.sin_port = htons(PORT);
|
||||||
|
|
||||||
|
// Connect the server and client sockets, Kronk:
|
||||||
|
if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0)
|
||||||
|
{
|
||||||
|
slowprint("Connection with the Silverkin Industries Comm-Link Server Failed:\nPlease contact your service representative.\n", 8000);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slowprint("Connected to the Silverkin Industries Comm-Link Server:\nHave a pleasant day.\n", 8000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a thread to send messages, and use main to recieve.
|
||||||
|
pthread_create(&messagingThread, NULL, messageSender, (void *)(long)sockfd);
|
||||||
|
messageReceiver((void *)(long)sockfd);
|
||||||
|
|
||||||
|
// Close the socket.
|
||||||
|
close(sockfd);
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
// Silverkin Industries Comm-Link Server, Engineering Sample Alpha 0.1.
|
||||||
|
// PROJECT CODENAME: WHAT DO I PAY YOU FOR? | Level-3 Clearance.
|
||||||
|
// Barry Kane, 2021
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include "misc/texteffects.h"
|
||||||
|
const int PORT = 5000;
|
||||||
|
const int MAX = 1024;
|
||||||
|
typedef struct sockaddr sockaddr;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int socketFileDesc, connectionFileDesc, length, clientsAmount,
|
||||||
|
socketCheck, activityCheck, readLength;
|
||||||
|
int clientSockets[64];
|
||||||
|
int maxClients = 64;
|
||||||
|
char receiveBuffer[MAX];
|
||||||
|
fd_set connectedClients;
|
||||||
|
struct sockaddr_in serverAddress, clientAddress;
|
||||||
|
|
||||||
|
// Give an intro: Display the Silverkin Industries logo and splash text.
|
||||||
|
slowprint(logostring, 3000);
|
||||||
|
slowprint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK SERVER ====--\nVersion Alpha 0.1\n", 5000);
|
||||||
|
|
||||||
|
// Initialize the sockets to 0, so we don't crash.
|
||||||
|
for (int index = 0; index < maxClients; index++)
|
||||||
|
{
|
||||||
|
clientSockets[index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a socket and make sure we actually get one.
|
||||||
|
socketFileDesc = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (socketFileDesc == -1)
|
||||||
|
{
|
||||||
|
perror("Socket creation is \033[33;40mRED.\033[0m Aborting launch.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slowprint(" Socket creation is \033[32;40mGREEN.\033[0m\n", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(&serverAddress, sizeof(serverAddress));
|
||||||
|
|
||||||
|
// Assign IP and port:
|
||||||
|
serverAddress.sin_family = AF_INET;
|
||||||
|
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serverAddress.sin_port = htons(PORT);
|
||||||
|
|
||||||
|
// Binding newly created socket to given IP, and checking it works:
|
||||||
|
if ((bind(socketFileDesc, (sockaddr*)&serverAddress, sizeof(serverAddress))) != 0)
|
||||||
|
{
|
||||||
|
perror("Socket binding is \033[33;40mRED.\033[0m Aborting launch.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slowprint(" Socket binding is \033[32;40mGREEN.\033[0m\n", 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's start listening:
|
||||||
|
if ((listen(socketFileDesc, 64)) != 0)
|
||||||
|
{
|
||||||
|
perror("Server listening is \033[33;40mRED.\033[0m Aborting launch.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slowprint(" Server listening is \033[32;40mGREEN.\033[0m\n", 5000);
|
||||||
|
}
|
||||||
|
length = sizeof(clientAddress);
|
||||||
|
|
||||||
|
//connectionFileDesc = accept(socketFileDesc, (sockaddr*)&clientAddress, &length);
|
||||||
|
// Accept the data packet from client and verification
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
FD_ZERO(&connectedClients);
|
||||||
|
FD_SET(socketFileDesc, &connectedClients);
|
||||||
|
clientsAmount = socketFileDesc;
|
||||||
|
bzero(receiveBuffer, sizeof(receiveBuffer));
|
||||||
|
for (int i = 0; i < maxClients; i++)
|
||||||
|
{
|
||||||
|
// Just get the one we're working with to another name:
|
||||||
|
socketCheck = clientSockets[i];
|
||||||
|
|
||||||
|
// If it's working, bang it into the list:
|
||||||
|
if(socketCheck > 0)
|
||||||
|
{
|
||||||
|
FD_SET(socketCheck, &connectedClients);
|
||||||
|
}
|
||||||
|
// The amount of clients is needed for select():
|
||||||
|
if(socketCheck > clientsAmount)
|
||||||
|
{
|
||||||
|
clientsAmount = socketCheck;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if a connection is ready to be interacted with:
|
||||||
|
activityCheck = select((clientsAmount + 1), &connectedClients, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
// Check if select() worked:
|
||||||
|
if ((activityCheck < 0) && (errno != EINTR))
|
||||||
|
{
|
||||||
|
perror("Error in select(), retrying.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's the master socket selected, there is a new connection:
|
||||||
|
if (FD_ISSET(socketFileDesc, &connectedClients))
|
||||||
|
{
|
||||||
|
if ((connectionFileDesc = accept(socketFileDesc,
|
||||||
|
(struct sockaddr *)&clientAddress, (socklen_t*)&length))<0)
|
||||||
|
{
|
||||||
|
perror("Failed to accept connection. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print new connection details:
|
||||||
|
printf("Client connected: Socket file descriptor: #%d, IP address: %s, Port: %d.\n",
|
||||||
|
connectionFileDesc, inet_ntoa(clientAddress.sin_addr) , ntohs
|
||||||
|
(clientAddress.sin_port));
|
||||||
|
|
||||||
|
// See if we can put in the client:
|
||||||
|
for (int i = 0; i < maxClients; i++)
|
||||||
|
{
|
||||||
|
// When there is an empty slot, pop it in:
|
||||||
|
if( clientSockets[i] == 0 )
|
||||||
|
{
|
||||||
|
clientSockets[i] = connectionFileDesc;
|
||||||
|
printf("Adding to list of sockets as %d.\n" , i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, it's a client socket to be interacted with:
|
||||||
|
for (int i = 0; i < maxClients; i++)
|
||||||
|
{
|
||||||
|
socketCheck = clientSockets[i];
|
||||||
|
|
||||||
|
if (FD_ISSET(socketCheck, &connectedClients))
|
||||||
|
{
|
||||||
|
//Check if it was for closing, and also read the incoming message
|
||||||
|
explicit_bzero(receiveBuffer, sizeof(receiveBuffer));
|
||||||
|
readLength = read(socketCheck, receiveBuffer, sizeof(receiveBuffer));
|
||||||
|
if (readLength == 0)
|
||||||
|
{
|
||||||
|
// Somebody disconnected , get his details and print:
|
||||||
|
getpeername(socketCheck, (struct sockaddr*)&clientAddress, (socklen_t*)&length);
|
||||||
|
printf("Client disconnected: IP Address: %s, Port: %d.\n",
|
||||||
|
inet_ntoa(clientAddress.sin_addr) , ntohs(clientAddress.sin_port));
|
||||||
|
|
||||||
|
// Close the socket and mark as 0 in list for reuse:
|
||||||
|
close(socketCheck);
|
||||||
|
clientSockets[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo back the message that came in:
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%d: %s", clientSockets[i], receiveBuffer);
|
||||||
|
fflush(stdout);
|
||||||
|
for (int sendIndex = 0; sendIndex < clientsAmount; sendIndex++)
|
||||||
|
{
|
||||||
|
if(sendIndex != i && clientSockets[sendIndex] != STDIN_FILENO && clientSockets[sendIndex] != STDOUT_FILENO && clientSockets[sendIndex] != STDERR_FILENO)
|
||||||
|
{
|
||||||
|
write(clientSockets[sendIndex], receiveBuffer, sizeof(receiveBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bzero(receiveBuffer, sizeof(receiveBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
// texteffects.c: Implementation of text effect library for SilverMUD.
|
||||||
|
// Barry Kane, 2021.
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void slowprint(char * stringToPrint, int delay)
|
||||||
|
{
|
||||||
|
int characterIndex = 0;
|
||||||
|
while(stringToPrint[characterIndex] != '\0')
|
||||||
|
{
|
||||||
|
putchar(stringToPrint[characterIndex]);
|
||||||
|
// Flush the buffer so there's no line buffering.
|
||||||
|
fflush(stdout);
|
||||||
|
usleep(delay);
|
||||||
|
characterIndex++;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef TEXTEFFECTS_H_
|
||||||
|
#define TEXTEFFECTS_H_
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// A fancy, character by character print. Similar to a serial terminal with lower baud rate.
|
||||||
|
void slowprint(char * stringToPrint, int delay);
|
||||||
|
|
||||||
|
// A string containing an ASCII art version of the Silverkin Industries logo.
|
||||||
|
char * logostring = " ///////\n //////////////////////////////////////////\n ///////////////////////////////////////////////////////////\n ////////// ////////////////////////////\n ### # # # # ##### ### # # # # # /////////////////\n ### # # # # ## # # ## # ## # //////////////\n ## # # # # # ### # # # # # # /////////\n #### # ### # ##### # # # # # # ## ///////\n # ## # ##### # # ### ### ### # ##### ### ////// \n # # # # # # # # ## # # # # ## ## ////\n # # # # # # # # ## # ### # # ## //\n # # ### ##### ##### ### # # # # #### ### //\n";
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue