]> PatchyGit - patchyircd.git/commitdiff
job: use lambdas
authorEgor <egor@patchysicp.xyz>
Tue, 20 Jan 2026 17:28:36 +0000 (19:28 +0200)
committerEgor <egor@patchysicp.xyz>
Tue, 20 Jan 2026 17:29:39 +0000 (19:29 +0200)
src/common.hpp
src/db.hpp
src/dbtool.cpp
src/irc.cpp
src/job.cpp
src/job.hpp
src/main.cpp

index 90d73c4..196552c 100644 (file)
 /* C++ standard */
 #include <algorithm>
 #include <deque>
+#include <functional>
+#include <iostream>
 #include <iterator>
+#include <memory>
+#include <string>
 #include <string_view>
 #include <utility>
 #include <vector>
index 0bf2d58..3850a48 100644 (file)
@@ -4,8 +4,6 @@
 #define DB_H_
 typedef struct sqlite3 sqlite3;
 typedef struct sqlite3_stmt sqlite3_stmt;
-#include <string_view>
-#include <utility>
 namespace db {
        struct Statement;
        struct Database {
index f4e44b5..9aaa78b 100644 (file)
@@ -4,9 +4,6 @@
 #include "db.hpp"
 #include "passwd.hpp"
 #include "util.hpp"
-#include <stdio.h>
-#include <functional>
-#include <iostream>
 static const char *argv0 = nullptr;
 static void usage() {
        printf("Usage: %s import\n", argv0);
index 082b0c1..12a85fa 100644 (file)
@@ -180,62 +180,6 @@ int irc_parse_line(Client *client, char *p, char *end) {
        fprintf(stderr, "\n");
        return irc_process_line(client, source, commandsv, argc, args);
 }
-static void cont_webirc(Client *client, int res) {
-       if (!(client->umode & UMODE_SECURE) || res != 0) {
-               free(client->webircpeername);
-               client->webircpeername = 0;
-               err_passwdmismatch(client), sendbuf(client);
-       } else {
-               free(client->peername);
-               client->peername = client->webircpeername;
-               if (client->webirchostname) {
-                       client_chghost(client, 0, client->webirchostname);
-                       free(client->webirchostname);
-                       client->webirchostname = 0;
-               }
-               client->webircpeername = 0;
-               if (client->webircwait == 2) {
-                       // NOTE: this relies on the job system being FIFO
-                       client->umode &= ~UMODE_SECURE;
-               }
-               client->webircwait = 0;
-               newUser(client);
-       }
-}
-static void cont_oper(Client *client, int res) {
-       if (!(client->umode & UMODE_SECURE) || res != 0) {
-               err_passwdmismatch(client), sendbuf(client);
-       } else {
-               client->umode |= UMODE_OPER;
-               rpl_youreoper(client), sendbuf(client);
-               copy_strf(&databuf, ":%s MODE %s +o\r\n", hostname, client->nick);
-               sendbuf(client);
-       }
-}
-static void cont_sasl(Client *client, int res) {
-       if (client->saslusername) {
-               if (res == 0) {
-                       rpl_saslsuccess(), sendbuf(client);
-                       client_chghost(client, client->saslusername, 0);
-               } else {
-                       err_saslfail(), sendbuf(client);
-               }
-               free(client->saslusername);
-               client->saslusername = 0;
-               newUser(client);
-       }
-}
-static void cont_pass(Client *client, int res) {
-       if (client->passwait) {
-               client->passwait = 0;
-               if (!(client->umode & UMODE_SECURE) || res != 0) {
-                       err_passwdmismatch(client), sendbuf(client);
-               } else {
-                       client_chghost(client, client->username+1, 0);
-               }
-               newUser(client);
-       }
-}
 #define USE_COMMAND_HASH
 #ifdef USE_COMMAND_HASH
 constexpr size_t command_hash(std::string_view sv) {
@@ -446,7 +390,19 @@ int irc_process_line(Client *client, char *source, std::string_view command, int
                                        char *password = strchr(p, '\0')+1;
                                        if (password > client->saslbuf + client->saslbufLen)
                                                goto saslerr;
-                                       job_password_check(client, username, password, "users", cont_sasl);
+                                       job_password_check(client, username, password, "users", [client](int res) {
+                                               if (client->saslusername) {
+                                                       if (res == 0) {
+                                                               rpl_saslsuccess(), sendbuf(client);
+                                                               client_chghost(client, client->saslusername, 0);
+                                                       } else {
+                                                               err_saslfail(), sendbuf(client);
+                                                       }
+                                                       free(client->saslusername);
+                                                       client->saslusername = 0;
+                                                       newUser(client);
+                                               }
+                                       });
                                        // we'll clear the whole buffer later, this is just in case username alloc fails
                                        memset(password, 0, strlen(password));
                                        client->saslusername = mystrdup(username);
@@ -540,7 +496,28 @@ saslcleanup:
                                        memcpy(client->webirchostname+len, ".xmpp", sizeof(".xmpp"));
                                }
                        }
-                       job_password_check(client, args[1], args[0], "webirc", cont_webirc);
+                       job_password_check(client, args[1], args[0], "webirc", [client](int res) {
+                               if (!(client->umode & UMODE_SECURE) || res != 0) {
+                                       free(client->webircpeername);
+                                       client->webircpeername = 0;
+                                       err_passwdmismatch(client), sendbuf(client);
+                               } else {
+                                       free(client->peername);
+                                       client->peername = client->webircpeername;
+                                       if (client->webirchostname) {
+                                               client_chghost(client, 0, client->webirchostname);
+                                               free(client->webirchostname);
+                                               client->webirchostname = 0;
+                                       }
+                                       client->webircpeername = 0;
+                                       if (client->webircwait == 2) {
+                                               // NOTE: this relies on the job system being FIFO
+                                               client->umode &= ~UMODE_SECURE;
+                                       }
+                                       client->webircwait = 0;
+                                       newUser(client);
+                               }
+                       });
                        memset(args[0], 0, strlen(args[0]));
                }
        } MATCH_COMMAND("OPER") {
@@ -549,7 +526,16 @@ saslcleanup:
                if (argc < 2)
                        return err_needmoreparams(client, command), sendbuf(client), 0;
                stringlower(args[0]);
-               job_password_check(client, args[0], args[1], "ops", cont_oper);
+               job_password_check(client, args[0], args[1], "ops", [client](int res) {
+                       if (!(client->umode & UMODE_SECURE) || res != 0) {
+                               err_passwdmismatch(client), sendbuf(client);
+                       } else {
+                               client->umode |= UMODE_OPER;
+                               rpl_youreoper(client), sendbuf(client);
+                               copy_strf(&databuf, ":%s MODE %s +o\r\n", hostname, client->nick);
+                               sendbuf(client);
+                       }
+               });
                memset(args[1], 0, strlen(args[1]));
        } MATCH_COMMAND("NEWACC") {
                if (!is_registered(client))
@@ -1259,7 +1245,17 @@ void newUser(Client *client) {
                }
        }
        if (client->username[0] == '~' && client->pass_reg) {
-               job_password_check(client, client->username+1, client->pass_reg, "users", cont_pass);
+               job_password_check(client, client->username+1, client->pass_reg, "users", [client](int res) {
+                       if (client->passwait) {
+                               client->passwait = 0;
+                               if (!(client->umode & UMODE_SECURE) || res != 0) {
+                                       err_passwdmismatch(client), sendbuf(client);
+                               } else {
+                                       client_chghost(client, client->username+1, 0);
+                               }
+                               newUser(client);
+                       }
+               });
                client->passwait = 1;
                memset(client->pass_reg, 0, strlen(client->pass_reg));
                free(client->pass_reg);
index 597b9f6..763ad41 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (c) 2024-2025 Egor
+// Copyright (c) 2024-2026 Egor
 // SPDX-License-Identifier: GPL-2.0-or-later
 #include "common.hpp"
 #include "job.hpp"
@@ -8,8 +8,6 @@ struct jobent {
        Client *client;
        jobproc_t job;
        contproc_t then;
-       char *data;
-       size_t len;
 };
 
 static std::deque<jobent> jobq;
@@ -52,7 +50,7 @@ void job_process(void)
        if (!jobq.empty()) {
                jobent &job = jobq.front();
                if (!job.job && current_child == -1) {
-                       job.then(job.client, current_result);
+                       job.then(current_result);
                        jobq.pop_front();
                }
        }
@@ -63,27 +61,19 @@ void job_process(void)
                        if (pid == -1) {
                                abortf("job_process: fork failed\n");
                        } else if (pid == 0) {
-                               int rv = job.job(job.client, job.data, job.len);
-                               memset(job.data, 0, job.len);
+                               int rv = job.job();
                                _exit(rv);
                        } else {
                                current_child = pid;
-                               memset(job.data, 0, job.len);
-                               free(job.data);
-                               job.data = 0;
-                               job.len = 0;
-                               job.job = 0;
+                               job.job = nullptr;
                        }
                }
        }
 }
 
