--- /dev/null
+#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);
+}
--- /dev/null
+#ifndef _netsock_h
+#define _netsock_h
+#define FD_SETSIZE 1024
+
+// Standard headers
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+// Windows
+#if defined(_WIN32)
+#pragma message("Warning: Windows detected.")
+#pragma message("IMPORTANT: COMPILE WITH -lws2_32")
+#pragma comment(lib, "ws2_32.lib")
+//#include <WinSock2.h>
+//#include <WS2tcpip.h>
+//#include <Windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+//#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 <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+//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
--- /dev/null
+#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
--- /dev/null
+#define LISTENING_PORT 6667
+#define LISTENING_BACKLOG 10
+#define CLIENTS 30
+#define SUPPORT_IPV4
+#define SUPPORT_IPV6
--- /dev/null
+#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;i<size;i++){
+ // CR/^M
+ if(client->nick[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;
+}
--- /dev/null
+#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
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#if defined(_WIN32)
-#pragma message("Warning: Windows detected.")
-//#include <WinSock2.h>
-//#include <WS2tcpip.h>
-//#include <Windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#pragma message("IMPORTANT: COMPILE WITH -lws2_32")
-#pragma comment(lib, "ws2_32.lib")
-#define PRISocket "llu"
-#else
-#include <unistd.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/select.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <fcntl.h>
-//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;i<CLIENT_SOCKETS;i++) {
- if(client_socket[i].FD == socket || client_socket[i].FD == 0) {
- continue;
- } else {
- printf("SERVER: %"PRISocket" %s", client_socket[i].FD, (char*)buffer);
- fflush(stdout);
- send(client_socket[i].FD, buffer, length, flags);
- }
- }
-}
-
-// IRC STUFF COPY THIS WHEN WE REFINE ALL OF THIS CODE INTO THE NEW SERVER
-
-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);
-
-// TODO: check for newlines are process each one as a different packet
-void processPacket(struct client_data *client, char *packet, size_t packetLen) {
- if(strncmp(packet, "PING", 4) == 0) {
- packet[1] = 'O';
- send_log(client_socket->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.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;i<size;i++){
- // CR/^M
- if(client->nick[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));
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);
}
#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;i<CLIENT_SOCKETS;i++) {
- SD = client_socket[i].FD;
- // Valid FD
- if(SD>0){
- FD_SET(SD, &readfds);
- // Update highest FD
- if(SD>highestFD){
- highestFD = SD;
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] != 0){
+ FD_SET(clients[i]->FD, &readfds);
+ if(clients[i]->FD>highestFD){
+ highestFD = clients[i]->FD;
}
}
}
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);
fflush(stdout);
send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0);
// Add to list of sockets
- for(i=0;i<CLIENT_SOCKETS;i++) {
- if(client_socket[i].FD==0){
- client_socket[i].FD = newSocket;
- client_socket[i].type = 4;
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] == 0){
+ clients[i] = allocClient();
+ clients[i]->FD = newSocket;
+ clients[i]->type = 4;
// Set nonblock
- net_nonblock(client_socket[i].FD);
+ net_nonblock(clients[i]->FD);
break;
}
}
fflush(stdout);
send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0);
// Add to list of sockets
- for(i=0;i<CLIENT_SOCKETS;i++) {
- if(client_socket[i].FD==0){
- client_socket[i].FD = newSocket;
- client_socket[i].type = 6;
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] == 0){
+ clients[i] = allocClient();
+ clients[i]->FD = 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;i<CLIENT_SOCKETS;i++) {
- SD = client_socket[i].FD;
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] == 0) continue;
+ SD = clients[i]->FD;
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));
}
#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;
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;i<CLIENT_SOCKETS;i++) {
- if(client_socket[i].FD>0) {
- closesocket(client_socket[i].FD);
+ puts("[PatchyIRCD]: Cleaning up...");
+ fflush(stdout);
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] != 0) {
+ killConnection(clients[i]);
}
}
+ net_cleanup();
return 0;
}
-
--- /dev/null
+#include "net.h"
+
+void sendall_log(SOCKET socket, const char *buffer, size_t length, int flags) {
+ int i;
+ for(i=0;i<CLIENTS;i++) {
+ if(clients[i] == 0) continue;
+ if(clients[i]->FD == 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;i<CLIENTS;i++) {
+ if(clients[i] == client) {
+ clients[i] = 0;
+ }
+ }
+ closesocket(client->FD);
+ free(client);
+}
--- /dev/null
+#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
--- /dev/null
+// 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#if defined(_WIN32)
+#pragma message("Warning: Windows detected.")
+//#include <WinSock2.h>
+//#include <WS2tcpip.h>
+//#include <Windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#pragma message("IMPORTANT: COMPILE WITH -lws2_32")
+#pragma comment(lib, "ws2_32.lib")
+#define PRISocket "llu"
+#else
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+//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;i<CLIENT_SOCKETS;i++) {
+ if(client_socket[i].FD == socket || client_socket[i].FD == 0) {
+ continue;
+ } else {
+ printf("SERVER: %"PRISocket" %s", client_socket[i].FD, (char*)buffer);
+ fflush(stdout);
+ send(client_socket[i].FD, buffer, length, flags);
+ }
+ }
+}
+
+// IRC STUFF COPY THIS WHEN WE REFINE ALL OF THIS CODE INTO THE NEW SERVER
+
+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);
+
+// TODO: check for newlines are process each one as a different packet
+void processPacket(struct client_data *client, char *packet, size_t packetLen) {
+ if(strncmp(packet, "PING", 4) == 0) {
+ packet[1] = 'O';
+ send_log(client_socket->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.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;i<size;i++){
+ // CR/^M
+ if(client->nick[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;i<CLIENT_SOCKETS;i++) {
+ SD = client_socket[i].FD;
+ // Valid FD
+ if(SD>0){
+ 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;i<CLIENT_SOCKETS;i++) {
+ if(client_socket[i].FD==0){
+ client_socket[i].FD = newSocket;
+ client_socket[i].type = 4;
+ // Set nonblock
+ net_nonblock(client_socket[i].FD);
+ break;
+ }
+ }
+ }
+#endif
+#ifdef SUPPORT_IPV6
+ if (FD_ISSET(serverSocketV6, &readfds)) {
+ SOCKET newSocket = accept(serverSocketV6, NULL, NULL);
+ if(newSocket == (SOCKET)INVALID_SOCKET){
+ net_perror("ERROR newSocket IPV6");
+ }
+ getpeername(newSocket,(struct sockaddr*)&serverAddrV6,(socklen_t*)&serverAddrV6len);
+ inet_ntop(AF_INET6, &(serverAddrV6.sin6_addr), client_addr, sizeof(client_addr));
+ printf("Connection accepted from Socket: %"PRISocket", IP: %s PORT: %d\n", newSocket, client_addr, ntohs(serverAddrV6.sin6_port));
+ fflush(stdout);
+ send_log(newSocket, welcomeMessage, strlen(welcomeMessage), 0);
+ // Add to list of sockets
+ for(i=0;i<CLIENT_SOCKETS;i++) {
+ if(client_socket[i].FD==0){
+ client_socket[i].FD = newSocket;
+ client_socket[i].type = 6;
+ // Set nonblock
+ net_nonblock(client_socket[i].FD);
+ break;
+ }
+ }
+ }
+#endif
+ // Respond to already connected clients
+ for(i=0;i<CLIENT_SOCKETS;i++) {
+ SD = client_socket[i].FD;
+ if(FD_ISSET(SD, &readfds)) {
+ //bytesRead = read(SD, buffer, sizeof(buffer));
+ bytesRead = recv(SD,buffer,sizeof(buffer), 0);
+ // Disconnect
+ if(bytesRead == 0) {
+#ifdef SUPPORT_IPV4
+ if(client_socket[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));
+ fflush(stdout);
+ }
+#endif
+#ifdef SUPPORT_IPV6
+ if(client_socket[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;
+ } 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;
+ char tmp;
+ for(j=0;j<bytesRead;j++){
+ if(buffer[j] == '\n'){
+ char tmp = buffer[j+1];
+ buffer[j+1] = 0;
+ //Send to processing
+ processPacket(&(client_socket[i]), buffer2, strlen(buffer2));
+ buffer[j+1] = tmp;
+ buffer2 = &(buffer[j+1]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+#if defined(_WIN32)
+ WSACleanup();
+#endif
+ for(i=0;i<CLIENT_SOCKETS;i++) {
+ if(client_socket[i].FD>0) {
+ closesocket(client_socket[i].FD);
+ }
+ }
+ return 0;
+}
+