Moved scheme initialization to main thread, added basic networking
The server can now listen on a port and send data to a client.
This commit is contained in:
parent
8b0920c35d
commit
e2ef744e87
|
@ -4,22 +4,114 @@
|
||||||
// | See end of file for copyright notice. |
|
// | See end of file for copyright notice. |
|
||||||
// =========================================
|
// =========================================
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <libguile.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "scheme-integration.h"
|
#include "scheme-integration.h"
|
||||||
|
|
||||||
|
static const int PORT = 5000;
|
||||||
|
static const int CONCURRENT_PLAYER_COUNT = 256;
|
||||||
|
|
||||||
int main (int argc, char ** argv)
|
int main (int argc, char ** argv)
|
||||||
{
|
{
|
||||||
// Print a welcome message:
|
// Print a welcome message:
|
||||||
printf("SilverMUD Server - Starting Now.\n"
|
printf("SilverMUD Server - Starting Now.\n"
|
||||||
"================================\n");
|
"================================\n");
|
||||||
|
|
||||||
// Create the Scheme thread:
|
// Initialize Scheme:
|
||||||
pthread_t schemeThread;
|
scm_init_guile();
|
||||||
pthread_create(&schemeThread, NULL, schemeThreadHandler, NULL);
|
|
||||||
|
|
||||||
|
// Start the REPL server on a UNIX socket:
|
||||||
|
scm_c_eval_string("(begin (use-modules (system repl server))"
|
||||||
|
"(if (file-exists? \"silvermud-repl\") (delete-file \"silvermud-repl\"))"
|
||||||
|
"(spawn-server (make-unix-domain-server-socket #:path \"silvermud-repl\")))");
|
||||||
|
|
||||||
|
// Create a socket to listen for connections on:
|
||||||
|
int masterSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (masterSocket < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to create socket. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow reusing the address so that quick re-launching doesn't fail:
|
||||||
|
//setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||||
|
//setsockopt(masterSocket, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int));
|
||||||
|
|
||||||
|
// Setup the server address struct to bind the master socket to:
|
||||||
|
struct sockaddr_in serverAddress;
|
||||||
|
memset(&serverAddress, 0, sizeof(struct sockaddr_in));
|
||||||
|
|
||||||
|
// Assign the IP address and port to the server address struct:
|
||||||
|
serverAddress.sin_family = AF_INET;
|
||||||
|
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
serverAddress.sin_port = htons(PORT);
|
||||||
|
|
||||||
|
// Bind the master socket to the server address:
|
||||||
|
if ((bind(masterSocket, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in))) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to bind socket. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin listening:
|
||||||
|
if ((listen(masterSocket, CONCURRENT_PLAYER_COUNT)) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to begin listening on the master socket. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an epoll instance for managing connections, and add the master socket to it:
|
||||||
|
int connectedClients = epoll_create(CONCURRENT_PLAYER_COUNT);
|
||||||
|
if (connectedClients < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to create epoll instance. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
struct epoll_event watchedEvents;
|
||||||
|
watchedEvents.events = EPOLLIN;
|
||||||
|
watchedEvents.data.fd = masterSocket;
|
||||||
|
epoll_ctl(connectedClients, EPOLL_CTL_ADD, masterSocket, &watchedEvents);
|
||||||
|
|
||||||
|
int eventsCount = 0;
|
||||||
|
struct epoll_event events[1024];
|
||||||
|
|
||||||
|
// Start a REPL thread:
|
||||||
|
pthread_t schemeREPLThread;
|
||||||
|
pthread_create(&schemeREPLThread, NULL, schemeREPLHandler, NULL);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
eventsCount = epoll_wait(connectedClients, events, 1024, -1);
|
||||||
|
if (eventsCount == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "epoll_wait() failed. Aborting.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
for (int index = 0; index < eventsCount; index++)
|
||||||
|
{
|
||||||
|
// If it's the master socket, it's a new client connecting:
|
||||||
|
if (events[index].data.fd == masterSocket)
|
||||||
|
{
|
||||||
|
int newSocket = accept(masterSocket, NULL, NULL);
|
||||||
|
send(newSocket, "Hello, world!", 13, 0);
|
||||||
|
close(newSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for all other threads to terminate:
|
// Wait for all other threads to terminate:
|
||||||
pthread_join(schemeThread, NULL);
|
pthread_join(schemeREPLThread, NULL);
|
||||||
|
|
||||||
// Return a successful status code to the operating system:
|
// Return a successful status code to the operating system:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -7,23 +7,15 @@
|
||||||
|
|
||||||
#include "scheme-integration.h"
|
#include "scheme-integration.h"
|
||||||
|
|
||||||
// The function ran by the Scheme thread which initializes the REPL:
|
// The function ran by the Scheme thread which runs a text-based REPL:
|
||||||
void * schemeThreadHandler (void * threadParameters)
|
void * schemeREPLHandler (void * threadParameters)
|
||||||
{
|
{
|
||||||
// Unpack the parameters given to the thread:
|
// Initialize Scheme:
|
||||||
struct SchemeThreadArguments * arguments = threadParameters;
|
|
||||||
|
|
||||||
// Initialize GNU Guile:
|
|
||||||
scm_init_guile();
|
scm_init_guile();
|
||||||
|
|
||||||
// Enable Readline support:
|
// Enable Readline support:
|
||||||
scm_c_eval_string("(begin (use-modules (ice-9 readline)) (activate-readline))");
|
scm_c_eval_string("(begin (use-modules (ice-9 readline)) (activate-readline))");
|
||||||
|
|
||||||
// Start the REPL server on a UNIX socket:
|
|
||||||
scm_c_eval_string("(begin (use-modules (system repl server))"
|
|
||||||
"(if (file-exists? \"silvermud-repl\") (delete-file \"silvermud-repl\"))"
|
|
||||||
"(spawn-server (make-unix-domain-server-socket #:path \"silvermud-repl\")))");
|
|
||||||
|
|
||||||
// Start a Scheme REPL:
|
// Start a Scheme REPL:
|
||||||
scm_shell(0, NULL);
|
scm_shell(0, NULL);
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
#ifndef SCHEME_INTEGRATION_H
|
#ifndef SCHEME_INTEGRATION_H
|
||||||
#define SCHEME_INTEGRATION_H
|
#define SCHEME_INTEGRATION_H
|
||||||
|
|
||||||
struct SchemeThreadArguments
|
struct SchemeThreadArguments
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The function ran by the Scheme thread which initializes the REPL:
|
// The function ran by the Scheme thread which initializes the REPL:
|
||||||
void * schemeThreadHandler (void * threadParameters);
|
void * schemeREPLHandler (void * threadParameters);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// ==========================================================
|
// ==========================================================
|
||||||
// | End of scheme-integration.h, copyright notice follows. |
|
// | End of scheme-integration.h, copyright notice follows. |
|
||||||
|
|
Loading…
Reference in New Issue