-void job_add(Client *cl, jobproc_t job, contproc_t then, char *data, size_t len)
+void job_add(Client *cl, jobproc_t&& job, contproc_t&& then)
 {
-       if (!job)
-               return;
-       struct jobent ent = { cl, job, then, data, len };
-       jobq.push_back(ent);
+       jobq.push_back(jobent{cl, std::move(job), std::move(then)});
 }
 void job_kill(Client *cl)
 {
@@ -93,43 +83,53 @@ void job_kill(Client *cl)
        auto q = p;
        while (p != jobq.end()) {
                if (p->client != cl) {
-                       *q++ = *p++;
+                       *q++ = std::move(*p++);
                } else {
-                       memset(p->data, 0, p->len);
-                       free(p->data);
                        p++;
                }
        }
        jobq.erase(q, jobq.end());
 }
-
-static int job_password_check_job(Client *cl, const char *data, size_t len)
-{
-       (void)cl;
-       if (!len)
-               return 1;
-       const char *pw = data;
-       const char *salt = strchr(pw, '\0')+1;
-       char *hash = password_crypt(pw, salt);
-       int rv = !hash || strcmp(hash, salt) != 0;
-       if (hash)
-               memset(hash, 0, strlen(hash));
-       return rv;
-}
-void job_password_check(Client *client, const char *key, const char *pw, const char *fn, contproc_t then)
+// FIXME: make a better version of this and use it throughout the codebase
+struct SecureStringWrapper {
+       char *data;
+       operator char*() { return data; }
+       SecureStringWrapper(const char *s) :data(nullptr) {
+               if (s) {
+                       size_t len = strlen(s);
+                       data = new char[len+1];
+                       memcpy(data, s, len);
+                       data[len] = '\0';
+               }
+       }
+       SecureStringWrapper(const SecureStringWrapper &) = delete;
+       SecureStringWrapper& operator=(const SecureStringWrapper &) = delete;
+       SecureStringWrapper(SecureStringWrapper &&other) {
+               data = std::exchange(other.data, nullptr);
+       }
+       SecureStringWrapper& operator=(SecureStringWrapper &&other) {
+               std::swap(data, other.data);
+               return *this;
+       }
+       ~SecureStringWrapper() {
+               if (data) {
+                       memset(data, 0, strlen(data));
+                       delete[] data;
+               }
+       }
+};
+void job_password_check(Client *client, const char *key, const char *pw, const char *fn, contproc_t&& then)
 {
        char *salt = password_get(key, fn);
-       if (!salt) {
-               job_add(client, job_password_check_job, then, 0, 0);
-       } else {
-               size_t pwlen = strlen(pw)+1;
-               size_t len = pwlen+strlen(salt)+1;
-               char *buf = (char *)malloc(len);
-               if (!buf)
-                       abortf("job_password_check: allocation failure\n");
-               memcpy(buf, pw, pwlen);
-               memcpy(buf+pwlen, salt, len-pwlen);
-               job_add(client, job_password_check_job, then, buf, len);
-               memset(salt, 0, len-pwlen);
-       }
+       // FIXME: make_shared only really needed here cuz std::function wants a copyable object
+       // C++23 adds a std::move_only_function
+       job_add(client, [pw=std::make_shared<SecureStringWrapper>(pw), salt=std::make_shared<SecureStringWrapper>(salt)]() -> int {
+               if (!*salt)
+                       return 1;
+               char *hash = password_crypt(*pw, *salt);
+               int rv = !hash || strcmp(hash, *salt) != 0;
+               if (hash)
+                       memset(hash, 0, strlen(hash));
+               return rv;
+       }, std::move(then));
 }
