]> PatchyGit - patchyircd.git/commitdiff
add tls support
authorEgor <egor@patchysicp.xyz>
Wed, 11 May 2022 09:34:23 +0000 (12:34 +0300)
committerEgor <egor@patchysicp.xyz>
Wed, 11 May 2022 09:34:23 +0000 (12:34 +0300)
.gitignore
common.h
config.example.mk
config.h
irc.c
main.c
net.c
net.h
passwd.c

index 5c04fc5..d6975e7 100644 (file)
@@ -5,3 +5,5 @@ setpass
 ops.txt
 init.txt
 chanlog.txt
+cert.pem
+key.pem
index a1b0fb5..31d4ea1 100644 (file)
--- a/common.h
+++ b/common.h
@@ -4,6 +4,11 @@
 #include "config.h"
 #include "trie.h"
 #include <time.h>
+#ifdef HAS_TLS
+#include <tls.h>
+#else
+struct tls;
+#endif
 
 #define SETBIT(var, bit, val) ((void)((val) ? ((var)|=(bit)) : ((var)&=~(bit))))
 #define UMODE_INVISIBLE 1
 #define UMODE_LOPER 4
 #define UMODE_REGISTERED 8
 #define UMODE_WALLOPS 16
+#define UMODE_SECURE 32
 #define REG_INIT 0
 #define REG_CAPLS 1
 #define REG_REGISTERED 2
 struct client_data {
        SOCKET FD;
+       struct tls *cctx;
        char   type;
        char   *nick;
        char   *key; // case-mapped nick
@@ -25,9 +32,10 @@ struct client_data {
        char   *away;
        char   *nick_reg;
        char   *pass_reg;
+       char   *peername;
+       unsigned short peerport;
        char   buf[2048];
        size_t bufLen;
-       size_t bufCap;
        char   umode;
        char   regstate;
        struct trie_node *channels;
@@ -70,4 +78,9 @@ extern struct sockaddr_in6 serverAddrV6;
 extern size_t              serverAddrV4len;
 extern size_t              serverAddrV6len;
 
+#ifndef _MSC_VER
+#pragma GCC poison recv_log
+#pragma GCC poison send_log
+#endif
+
 #endif
index 686ee88..9bb7a5e 100644 (file)
@@ -1,6 +1,7 @@
 HEADERS+=config.mk
 CC=clang
-CFLAGS=-Wall -Wextra
+CFLAGS=-Wall -Wextra -DHAS_TLS
+LDLIBS=-ltls
 CC.w32=i686-w64-mingw32-gcc
 CFLAGS.w32=-Wall -Wextra -DI_KNOW_HOW_TO_USE_A_LINKER -DWINVER=0x0600 -D_WIN32_WINNT=0x0600
 LDLIBS.w32=-lws2_32
index 36d19ae..45ff1f9 100644 (file)
--- a/config.h
+++ b/config.h
@@ -1,4 +1,5 @@
 #define LISTENING_PORT 6667
+#define LISTENING_PORT_TLS 6697
 #define LISTENING_BACKLOG 10
 #define CLIENTS 30
 #define SUPPORT_IPV4
diff --git a/irc.c b/irc.c
index 0f6658d..5664232 100644 (file)
--- a/irc.c
+++ b/irc.c
@@ -10,7 +10,7 @@ struct trie_node *channel_map = NULL;
 const char *hostname = "irc.patchysicp.xyz";
 #define is_registered(cl) ((cl)->regstate == REG_REGISTERED)
 void sendbuf(struct client_data *client) {
-       send_log(client->FD, databuf.buf, databuf.len, 0);
+       sendClient(client, databuf.buf, databuf.len);
 }
 void chanlog_time(time_t timestamp) {
        extern FILE *fchanlog;
@@ -408,6 +408,7 @@ int processPacket(struct client_data *client, char *source, char *command, int a
                                if (cl->umode & UMODE_LOPER) append_str(&databuf, "O");
                                if (cl->umode & UMODE_REGISTERED) append_str(&databuf, "r");
                                if (cl->umode & UMODE_WALLOPS) append_str(&databuf, "w");
+                               if (cl->umode & UMODE_SECURE) append_str(&databuf, "Z");
                                append_str(&databuf, "\r\n");
                                sendbuf(client);
                        } else {
diff --git a/main.c b/main.c
index 82e0c88..e6f8262 100644 (file)
--- a/main.c
+++ b/main.c
@@ -80,14 +80,108 @@ fd_set readfds;
        size_t serverAddrV6len;
 #endif
 FILE *fchanlog = NULL;
-int main() {
+
+SOCKET create_listen_sock(int af, struct sockaddr *addr, size_t len)
+{
+       SOCKET sock;
+       // Create socket
+       sock = socket(af, SOCK_STREAM, 0);
+       if(sock == (SOCKET)INVALID_SOCKET) {
+               net_perror("ERROR SOCKET");
+               exit(EXIT_FAILURE);
+       }
+       // Set socket options
        int opt = 1;
-       SOCKET serverSocketV4 = 0;
-       SOCKET serverSocketV6 = 0;
-       SOCKET highestFD;
-       SOCKET SD;
-       int i;
-       char client_addr[100];
+       if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) == -1) {
+               net_perror("ERROR SOCKET");
+               exit(EXIT_FAILURE);
+       }
+#ifdef SUPPORT_IPV6
+       // IPV6 Only
+       if(af == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&opt, sizeof(opt)) == -1) {
+               net_perror("ERROR SOCKET IPV6");
+               exit(EXIT_FAILURE);
+       }
+#endif
+       // Set nonblock
+       net_nonblock(sock);
+       // Bind to socket
+       if(bind(sock, addr, len) == -1) {
+               net_perror("ERROR BIND");
+               exit(EXIT_FAILURE);
+       }
+       // Listen to socket
+       if(listen(sock, LISTENING_BACKLOG) == -1) {
+               net_perror("ERROR LISTEN");
+               exit(EXIT_FAILURE);
+       }
+       return sock;
+}
+
+void accept_from_sock(SOCKET serverSocket, struct tls *ctx)
+{
+       while (true) {
+               struct sockaddr_storage addr;
+               socklen_t len = sizeof(addr);
+               SOCKET newSocket = accept(serverSocket, (struct sockaddr *)&addr, &len);
+               if (newSocket == (SOCKET)INVALID_SOCKET) {
+                       if (!net_wouldblock())
+                               net_perror("ERROR newSocket");
+                       break;
+               }
+               // Set nonblock
+               net_nonblock(newSocket);
+
+               char client_addr[100];
+               int port;
+               if (addr.ss_family == AF_INET) {
+                       inet_ntop(AF_INET, &((struct sockaddr_in*)&addr)->sin_addr, client_addr, sizeof(client_addr));
+                       port = ntohs(((struct sockaddr_in*)&addr)->sin_port);
+               } else if (addr.ss_family == AF_INET6) {
+                       inet_ntop(AF_INET6, &((struct sockaddr_in6*)&addr)->sin6_addr, client_addr, sizeof(client_addr));
+                       port = ntohs(((struct sockaddr_in6*)&addr)->sin6_port);
+               } else {
+                       strcpy(client_addr, "?");
+                       port = 0;
+               }
+               printf("Connection accepted from Socket: %"PRISocket", IP: %s PORT: %d\n", newSocket,
+                               client_addr, port);
+               fflush(stdout);
+               struct tls *cctx = NULL;
+               if (ctx) {
+#ifdef HAS_TLS
+                       if (tls_accept_socket(ctx, &cctx, newSocket) == -1) {
+                               close(newSocket);
+                               fprintf(stderr, "tls_accept_socket: %s\n", tls_error(ctx));
+                               continue;
+                       }
+#endif
+               }
+               // Add to list of sockets
+               for(int i=0;i<CLIENTS;i++) {
+                       if(clients[i] == 0){
+                               clients[i] = allocClient();
+                               clients[i]->FD = newSocket;
+                               clients[i]->cctx = cctx;
+                               clients[i]->type = addr.ss_family == AF_INET6 ? 6 : 4;
+                               clients[i]->peername = mystrdup(client_addr);
+                               if (!clients[i]->peername) abort();
+                               clients[i]->peerport = port;
+                               if (cctx)
+                                       clients[i]->umode |= UMODE_SECURE;
+                               extern const char *hostname;
+                               copy_strf(&databuf, ":%s NOTICE * :Hello welcome to PatchyIRCD!\r\n", hostname);
+                               sendbuf(clients[i]);
+                               break;
+                       }
+               }
+       }
+}
+
+int main() {
+       SOCKET listeners[4];
+       struct tls *listeners_tls[4];
+       int listener_count = 0;
        puts("[PatchyIRCD]: Starting up...");
        fflush(stdout);
 
@@ -106,6 +200,8 @@ int main() {
        serverAddrV4.sin_port = htons(LISTENING_PORT);
        serverAddrV4.sin_family = AF_INET;
        serverAddrV4len = sizeof(serverAddrV4);
+       listeners_tls[listener_count] = NULL;
+       listeners[listener_count++] = create_listen_sock(AF_INET, (struct sockaddr*)&serverAddrV4, sizeof(struct sockaddr_in));
 #endif
 #ifdef SUPPORT_IPV6
        memset(&serverAddrV6, 0, sizeof(struct sockaddr_in6));
@@ -114,76 +210,41 @@ int main() {
        serverAddrV6.sin6_port = htons(LISTENING_PORT);
        serverAddrV6.sin6_family = AF_INET6;
        serverAddrV6len = sizeof(serverAddrV6);
+       listeners_tls[listener_count] = NULL;
+       listeners[listener_count++] = create_listen_sock(AF_INET6, (struct sockaddr*)&serverAddrV6, sizeof(struct sockaddr_in6));
 #endif
+#ifdef HAS_TLS
+       struct tls_config *tls_cfg;
+       struct tls *tls_ctx;
+       if (tls_init() == -1)
+               return fprintf(stderr, "tls_init error\n"), 1;
+       if (!(tls_cfg = tls_config_new()))
+               return fprintf(stderr, "tls_config_new error\n"), 1;
+       if (tls_config_set_cert_file(tls_cfg, "cert.pem") == -1)
+               return fprintf(stderr, "tls_config_set_cert_file: %s\n", tls_config_error(tls_cfg)), 1;
+       if (tls_config_set_key_file(tls_cfg, "key.pem") == -1)
+               return fprintf(stderr, "tls_config_set_key_file: %s\n", tls_config_error(tls_cfg)), 1;
+       if (!(tls_ctx = tls_server()))
+               return fprintf(stderr, "tls_server error\n"), 1;
+       if (tls_configure(tls_ctx, tls_cfg) == -1)
+               return fprintf(stderr, "tls_configure: %s\n", tls_error(tls_ctx)), 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);
-       }
+       serverAddrV4.sin_port = htons(LISTENING_PORT_TLS);
+       listeners_tls[listener_count] = tls_ctx;
+       listeners[listener_count++] = create_listen_sock(AF_INET, (struct sockaddr*)&serverAddrV4, sizeof(struct sockaddr_in));
 #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);
-       }
+       serverAddrV6.sin6_port = htons(LISTENING_PORT_TLS);
+       listeners_tls[listener_count] = tls_ctx;
+       listeners[listener_count++] = create_listen_sock(AF_INET6, (struct sockaddr*)&serverAddrV6, sizeof(struct sockaddr_in6));
+#endif
 #endif
 
        FILE *f = fopen("init.txt", "rb");
        if (f) {
                struct client_data *fake = allocClient();
-               fake->bufCap = sizeof(fake->buf)-1;
-               fake->umode |= UMODE_OPER;
+               fake->umode |= UMODE_OPER | UMODE_SECURE;
                strcpy(fake->buf, "NICK :root\r\n");
                fake->bufLen = strlen(fake->buf);
                parsePacket(fake);
@@ -238,30 +299,28 @@ int main() {
        while(is_running){
                FD_ZERO(&readfds); 
                // Add listening SOCKETS to FDSET
-#ifdef SUPPORT_IPV4
-               FD_SET(serverSocketV4, &readfds);
-#endif
-#ifdef SUPPORT_IPV6
-               FD_SET(serverSocketV6, &readfds);
-#endif
+               for (int i = 0; i < listener_count; i++)
+                       FD_SET(listeners[i], &readfds);
 #ifdef _WIN32
-               // we don't need to do highestFD for this on, cuz it's windows only
                if (self_sock != INVALID_SOCKET)
                        FD_SET(self_sock, &readfds);
 #endif
+               for (int i = 0; i < CLIENTS; i++)
+                       if (clients[i])
+                               FD_SET(clients[i]->FD, &readfds);
 
                // Set highestFD
-               if(serverSocketV4 < serverSocketV6) highestFD = serverSocketV6;
-               else highestFD = serverSocketV4;
-               for(i=0;i<CLIENTS;i++) {
-                       if(clients[i] != 0){
-                               FD_SET(clients[i]->FD, &readfds);
-                               if(clients[i]->FD>highestFD){
+#ifdef _WIN32
+               int highestFD = -1;
+#else
+               SOCKET highestFD = -1;
+               for (int i = 0; i < listener_count; i++)
+                       if (highestFD < listeners[i])
+                               highestFD = listeners[i];
+               for (int i = 0; i < CLIENTS; i++)
+                       if (clients[i] && highestFD < clients[i]->FD)
                                        highestFD = clients[i]->FD;
-                               }
-                       }
-               }
-
+#endif
                // Wait until activity on sockets
                if(select(highestFD+1,&readfds,NULL,NULL,NULL) == -1) {
 #ifndef _WIN32
@@ -279,79 +338,24 @@ int main() {
 #endif
 
                // Accept new connections
-               // TODO: Optimize this with goto
-#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);
-                       extern const char *hostname;
-                       copy_strf(&databuf, ":%s NOTICE * :Hello welcome to PatchyIRCD!\r\n", hostname);
-                       send_log(newSocket, databuf.buf, databuf.len, 0);
-                       // Add to list of sockets
-                       for(i=0;i<CLIENTS;i++) {
-                               if(clients[i] == 0){
-                                       clients[i] = allocClient();
-                                       clients[i]->FD = newSocket;
-                                       clients[i]->type = 4;
-                                       clients[i]->bufCap = sizeof(clients[i]->buf);
-                                       // Set nonblock
-                                       net_nonblock(clients[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);
-                       extern const char *hostname;
-                       copy_strf(&databuf, ":%s NOTICE * :Hello welcome to PatchyIRCD!\r\n", hostname);
-                       send_log(newSocket, databuf.buf, databuf.len, 0);
-                       // Add to list of sockets
-                       for(i=0;i<CLIENTS;i++) {
-                               if(clients[i] == 0){
-                                       clients[i] = allocClient();
-                                       clients[i]->FD = newSocket;
-                                       clients[i]->type = 6;
-                                       clients[i]->bufCap = sizeof(clients[i]->buf);
-                                       // Set nonblock
-                                       net_nonblock(clients[i]->FD);
-                                       break;
-                               }
-                       }
-               }
-#endif
+               for (int i = 0; i < listener_count; i++)
+                       if (FD_ISSET(listeners[i], &readfds))
+                               accept_from_sock(listeners[i], listeners_tls[i]);
                // Respond to already connected clients
-               for(i=0;i<CLIENTS;i++) {
-                       if(clients[i] == 0) continue;
-                       SD = clients[i]->FD;
-                       if(FD_ISSET(SD, &readfds)) {
+               for (int i = 0; i < CLIENTS; i++)
+                       if (clients[i] && FD_ISSET(clients[i]->FD, &readfds))
                                recvProc(clients[i]);
-                       }
-               }
        }
 
        puts("[PatchyIRCD]: Cleaning up...");
        fflush(stdout);
-       for(i=0;i<CLIENTS;i++) {
-               if(clients[i] != 0) {
+       for (int i = 0; i < CLIENTS; i++)
+               if (clients[i])
                        killConnection(clients[i], false);
-               }
-       }
        net_cleanup();
+#ifdef HAS_TLS
+       tls_free(tls_ctx);
+#endif
        free(databuf.buf);
        return 0;
 }
diff --git a/net.c b/net.c
index c1a5144..850ef4d 100644 (file)
--- a/net.c
+++ b/net.c
@@ -10,30 +10,14 @@ struct client_data *allocClient(){
 };
 
 void killConnection(struct client_data *cl, bool byChoice) {
-       int i;
-       char data[1024];
-       if(cl == 0) return;
-       for(i=0;i<CLIENTS;i++) {
-               if(clients[i] == cl) {
+       if (!cl) return;
+       for (int i = 0; i < CLIENTS; i++)
+               if(clients[i] == cl)
                        clients[i] = 0;
-               }
-       }
-#ifdef SUPPORT_IPV4
-       if(cl->type == 4) {
-               getpeername(cl->FD,(struct sockaddr*)&serverAddrV4,(socklen_t*)&serverAddrV4len);  
-               inet_ntop(AF_INET, &(serverAddrV4.sin_addr), data, sizeof(data));
-               printf("Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", cl->FD, data, ntohs(serverAddrV4.sin_port));
-               fflush(stdout);
-       }
-#endif
-#ifdef SUPPORT_IPV6
-       if(cl->type == 6) {
-               getpeername(cl->FD,(struct sockaddr*)&serverAddrV6,(socklen_t*)&serverAddrV6len);  
-               inet_ntop(AF_INET6, &(serverAddrV6.sin6_addr), data, sizeof(data));
-               printf("Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", cl->FD, data, ntohs(serverAddrV6.sin6_port));
+       if (cl->peername) {
+               printf("Client disconnected from Socket: %"PRISocket", IP: %s PORT: %d\n", cl->FD, cl->peername, cl->peerport);
                fflush(stdout);
        }
-#endif
        // Start GitHub Copilot
        if(!byChoice && cl->nick && cl->username) {
                msg_quit(cl, "", "Has left the building (Forced)");
@@ -44,6 +28,20 @@ void killConnection(struct client_data *cl, bool byChoice) {
        sendbuf(cl);
        // End GitHub Copilot
        if (cl->FD != INVALID_SOCKET) {
+#ifdef HAS_TLS
+               if (cl->cctx) {
+                       // FIXME: this blocks
+                       int rv;
+                       do {
+                               rv = tls_close(cl->cctx);
+                       } while (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT);
+                       if (rv == -1) {
+                               fprintf(stderr, "tls_close (%"PRISocket"): %s\n", cl->FD, tls_error(cl->cctx));
+                       }
+                       tls_free(cl->cctx);
+                       cl->cctx = NULL;
+               }
+#endif
                shutdown(cl->FD, SHUT_RDWR);
                closesocket(cl->FD);
        }
@@ -66,6 +64,7 @@ void killConnection(struct client_data *cl, bool byChoice) {
        if (cl->pass_reg)
                memset(cl->pass_reg, 0, strlen(cl->pass_reg));
        free(cl->pass_reg);
+       free(cl->peername);
        free(cl);
 }
 
@@ -75,20 +74,43 @@ void recvProc(struct client_data *cl) {
        int packetReturn;
        while(1){
                // I hate you
-               if(cl->bufLen == cl->bufCap) { killConnection(cl, false); return; }
-               bytesRead = recv(cl->FD,cl->buf + cl->bufLen,cl->bufCap - cl->bufLen, 0);
-               switch(bytesRead){
-                       // Disconnect
-                       case 0:
-                               killConnection(cl, false);
-                               return;
-                       // Error
-                       case -1:
-                               if(!net_wouldblock()){
+               if(cl->bufLen == sizeof(cl->buf)) { killConnection(cl, false); return; }
+#if HAS_TLS
+               if (cl->cctx) {
+                       bytesRead = tls_read(cl->cctx, cl->buf + cl->bufLen, sizeof(cl->buf) - cl->bufLen);
+                       switch (bytesRead) {
+                               // Disconnect
+                               case 0:
                                        killConnection(cl, false);
-                                       net_perror("RECV");
-                               }
-                               return;
+                                       return;
+                               // Error
+                               case -1:
+                                       killConnection(cl, false);
+                                       fprintf(stderr, "tls_read: %s\n", tls_error(cl->cctx));
+                                       return;
+                               case TLS_WANT_POLLIN:
+                                       return;
+                               case TLS_WANT_POLLOUT: // FIXME: this blocks
+                                       continue;
+                       }
+               }
+               else
+#endif
+               {
+                       bytesRead = recv(cl->FD,cl->buf + cl->bufLen,sizeof(cl->buf) - cl->bufLen, 0);
+                       switch(bytesRead){
+                               // Disconnect
+                               case 0:
+                                       killConnection(cl, false);
+                                       return;
+                               // Error
+                               case -1:
+                                       if(!net_wouldblock()){
+                                               killConnection(cl, false);
+                                               net_perror("RECV");
+                                       }
+                                       return;
+                       }
                }
                cl->bufLen += bytesRead;
                while(1){
@@ -104,3 +126,38 @@ void recvProc(struct client_data *cl) {
                }
        }
 }
+
+void sendClient(struct client_data *cl, const char *buf, size_t len)
+{
+       if (cl->FD == (SOCKET)INVALID_SOCKET)
+               return;
+       fprintf(stderr, "SERVER %"PRISocket": %.*s", cl->FD, (int)len, (char*)buf);
+       // TODO: error handling
+       // FIXME: blocks, probably the reason why server is slow
+#ifdef HAS_TLS
+       if (cl->cctx) {
+               while (len) {
+                       int rv = tls_write(cl->cctx, buf, len);
+                       if (rv == -1)
+                               break;
+                       if (rv == TLS_WANT_POLLIN || rv == TLS_WANT_POLLOUT)
+                               continue;
+                       buf += rv;
+                       len -= rv;
+               }
+       } else
+#endif
+       {
+               while (len) {
+                       int rv = send(cl->FD, buf, len, 0);
+                       if (rv == -1) {
+                               if (net_wouldblock())
+                                       continue;
+                               else
+                                       break;
+                       }
+                       buf += rv;
+                       len -= rv;
+               }
+       }
+}
diff --git a/net.h b/net.h
index 19c1ae1..0c3daf1 100644 (file)
--- a/net.h
+++ b/net.h
@@ -8,5 +8,6 @@ void sendbuf_visible(struct client_data *client);
 struct client_data *allocClient();
 void killConnection(struct client_data *client, bool byChoice);
 void recvProc(struct client_data *cl);
+void sendClient(struct client_data *cl, const char *buf, size_t len);
 
 #endif
index 88d83d4..26e4b19 100644 (file)
--- a/passwd.c
+++ b/passwd.c
@@ -1,10 +1,17 @@
 #ifdef _WIN32
 int password_set(const char *key, const char *pw, const char *fn, const char *tmpfn)
 {
+       (void)key;
+       (void)pw;
+       (void)fn;
+       (void)tmpfn;
        return -1;
 }
 int password_check(const char *key, const char *pw, const char *fn)
 {
+       (void)key;
+       (void)pw;
+       (void)fn;
        return -1;
 }
 #else