From 0519ba9a66167254e9267b1c1436a74b7c644d1c Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Sun, 24 Apr 2022 11:44:55 -0700 Subject: [PATCH] Organized everything --- NetSock/netsock.c | 98 ++++++ NetSock/netsock.h | 61 ++++ common.h | 15 + config.h | 5 + irc.c | 101 ++++++ irc.h | 12 + main.c | 327 ++++-------------- net.c | 30 ++ net.h | 9 + client.c => networking-tests/client.c | 0 networking-tests/main.c | 455 ++++++++++++++++++++++++++ 11 files changed, 850 insertions(+), 263 deletions(-) create mode 100644 NetSock/netsock.c create mode 100644 NetSock/netsock.h create mode 100644 common.h create mode 100644 config.h create mode 100644 irc.c create mode 100644 irc.h mode change 100755 => 100644 main.c create mode 100644 net.c create mode 100644 net.h rename client.c => networking-tests/client.c (100%) create mode 100755 networking-tests/main.c diff --git a/NetSock/netsock.c b/NetSock/netsock.c new file mode 100644 index 0000000..322479b --- /dev/null +++ b/NetSock/netsock.c @@ -0,0 +1,98 @@ +#include "netsock.h" + +// Windows +#if defined(_WIN32) +// Variables +struct WSAData net_wd; +// Funcs +#define net_errno() (WSAGetLastError()) +const char *net_strerror(int e) { + static char msg[256]; + if (!FormatMessageA(\ + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, 0, msg, 256, NULL)) + sprintf(msg, "WSA Error %d", e); + return msg; +} +int net_nonblock(SOCKET fd) { + u_long v = 1; + return ioctlsocket(fd, FIONBIO, &v); +} + +// POSIX +#else +// Funcs +int net_nonblock(SOCKET fd) { +#if defined(O_NONBLOCK) + int f = fcntl(fd, F_GETFL); + if (f == -1) + return -1; + return fcntl(fd, F_SETFL, f | O_NONBLOCK); +#else + u_long v = 1; + return ioctlsocket(fd, FIONBIO, &v); +#endif +} +#endif + +// Funcs +void net_perror(const char *p) +{ + if (p && *p) { + fprintf(stderr, "%s: %s\n", p, net_strerror(net_errno())); + } else { + fprintf(stderr, "%s\n", net_strerror(net_errno())); + } +} + +// Init and shutdown +void net_init(void) { + puts("[NetSock]: NetSock initializing..."); + fflush(stdout); + // Initialize WSA +#if defined(_WIN32) + int WStartCode = WSAStartup(MAKEWORD(2, 0), &net_wd); + if (WStartCode) { + fprintf(stderr, "Winsock API startup failed: %s\n", net_strerror(WStartCode)); + exit(EXIT_FAILURE); + } + printf("[NetSock]: WinSock initialized V%d.%d!\n",LOBYTE(net_wd.wVersion), HIBYTE(net_wd.wVersion)); + fflush(stdout); +#endif +} +void net_cleanup(void) { + puts("[NetSock]: NetSock cleaning up..."); + fflush(stdout); + // Initialize WSA +#if defined(_WIN32) + WSACleanup(); + puts("[NetSock]: WinSock cleaned up! (probably)"); + fflush(stdout); +#endif +} + +// Misc +ssize_t send_log(SOCKET socket, const char *buffer, size_t length, int flags) { + printf("SERVER %"PRISocket": %s", socket, (char*)buffer); + fflush(stdout); + return send(socket, buffer, length, flags); +} +ssize_t recv_log(SOCKET socket, char *buffer, size_t length, int flags) { + ssize_t bytesRead = recv(socket,buffer,length,flags); + if(bytesRead > 0) { + buffer[bytesRead] = 0; + printf("CLIENT %"PRISocket": %s", socket, (char*)buffer); + fflush(stdout); + } + return bytesRead; +} +void net_sleep(unsigned int sec) { + struct timeval sleeptime; + sleeptime.tv_sec = sec; + select(0, NULL, NULL, NULL, &sleeptime); +} +void net_usleep(unsigned int usec) { + struct timeval sleeptime; + sleeptime.tv_usec = usec; + select(0, NULL, NULL, NULL, &sleeptime); +} diff --git a/NetSock/netsock.h b/NetSock/netsock.h new file mode 100644 index 0000000..ead46ed --- /dev/null +++ b/NetSock/netsock.h @@ -0,0 +1,61 @@ +#ifndef _netsock_h +#define _netsock_h +#define FD_SETSIZE 1024 + +// Standard headers +#include +#include +#include +#include + +// Windows +#if defined(_WIN32) +#pragma message("Warning: Windows detected.") +#pragma message("IMPORTANT: COMPILE WITH -lws2_32") +#pragma comment(lib, "ws2_32.lib") +//#include +//#include +//#include +#include +#include +#include +//#define PRISocket "llu" // The format string for SOCKET +#define PRISocket "p" // The format string for SOCKET +#define net_errno() (WSAGetLastError()) +#define net_wouldblock() (WSAGetLastError() == WSAEWOULDBLOCK) +// Funcs +const char *net_strerror(int e); +// Variables +extern struct WSAData net_wd; + +// POSIX +#else +#include +#include +#include +#include +#include +#include +#include +#include +//typedef unsigned long long SOCKET; +typedef int SOCKET; +#define PRISocket "d" // The format string for SOCKET +#define net_errno() ((int)errno) +#define net_strerror(e) strerror((e)) +#define net_wouldblock() (errno == EAGAIN || errno == EWOULDBLOCK) +#define closesocket close +#define ioctlsocket ioctl +#define INVALID_SOCKET -1 +#endif + +// Funcs +int net_nonblock(SOCKET fd); +void net_perror(const char *p); +void net_init(void); +void net_cleanup(void); +ssize_t send_log(SOCKET socket, const char *buffer, size_t length, int flags); +ssize_t recv_log(SOCKET socket, char *buffer, size_t length, int flags); +void net_sleep(unsigned int sec); +void net_usleep(unsigned int usec); +#endif diff --git a/common.h b/common.h new file mode 100644 index 0000000..7bbd8d9 --- /dev/null +++ b/common.h @@ -0,0 +1,15 @@ +#ifndef _common_h +#define _common_h +#include "NetSock/netsock.h" +#include "config.h" + +struct client_data { + SOCKET FD; + char type; + char nick[32]; + size_t nickLen; +}; +extern struct client_data *clients[CLIENTS]; +extern fd_set readfds; + +#endif diff --git a/config.h b/config.h new file mode 100644 index 0000000..913d250 --- /dev/null +++ b/config.h @@ -0,0 +1,5 @@ +#define LISTENING_PORT 6667 +#define LISTENING_BACKLOG 10 +#define CLIENTS 30 +#define SUPPORT_IPV4 +#define SUPPORT_IPV6 diff --git a/irc.c b/irc.c new file mode 100644 index 0000000..b0c7411 --- /dev/null +++ b/irc.c @@ -0,0 +1,101 @@ +#include "irc.h" + +void processPacket(struct client_data *client, char *packet, size_t packetLen) { + if(strncmp(packet, "PING", 4) == 0) { + packet[1] = 'O'; + send_log(client->FD, packet, packetLen, 0); + } else if(strncmp(packet, "NICK ", 5) == 0) { + // User now registered + setNick(client, packet+5, 32); + printf("USER SET NICKNAME %lu %s\n", client->nickLen, client->nick); + fflush(stdout); + } else if(strncmp(packet, "USER ", 5) == 0) { + // Send welcome + newUser(client); + } else if(strncmp(packet, "MOTD", 4) == 0) { + // Send welcome + sendMOTD(client); + // Horrible join but it works and its funny + } else if(strncmp(packet, "JOIN ", 5) == 0) { + char data[256]; + data[0] = ':'; + strcpy(data+1, client->nick); + strcpy(data+1+client->nickLen, " JOIN :"); + strcpy(data+8+client->nickLen, packet+5); + send_log(client->FD, data, strlen(data), 0); + sendall_log(client->FD, data, strlen(data), 0); + } else if(strncmp(packet, "PRIVMSG ", 8) == 0) { + char data[256]; + data[0] = ':'; + strcpy(data+1, client->nick); + data[1+client->nickLen] = ' '; + strcpy(data+2+client->nickLen, packet); + sendall_log(client->FD, data, strlen(data), 0); + } +} + +void newUser(struct client_data *client) { + char data[1024]; + // Copy in basics + strcpy(data, ":irc.patchysicp.xyz 001 "); + strcpy(data+24, client->nick); + strcpy(data+24+client->nickLen, " :Welcome to PatchyIRCD!!!\n"); + //send_log(client->FD, data, (26+client->nickLen+27), 0); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Your host is PatchyIRCD V0.0.1\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '3'; + strcpy(data+26+client->nickLen, "This server was created when I had cybersex with your mother.\n"); + send_log(client->FD, data, strlen(data), 0); + data[20] = '2'; + data[21] = '5'; + data[22] = '1'; + strcpy(data+26+client->nickLen, "This server exists\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Jannies don't exist\n"); + send_log(client->FD, data, strlen(data), 0); + sendMOTD(client); +} + +void sendMOTD(struct client_data *client) { + char data[1024]; + // Copy in basics + strcpy(data, ":irc.patchysicp.xyz 375 "); + strcpy(data+24, client->nick); + strcpy(data+24+client->nickLen, " :PatchySICP /MOTD\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Welcome to Montreal!\n"); + send_log(client->FD, data, strlen(data), 0); + strcpy(data+26+client->nickLen, "You are retarded and I will have cybersex with your mom.\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '6'; + strcpy(data+26+client->nickLen, "/MOTD over\n"); + send_log(client->FD, data, strlen(data), 0); +} + +void setNick(struct client_data *client, char* nickname, size_t size) { + // TODO: perform basic sanitization + strncpy(client->nick, nickname, size); + // Null term + client->nick[size-1] = 0; + // Remove newline + int i; + for(i=0;inick[i] == 13) { + client->nick[i] = 0; + break; + } + // Newline + if(client->nick[i] == 10) { + client->nick[i] = 0; + break; + } + } + // Set length + client->nickLen = strlen(client->nick); + return; +} diff --git a/irc.h b/irc.h new file mode 100644 index 0000000..b8cdb40 --- /dev/null +++ b/irc.h @@ -0,0 +1,12 @@ +#ifndef _irc_h +#define _irc_h + +#include "common.h" +#include "net.h" + +void processPacket(struct client_data *client, char *packet, size_t packetLen); +void newUser(struct client_data *client); +void sendMOTD(struct client_data *client); +void setNick(struct client_data *client, char* nickname, size_t size); + +#endif diff --git a/main.c b/main.c old mode 100755 new mode 100644 index 94e9af5..a6e39bf --- a/main.c +++ b/main.c @@ -1,231 +1,32 @@ -// Some macros to control options -#define LISTENING_PORT 6667 -#define LISTENING_BACKLOG 10 -#define CLIENT_SOCKETS 30 -#define FD_SETSIZE 1024 -#define SUPPORT_IPV4 -#define SUPPORT_IPV6 +#include "common.h" +#include "net.h" +#include "irc.h" -#include -#include -#include -#include -#if defined(_WIN32) -#pragma message("Warning: Windows detected.") -//#include -//#include -//#include -#include -#include -#include -#pragma message("IMPORTANT: COMPILE WITH -lws2_32") -#pragma comment(lib, "ws2_32.lib") -#define PRISocket "llu" -#else -#include -#include -#include -#include -#include -#include -#include -#include -//typedef unsigned long long SOCKET; -typedef int SOCKET; -#define PRISocket "d" -#endif - -struct client_data { - SOCKET FD; - char type; - char nick[32]; - size_t nickLen; -}; - -struct client_data client_socket[CLIENT_SOCKETS]; - -#if defined(_WIN32) -#define net_errno() (WSAGetLastError()) -const char *net_strerror(int e) { - static char msg[256]; - if (!FormatMessageA(\ - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, e, 0, msg, 256, NULL)) - sprintf(msg, "WSA Error %d", e); - return msg; -} -int net_nonblock(SOCKET fd) { - u_long v = 1; - return ioctlsocket(fd, FIONBIO, &v); -} -#else -#define net_errno() ((int)errno) -#define net_strerror(e) strerror((e)) -#define closesocket close -#define INVALID_SOCKET -1 -int net_nonblock(SOCKET fd) { - int f = fcntl(fd, F_GETFL); - if (f == -1) - return -1; - return fcntl(fd, F_SETFL, f | O_NONBLOCK); -} -#endif -void net_perror(const char *p) -{ - if (p && *p) - fprintf(stderr, "%s: %s\n", p, net_strerror(net_errno())); - else - fprintf(stderr, "%s\n", net_strerror(net_errno())); -} - -size_t send_log(int socket, const void *buffer, size_t length, int flags) { - printf("SERVER: %s", (char*)buffer); - fflush(stdout); - return send(socket, buffer, length, flags); -} - -void sendall_log(int socket, const void *buffer, size_t length, int flags) { - int i; - for(i=0;iFD, packet, packetLen, 0); - } else if(strncmp(packet, "NICK ", 5) == 0) { - // User now registered - setNick(client, packet+5, 32); - printf("USER SET NICKNAME %lu %s\n", client->nickLen, client->nick); - fflush(stdout); - } else if(strncmp(packet, "USER ", 5) == 0) { - // Send welcome - newUser(client); - } else if(strncmp(packet, "MOTD", 4) == 0) { - // Send welcome - sendMOTD(client); - // Horrible join but it works and its funny - } else if(strncmp(packet, "JOIN ", 5) == 0) { - char data[256]; - data[0] = ':'; - strcpy(data+1, client->nick); - strcpy(data+1+client->nickLen, " JOIN :"); - strcpy(data+8+client->nickLen, packet+5); - send_log(client->FD, data, strlen(data), 0); - sendall_log(client->FD, data, strlen(data), 0); - } else if(strncmp(packet, "PRIVMSG ", 8) == 0) { - char data[256]; - data[0] = ':'; - strcpy(data+1, client->nick); - data[1+client->nickLen] = ' '; - strcpy(data+2+client->nickLen, packet); - sendall_log(client->FD, data, strlen(data), 0); - } - -} - -void newUser(struct client_data *client) { - char data[1024]; - // Copy in basics - strcpy(data, ":irc.patchysicp.xyz 001 "); - strcpy(data+24, client->nick); - strcpy(data+24+client->nickLen, " :Welcome to PatchyIRCD!!!\n"); - //send_log(client->FD, data, (26+client->nickLen+27), 0); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Your host is PatchyIRCD V0.0.0\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '3'; - strcpy(data+26+client->nickLen, "This server was created when I had cybersex with your mother.\n"); - send_log(client->FD, data, strlen(data), 0); - data[20] = '2'; - data[21] = '5'; - data[22] = '1'; - strcpy(data+26+client->nickLen, "This server exists\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Jannies don't exist\n"); - send_log(client->FD, data, strlen(data), 0); - sendMOTD(client); -} - -void sendMOTD(struct client_data *client) { - char data[1024]; - // Copy in basics - strcpy(data, ":irc.patchysicp.xyz 375 "); - strcpy(data+24, client->nick); - strcpy(data+24+client->nickLen, " :PatchySICP /MOTD\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '2'; - strcpy(data+26+client->nickLen, "Welcome to Montreal!\n"); - send_log(client->FD, data, strlen(data), 0); - strcpy(data+26+client->nickLen, "You are retarded and I will have cybersex with your mom.\n"); - send_log(client->FD, data, strlen(data), 0); - data[22] = '6'; - strcpy(data+26+client->nickLen, "/MOTD over\n"); - send_log(client->FD, data, strlen(data), 0); -} +// Client linked list +struct client_data *clients[CLIENTS]; +// FDSET List +fd_set readfds; -void setNick(struct client_data *client, char* nickname, size_t size) { - // TODO: perform basic sanitization - strncpy(client->nick, nickname, size); - // Null term - client->nick[size-1] = 0; - // Remove newline - int i; - for(i=0;inick[i] == 13) { - client->nick[i] = 0; - break; - } - // Newline - if(client->nick[i] == 10) { - client->nick[i] = 0; - break; - } - } - // Set length - client->nickLen = strlen(client->nick); - return; -} - -int main(){ - fd_set readfds; - SOCKET highestFD; - int i; - SOCKET SD; +int main() { + int opt = 1; SOCKET serverSocketV4 = 0; SOCKET serverSocketV6 = 0; + SOCKET highestFD; + SOCKET SD; + int i; char client_addr[100]; char *welcomeMessage = ":irc.patchysicp.xyz NOTICE * :Hello welcome to PatchyIRCD!\n"; char buffer[1024]; size_t bytesRead; + puts("[PatchyIRCD]: Starting up..."); + fflush(stdout); -#if defined(_WIN32) - struct WSAData wd; - if (WSAStartup(MAKEWORD(2, 0), &wd)) printf("Winsock API startup failed.\n"); -#endif + net_init(); - puts("Starting"); - fflush(stdout); + // Zero stuff out + memset(clients, 0, sizeof(clients)); + // Setup structs #ifdef SUPPORT_IPV4 struct sockaddr_in serverAddrV4; memset(&serverAddrV4, 0, sizeof(struct sockaddr_in)); @@ -243,8 +44,6 @@ int main(){ serverAddrV6.sin6_family = AF_INET6; size_t serverAddrV6len = sizeof(serverAddrV6); #endif - - int opt = 1; #ifdef SUPPORT_IPV4 // Create socket serverSocketV4 = socket(AF_INET, SOCK_STREAM, 0); @@ -309,32 +108,26 @@ int main(){ } #endif - memset(client_socket, 0, sizeof(client_socket)); - puts("Ready"); - fflush(stdout); + + // Main loop while(1){ - // Clear all sockets FD_ZERO(&readfds); - // Add main sockets + // Add listening SOCKETS to FDSET #ifdef SUPPORT_IPV4 FD_SET(serverSocketV4, &readfds); #endif #ifdef SUPPORT_IPV6 FD_SET(serverSocketV6, &readfds); #endif + // Set highestFD if(serverSocketV4 < serverSocketV6) highestFD = serverSocketV6; else highestFD = serverSocketV4; - - // Check for new sockets - for(i=0;i0){ - FD_SET(SD, &readfds); - // Update highest FD - if(SD>highestFD){ - highestFD = SD; + for(i=0;iFD, &readfds); + if(clients[i]->FD>highestFD){ + highestFD = clients[i]->FD; } } } @@ -344,6 +137,8 @@ int main(){ net_perror("ERROR SELECT"); } + // Accept new connections + // TODO: Optimize this with goto #ifdef SUPPORT_IPV4 if (FD_ISSET(serverSocketV4, &readfds)) { SOCKET newSocket = accept(serverSocketV4, NULL, NULL); @@ -356,12 +151,13 @@ int main(){ fflush(stdout); send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0); // Add to list of sockets - for(i=0;iFD = newSocket; + clients[i]->type = 4; // Set nonblock - net_nonblock(client_socket[i].FD); + net_nonblock(clients[i]->FD); break; } } @@ -379,27 +175,37 @@ int main(){ fflush(stdout); send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0); // Add to list of sockets - for(i=0;iFD = newSocket; + clients[i]->type = 6; // Set nonblock - net_nonblock(client_socket[i].FD); + net_nonblock(clients[i]->FD); break; } } } #endif // Respond to already connected clients - for(i=0;iFD; if(FD_ISSET(SD, &readfds)) { //bytesRead = read(SD, buffer, sizeof(buffer)); - bytesRead = recv(SD,buffer,sizeof(buffer), 0); + bytesRead = recv_log(SD,buffer,sizeof(buffer), 0); + + if(bytesRead == -1) { + if(net_wouldblock()) { + goto endOfLoop; + } + net_perror("RECV"); + } + // Disconnect if(bytesRead == 0) { #ifdef SUPPORT_IPV4 - if(client_socket[i].type == 4) { + if(clients[i]->type == 4) { getpeername(SD,(struct sockaddr*)&serverAddrV4,(socklen_t*)&serverAddrV4len); inet_ntop(AF_INET, &(serverAddrV4.sin_addr), client_addr, sizeof(client_addr)); printf("Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", SD, client_addr, ntohs(serverAddrV4.sin_port)); @@ -407,22 +213,17 @@ int main(){ } #endif #ifdef SUPPORT_IPV6 - if(client_socket[i].type == 6) { + if(clients[i]->type == 6) { getpeername(SD,(struct sockaddr*)&serverAddrV6,(socklen_t*)&serverAddrV6len); inet_ntop(AF_INET6, &(serverAddrV6.sin6_addr), client_addr, sizeof(client_addr)); printf("Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", SD, client_addr, ntohs(serverAddrV6.sin6_port)); fflush(stdout); } #endif - closesocket(SD); - client_socket[i].FD = 0; + killConnection(clients[i]); } else { // Add null byte buffer[bytesRead] = '\0'; - // Send it back - //send(SD,buffer,bytesRead,0); - printf("CLIENT: %s", buffer); - fflush(stdout); int j; char *buffer2 = buffer; @@ -432,24 +233,24 @@ int main(){ char tmp = buffer[j+1]; buffer[j+1] = 0; //Send to processing - processPacket(&(client_socket[i]), buffer2, strlen(buffer2)); + processPacket(clients[i], buffer2, strlen(buffer2)); buffer[j+1] = tmp; buffer2 = &(buffer[j+1]); } } } + endOfLoop:; } } } -#if defined(_WIN32) - WSACleanup(); -#endif - for(i=0;i0) { - closesocket(client_socket[i].FD); + puts("[PatchyIRCD]: Cleaning up..."); + fflush(stdout); + for(i=0;iFD == socket) { + continue; + } else { + send_log(clients[i]->FD, buffer, length, flags); + } + } +} + +struct client_data *allocClient(){ + struct client_data *NewClient = malloc(sizeof(struct client_data)); + memset(NewClient, 0, sizeof(struct client_data)); + return NewClient; +}; + +void killConnection(struct client_data *client) { + int i; + for(i=0;iFD); + free(client); +} diff --git a/net.h b/net.h new file mode 100644 index 0000000..5df0459 --- /dev/null +++ b/net.h @@ -0,0 +1,9 @@ +#ifndef _net_h +#define _net_h +#include "common.h" + +void sendall_log(SOCKET socket, const char *buffer, size_t length, int flags); +struct client_data *allocClient(); +void killConnection(struct client_data *client); + +#endif diff --git a/client.c b/networking-tests/client.c similarity index 100% rename from client.c rename to networking-tests/client.c diff --git a/networking-tests/main.c b/networking-tests/main.c new file mode 100755 index 0000000..94e9af5 --- /dev/null +++ b/networking-tests/main.c @@ -0,0 +1,455 @@ +// Some macros to control options +#define LISTENING_PORT 6667 +#define LISTENING_BACKLOG 10 +#define CLIENT_SOCKETS 30 +#define FD_SETSIZE 1024 +#define SUPPORT_IPV4 +#define SUPPORT_IPV6 + +#include +#include +#include +#include +#if defined(_WIN32) +#pragma message("Warning: Windows detected.") +//#include +//#include +//#include +#include +#include +#include +#pragma message("IMPORTANT: COMPILE WITH -lws2_32") +#pragma comment(lib, "ws2_32.lib") +#define PRISocket "llu" +#else +#include +#include +#include +#include +#include +#include +#include +#include +//typedef unsigned long long SOCKET; +typedef int SOCKET; +#define PRISocket "d" +#endif + +struct client_data { + SOCKET FD; + char type; + char nick[32]; + size_t nickLen; +}; + +struct client_data client_socket[CLIENT_SOCKETS]; + +#if defined(_WIN32) +#define net_errno() (WSAGetLastError()) +const char *net_strerror(int e) { + static char msg[256]; + if (!FormatMessageA(\ + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, 0, msg, 256, NULL)) + sprintf(msg, "WSA Error %d", e); + return msg; +} +int net_nonblock(SOCKET fd) { + u_long v = 1; + return ioctlsocket(fd, FIONBIO, &v); +} +#else +#define net_errno() ((int)errno) +#define net_strerror(e) strerror((e)) +#define closesocket close +#define INVALID_SOCKET -1 +int net_nonblock(SOCKET fd) { + int f = fcntl(fd, F_GETFL); + if (f == -1) + return -1; + return fcntl(fd, F_SETFL, f | O_NONBLOCK); +} +#endif +void net_perror(const char *p) +{ + if (p && *p) + fprintf(stderr, "%s: %s\n", p, net_strerror(net_errno())); + else + fprintf(stderr, "%s\n", net_strerror(net_errno())); +} + +size_t send_log(int socket, const void *buffer, size_t length, int flags) { + printf("SERVER: %s", (char*)buffer); + fflush(stdout); + return send(socket, buffer, length, flags); +} + +void sendall_log(int socket, const void *buffer, size_t length, int flags) { + int i; + for(i=0;iFD, packet, packetLen, 0); + } else if(strncmp(packet, "NICK ", 5) == 0) { + // User now registered + setNick(client, packet+5, 32); + printf("USER SET NICKNAME %lu %s\n", client->nickLen, client->nick); + fflush(stdout); + } else if(strncmp(packet, "USER ", 5) == 0) { + // Send welcome + newUser(client); + } else if(strncmp(packet, "MOTD", 4) == 0) { + // Send welcome + sendMOTD(client); + // Horrible join but it works and its funny + } else if(strncmp(packet, "JOIN ", 5) == 0) { + char data[256]; + data[0] = ':'; + strcpy(data+1, client->nick); + strcpy(data+1+client->nickLen, " JOIN :"); + strcpy(data+8+client->nickLen, packet+5); + send_log(client->FD, data, strlen(data), 0); + sendall_log(client->FD, data, strlen(data), 0); + } else if(strncmp(packet, "PRIVMSG ", 8) == 0) { + char data[256]; + data[0] = ':'; + strcpy(data+1, client->nick); + data[1+client->nickLen] = ' '; + strcpy(data+2+client->nickLen, packet); + sendall_log(client->FD, data, strlen(data), 0); + } + +} + +void newUser(struct client_data *client) { + char data[1024]; + // Copy in basics + strcpy(data, ":irc.patchysicp.xyz 001 "); + strcpy(data+24, client->nick); + strcpy(data+24+client->nickLen, " :Welcome to PatchyIRCD!!!\n"); + //send_log(client->FD, data, (26+client->nickLen+27), 0); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Your host is PatchyIRCD V0.0.0\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '3'; + strcpy(data+26+client->nickLen, "This server was created when I had cybersex with your mother.\n"); + send_log(client->FD, data, strlen(data), 0); + data[20] = '2'; + data[21] = '5'; + data[22] = '1'; + strcpy(data+26+client->nickLen, "This server exists\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Jannies don't exist\n"); + send_log(client->FD, data, strlen(data), 0); + sendMOTD(client); +} + +void sendMOTD(struct client_data *client) { + char data[1024]; + // Copy in basics + strcpy(data, ":irc.patchysicp.xyz 375 "); + strcpy(data+24, client->nick); + strcpy(data+24+client->nickLen, " :PatchySICP /MOTD\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '2'; + strcpy(data+26+client->nickLen, "Welcome to Montreal!\n"); + send_log(client->FD, data, strlen(data), 0); + strcpy(data+26+client->nickLen, "You are retarded and I will have cybersex with your mom.\n"); + send_log(client->FD, data, strlen(data), 0); + data[22] = '6'; + strcpy(data+26+client->nickLen, "/MOTD over\n"); + send_log(client->FD, data, strlen(data), 0); +} + +void setNick(struct client_data *client, char* nickname, size_t size) { + // TODO: perform basic sanitization + strncpy(client->nick, nickname, size); + // Null term + client->nick[size-1] = 0; + // Remove newline + int i; + for(i=0;inick[i] == 13) { + client->nick[i] = 0; + break; + } + // Newline + if(client->nick[i] == 10) { + client->nick[i] = 0; + break; + } + } + // Set length + client->nickLen = strlen(client->nick); + return; +} + +int main(){ + fd_set readfds; + SOCKET highestFD; + int i; + SOCKET SD; + SOCKET serverSocketV4 = 0; + SOCKET serverSocketV6 = 0; + char client_addr[100]; + char *welcomeMessage = ":irc.patchysicp.xyz NOTICE * :Hello welcome to PatchyIRCD!\n"; + char buffer[1024]; + size_t bytesRead; + +#if defined(_WIN32) + struct WSAData wd; + if (WSAStartup(MAKEWORD(2, 0), &wd)) printf("Winsock API startup failed.\n"); +#endif + + puts("Starting"); + fflush(stdout); + +#ifdef SUPPORT_IPV4 + struct sockaddr_in serverAddrV4; + memset(&serverAddrV4, 0, sizeof(struct sockaddr_in)); + serverAddrV4.sin_addr.s_addr = INADDR_ANY; + serverAddrV4.sin_port = htons(LISTENING_PORT); + serverAddrV4.sin_family = AF_INET; + size_t serverAddrV4len = sizeof(serverAddrV4); +#endif +#ifdef SUPPORT_IPV6 + struct sockaddr_in6 serverAddrV6; + memset(&serverAddrV6, 0, sizeof(struct sockaddr_in6)); + serverAddrV6.sin6_addr = in6addr_any; + serverAddrV6.sin6_flowinfo = 0; + serverAddrV6.sin6_port = htons(LISTENING_PORT); + serverAddrV6.sin6_family = AF_INET6; + size_t serverAddrV6len = sizeof(serverAddrV6); +#endif + + int opt = 1; +#ifdef SUPPORT_IPV4 + // Create socket + serverSocketV4 = socket(AF_INET, SOCK_STREAM, 0); + if(serverSocketV4 == (SOCKET)INVALID_SOCKET) { + net_perror("ERROR SOCKET IPV4"); + exit(EXIT_FAILURE); + } + // Set socket options + if(setsockopt(serverSocketV4, SOL_SOCKET,\ + SO_REUSEADDR,\ + (void*)&opt, sizeof(opt)) == -1) { + net_perror("ERROR SOCKET IPV4"); + exit(EXIT_FAILURE); + } + // Set nonblock + net_nonblock(serverSocketV4); + // Bind to socket + if(bind(serverSocketV4, (struct sockaddr*)&serverAddrV4,\ + sizeof(struct sockaddr_in)) == -1) { + net_perror("ERROR BIND IPV4"); + exit(EXIT_FAILURE); + } + // Listen to socket + if(listen(serverSocketV4, LISTENING_BACKLOG) == -1) { + net_perror("ERROR LISTEN IPV4"); + exit(EXIT_FAILURE); + } +#endif +#ifdef SUPPORT_IPV6 + // Create socket + serverSocketV6 = socket(AF_INET6, SOCK_STREAM, 0); + if(serverSocketV6 == (SOCKET)INVALID_SOCKET) { + net_perror("ERROR SOCKET IPV6"); + exit(EXIT_FAILURE); + } + // Set socket options + if(setsockopt(serverSocketV6, SOL_SOCKET,\ + SO_REUSEADDR,\ + (void*)&opt, sizeof(opt)) == -1) { + net_perror("ERROR SOCKET IPV6"); + exit(EXIT_FAILURE); + } + // IPV6 Only + if(setsockopt(serverSocketV6, IPPROTO_IPV6,\ + IPV6_V6ONLY,\ + (void*)&opt, sizeof(opt)) == -1) { + net_perror("ERROR SOCKET IPV6"); + exit(EXIT_FAILURE); + } + // Set nonblock + net_nonblock(serverSocketV6); + // Bind to socket + if(bind(serverSocketV6, (struct sockaddr*)&serverAddrV6,\ + sizeof(struct sockaddr_in6)) == -1) { + net_perror("ERROR BIND IPV6"); + exit(EXIT_FAILURE); + } + // Listen to socket + if(listen(serverSocketV6, LISTENING_BACKLOG) == -1) { + net_perror("ERROR LISTEN IPV6"); + exit(EXIT_FAILURE); + } +#endif + + memset(client_socket, 0, sizeof(client_socket)); + + puts("Ready"); + fflush(stdout); + while(1){ + // Clear all sockets + FD_ZERO(&readfds); + // Add main sockets +#ifdef SUPPORT_IPV4 + FD_SET(serverSocketV4, &readfds); +#endif +#ifdef SUPPORT_IPV6 + FD_SET(serverSocketV6, &readfds); +#endif + if(serverSocketV4 < serverSocketV6) highestFD = serverSocketV6; + else highestFD = serverSocketV4; + + // Check for new sockets + for(i=0;i0){ + FD_SET(SD, &readfds); + // Update highest FD + if(SD>highestFD){ + highestFD = SD; + } + } + } + + // Wait until activity on sockets + if(select(highestFD+1,&readfds,NULL,NULL,NULL) == -1) { + net_perror("ERROR SELECT"); + } + +#ifdef SUPPORT_IPV4 + if (FD_ISSET(serverSocketV4, &readfds)) { + SOCKET newSocket = accept(serverSocketV4, NULL, NULL); + if(newSocket == (SOCKET)INVALID_SOCKET){ + net_perror("ERROR newSocket IPV4"); + } + getpeername(newSocket,(struct sockaddr*)&serverAddrV4,(socklen_t*)&serverAddrV4len); + inet_ntop(AF_INET, &(serverAddrV4.sin_addr), client_addr, sizeof(client_addr)); + printf("Connection accepted from Socket: %"PRISocket", IP: %s PORT: %d\n", newSocket, client_addr, ntohs(serverAddrV4.sin_port)); + fflush(stdout); + send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0); + // Add to list of sockets + for(i=0;i0) { + closesocket(client_socket[i].FD); + } + } + return 0; +} + -- 2.56.0