index a44448c..490e018 100644 (file)
@@ -1,14 +1,14 @@
-// Copyright (c) 2024-2025 Egor
+// Copyright (c) 2024-2026 Egor
 // SPDX-License-Identifier: GPL-2.0-or-later
 #ifndef JOB_H_
 #define JOB_H_
 #include "ircdata.hpp"
-typedef int (*jobproc_t)(Client *cl, const char *data, size_t len);
-typedef void (*contproc_t)(Client *cl, int res);
+using jobproc_t = std::function<int()>;
+using contproc_t = std::function<void(int res)>;
 void job_init(void);
 void job_fini(void);
 void job_process(void);
-void job_add(Client *client, jobproc_t job, contproc_t then, char *data, size_t len);
+void job_add(Client *client, jobproc_t&& job, contproc_t&& then);
 void job_kill(Client *client);
-void job_password_check(Client *client, const char *key, const char *pw, const char *fn, contproc_t then);
+void job_password_check(Client *client, const char *key, const char *pw, const char *fn, contproc_t&& then);
 #endif
index b9171bd..d2848fe 100644 (file)
@@ -187,7 +187,7 @@ static void show_license(void)
        fprintf(stderr,
 PACKAGE_STRING "\n"
 "Copyright (c) 2022, 2024 Sam Smith\n"
-"Copyright (c) 2022-2025 Egor\n"
+"Copyright (c) 2022-2026 Egor\n"
 "\n"
 "This program is free software; you can redistribute it and/or modify\n"
 "it under the terms of the GNU General Public License as published by\n"