ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/utils.C
(Generate patch)

Comparing deliantra/server/common/utils.C (file contents):
Revision 1.65 by root, Thu Aug 16 06:36:56 2007 UTC vs.
Revision 1.92 by root, Tue Nov 3 23:18:23 2009 UTC

1/* 1/*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team 4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 * 7 *
8 * Crossfire TRT is free software: you can redistribute it and/or modify 8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * it under the terms of the GNU General Public License as published by 9 * the terms of the Affero GNU General Public License as published by the
10 * the Free Software Foundation, either version 3 of the License, or 10 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 11 * option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the Affero GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
20 * 21 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de> 22 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 23 */
23 24
24/* 25/*
25 * General convenience functions for crossfire. 26 * General convenience functions for deliantra.
26 */ 27 */
27 28
28#include <cstdlib> 29#include <cstdlib>
29#include <sys/types.h> 30#include <sys/types.h>
30#include <unistd.h> 31#include <unistd.h>
31#include <sys/time.h> 32#include <sys/time.h>
32#include <time.h> 33#include <time.h>
33#include <signal.h> 34#include <signal.h>
34 35
35#include <global.h> 36#include <global.h>
36#include <funcpoint.h>
37#include <material.h> 37#include <material.h>
38#include <object.h>
39
40#include <sys/time.h>
41#include <sys/resource.h>
38 42
39#include <glib.h> 43#include <glib.h>
40 44
41refcnt_base::refcnt_t refcnt_dummy; 45refcnt_base::refcnt_t refcnt_dummy;
42 46ssize_t slice_alloc;
43rand_gen rndm; 47rand_gen rndm, rmg_rndm;
44 48
45void 49void
46tausworthe_random_generator::seed (uint32_t seed) 50tausworthe_random_generator::seed (uint32_t seed)
47{ 51{
48 state [0] = seed * 69069U; if (state [0] < 2U) state [0] += 2U; 52 state [0] = seed * 69069U; if (state [0] < 2U) state [0] += 2U;
49 state [1] = state [0] * 69069U; if (state [0] < 8U) state [0] += 8U; 53 state [1] = state [0] * 69069U; if (state [0] < 8U) state [0] += 8U;
50 state [2] = state [1] * 69069U; if (state [0] < 16U) state [0] += 16U; 54 state [2] = state [1] * 69069U; if (state [0] < 16U) state [0] += 16U;
51 state [3] = state [2] * 69069U; if (state [0] < 128) state [0] += 128U; 55 state [3] = state [2] * 69069U; if (state [0] < 128U) state [0] += 128U;
52 56
53 for (int i = 11; --i; ) 57 for (int i = 11; --i; )
54 operator ()(); 58 next ();
55} 59}
56 60
57uint32_t 61uint32_t
58tausworthe_random_generator::next () 62tausworthe_random_generator::next ()
59{ 63{
63 state [3] = ((state [3] & 0xFFFFFF80U) << 13U) ^ (((state [3] << 3U) ^ state [3]) >> 12U); 67 state [3] = ((state [3] & 0xFFFFFF80U) << 13U) ^ (((state [3] << 3U) ^ state [3]) >> 12U);
64 68
65 return state [0] ^ state [1] ^ state [2] ^ state [3]; 69 return state [0] ^ state [1] ^ state [2] ^ state [3];
66} 70}
67 71
72template<class generator>
68uint32_t 73uint32_t
69tausworthe_random_generator::get_range (uint32_t num) 74random_number_generator<generator>::get_range (uint32_t num)
70{ 75{
71 return (next () * (uint64_t)num) >> 32U; 76 return (this->next () * (uint64_t)num) >> 32U;
72} 77}
73 78
74// return a number within (min .. max) 79// return a number within (min .. max)
80template<class generator>
75int 81int
76tausworthe_random_generator::get_range (int r_min, int r_max) 82random_number_generator<generator>::get_range (int r_min, int r_max)
77{ 83{
78 return r_min + get_range (max (r_max - r_min + 1, 0)); 84 return r_min + get_range (max (r_max - r_min + 1, 0));
79} 85}
86
87template struct random_number_generator<tausworthe_random_generator>;
88template struct random_number_generator<xorshift_random_generator>;
80 89
81/* 90/*
82 * The random functions here take luck into account when rolling random 91 * The random functions here take luck into account when rolling random
83 * dice or numbers. This function has less of an impact the larger the 92 * dice or numbers. This function has less of an impact the larger the
84 * difference becomes in the random numbers. IE, the effect is lessened 93 * difference becomes in the random numbers. IE, the effect is lessened
94 * not the recipient (ie, the poor slob getting hit). [garbled 20010916] 103 * not the recipient (ie, the poor slob getting hit). [garbled 20010916]
95 */ 104 */
96int 105int
97random_roll (int r_min, int r_max, const object *op, int goodbad) 106random_roll (int r_min, int r_max, const object *op, int goodbad)
98{ 107{
108 r_max = max (r_min, r_max);
109
99 int base = r_max - r_min > 1 ? 20 : 50; /* d2 and d3 are corner cases */ 110 int base = r_max - r_min > 1 ? 20 : 50; /* d2 and d3 are corner cases */
100
101 if (r_max < r_min)
102 {
103 LOG (llevError | logBacktrace, "Calling random_roll with min=%d max=%d\n", r_min, r_max);
104 return r_min;
105 }
106 111
107 if (op->type == PLAYER) 112 if (op->type == PLAYER)
108 { 113 {
109 int luck = op->stats.luck; 114 int luck = op->stats.luck;
110 115
120/* 125/*
121 * This is a 64 bit version of random_roll above. This is needed 126 * This is a 64 bit version of random_roll above. This is needed
122 * for exp loss calculations for players changing religions. 127 * for exp loss calculations for players changing religions.
123 */ 128 */
124sint64 129sint64
125random_roll64 (sint64 min, sint64 max, const object *op, int goodbad) 130random_roll64 (sint64 r_min, sint64 r_max, const object *op, int goodbad)
126{ 131{
127 sint64 omin = min; 132 sint64 omin = r_min;
128 sint64 diff = max - min + 1; 133 sint64 range = max (0, r_max - r_min + 1);
129 int base = diff > 2 ? 20 : 50; /* d2 and d3 are corner cases */ 134 int base = range > 2 ? 20 : 50; /* d2 and d3 are corner cases */
130
131 if (diff < 0)
132 {
133 LOG (llevError | logBacktrace, "Calling random_roll64 with min=%" PRId64 " max=%" PRId64 "\n", min, max);
134 return (min); /* avoids a float exception */
135 }
136 135
137 /* 136 /*
138 * Make a call to get two 32 bit unsigned random numbers, and just to 137 * Make a call to get two 32 bit unsigned random numbers, and just to
139 * a little bitshifting. 138 * a little bitshifting.
140 */ 139 */
141 sint64 ran = (sint64) rndm.next () ^ ((sint64) rndm.next () << 31); 140 sint64 ran = (sint64) rndm.next () ^ ((sint64) rndm.next () << 31);
142 141
143 if (op->type != PLAYER) 142 if (op->type != PLAYER)
144 return ((ran % diff) + min); 143 return ((ran % range) + r_min);
145 144
146 int luck = op->stats.luck; 145 int luck = op->stats.luck;
147 146
148 if (rndm (base) < MIN (10, abs (luck))) 147 if (rndm (base) < min (10, abs (luck)))
149 { 148 {
150 /* we have a winner */ 149 /* we have a winner */
151 ((luck > 0) ? (luck = 1) : (luck = -1)); 150 ((luck > 0) ? (luck = 1) : (luck = -1));
152 diff -= luck; 151 range -= luck;
153 if (diff < 1) 152 if (range < 1)
154 return (omin); /*check again */ 153 return (omin); /*check again */
155 154
156 ((goodbad) ? (min += luck) : (diff)); 155 ((goodbad) ? (r_min += luck) : (range));
157 156
158 return (MAX (omin, MIN (max, (ran % diff) + min))); 157 return (max (omin, min (r_max, (ran % range) + r_min)));
159 } 158 }
160 159
161 return ran % diff + min; 160 return ran % range + r_min;
162} 161}
163 162
164/* 163/*
165 * Roll a number of dice (2d3, 4d6). Uses op to determine luck, 164 * Roll a number of dice (2d3, 4d6). Uses op to determine luck,
166 * If goodbad is non-zero, luck increases the roll, if zero, it decreases. 165 * If goodbad is non-zero, luck increases the roll, if zero, it decreases.
208} 207}
209 208
210/* convert materialname to materialtype_t */ 209/* convert materialname to materialtype_t */
211 210
212materialtype_t * 211materialtype_t *
213name_to_material (const shstr &name) 212name_to_material (const shstr_cmp name)
214{ 213{
215 for (materialtype_t *mt = materialt; mt && mt->next; mt = mt->next) 214 for (materialtype_t *mt = materialt; mt; mt = mt->next)
216 if (name == mt->name) 215 if (name == mt->name)
217 return mt; 216 return mt;
218 217
219 return 0; 218 return 0;
220} 219}
226transmute_materialname (object *op, const object *change) 225transmute_materialname (object *op, const object *change)
227{ 226{
228 materialtype_t *mt; 227 materialtype_t *mt;
229 int j; 228 int j;
230 229
231 if (op->materialname == NULL) 230 if (!op->materialname)
232 return; 231 return;
233 232
234 if (change->materialname != NULL && strcmp (op->materialname, change->materialname)) 233 if (op->materialname != change->materialname)
235 return; 234 return;
236 235
237 if (!op->is_armor ()) 236 if (!op->is_armor ())
238 return; 237 return;
239 238
259void 258void
260set_materialname (object *op, int difficulty, materialtype_t *nmt) 259set_materialname (object *op, int difficulty, materialtype_t *nmt)
261{ 260{
262 materialtype_t *mt, *lmt; 261 materialtype_t *mt, *lmt;
263 262
264 if (op->materialname != NULL) 263 if (!op->materialname)
265 return; 264 return;
266 265
267 if (nmt == NULL) 266 if (nmt)
267 lmt = nmt;
268 else
268 { 269 {
269 lmt = NULL; 270 lmt = 0;
270 271
271 for (mt = materialt; mt && mt->next; mt = mt->next) 272 for (mt = materialt; mt; mt = mt->next)
272 if (op->materials & mt->material && rndm (1, 100) <= mt->chance && 273 if (op->materials & mt->material && rndm (1, 100) <= mt->chance &&
273 difficulty >= mt->difficulty && (op->magic >= mt->magic || mt->magic == 0)) 274 difficulty >= mt->difficulty && (op->magic >= mt->magic || mt->magic == 0))
274 { 275 {
275 lmt = mt; 276 lmt = mt;
276 if (!(op->is_weapon () || op->is_armor ())) 277 if (!(op->is_weapon () || op->is_armor ()))
277 break; 278 break;
278 } 279 }
279 } 280 }
280 else
281 lmt = nmt;
282 281
283 if (lmt != NULL) 282 if (lmt)
284 { 283 {
285 if (op->stats.dam && op->is_weapon ()) 284 if (op->stats.dam && op->is_weapon ())
286 { 285 {
287 op->stats.dam += lmt->damage; 286 op->stats.dam += lmt->damage;
288 if (op->stats.dam < 1) 287 if (op->stats.dam < 1)
411 } 410 }
412 } 411 }
413 result[resultlen] = '\0'; 412 result[resultlen] = '\0';
414} 413}
415 414
416/** 415/******************************************************************************/
417 * Taking a string as an argument, mutate it into a string that looks like a list.
418 * a 'list' for the purposes here, is a string of items, seperated by commas, except
419 * for the last entry, which has an 'and' before it, and a full stop (period) after it.
420 * This function will also strip all trailing non alphanumeric characters.
421 * It does not insert an oxford comma.
422 */
423void
424make_list_like (char *input)
425{
426 char *p, tmp[MAX_BUF];
427 int i;
428 416
429 if (!input || strlen (input) > MAX_BUF - 5) 417/* Checks a player-provided string which will become the msg property of
430 return; 418 * an object for dangerous input.
431 /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */ 419 */
420bool
421msg_is_safe (const char *msg)
422{
423 bool safe = true;
432 424
433 strncpy (tmp, input, MAX_BUF - 5); 425 /* Trying to cheat by getting data into the object */
434 /*trim all trailing commas, spaces etc. */ 426 if (!strncmp (msg, "endmsg", sizeof ("endmsg") - 1)
435 for (i = strlen (tmp); !isalnum (tmp[i]) && i >= 0; i--) 427 || strstr (msg, "\nendmsg"))
436 tmp[i] = '\0'; 428 safe = false;
437 429
438 strcat (tmp, "."); 430 /* Trying to make the object talk, and potentially access arbitrary code */
431 if (object::msg_has_dialogue (msg))
432 safe = false;
439 433
440 p = strrchr (tmp, ',');
441 if (p)
442 {
443 *p = '\0';
444 strcpy (input, tmp);
445 p++;
446 strcat (input, " and");
447 strcat (input, p);
448 }
449 else
450 strcpy (input, tmp);
451
452 return; 434 return safe;
453} 435}
454 436
455///////////////////////////////////////////////////////////////////////////// 437/////////////////////////////////////////////////////////////////////////////
456 438
457void 439void
458fork_abort (const char *msg) 440fork_abort (const char *msg)
459{ 441{
460 if (!fork ()) 442 if (!fork ())
461 { 443 {
444 signal (SIGINT , SIG_IGN);
445 signal (SIGTERM, SIG_IGN);
462 signal (SIGABRT, SIG_DFL); 446 signal (SIGABRT, SIG_IGN);
447
448 signal (SIGSEGV, SIG_DFL);
449 signal (SIGBUS , SIG_DFL);
450 signal (SIGILL , SIG_DFL);
451 signal (SIGTRAP, SIG_DFL);
452
463 // try to put corefiles into a subdirectory, if existing, to allow 453 // try to put corefiles into a subdirectory, if existing, to allow
464 // an administrator to reduce the I/O load. 454 // an administrator to reduce the I/O load.
465 chdir ("cores"); 455 chdir ("cores");
456
457 // try to detach us from as many external dependencies as possible
458 // as coredumping can take time by closing all fd's.
459 {
460 struct rlimit lim;
461
462 if (getrlimit (RLIMIT_NOFILE, &lim))
463 lim.rlim_cur = 1024;
464
465 for (int i = 0; i < lim.rlim_cur; ++i)
466 close (i);
467 }
468
469 {
470 sigset_t empty;
471 sigemptyset (&empty);
472 sigprocmask (SIG_SETMASK, &empty, 0);
473 }
474
475 // try to coredump with SIGTRAP
476 kill (getpid (), SIGTRAP);
466 abort (); 477 abort ();
467 } 478 }
468 479
469 LOG (llevError, "fork abort: %s\n", msg); 480 LOG (llevError, "fork abort: %s\n", msg);
470} 481}
471 482
472void *salloc_ (int n) throw (std::bad_alloc) 483void *salloc_ (int n) throw (std::bad_alloc)
473{ 484{
474#ifdef PREFER_MALLOC
475 void *ptr = malloc (n);
476#else
477 void *ptr = g_slice_alloc (n); 485 void *ptr = g_slice_alloc (n);
478#endif
479 486
480 if (!ptr) 487 if (!ptr)
481 throw std::bad_alloc (); 488 throw std::bad_alloc ();
482 489
490 slice_alloc += n;
483 return ptr; 491 return ptr;
484} 492}
485 493
486void *salloc_ (int n, void *src) throw (std::bad_alloc) 494void *salloc_ (int n, void *src) throw (std::bad_alloc)
487{ 495{
493 memset (ptr, 0, n); 501 memset (ptr, 0, n);
494 502
495 return ptr; 503 return ptr;
496} 504}
497 505
506/******************************************************************************/
507
508#if DEBUG_SALLOC
509
510#define MAGIC 0xa1b2c35543deadLL
511
512void *g_slice_alloc (unsigned long size)
513{
514 unsigned long *p = (unsigned long *) (g_slice_alloc)(size + sizeof (unsigned long));
515 *p++ = size ^ MAGIC;
516 //fprintf (stderr, "g_slice_alloc %ld %p\n", size, p);//D
517 return (void *)p;
518}
519
520void *g_slice_alloc0 (unsigned long size)
521{
522 return memset (g_slice_alloc (size), 0, size);
523}
524
525void g_slice_free1 (unsigned long size, void *ptr)
526{
527 //fprintf (stderr, "g_slice_free %ld %p\n", size, ptr);//D
528 if (expect_true (ptr))
529 {
530 unsigned long *p = (unsigned long *)ptr;
531 unsigned long s = *--p ^ MAGIC;
532
533 if (size != (unsigned long)(*p ^ MAGIC))
534 {
535 LOG (logBacktrace | llevError, "slice free size (%lx) doesn't match alloc size (%lx)\n", size, s);
536 abort ();
537 }
538
539 *p = MAGIC;
540
541 (g_slice_free1)(s + sizeof (unsigned long), p);
542 }
543}
544
545#endif
546
547/******************************************************************************/
548
549int
498void assign (char *dst, const char *src, int maxlen) 550assign (char *dst, const char *src, int maxsize)
499{ 551{
500 if (!src) 552 if (!src)
501 src = ""; 553 src = "";
502 554
503 int len = strlen (src); 555 int len = strlen (src);
504 556
505 if (len >= maxlen - 1) 557 if (len >= maxsize)
506 { 558 {
507 if (maxlen <= 4) 559 if (maxsize <= 4)
508 { 560 {
509 memset (dst, '.', maxlen - 1); 561 memset (dst, '.', maxsize - 2);
510 dst [maxlen - 1] = 0; 562 dst [maxsize - 1] = 0;
511 } 563 }
512 else 564 else
513 { 565 {
514 memcpy (dst, src, maxlen - 4); 566 memcpy (dst, src, maxsize - 4);
515 memcpy (dst + maxlen - 4, "...", 4); 567 memcpy (dst + maxsize - 4, "...", 4);
516 } 568 }
569
570 len = maxsize;
517 } 571 }
518 else 572 else
519 memcpy (dst, src, len + 1); 573 memcpy (dst, src, ++len);
520}
521 574
522const char * 575 return len;
576}
577
578char *
579vformat (const char *format, va_list ap)
580{
581 static dynbuf_text buf; buf.clear ();
582 buf.vprintf (format, ap);
583 return buf;
584}
585
586char *
523format (const char *format, ...) 587format (const char *format, ...)
524{ 588{
525 static dynbuf_text buf;
526
527 buf.clear ();
528
529 va_list ap; 589 va_list ap;
530 va_start (ap, format); 590 va_start (ap, format);
531 buf.vprintf (format, ap); 591 char *buf = vformat (format, ap);
532 va_end (ap); 592 va_end (ap);
533 593
534 return buf; 594 return buf;
535} 595}
536 596
607 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 667 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
608 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 668 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
609 0x2d02ef8dL 669 0x2d02ef8dL
610}; 670};
611 671
612#if 0 672void thread::start (void *(*start_routine)(void *), void *arg)
613void xyzzy (object_ptr &a, object_ptr &o)
614{ 673{
615 asm volatile ("int3"); 674 pthread_attr_t attr;
616 a = o; 675
617 asm volatile ("int3"); 676 pthread_attr_init (&attr);
618} 677 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
678 pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < sizeof (long) * 4096
679 ? sizeof (long) * 4096 : PTHREAD_STACK_MIN);
680#ifdef PTHREAD_SCOPE_PROCESS
681 pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
619#endif 682#endif
620 683
684 sigset_t fullsigset, oldsigset;
685 sigfillset (&fullsigset);
686
687 pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset);
688
689 if (pthread_create (&id, &attr, start_routine, arg))
690 cleanup ("unable to create a new thread");
691
692 pthread_sigmask (SIG_SETMASK, &oldsigset, 0);
693}
694

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines