]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Command line: -sessionid, cvars: locksession, (R/O) sessionid
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 1 Nov 2011 14:45:57 +0000 (14:45 +0000)
committerRudolf Polzer <divverent@xonotic.org>
Wed, 2 Nov 2011 08:12:05 +0000 (09:12 +0100)
Allows games to require a session lock. Put "locksession 1" in the game's default config file and users then need to run instances with unique -sessionid parameter.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11513 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::merge=927bd7b13c9a18fb07a8681c7483f632c7ea32f3

crypto.c
crypto.h
fs.c
host.c
netconn.c
prvm_edict.c
quakedef.h

index 7bd36d12b2704c093602c0c2a795ad5a8f0c17d2..6333d1819097c4ea813080f35349571001ce82bd 100644 (file)
--- a/crypto.c
+++ b/crypto.c
@@ -340,12 +340,12 @@ void sha256(unsigned char *out, const unsigned char *in, int n)
        qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
 }
 
-static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
+static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir)
 {
        qfile_t *f = NULL;
        fs_offset_t n;
        if(*fs_userdir)
-               f = FS_SysOpen(va("%s%s", fs_userdir, path), "rb", false);
+               f = FS_SysOpen(va("%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
        if(!f)
                f = FS_SysOpen(va("%s%s", fs_basedir, path), "rb", false);
        if(!f)
@@ -748,12 +748,20 @@ static void Crypto_BuildChallengeAppend(void)
        challenge_append_length = p - challenge_append;
 }
 
-static void Crypto_LoadKeys(void)
+void Crypto_LoadKeys(void)
 {
        char buf[8192];
        size_t len, len2;
        int i;
 
+       if(!d0_blind_id_dll) // don't if we can't
+               return;
+
+       if(crypto_idstring) // already loaded? then not
+               return;
+
+       Host_LockSession(); // we use the session ID here
+
        // load keys
        // note: we are just a CLIENT
        // so we load:
@@ -767,14 +775,14 @@ static void Crypto_LoadKeys(void)
                memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
                memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
                pubkeys_havepriv[i] = false;
-               len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf));
+               len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf), false);
                if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
                {
                        len2 = FP64_SIZE;
                        if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
                        {
                                Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
-                               len = Crypto_LoadFile(va("key_%d.d0si", i), buf, sizeof(buf));
+                               len = Crypto_LoadFile(va("key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
                                if(len)
                                {
                                        if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
@@ -782,7 +790,7 @@ static void Crypto_LoadKeys(void)
                                                len2 = FP64_SIZE;
                                                if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
                                                {
-                                                       Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (public key fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
+                                                       Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]);
                                                        pubkeys_havepriv[i] = true;
                                                        strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
                                                }
@@ -910,7 +918,6 @@ void Crypto_Init(void)
        Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
 
        Crypto_InitHostKeys();
-       Crypto_LoadKeys();
 }
 // end
 
@@ -1072,26 +1079,18 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
                return;
        }
 
-       if(*fs_userdir)
-       {
-               FS_CreatePath(va("%skey_%d.d0si", fs_userdir, keygen_i));
-               f = FS_SysOpen(va("%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
-       }
-       if(!f)
-       {
-               FS_CreatePath(va("%skey_%d.d0si", fs_basedir, keygen_i));
-               f = FS_SysOpen(va("%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
-       }
+       FS_CreatePath(va("%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
+       f = FS_SysOpen(va("%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
        if(!f)
        {
-               Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
+               Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
                keygen_i = -1;
                return;
        }
        FS_Write(f, buf2, buf2size);
        FS_Close(f);
 
-       Con_Printf("Saved to key_%d.d0si\n", keygen_i);
+       Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
        keygen_i = -1;
 }
 
@@ -1113,6 +1112,7 @@ static void Crypto_KeyGen_f(void)
                Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
                return;
        }
+       Crypto_LoadKeys();
        i = atoi(Cmd_Argv(1));
        if(!pubkeys[i])
        {
@@ -1192,7 +1192,7 @@ static void Crypto_Keys_f(void)
                {
                        Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
                        if(pubkeys_havepriv[i])
-                               Con_Printf("    private ID key_%d.d0si (public key fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
+                               Con_Printf("    private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
                }
        }
 }
index 2cff5c2db1f02ff8457c12889d9199118f4bad71..7b2b9921bca3c030b233834146beeeb0b2d60c87 100644 (file)
--- a/crypto.h
+++ b/crypto.h
@@ -31,6 +31,7 @@ crypto_t;
 
 void Crypto_Init(void);
 void Crypto_Init_Commands(void);
+void Crypto_LoadKeys(void);
 void Crypto_Shutdown(void);
 qboolean Crypto_Available(void);
 void sha256(unsigned char *out, const unsigned char *in, int n); // may ONLY be called if Crypto_Available()
diff --git a/fs.c b/fs.c
index 4288ab5dd1c20378928cd2edd9c80b6942b68a63..1917fd2f01fd9267862b286ca8aa40c6f0c3b2af 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -773,11 +773,7 @@ pack_t *FS_LoadPackPK3FromFD (const char *packfile, int packhandle, qboolean sil
 pack_t *FS_LoadPackPK3 (const char *packfile)
 {
        int packhandle;
-#if _MSC_VER >= 1400
-       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
-       packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+       packhandle = FS_SysOpenFD (packfile, "rb", false);
        if (packhandle < 0)
                return NULL;
        return FS_LoadPackPK3FromFD(packfile, packhandle, false);
@@ -947,11 +943,7 @@ pack_t *FS_LoadPackPAK (const char *packfile)
        pack_t *pack;
        dpackfile_t *info;
 
-#if _MSC_VER >= 1400
-       _sopen_s(&packhandle, packfile, O_RDONLY | O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE);
-#else
-       packhandle = open (packfile, O_RDONLY | O_BINARY);
-#endif
+       packhandle = FS_SysOpenFD(packfile, "rb", false);
        if (packhandle < 0)
                return NULL;
        if(read (packhandle, (void *)&header, sizeof(header)) != sizeof(header))
@@ -1884,11 +1876,8 @@ int FS_ChooseUserDir(userdirmode_t userdirmode, char *userdir, size_t userdirsiz
 
        // see if we can write to this path (note: won't create path)
 #ifdef WIN32
-# if _MSC_VER >= 1400
-       _sopen_s(&fd, va("%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, _SH_DENYNO, _S_IREAD | _S_IWRITE); // note: no O_TRUNC here!
-# else
-       fd = open (va("%s%s/config.cfg", userdir, gamedirname1), O_WRONLY | O_CREAT, 0666); // note: no O_TRUNC here!
-# endif
+       // no access() here, we must try to open the file for appending
+       fd = Sys_OpenFD(va("%s%s/config.cfg", userdir, gamedirname1), "a", false);
        if(fd >= 0)
                close(fd);
 #else
@@ -2105,9 +2094,10 @@ void FS_Shutdown (void)
 
 int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
 {
-       int handle;
+       int handle = -1;
        int mod, opt;
        unsigned int ind;
+       qboolean dolock = false;
 
        // Parse the mode string
        switch (mode[0])
@@ -2138,6 +2128,9 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
                        case 'b':
                                opt |= O_BINARY;
                                break;
+                       case 'l':
+                               dolock = true;
+                               break;
                        default:
                                Con_Printf ("FS_SysOpen(%s, %s): unknown character in mode (%c)\n",
                                                        filepath, mode, mode[ind]);
@@ -2147,11 +2140,29 @@ int FS_SysOpenFD(const char *filepath, const char *mode, qboolean nonblocking)
        if (nonblocking)
                opt |= O_NONBLOCK;
 
-#if _MSC_VER >= 1400
-       _sopen_s(&handle, filepath, mod | opt, _SH_DENYNO, _S_IREAD | _S_IWRITE);
+#ifdef WIN32
+# if _MSC_VER >= 1400
+       _sopen_s(&handle, filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+# else
+       handle = _sopen (filepath, mod | opt, (dolock ? ((mod == O_RDONLY) ? _SH_DENYRD : _SH_DENYRW) : _SH_DENYNO), _S_IREAD | _S_IWRITE);
+# endif
 #else
        handle = open (filepath, mod | opt, 0666);
+       if(handle >= 0 && dolock)
+       {
+               struct flock l;
+               l.l_type = ((mod == O_RDONLY) ? F_RDLCK : F_WRLCK);
+               l.l_whence = SEEK_SET;
+               l.l_start = 0;
+               l.l_len = 0;
+               if(fcntl(handle, F_SETLK, &l) == -1)
+               {
+                       close(handle);
+                       handle = -1;
+               }
+       }
 #endif
+
        return handle;
 }
 
diff --git a/host.c b/host.c
index 3f70370ea60ca7fb6176df15706d75ccc263d341..be123bf9e27a515c37caf22519d74963cf6f38ab 100644 (file)
--- a/host.c
+++ b/host.c
@@ -83,6 +83,9 @@ cvar_t developer_entityparsing = {0, "developer_entityparsing", "0", "prints det
 cvar_t timestamps = {CVAR_SAVE, "timestamps", "0", "prints timestamps on console messages"};
 cvar_t timeformat = {CVAR_SAVE, "timeformat", "[%Y-%m-%d %H:%M:%S] ", "time format to use on timestamped console messages"};
 
+cvar_t sessionid = {CVAR_READONLY, "sessionid", "", "ID of the current session (use the -sessionid parameter to set it); this is always either empty or begins with a dot (.)"};
+cvar_t locksession = {0, "locksession", "0", "Lock the session? 0 = no, 1 = yes and abort on failure, 2 = yes and continue on failure"};
+
 /*
 ================
 Host_AbortCurrentFrame
@@ -1051,6 +1054,63 @@ extern void COM_Init_Commands(void);
 extern void FS_Init_Commands(void);
 extern qboolean host_stuffcmdsrun;
 
+static qfile_t *locksession_fh = NULL;
+static qboolean locksession_run = false;
+static void Host_InitSession(void)
+{
+       int i;
+       Cvar_RegisterVariable(&sessionid);
+       Cvar_RegisterVariable(&locksession);
+
+       // load the session ID into the read-only cvar
+       if ((i = COM_CheckParm("-sessionid")) && (i + 1 < com_argc))
+       {
+               char vabuf[1024];
+               if(com_argv[i+1][0] == '.')
+                       Cvar_SetQuick(&sessionid, com_argv[i+1]);
+               else
+                       Cvar_SetQuick(&sessionid, va(vabuf, sizeof(vabuf), ".%s", com_argv[i+1]));
+       }
+}
+void Host_LockSession(void)
+{
+       if(locksession_run)
+               return;
+       locksession_run = true;
+       if(locksession.integer != 0)
+       {
+               char vabuf[1024];
+               locksession_fh = FS_SysOpen(va(vabuf, sizeof(vabuf), "%slock%s", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string), "wl", false);
+               // TODO maybe write the pid into the lockfile, while we are at it? may help server management tools
+               if(!locksession_fh)
+               {
+                       if(locksession.integer == 2)
+                       {
+                               Con_Printf("WARNING: session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name. Continuing anyway.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+                       }
+                       else
+                       {
+                               Sys_Error("session lock %slock%s could not be acquired. Please run with -sessionid and an unique session name.\n", *fs_userdir ? fs_userdir : fs_basedir, sessionid.string);
+                       }
+               }
+       }
+}
+void Host_UnlockSession(void)
+{
+       if(!locksession_run)
+               return;
+       locksession_run = false;
+
+       if(locksession_fh)
+       {
+               FS_Close(locksession_fh);
+               // NOTE: we can NOT unlink the lock here, as doing so would
+               // create a race condition if another process created it
+               // between our close and our unlink
+               locksession_fh = NULL;
+       }
+}
+
 /*
 ====================
 Host_Init
@@ -1147,6 +1207,9 @@ static void Host_Init (void)
        // initialize filesystem (including fs_basedir, fs_gamedir, -game, scr_screenshot_name)
        FS_Init();
 
+       // register the cvars for session locking
+       Host_InitSession();
+
        // must be after FS_Init
        Crypto_Init();
        Crypto_Init_Commands();
@@ -1325,7 +1388,10 @@ void Host_Shutdown(void)
        Sys_Shutdown();
        Log_Close();
        Crypto_Shutdown();
-       FS_Shutdown();
+
+       Host_UnlockSession();
+
+       S_Shutdown();
        Con_Shutdown();
        Memory_Shutdown();
 }
index c6b3ea03a3278f6e202a1fdde48da1f7a4de1548..3a8b8beb7f50eafb1f83ad6745a7b2460ae95c0d 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -922,6 +922,9 @@ void NetConn_OpenClientPorts(void)
 {
        int port;
        NetConn_CloseClientPorts();
+
+       Crypto_LoadKeys(); // client sockets
+
        port = bound(0, cl_netport.integer, 65535);
        if (cl_netport.integer != port)
                Cvar_SetValueQuick(&cl_netport, port);
@@ -987,6 +990,9 @@ void NetConn_OpenServerPorts(int opennetports)
 {
        int port;
        NetConn_CloseServerPorts();
+
+       Crypto_LoadKeys(); // server sockets
+
        NetConn_UpdateSockets();
        port = bound(0, sv_netport.integer, 65535);
        if (port == 0)
index ec094fb8a15cffda36054185c7cb958fa6fbf190..2aa49200f030f14f9cd75f195d29219848ebe333 100644 (file)
@@ -1954,6 +1954,9 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, const char **re
        if (prog->loaded)
                PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME );
 
+       Host_LockSession(); // all progs can use the session cvar
+       Crypto_LoadKeys(); // all progs might use the keys at init time
+
        dprograms = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false, &filesize);
        if (dprograms == NULL || filesize < (fs_offset_t)sizeof(dprograms_t))
                PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME);
index e90be22ecb4493a3f33b7c0a729fc60182ddd726..684e23fa8fd3c95f973af85ec7faca271b606c7f 100644 (file)
@@ -404,6 +404,8 @@ extern cvar_t developer_insane;
 extern cvar_t developer_loadfile;
 extern cvar_t developer_loading;
 
+extern cvar_t sessionid;
+
 #define STARTCONFIGFILENAME "quake.rc"
 #define CONFIGFILENAME "config.cfg"
 
@@ -512,6 +514,8 @@ void Host_ClientCommands(const char *fmt, ...) DP_FUNC_PRINTF(1);
 void Host_ShutdownServer(void);
 void Host_Reconnect_f(void);
 void Host_NoOperation_f(void);
+void Host_LockSession(void);
+void Host_UnlockSession(void);
 
 void Host_AbortCurrentFrame(void);