24c6c12000-02-20Martin Nilsson // The Roxen Webserver main program. // Copyright © 1996 - 2000, Roxen IS. // // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others.
edc9af1998-07-11David Hedbor  // ABS and suicide systems contributed freely by Francesco Chemolli
27008b2000-03-20Martin Stjernholm constant cvs_version="$Id: roxen.pike,v 1.459 2000/03/20 07:03:26 mast Exp $";
34d3fa1999-04-22Per Hedbor  object backend_thread;
855c391999-11-29Per Hedbor ArgCache argcache;
1720541998-10-04Henrik Grubbström (Grubba)  // Some headerfiles
4dd97c1996-12-04Per Hedbor #define IN_ROXEN
8540e11997-06-14Francesco Chemolli #include <roxen.h> #include <config.h>
b1fca01996-11-12Per Hedbor #include <module.h> #include <variables.h>
753a831999-08-30Per Hedbor #include <stat.h>
14179b1997-01-29Per Hedbor 
1720541998-10-04Henrik Grubbström (Grubba) // Inherits
753a831999-08-30Per Hedbor inherit "global_variables";
b1fca01996-11-12Per Hedbor inherit "hosts"; inherit "disk_cache"; inherit "language";
2ff8461999-09-02Per Hedbor inherit "supports";
7c92b91998-11-19Per Hedbor 
9b11391999-12-28Martin Nilsson // --- Debug defines ---
81f8af1999-12-20Martin Nilsson 
9920831999-12-07Martin Stjernholm // #define SSL3_DEBUG
81f8af1999-12-20Martin Nilsson // #define PRIVS_DEBUG // #define THREAD_DEBUG // #define DUMP_DEBUG #ifdef SSL3_DEBUG
bfb4d41999-12-28Martin Nilsson # define SSL3_WERR(X) werror("SSL3: "+X+"\n")
81f8af1999-12-20Martin Nilsson #else
bfb4d41999-12-28Martin Nilsson # define SSL3_WERR(X)
81f8af1999-12-20Martin Nilsson #endif #ifdef THREAD_DEBUG
bfb4d41999-12-28Martin Nilsson # define THREAD_WERR(X) werror("Thread: "+X+"\n")
81f8af1999-12-20Martin Nilsson #else
bfb4d41999-12-28Martin Nilsson # define THREAD_WERR(X)
81f8af1999-12-20Martin Nilsson #endif
60a9121999-10-10Henrik Grubbström (Grubba) 
855c391999-11-29Per Hedbor 
7c92b91998-11-19Per Hedbor // Prototypes for other parts of roxen.
855c391999-11-29Per Hedbor  class RoxenModule { constant is_module=1; constant module_type = 0; constant module_unique = 1; string|mapping(string:string) module_name; string|mapping(string:string) module_doc; array(int|string|mapping) register_module(); string file_name_and_stuff(); void start(void|int num, void|object conf); void defvar(string var, mixed value, string name, int type, string|void doc_str, mixed|void misc, int|function|void not_in_config); void definvisvar(string name, int value, int type, array|void misc);
81f8af1999-12-20Martin Nilsson  void deflocaledoc( string locale, string variable, string name, string doc,
855c391999-11-29Per Hedbor  mapping|void translate ); int killvar(string var); string check_variable( string s, mixed value ); mixed query(string|void var, int|void ok); void set(string var, mixed value); int setvars( mapping (string:mixed) vars ); string query_internal_location(); string query_location(); string query_provides(); array query_seclevels(); array(int) stat_file(string f, RequestID id); array(String) find_dir(string f, RequestID id); mapping(string:array(mixed)) find_dir_stat(string f, RequestID id); string real_file(string f, RequestID id); void save(); mapping api_functions(); mapping query_tag_callers(); mapping query_container_callers();
81f8af1999-12-20Martin Nilsson 
855c391999-11-29Per Hedbor  string info(object conf); string comment(); }
81f8af1999-12-20Martin Nilsson class RequestID
7c92b91998-11-19Per Hedbor { object conf; // Really Configuration, but that's sort of recursive. int time; string raw_url; int do_not_disconnect; mapping (string:string) variables; mapping (string:mixed) misc; mapping (string:string) cookies; mapping (string:string) request_headers;
df4fbf1999-10-10Francesco Chemolli  mapping (string:mixed) throttle;
e2900e2000-03-07Martin Nilsson  mapping (string:string) client_var;
7c92b91998-11-19Per Hedbor  multiset(string) prestate; multiset(string) config; multiset(string) supports; multiset(string) pragma; array(string) client; array(string) referer;
2ec1182000-02-04Per Hedbor  Stdio.File my_fd;
7c92b91998-11-19Per Hedbor  string prot; string clientprot; string method;
81f8af1999-12-20Martin Nilsson 
7c92b91998-11-19Per Hedbor  string realfile; string virtfile; string rest_query; string raw; string query; string not_query; string extra_extension; string data; string leftovers; array (int|string) auth; string rawauth; string realauth; string since;
e682c11998-11-22Per Hedbor  string remoteaddr; string host;
aa3b4f2000-03-13Martin Nilsson  string version();
e682c11998-11-22Per Hedbor  void create(object|void master_request_id);
7c92b91998-11-19Per Hedbor  void send(string|object what, int|void len); string scan_for_query( string in ); void end(string|void s, int|void keepit); void ready_to_receive(); void send_result(mapping|void result); RequestID clone_me();
84fb682000-02-03Per Hedbor  Stdio.File connection( ); object configuration(); // really Configuration
7c92b91998-11-19Per Hedbor };
5964251999-11-19Per Hedbor string filename( program|object o )
95b69e1999-09-05Per Hedbor {
5964251999-11-19Per Hedbor  if( objectp( o ) ) o = object_program( o );
2537c32000-02-14Per Hedbor  string fname = master()->program_name( o );
5964251999-11-19Per Hedbor  if( !fname ) fname = "Unknown Program"; return fname-(getcwd()+"/");
95b69e1999-09-05Per Hedbor }
0f8b2f1999-03-27Henrik Grubbström (Grubba) #ifdef THREADS // This mutex is used by Privs
855c391999-11-29Per Hedbor Thread.Mutex euid_egid_lock = Thread.Mutex();
0f8b2f1999-03-27Henrik Grubbström (Grubba) #endif /* THREADS */
c5e0961999-10-04Per Hedbor /* * The privilege changer. * * Based on privs.pike,v 1.36. */
0f8b2f1999-03-27Henrik Grubbström (Grubba) int privs_level;
81f8af1999-12-20Martin Nilsson static class Privs
c5e0961999-10-04Per Hedbor {
0f8b2f1999-03-27Henrik Grubbström (Grubba) #if efun(seteuid) int saved_uid; int saved_gid; int new_uid; int new_gid; #define LOGP (variables && variables->audit && GLOBVAR(audit)) #if constant(geteuid) && constant(getegid) && constant(seteuid) && constant(setegid) #define HAVE_EFFECTIVE_USER #endif static private string _getcwd() { if (catch{return(getcwd());}) { return("Unknown directory (no x-bit on current directory?)"); } } static private string dbt(array t) { if(!arrayp(t) || (sizeof(t)<2)) return ""; return (((t[0]||"Unknown program")-(_getcwd()+"/"))-"base_server/")+":"+t[1]+"\n"; } #ifdef THREADS
b84a161999-06-07Martin Stjernholm  static mixed mutex_key; // Only one thread may modify the euid/egid at a time.
d3a71c1999-04-20Martin Stjernholm  static object threads_disabled;
0f8b2f1999-03-27Henrik Grubbström (Grubba) #endif /* THREADS */ int p_level; void create(string reason, int|string|void uid, int|string|void gid) { #ifdef PRIVS_DEBUG werror(sprintf("Privs(%O, %O, %O)\n" "privs_level: %O\n", reason, uid, gid, privs_level)); #endif /* PRIVS_DEBUG */ #ifdef HAVE_EFFECTIVE_USER array u; #ifdef THREADS if (euid_egid_lock) { catch { mutex_key = euid_egid_lock->lock(); }; }
d3a71c1999-04-20Martin Stjernholm  threads_disabled = _disable_threads();
0f8b2f1999-03-27Henrik Grubbström (Grubba) #endif /* THREADS */ p_level = privs_level++; if(getuid()) return; /* Needs to be here since root-priviliges may be needed to * use getpw{uid,nam}. */ saved_uid = geteuid(); saved_gid = getegid(); seteuid(0); /* A string of digits? */
c5e0961999-10-04Per Hedbor  if(stringp(uid) && (replace(uid,"0123456789"/"",({""})*10)==""))
0f8b2f1999-03-27Henrik Grubbström (Grubba)  uid = (int)uid;
c5e0961999-10-04Per Hedbor 
3a4b9a1999-12-27Martin Nilsson  if(stringp(gid) && (replace(gid, "0123456789"/"", ({"" })*10) == ""))
0f8b2f1999-03-27Henrik Grubbström (Grubba)  gid = (int)gid;
c5e0961999-10-04Per Hedbor  if(!stringp(uid))
0f8b2f1999-03-27Henrik Grubbström (Grubba)  u = getpwuid(uid);
81f8af1999-12-20Martin Nilsson  else
c5e0961999-10-04Per Hedbor  {
0f8b2f1999-03-27Henrik Grubbström (Grubba)  u = getpwnam(uid);
81f8af1999-12-20Martin Nilsson  if(u)
0f8b2f1999-03-27Henrik Grubbström (Grubba)  uid = u[2]; }
81f8af1999-12-20Martin Nilsson  if(u && !gid)
c5e0961999-10-04Per Hedbor  gid = u[3];
81f8af1999-12-20Martin Nilsson  if(!u)
c5e0961999-10-04Per Hedbor  {
81f8af1999-12-20Martin Nilsson  if (uid && (uid != "root"))
c5e0961999-10-04Per Hedbor  {
81f8af1999-12-20Martin Nilsson  if (intp(uid) && (uid >= 60000))
c5e0961999-10-04Per Hedbor  {
b84a161999-06-07Martin Stjernholm  report_warning(sprintf("Privs: User %d is not in the password database.\n" "Assuming nobody.\n", uid));
0f8b2f1999-03-27Henrik Grubbström (Grubba)  // Nobody. gid = gid || uid; // Fake a gid also. u = ({ "fake-nobody", "x", uid, gid, "A real nobody", "/", "/sbin/sh" }); } else { error("Unknown user: "+uid+"\n"); } } else { u = ({ "root", "x", 0, gid, "The super-user", "/", "/sbin/sh" }); } } if(LOGP) report_notice(sprintf("Change to %s(%d):%d privs wanted (%s), from %s", (string)u[0], (int)uid, (int)gid, (string)reason, (string)dbt(backtrace()[-2]))); #if efun(cleargroups) catch { cleargroups(); }; #endif /* cleargroups */ #if efun(initgroups) catch { initgroups(u[0], u[3]); }; #endif gid = gid || getgid(); int err = (int)setegid(new_gid = gid); if (err < 0) {
07c9921999-11-23Per Hedbor  report_warning(sprintf("Privs: WARNING: Failed to set the effective group id to %d!\n"
0f8b2f1999-03-27Henrik Grubbström (Grubba)  "Check that your password database is correct for user %s(%d),\n" "and that your group database is correct.\n", gid, (string)u[0], (int)uid)); int gid2 = gid; #ifdef HPUX_KLUDGE if (gid >= 60000) { /* HPUX has doesn't like groups higher than 60000, * but has assigned nobody to group 60001 (which isn't even * in /etc/group!). * * HPUX's libc also insists on filling numeric fields it doesn't like * with the value 60001! */
81f8af1999-12-20Martin Nilsson  report_debug("Privs: WARNING: Assuming nobody-group.\n"
0f8b2f1999-03-27Henrik Grubbström (Grubba)  "Trying some alternatives...\n"); // Assume we want the nobody group, and try a couple of alternatives foreach(({ 60001, 65534, -2 }), gid2) {
81f8af1999-12-20Martin Nilsson  report_debug("%d... ", gid2);
0f8b2f1999-03-27Henrik Grubbström (Grubba)  if (initgroups(u[0], gid2) >= 0) { if ((err = setegid(new_gid = gid2)) >= 0) {
81f8af1999-12-20Martin Nilsson  report_debug("Success!\n");
0f8b2f1999-03-27Henrik Grubbström (Grubba)  break; } } } } #endif /* HPUX_KLUDGE */ if (err < 0) {
81f8af1999-12-20Martin Nilsson  report_debug("Privs: Failed\n");
0f8b2f1999-03-27Henrik Grubbström (Grubba)  throw(({ sprintf("Failed to set EGID to %d\n", gid), backtrace() })); }
81f8af1999-12-20Martin Nilsson  report_debug("Privs: WARNING: Set egid to %d instead of %d.\n",
0f8b2f1999-03-27Henrik Grubbström (Grubba)  gid2, gid); gid = gid2; } if(getgid()!=gid) setgid(gid||getgid()); seteuid(new_uid = uid); #endif /* HAVE_EFFECTIVE_USER */ } void destroy() { #ifdef PRIVS_DEBUG werror(sprintf("Privs->destroy()\n" "privs_level: %O\n", privs_level)); #endif /* PRIVS_DEBUG */ #ifdef HAVE_EFFECTIVE_USER /* Check that we don't increase the privs level */ if (p_level >= privs_level) { report_error(sprintf("Change back to uid#%d gid#%d from uid#%d gid#%d\n" "in wrong order! Saved level:%d Current level:%d\n" "Occurs in:\n%s\n", saved_uid, saved_gid, new_uid, new_gid, p_level, privs_level, describe_backtrace(backtrace()))); return(0); } if (p_level != privs_level-1) { report_error(sprintf("Change back to uid#%d gid#%d from uid#%d gid#%d\n" "Skips privs level. Saved level:%d Current level:%d\n" "Occurs in:\n%s\n", saved_uid, saved_gid, new_uid, new_gid, p_level, privs_level, describe_backtrace(backtrace()))); } privs_level = p_level; if(LOGP) { catch { array bt = backtrace(); if (sizeof(bt) >= 2) {
d3a71c1999-04-20Martin Stjernholm  report_notice(sprintf("Change back to uid#%d gid#%d, from %s\n", saved_uid, saved_gid, dbt(bt[-2])));
0f8b2f1999-03-27Henrik Grubbström (Grubba)  } else {
d3a71c1999-04-20Martin Stjernholm  report_notice(sprintf("Change back to uid#%d gid#%d, from backend\n", saved_uid, saved_gid));
0f8b2f1999-03-27Henrik Grubbström (Grubba)  } }; } if(getuid()) return;
81f8af1999-12-20Martin Nilsson #ifdef PRIVS_DEBUG
0f8b2f1999-03-27Henrik Grubbström (Grubba)  int uid = geteuid(); if (uid != new_uid) {
81f8af1999-12-20Martin Nilsson  werror("Privs: UID #%d differs from expected #%d\n" "%s\n", uid, new_uid, describe_backtrace(backtrace()));
0f8b2f1999-03-27Henrik Grubbström (Grubba)  } int gid = getegid(); if (gid != new_gid) {
81f8af1999-12-20Martin Nilsson  werror("Privs: GID #%d differs from expected #%d\n" "%s\n", gid, new_gid, describe_backtrace(backtrace()));
0f8b2f1999-03-27Henrik Grubbström (Grubba)  }
81f8af1999-12-20Martin Nilsson #endif /* PRIVS_DEBUG */
0f8b2f1999-03-27Henrik Grubbström (Grubba)  seteuid(0); array u = getpwuid(saved_uid); #if efun(cleargroups) catch { cleargroups(); }; #endif /* cleargroups */ if(u && (sizeof(u) > 3)) { catch { initgroups(u[0], u[3]); }; } setegid(saved_gid); seteuid(saved_uid); #endif /* HAVE_EFFECTIVE_USER */ } #endif /* efun(seteuid) */
c5e0961999-10-04Per Hedbor }
0f8b2f1999-03-27Henrik Grubbström (Grubba)  /* Used by read_config.pike, since there seems to be problems with * overloading otherwise. */ static object PRIVS(string r, int|string|void u, int|string|void g) { return Privs(r, u, g); }
2ff8461999-09-02Per Hedbor #ifndef THREADS
b796b51998-11-18Per Hedbor class container { mixed value; mixed set(mixed to) { return value=to; } mixed get() { return value; } }
2ff8461999-09-02Per Hedbor #endif
b796b51998-11-18Per Hedbor 
c31f7b1998-10-10Henrik Grubbström (Grubba) // Locale support
2537c32000-02-14Per Hedbor RoxenLocale.standard default_locale=RoxenLocale.standard;
fb7ef91998-11-02Per Hedbor object fonts;
c5e0961999-10-04Per Hedbor #if constant( thread_local )
59912f1998-10-15Henrik Grubbström (Grubba) object locale = thread_local(); #else
81f8af1999-12-20Martin Nilsson object locale = container();
59912f1998-10-15Henrik Grubbström (Grubba) #endif /* THREADS */
c5e0961999-10-04Per Hedbor 
59912f1998-10-15Henrik Grubbström (Grubba) #define LOCALE LOW_LOCALE->base_server
c31f7b1998-10-10Henrik Grubbström (Grubba) 
dca5dc1998-09-12Per Hedbor program Configuration; /*set in create*/
b1fca01996-11-12Per Hedbor 
48fa361997-04-05Per Hedbor array configurations = ({});
b1fca01996-11-12Per Hedbor 
4f4bc11998-02-04Per Hedbor int die_die_die;
506ede1997-11-11Henrik Grubbström (Grubba) 
1720541998-10-04Henrik Grubbström (Grubba) // Function that actually shuts down Roxen. (see low_shutdown).
a9d8111998-09-01Henrik Grubbström (Grubba) private static void really_low_shutdown(int exit_code) { // Die nicely.
3107101998-09-01Marcus Comstedt #ifdef THREADS
c974c91999-06-27Per Hedbor  catch( stop_handler_threads() );
3107101998-09-01Marcus Comstedt #endif /* THREADS */
a9d8111998-09-01Henrik Grubbström (Grubba)  exit(exit_code); // Now we die... }
3a4b9a1999-12-27Martin Nilsson 
a9d8111998-09-01Henrik Grubbström (Grubba) // Shutdown Roxen // exit_code = 0 True shutdown // exit_code = -1 Restart private static void low_shutdown(int exit_code) {
81f8af1999-12-20Martin Nilsson  catch
c5e0961999-10-04Per Hedbor  { configurations->stop(); int pid; if (exit_code) {
81f8af1999-12-20Martin Nilsson  report_debug("Restarting Roxen.\n");
c5e0961999-10-04Per Hedbor  } else {
81f8af1999-12-20Martin Nilsson  report_debug("Shutting down Roxen.\n");
c5e0961999-10-04Per Hedbor  // exit(0); } }; call_out(really_low_shutdown, 0.01, exit_code);
b1fca01996-11-12Per Hedbor }
a9d8111998-09-01Henrik Grubbström (Grubba) // Perhaps somewhat misnamed, really... This function will close all
c974c91999-06-27Per Hedbor // listen ports and then quit. The 'start' script should then start a // new copy of roxen automatically.
81f8af1999-12-20Martin Nilsson void restart(float|void i) { call_out(low_shutdown, i, -1); } void shutdown(float|void i) { call_out(low_shutdown, i, 0);
f4e1b71999-10-08Per Hedbor }
14179b1997-01-29Per Hedbor 
4820e01999-07-27Henrik Grubbström (Grubba) /* * handle() stuff */
2ff8461999-09-02Per Hedbor #ifndef THREADS
1720541998-10-04Henrik Grubbström (Grubba) // handle function used when THREADS is not enabled.
3aaaa71997-06-12Wilhelm Köhler void unthreaded_handle(function f, mixed ... args) { f(@args); }
34fbbc1998-02-05Henrik Grubbström (Grubba) function handle = unthreaded_handle;
2ff8461999-09-02Per Hedbor #else
7277a11999-09-02Per Hedbor function handle = threaded_handle;
2ff8461999-09-02Per Hedbor #endif
34fbbc1998-02-05Henrik Grubbström (Grubba) 
1720541998-10-04Henrik Grubbström (Grubba) /* * THREADS code starts here */
34fbbc1998-02-05Henrik Grubbström (Grubba) #ifdef THREADS
4f4bc11998-02-04Per Hedbor object do_thread_create(string id, function f, mixed ... args) { object t = thread_create(f, @args); catch(t->set_name( id ));
bfb4d41999-12-28Martin Nilsson  THREAD_WERR(id+" started");
4f4bc11998-02-04Per Hedbor  return t; }
1720541998-10-04Henrik Grubbström (Grubba) // Queue of things to handle. // An entry consists of an array(function fp, array args)
3107101998-09-01Marcus Comstedt static object (Thread.Queue) handle_queue = Thread.Queue();
1720541998-10-04Henrik Grubbström (Grubba)  // Number of handler threads that are alive.
3107101998-09-01Marcus Comstedt static int thread_reap_cnt;
14179b1997-01-29Per Hedbor  void handler_thread(int id) {
4f4bc11998-02-04Per Hedbor  array (mixed) h, q;
34d3fa1999-04-22Per Hedbor  while(!die_die_die)
4f4bc11998-02-04Per Hedbor  { if(q=catch {
45cae31998-03-06Henrik Grubbström (Grubba)  do {
bfb4d41999-12-28Martin Nilsson  THREAD_WERR("Handle thread ["+id+"] waiting for next event");
3107101998-09-01Marcus Comstedt  if((h=handle_queue->read()) && h[0]) {
bfb4d41999-12-28Martin Nilsson  THREAD_WERR(sprintf("Handle thread [%O] calling %O(@%O)...",
81f8af1999-12-20Martin Nilsson  id, h[0], h[1..]));
b796b51998-11-18Per Hedbor  SET_LOCALE(default_locale);
45cae31998-03-06Henrik Grubbström (Grubba)  h[0](@h[1]); h=0;
3107101998-09-01Marcus Comstedt  } else if(!h) { // Roxen is shutting down.
81f8af1999-12-20Martin Nilsson  report_debug("Handle thread ["+id+"] stopped\n");
3107101998-09-01Marcus Comstedt  thread_reap_cnt--; return;
45cae31998-03-06Henrik Grubbström (Grubba)  } } while(1); }) {
774c9e2000-01-13Henrik Grubbström (Grubba)  if (h = catch { report_error(/* LOCALE->uncaught_error(*/describe_backtrace(q)/*)*/); if (q = catch {h = 0;}) { report_error(LOCALE-> uncaught_error(describe_backtrace(q))); } }) { catch { report_error("Error reporting error:\n"); report_error(sprintf("Raw error: %O\n", h[0])); report_error(sprintf("Original raw error: %O\n", q[0])); };
45cae31998-03-06Henrik Grubbström (Grubba)  } }
4f4bc11998-02-04Per Hedbor  }
b1fca01996-11-12Per Hedbor }
3aaaa71997-06-12Wilhelm Köhler void threaded_handle(function f, mixed ... args) { handle_queue->write(({f, args })); }
14179b1997-01-29Per Hedbor int number_of_threads; void start_handler_threads() {
a60c4c1997-07-03Henrik Grubbström (Grubba)  if (QUERY(numthreads) <= 1) { QUERY(numthreads) = 1;
07c9921999-11-23Per Hedbor  report_notice("Starting one thread to handle requests.\n");
a60c4c1997-07-03Henrik Grubbström (Grubba)  } else {
07c9921999-11-23Per Hedbor  report_notice("Starting "+
ceadf12000-02-15Martin Nilsson  language_low("en")->number( QUERY(numthreads) )
2ff8461999-09-02Per Hedbor  +" threads to handle requests.\n");
a60c4c1997-07-03Henrik Grubbström (Grubba)  }
14179b1997-01-29Per Hedbor  for(; number_of_threads < QUERY(numthreads); number_of_threads++)
4f4bc11998-02-04Per Hedbor  do_thread_create( "Handle thread ["+number_of_threads+"]", handler_thread, number_of_threads );
14179b1997-01-29Per Hedbor }
06583f1997-09-03Per Hedbor 
3107101998-09-01Marcus Comstedt void stop_handler_threads() {
95b69e1999-09-05Per Hedbor  int timeout=10;
81f8af1999-12-20Martin Nilsson  report_debug("Stopping all request handler threads.\n");
3107101998-09-01Marcus Comstedt  while(number_of_threads>0) { number_of_threads--; handle_queue->write(0); thread_reap_cnt++; } while(thread_reap_cnt) { if(--timeout<=0) {
81f8af1999-12-20Martin Nilsson  report_debug("Giving up waiting on threads!\n");
3107101998-09-01Marcus Comstedt  return; }
34d3fa1999-04-22Per Hedbor  sleep(0.1);
3107101998-09-01Marcus Comstedt  } }
49284b2000-02-17Per Hedbor #endif /* THREADS */
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba) 
934b3f2000-02-04Per Hedbor mapping get_port_options( string key ) { return (query( "port_options" )[ key ] || ([])); } void set_port_options( string key, mapping value ) { mapping q = query("port_options"); q[ key ] = value; set( "port_options" , q ); save( ); }
49284b2000-02-17Per Hedbor 
c5e0961999-10-04Per Hedbor class Protocol {
761baa1999-12-08Per Hedbor  inherit Stdio.Port: port;
934b3f2000-02-04Per Hedbor  inherit "basic_defvar";
c5e0961999-10-04Per Hedbor  constant name = "unknown"; constant supports_ipless = 0; constant requesthandlerfile = ""; constant default_port = 4711;
934b3f2000-02-04Per Hedbor 
c5e0961999-10-04Per Hedbor  int port; int refs; string ip; program requesthandler;
ddefa61999-10-04Marcus Comstedt  array(string) sorted_urls = ({}); mapping(string:mapping) urls = ([]);
c5e0961999-10-04Per Hedbor 
ddefa61999-10-04Marcus Comstedt  void ref(string name, mapping data)
c5e0961999-10-04Per Hedbor  {
ddefa61999-10-04Marcus Comstedt  if(urls[name]) return;
38c5072000-02-28Per Hedbor 
c5e0961999-10-04Per Hedbor  refs++;
ddefa61999-10-04Marcus Comstedt  urls[name] = data; sorted_urls = Array.sort_array(indices(urls), lambda(string a, string b) { return sizeof(a)<sizeof(b); });
c5e0961999-10-04Per Hedbor  }
ddefa61999-10-04Marcus Comstedt  void unref(string name)
c5e0961999-10-04Per Hedbor  {
ddefa61999-10-04Marcus Comstedt  if(!urls[name]) return; m_delete(urls, name); sorted_urls -= ({name});
c5e0961999-10-04Per Hedbor  if( !--refs ) destruct( ); // Close the port. } void got_connection() { object q = accept( ); if( !q ) ;// .. errno stuff here ..
df36c61999-10-08Henrik Grubbström (Grubba)  else { // FIXME: Add support for ANY => specific IP here.
ddefa61999-10-04Marcus Comstedt  requesthandler( q, this_object() );
df36c61999-10-08Henrik Grubbström (Grubba)  }
ddefa61999-10-04Marcus Comstedt  } object find_configuration_for_url( string url, RequestID id ) {
1d7d6d2000-02-16Per Hedbor // werror("find configuration for '"+url+"'\n"); object c;
ddefa61999-10-04Marcus Comstedt  foreach( sorted_urls, string in ) { if( glob( in+"*", url ) ) { if( urls[in]->path )
9699bf1999-10-11Per Hedbor  {
ddefa61999-10-04Marcus Comstedt  id->not_query = id->not_query[strlen(urls[in]->path)..];
9699bf1999-10-11Per Hedbor  id->misc->site_prefix_path = urls[in]->path; }
1d7d6d2000-02-16Per Hedbor  if(!(c=urls[ in ]->conf)->inited) c->enable_all_modules(); return c;
ddefa61999-10-04Marcus Comstedt  } } // Ouch.
7d18322000-03-10Henrik Grubbström (Grubba)  if(!(c = urls[sorted_urls[0]]->conf)->inited) c->enable_all_modules();
20b07e2000-02-02Per Hedbor  id->misc->defaulted=1;
1d7d6d2000-02-16Per Hedbor  return c;
c5e0961999-10-04Per Hedbor  }
934b3f2000-02-04Per Hedbor  mixed query_option( string x )
10bdc51999-10-08Henrik Grubbström (Grubba)  {
934b3f2000-02-04Per Hedbor  return query( x );
10bdc51999-10-08Henrik Grubbström (Grubba)  }
934b3f2000-02-04Per Hedbor  string get_key()
df36c61999-10-08Henrik Grubbström (Grubba)  {
934b3f2000-02-04Per Hedbor  return name+":"+ip+":"+port; }
df36c61999-10-08Henrik Grubbström (Grubba) 
934b3f2000-02-04Per Hedbor  void save() { set_port_options( get_key(), mkmapping( indices(variables), map(indices(variables),query))); }
df36c61999-10-08Henrik Grubbström (Grubba) 
934b3f2000-02-04Per Hedbor  void restore() { foreach( (array)get_port_options( get_key() ), array kv ) set( kv[0], kv[1] );
df36c61999-10-08Henrik Grubbström (Grubba)  }
c5e0961999-10-04Per Hedbor  void create( int pn, string i ) {
934b3f2000-02-04Per Hedbor  port = pn; ip = i; restore();
c5e0961999-10-04Per Hedbor  if( !requesthandler ) requesthandler = (program)requesthandlerfile;
df36c61999-10-08Henrik Grubbström (Grubba) 
c5e0961999-10-04Per Hedbor  ::create();
81f8af1999-12-20Martin Nilsson  if(!bind( port, got_connection, ip ))
b6fb051999-11-02Per Hedbor  {
81f8af1999-12-20Martin Nilsson  report_error("Failed to bind %s://%s:%d/ (%s)\n", (string)name,
b6fb051999-11-02Per Hedbor  (ip||"*"), (int)port, strerror( errno() ));
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); }
c5e0961999-10-04Per Hedbor  }
81f8af1999-12-20Martin Nilsson 
b6fb051999-11-02Per Hedbor  string _sprintf( ) { return "Protocol("+name+"://"+ip+":"+port+")"; }
c5e0961999-10-04Per Hedbor }
4820e01999-07-27Henrik Grubbström (Grubba) 
df36c61999-10-08Henrik Grubbström (Grubba) class SSLProtocol { inherit Protocol;
479d8a1999-11-25Henrik Grubbström (Grubba) #if constant(Standards) && constant(Standards.PKCS.RSA) && constant(SSL.sslfile)
dd7e661999-10-09Henrik Grubbström (Grubba) 
df36c61999-10-08Henrik Grubbström (Grubba)  // SSL context object ctx; class destruct_protected_sslfile { object sslfile; mixed `[](string s) { return sslfile[s]; }
60a9121999-10-10Henrik Grubbström (Grubba)  mixed `[]=(string s, mixed val) { return sslfile[s] = val; }
df36c61999-10-08Henrik Grubbström (Grubba)  mixed `->(string s) { return sslfile[s]; }
60a9121999-10-10Henrik Grubbström (Grubba)  mixed `->=(string s, mixed val) { return sslfile[s] = val; }
df36c61999-10-08Henrik Grubbström (Grubba)  void destroy() {
60a9121999-10-10Henrik Grubbström (Grubba)  if (sslfile) { sslfile->close(); }
df36c61999-10-08Henrik Grubbström (Grubba)  } void create(object q, object ctx) { sslfile = SSL.sslfile(q, ctx); } } object accept() { object q = ::accept(); if (q) { return destruct_protected_sslfile(q, ctx); } return 0; } void create(int pn, string i) { ctx = SSL.context();
6f72d42000-02-08Per Hedbor  set_up_ssl_variables( this_object() ); restore();
934b3f2000-02-04Per Hedbor 
df36c61999-10-08Henrik Grubbström (Grubba)  object privs = Privs("Reading cert file");
6f72d42000-02-08Per Hedbor 
df36c61999-10-08Henrik Grubbström (Grubba)  string f = Stdio.read_file(query_option("ssl_cert_file") || "demo_certificate.pem"); string f2 = query_option("ssl_key_file") &&
6f72d42000-02-08Per Hedbor  strlen(query_option("ssl_key_file")) && Stdio.read_file(query_option("ssl_key_file"));
df36c61999-10-08Henrik Grubbström (Grubba)  if (privs) destruct(privs); if (!f) {
81f8af1999-12-20Martin Nilsson  report_error("SSL3: Reading cert-file failed!\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } object msg = Tools.PEM.pem_msg()->init(f); object part = msg->parts["CERTIFICATE"] ||msg->parts["X509 CERTIFICATE"]; string cert;
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  if (!part || !(cert = part->decoded_body())) {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: No certificate found.\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; }
81f8af1999-12-20Martin Nilsson 
6f72d42000-02-08Per Hedbor  if (query_option("ssl_key_file") && strlen(query_option("ssl_key_file") ))
df36c61999-10-08Henrik Grubbström (Grubba)  { if (!f2) {
81f8af1999-12-20Martin Nilsson  report_error("SSL3: Reading key-file failed!\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } msg = Tools.PEM.pem_msg()->init(f2); } function r = Crypto.randomness.reasonably_random()->read;
bfb4d41999-12-28Martin Nilsson  SSL3_WERR(sprintf("key file contains: %O", indices(msg->parts)));
df36c61999-10-08Henrik Grubbström (Grubba)  if (part = msg->parts["RSA PRIVATE KEY"]) { string key; if (!(key = part->decoded_body())) {
81f8af1999-12-20Martin Nilsson  report_error("SSL3: Private rsa key not valid (PEM).\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; }
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  object rsa = Standards.PKCS.RSA.parse_private_key(key); if (!rsa) {
81f8af1999-12-20Martin Nilsson  report_error("SSL3: Private rsa key not valid (DER).\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } ctx->rsa = rsa;
81f8af1999-12-20Martin Nilsson 
bfb4d41999-12-28Martin Nilsson  SSL3_WERR(sprintf("RSA key size: %d bits", rsa->rsa_size()));
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  if (rsa->rsa_size() > 512) { /* Too large for export */ ctx->short_rsa = Crypto.rsa()->generate_key(512, r);
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  // ctx->long_rsa = Crypto.rsa()->generate_key(rsa->rsa_size(), r); } ctx->rsa_mode(); object tbs = Tools.X509.decode_certificate (cert); if (!tbs) {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: Certificate not valid (DER).\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } if (!tbs->public_key->rsa->public_key_equal (rsa)) {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: Certificate and private key do not match.\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } } else if (part = msg->parts["DSA PRIVATE KEY"]) { string key; if (!(key = part->decoded_body())) {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: Private dsa key not valid (PEM).\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; }
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  object dsa = Standards.PKCS.DSA.parse_private_key(key); if (!dsa) {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: Private dsa key not valid (DER).\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; }
bfb4d41999-12-28Martin Nilsson  SSL3_WERR(sprintf("Using DSA key."));
2f74c32000-01-21Per Hedbor 
df36c61999-10-08Henrik Grubbström (Grubba)  dsa->use_random(r); ctx->dsa = dsa; /* Use default DH parameters */ ctx->dh_params = SSL.cipher.dh_parameters(); ctx->dhe_dss_mode(); // FIXME: Add cert <-> private key check. } else {
dd7e661999-10-09Henrik Grubbström (Grubba)  report_error("ssl3: No private key found.\n");
df36c61999-10-08Henrik Grubbström (Grubba)  destruct(); return; } ctx->certificates = ({ cert }); ctx->random = r; #if EXPORT ctx->export_mode(); #endif ::create(pn, i); }
dd7e661999-10-09Henrik Grubbström (Grubba) #else /* !constant(SSL.sslfile) */ void create(int pn, string i) { report_error("No SSL support\n"); destruct(); }
df36c61999-10-08Henrik Grubbström (Grubba) #endif /* constant(SSL.sslfile) */
b6fb051999-11-02Per Hedbor  string _sprintf( ) { return "SSLProtocol("+name+"://"+ip+":"+port+")"; }
dd7e661999-10-09Henrik Grubbström (Grubba) }
df36c61999-10-08Henrik Grubbström (Grubba) 
761baa1999-12-08Per Hedbor #if constant(HTTPLoop.prog) class FHTTP { inherit Protocol; // inherit Stdio.Port : port; constant supports_ipless=1; constant name = "fhttp"; constant default_port = 80; int dolog; int requests, received, sent; HTTPLoop.Loop l; Stdio.Port portobj; mapping flatten_headers( mapping from ) { mapping res = ([]); foreach(indices(from), string f) res[f] = from[f]*", "; return res; } void setup_fake(object o) { mapping vars = ([]); o->extra_extension = ""; o->misc = flatten_headers(o->headers); o->cmf = 100*1024; o->cmp = 100*1024;
81f8af1999-12-20Martin Nilsson 
761baa1999-12-08Per Hedbor  // werror("%O\n", o->variables); if(o->method == "POST" && strlen(o->data)) { mapping variabels = ([]); switch((o->misc["content-type"]/";")[0]) { default: // Normal form data, handled in the C part. break;
81f8af1999-12-20Martin Nilsson 
761baa1999-12-08Per Hedbor  case "multipart/form-data": object messg = MIME.Message(o->data, o->misc); mapping misc = o->misc;
81f8af1999-12-20Martin Nilsson  foreach(messg->body_parts, object part)
761baa1999-12-08Per Hedbor  {
81f8af1999-12-20Martin Nilsson  if(part->disp_params->filename)
761baa1999-12-08Per Hedbor  { vars[part->disp_params->name]=part->getdata(); vars[part->disp_params->name+".filename"]= part->disp_params->filename; if(!misc->files) misc->files = ({ part->disp_params->name }); else misc->files += ({ part->disp_params->name }); } else { vars[part->disp_params->name]=part->getdata(); } } break; } o->variables = vars|o->variables; } string contents; if(contents = o->misc["cookie"]) { string c; mapping cookies = ([]); multiset config = (<>); o->misc->cookies = contents; foreach(((contents/";") - ({""})), c) { string name, value; while(sizeof(c) && c[0]==' ') c=c[1..]; if(sscanf(c, "%s=%s", name, value) == 2) { value=http_decode_string(value); name=http_decode_string(name); cookies[ name ]=value; if(name == "RoxenConfig" && strlen(value)) config = aggregate_multiset(@(value/"," + ({ }))); } } o->cookies = cookies; o->config = config; } else { o->cookies = ([]); o->config = (<>); }
81f8af1999-12-20Martin Nilsson 
761baa1999-12-08Per Hedbor  if(contents = o->misc->accept) o->misc->accept = contents/","; if(contents = o->misc["accept-charset"]) o->misc["accept-charset"] = ({ contents/"," }); if(contents = o->misc["accept-language"]) o->misc["accept-language"] = ({ contents/"," }); if(contents = o->misc["session-id"]) o->misc["session-id"] = ({ contents/"," }); } void handle_request(object o) { setup_fake( o ); // Equivalent to parse_got in http.pike handle( o->handle_request, this_object() ); } int cdel=10; void do_log() { if(l->logp()) { // werror("log..\n"); switch(query("log")) { case "None": l->log_as_array(); break;
934b3f2000-02-04Per Hedbor  case "CommonLog":
761baa1999-12-08Per Hedbor  object f = Stdio.File( query("log_file"), "wca" ); l->log_as_commonlog_to_file( f ); destruct(f); break;
934b3f2000-02-04Per Hedbor  default: report_notice( "It is not yet possible to log using the "+ query("log")+" method. Sorry. Out of time"); break;
761baa1999-12-08Per Hedbor  } cdel--; if(cdel < 1) cdel=1; } else { cdel++; // werror("nolog..\n"); } call_out(do_log, cdel); }
6796aa1999-12-11Per Hedbor  string status( )
761baa1999-12-08Per Hedbor  {
6796aa1999-12-11Per Hedbor  mapping m = l->cache_status(); string res; low_adjust_stats( m );
7256451999-12-08Per Hedbor #define PCT(X) ((int)(((X)/(float)(m->total+0.1))*100))
e3bbe11999-12-15Per Hedbor  res = ("\nCache statistics\n<pre>\n");
7256451999-12-08Per Hedbor  m->total = m->hits + m->misses + m->stale;
e3bbe11999-12-15Per Hedbor  res += sprintf(" %d elements in cache, size is %1.1fMb max is %1.1fMb\n"
6796aa1999-12-11Per Hedbor  " %d cache lookups, %d%% hits, %d%% misses and %d%% stale.\n", m->entries, m->size/(1024.0*1024.0), m->max_size/(1024*1024.0), m->total, PCT(m->hits), PCT(m->misses), PCT(m->stale));
e3bbe11999-12-15Per Hedbor  return res+"\n</pre>\n";
6796aa1999-12-11Per Hedbor  }
7256451999-12-08Per Hedbor 
6796aa1999-12-11Per Hedbor  void low_adjust_stats(mapping m) {
761baa1999-12-08Per Hedbor  array q = values( urls )->conf; if( sizeof( q ) ) /* This is not exactly correct if sizeof(q)>1 */ { q[0]->requests += m->num_request; q[0]->received += m->received_bytes; q[0]->sent += m->sent_bytes; } requests += m->num_requests; received += m->received_bytes; sent += m->sent_bytes; } void adjust_stats() { call_out(adjust_stats, 2);
ebdf942000-02-04Per Hedbor // werror( status() ); low_adjust_stats( l->cache_status() );
761baa1999-12-08Per Hedbor  } void create( int pn, string i ) { requesthandler = (program)"protocols/fhttp.pike"; port = pn; ip = i;
6f72d42000-02-08Per Hedbor  set_up_fhttp_variables( this_object() );
934b3f2000-02-04Per Hedbor  restore();
6f72d42000-02-08Per Hedbor 
934b3f2000-02-04Per Hedbor  dolog = (query_option( "log" ) && (query_option( "log" )!="None"));
761baa1999-12-08Per Hedbor  portobj = Stdio.Port(); /* No way to use ::create easily */ if( !portobj->bind( port, 0, ip ) ) { report_error("Failed to bind %s://%s:%d/ (%s)\n", name,ip||"*",(int)port, strerror(errno())); destruct(portobj); destruct(); return; }
81f8af1999-12-20Martin Nilsson  l = HTTPLoop.Loop( portobj, requesthandler,
761baa1999-12-08Per Hedbor  handle_request, 0,
0c989e2000-02-04Per Hedbor  ((int)query_option("ram_cache")||20)*1024*1024,
761baa1999-12-08Per Hedbor  dolog, (query_option("read_timeout")||120) ); call_out(adjust_stats, 10); if(dolog) call_out(do_log, 5); } } #endif
c5e0961999-10-04Per Hedbor class HTTP { inherit Protocol; constant supports_ipless = 1; constant name = "http"; constant requesthandlerfile = "protocols/http.pike"; constant default_port = 80;
934b3f2000-02-04Per Hedbor  void create( mixed ... args ) { set_up_http_variables( this_object() ); ::create( @args ); }
c5e0961999-10-04Per Hedbor }
b1fca01996-11-12Per Hedbor 
ac76fc1999-10-07Henrik Grubbström (Grubba) class HTTPS {
df36c61999-10-08Henrik Grubbström (Grubba)  inherit SSLProtocol;
ac76fc1999-10-07Henrik Grubbström (Grubba)  constant supports_ipless = 0; constant name = "https";
df36c61999-10-08Henrik Grubbström (Grubba)  constant requesthandlerfile = "protocols/http.pike";
ac76fc1999-10-07Henrik Grubbström (Grubba)  constant default_port = 443;
df36c61999-10-08Henrik Grubbström (Grubba) 
1d7d6d2000-02-16Per Hedbor  class fallback_redirect_request { string in = ""; string out; string default_prefix; int port; Stdio.File f; void die() { SSL3_WERR(sprintf("fallback_redirect_request::die()")); f->close(); destruct(f); destruct(this_object()); } void write_callback(object id) { SSL3_WERR(sprintf("fallback_redirect_request::write_callback()")); int written = id->write(out); if (written <= 0) die(); out = out[written..]; if (!strlen(out)) die(); } void read_callback(object id, string s) { SSL3_WERR(sprintf("fallback_redirect_request::read_callback(X, \"%s\")\n", s)); in += s; string name; string prefix; if (search(in, "\r\n\r\n") >= 0) { // werror("request = '%s'\n", in); array(string) lines = in / "\r\n"; array(string) req = replace(lines[0], "\t", " ") / " "; if (sizeof(req) < 2) { out = "HTTP/1.0 400 Bad Request\r\n\r\n"; } else { if (sizeof(req) == 2) { name = req[1]; } else { name = req[1..sizeof(req)-2] * " "; foreach(map(lines[1..], `/, ":"), array header) { if ( (sizeof(header) >= 2) && (lower_case(header[0]) == "host") ) prefix = "https://" + header[1] - " "; } } if (prefix) { if (prefix[-1] == '/') prefix = prefix[..strlen(prefix)-2]; prefix = prefix + ":" + port; } else { /* default_prefix (aka MyWorldLocation) already contains the * portnumber. */ if (!(prefix = default_prefix)) { /* This case is most unlikely to occur, * but better safe than sorry... */ string ip = (f->query_address(1)/" ")[0]; prefix = "https://" + ip + ":" + port; } else if (prefix[..4] == "http:") { /* Broken MyWorldLocation -- fix. */ prefix = "https:" + prefix[5..]; } } out = sprintf("HTTP/1.0 301 Redirect to secure server\r\n" "Location: %s%s\r\n\r\n", prefix, name); } f->set_read_callback(0); f->set_write_callback(write_callback); } } void create(object socket, string s, string l, int p) { SSL3_WERR(sprintf("fallback_redirect_request(X, \"%s\", \"%s\", %d)", s, l||"CONFIG PORT", p)); f = socket; default_prefix = l; port = p; f->set_nonblocking(read_callback, 0, die); f->set_id(f); read_callback(f, s); } }
dd7e661999-10-09Henrik Grubbström (Grubba) #if constant(SSL.sslfile)
df36c61999-10-08Henrik Grubbström (Grubba)  class http_fallback { object my_fd; void ssl_alert_callback(object alert, object|int n, string data) {
bfb4d41999-12-28Martin Nilsson  SSL3_WERR(sprintf("http_fallback(X, %O, \"%s\")", n, data));
df36c61999-10-08Henrik Grubbström (Grubba)  // trace(1); if ( (my_fd->current_write_state->seq_num == 0) && search(lower_case(data), "http")) { object raw_fd = my_fd->socket;
60a9121999-10-10Henrik Grubbström (Grubba)  my_fd->socket = 0;
df36c61999-10-08Henrik Grubbström (Grubba)  /* Redirect to a https-url */ // my_fd->set_close_callback(0); // my_fd->leave_me_alone = 1; fallback_redirect_request(raw_fd, data,
81f8af1999-12-20Martin Nilsson  my_fd->config &&
df36c61999-10-08Henrik Grubbström (Grubba)  my_fd->config->query("MyWorldLocation"), port); destruct(my_fd); destruct(this_object()); // my_fd = 0; /* Forget ssl-object */ } } void ssl_accept_callback(object id) {
bfb4d41999-12-28Martin Nilsson  SSL3_WERR(sprintf("ssl_accept_callback(X)"));
df36c61999-10-08Henrik Grubbström (Grubba)  id->set_alert_callback(0); /* Forget about http_fallback */ my_fd = 0; /* Not needed any more */ } void create(object fd) { my_fd = fd; fd->set_alert_callback(ssl_alert_callback); fd->set_accept_callback(ssl_accept_callback); } }
81f8af1999-12-20Martin Nilsson 
df36c61999-10-08Henrik Grubbström (Grubba)  object accept() { object q = ::accept(); if (q) { http_fallback(q); } return q; } #endif /* constant(SSL.sslfile) */
934b3f2000-02-04Per Hedbor  void create( mixed ... args ) { set_up_http_variables( this_object() ); ::create( @args ); }
dd7e661999-10-09Henrik Grubbström (Grubba) }
df36c61999-10-08Henrik Grubbström (Grubba) 
ac76fc1999-10-07Henrik Grubbström (Grubba) class FTP { inherit Protocol; constant supports_ipless = 0; constant name = "ftp"; constant requesthandlerfile = "protocols/ftp.pike"; constant default_port = 21;
df36c61999-10-08Henrik Grubbström (Grubba)  // Some statistics int sessions; int ftp_users; int ftp_users_now;
934b3f2000-02-04Per Hedbor  void create( mixed ... args ) { set_up_ftp_variables( this_object() ); ::create( @args ); }
ac76fc1999-10-07Henrik Grubbström (Grubba) }
df36c61999-10-08Henrik Grubbström (Grubba) class FTPS { inherit SSLProtocol; constant supports_ipless = 0; constant name = "ftps"; constant requesthandlerfile = "protocols/ftp.pike"; constant default_port = 21; /*** ???? ***/ // Some statistics int sessions; int ftp_users; int ftp_users_now;
934b3f2000-02-04Per Hedbor  void create( mixed ... args ) { set_up_ftp_variables( this_object() ); ::create( @args ); }
df36c61999-10-08Henrik Grubbström (Grubba) }
ac76fc1999-10-07Henrik Grubbström (Grubba) class GOPHER { inherit Protocol; constant supports_ipless = 0; constant name = "gopher"; constant requesthandlerfile = "protocols/gopher.pike"; constant default_port = 70; } class TETRIS { inherit Protocol; constant supports_ipless = 0; constant name = "tetris"; constant requesthandlerfile = "protocols/tetris.pike"; constant default_port = 2050; }
479d8a1999-11-25Henrik Grubbström (Grubba) class SMTP { inherit Protocol; constant supports_ipless = 1; constant name = "smtp"; constant requesthandlerfile = "protocols/smtp.pike"; constant default_port = Protocols.Ports.tcp.smtp; } class POP3 { inherit Protocol; constant supports_ipless = 0; constant name = "pop3"; constant requesthandlerfile = "protocols/pop3.pike"; constant default_port = Protocols.Ports.tcp.pop3; } class IMAP { inherit Protocol; constant supports_ipless = 0; constant name = "imap"; constant requesthandlerfile = "protocols/imap.pike"; constant default_port = Protocols.Ports.tcp.imap2; }
c5e0961999-10-04Per Hedbor mapping protocols = ([
761baa1999-12-08Per Hedbor #if constant(HTTPLoop.prog) "fhttp":FHTTP, #else "fhttp":HTTP, #endif
c5e0961999-10-04Per Hedbor  "http":HTTP,
ac76fc1999-10-07Henrik Grubbström (Grubba)  "ftp":FTP,
df36c61999-10-08Henrik Grubbström (Grubba) 
3eebb92000-02-12Martin Stjernholm  "https":HTTPS,
df36c61999-10-08Henrik Grubbström (Grubba)  "ftps":FTPS,
ac76fc1999-10-07Henrik Grubbström (Grubba)  "gopher":GOPHER, "tetris":TETRIS,
479d8a1999-11-25Henrik Grubbström (Grubba)  "smtp":SMTP, "pop3":POP3, "imap":IMAP,
c5e0961999-10-04Per Hedbor ]); mapping(string:mapping) open_ports = ([ ]); mapping(string:object) urls = ([]); array sorted_urls = ({});
dd7e661999-10-09Henrik Grubbström (Grubba) array(string) find_ips_for( string what )
b1fca01996-11-12Per Hedbor {
c5e0961999-10-04Per Hedbor  if( what == "*" || lower_case(what) == "any" )
b1fca01996-11-12Per Hedbor  return 0;
c5e0961999-10-04Per Hedbor 
15635b1999-10-10Per Hedbor  if( is_ip( what ) )
dd7e661999-10-09Henrik Grubbström (Grubba)  return ({ what });
c5e0961999-10-04Per Hedbor  array res = gethostbyname( what ); if( !res || !sizeof( res[1] ) ) report_error( "I cannot possibly bind to "+what+ ", that host is unknown. " "Substituting with ANY\n"); else
92898c1999-10-10Marcus Comstedt  return Array.uniq(res[1]);
c5e0961999-10-04Per Hedbor }
81f8af1999-12-20Martin Nilsson void unregister_url( string url )
c5e0961999-10-04Per Hedbor {
e7e6031999-11-05Per Hedbor  report_debug("Unregister "+url+"\n");
c5e0961999-10-04Per Hedbor  if( urls[ url ] && urls[ url ]->port ) {
ddefa61999-10-04Marcus Comstedt  urls[ url ]->port->unref(url);
c5e0961999-10-04Per Hedbor  m_delete( urls, url ); sort_urls();
b1fca01996-11-12Per Hedbor  } }
934b3f2000-02-04Per Hedbor array all_ports( ) { return Array.uniq( values( urls )->port ); } Protocol find_port( string name ) { foreach( all_ports(), Protocol p ) if( p->get_key() == name ) return p; }
c5e0961999-10-04Per Hedbor void sort_urls()
1668b21998-04-23Henrik Grubbström (Grubba) {
c5e0961999-10-04Per Hedbor  sorted_urls = indices( urls ); sort( map( map( sorted_urls, strlen ), `-), sorted_urls );
1668b21998-04-23Henrik Grubbström (Grubba) }
c5e0961999-10-04Per Hedbor int register_url( string url, object conf ) {
1e3cd52000-02-02Martin Stjernholm  if (!sizeof (url - " " - "\t")) return 1;
c5e0961999-10-04Per Hedbor  string protocol; string host; int port; string path;
b1fca01996-11-12Per Hedbor 
ac76fc1999-10-07Henrik Grubbström (Grubba)  url = replace( url, "/ANY", "/*" ); url = replace( url, "/any", "/*" );
c5e0961999-10-04Per Hedbor  sscanf( url, "%[^:]://%[^/]%s", protocol, host, path );
228fea2000-02-15Leif Stensson  if (!host || !stringp(host)) { report_error("Bad URL `" + url + "' for server `" + conf->query_name() + "'\n"); return 1; } sscanf(host, "%[^:]:%d", host, port);
c5e0961999-10-04Per Hedbor 
38c5072000-02-28Per Hedbor  if( !port ) { port = protocols[ protocol ]->default_port; url = protocol+"://"+host+":"+port+path; }
c5e0961999-10-04Per Hedbor  if( strlen( path ) && ( path[-1] == '/' ) ) path = path[..strlen(path)-2]; if( !strlen( path ) ) path = 0; if( urls[ url ] ) { if( urls[ url ]->conf != conf ) { report_error( "Cannot register URL "+url+
dfb2302000-02-20Martin Stjernholm  ", already registered by " +
c5e0961999-10-04Per Hedbor  urls[ url ]->conf->name + "!\n" ); return 0; }
ddefa61999-10-04Marcus Comstedt  urls[ url ]->port->ref(url, urls[url]);
c5e0961999-10-04Per Hedbor  return 1; }
dd7e661999-10-09Henrik Grubbström (Grubba)  Protocol prot;
c5e0961999-10-04Per Hedbor  if( !( prot = protocols[ protocol ] ) ) { report_error( "Cannot register URL "+url+
81f8af1999-12-20Martin Nilsson  ", cannot find the protocol " +
c5e0961999-10-04Per Hedbor  protocol + "!\n" ); return 0; } if( !port ) port = prot->default_port;
dd7e661999-10-09Henrik Grubbström (Grubba)  array(string) required_hosts;
b6fb051999-11-02Per Hedbor  /* if( !prot->supports_ipless )*/
dd7e661999-10-09Henrik Grubbström (Grubba)  required_hosts = find_ips_for( host );
81f8af1999-12-20Martin Nilsson  if (!required_hosts)
dd7e661999-10-09Henrik Grubbström (Grubba)  required_hosts = ({ 0 }); // ANY
b6fb051999-11-02Per Hedbor 
c5e0961999-10-04Per Hedbor  mapping m; if( !( m = open_ports[ protocol ] ) ) m = open_ports[ protocol ] = ([]);
81f8af1999-12-20Martin Nilsson 
c5e0961999-10-04Per Hedbor  urls[ url ] = ([ "conf":conf, "path":path ]); sorted_urls += ({ url });
dd7e661999-10-09Henrik Grubbström (Grubba)  int failures;
c5e0961999-10-04Per Hedbor 
38c5072000-02-28Per Hedbor  foreach(required_hosts, string required_host) {
dd7e661999-10-09Henrik Grubbström (Grubba)  if( m[ required_host ] && m[ required_host ][ port ] ) {
7c708f2000-02-05Henrik Grubbström (Grubba)  m[required_host][port]->ref(url, urls[url]);
38c5072000-02-28Per Hedbor 
7c708f2000-02-05Henrik Grubbström (Grubba)  urls[url]->port = m[required_host][port];
dd7e661999-10-09Henrik Grubbström (Grubba)  continue; /* No need to open a new port */ } if( !m[ required_host ] ) m[ required_host ] = ([ ]);
7c708f2000-02-05Henrik Grubbström (Grubba)  mixed err; if (err = catch { m[ required_host ][ port ] = prot( port, required_host ); }) { failures++; report_error(sprintf("Initializing the port handler for URL " + url + " failed!\n" "%s\n", describe_backtrace(err))); continue; }
dd7e661999-10-09Henrik Grubbström (Grubba)  if( !( m[ required_host ][ port ] ) ) { m_delete( m[ required_host ], port ); failures++; if (required_host) { report_warning("Binding the port on IP " + required_host +
b6fb051999-11-02Per Hedbor  " failed\n for URL " + url + "!\n");
dd7e661999-10-09Henrik Grubbström (Grubba)  } continue; } urls[ url ]->port = m[ required_host ][ port ]; m[ required_host ][ port ]->ref(url, urls[url]); } if (failures == sizeof(required_hosts)) {
c5e0961999-10-04Per Hedbor  m_delete( urls, url );
b6fb051999-11-02Per Hedbor  report_error( "Cannot register URL "+url+"!\n" );
dd7e661999-10-09Henrik Grubbström (Grubba)  sort_urls();
c5e0961999-10-04Per Hedbor  return 0; } sort_urls();
1d7d6d2000-02-16Per Hedbor  report_notice("Registered "+url+" for "+conf->query_name()+"\n");
c5e0961999-10-04Per Hedbor  return 1; } object find_configuration( string name )
b1fca01996-11-12Per Hedbor {
9699bf1999-10-11Per Hedbor  name = replace( lower_case( replace(name,"-"," ") )-" ", "/", "-" );
c5e0961999-10-04Per Hedbor  foreach( configurations, object o )
9699bf1999-10-11Per Hedbor  {
0666741999-12-07Henrik Grubbström (Grubba)  if( (lower_case( replace( replace(o->name, "-"," ") - " " , "/", "-" ) ) == name) || (lower_case( replace( replace(o->query_name(), "-", " ") - " " , "/", "-" ) ) == name) )
c5e0961999-10-04Per Hedbor  return o;
9699bf1999-10-11Per Hedbor  }
0666741999-12-07Henrik Grubbström (Grubba)  return 0;
b1fca01996-11-12Per Hedbor }
c5e0961999-10-04Per Hedbor mapping(string:array(int)) error_log=([]);
ec2fe11997-06-09Henrik Grubbström (Grubba) 
b1fca01996-11-12Per Hedbor // Write a string to the configuration interface error log and to stderr.
c60cae2000-02-02Johan Sundström void nwrite(string s, int|void perr, int|void errtype,
c821c31999-12-27Martin Stjernholm  object|void mod, object|void conf)
b1fca01996-11-12Per Hedbor {
c60cae2000-02-02Johan Sundström  int log_time = time();
0fe69d2000-03-19Martin Nilsson  string reference = (mod ? Roxen.get_modname(mod) : conf && conf->name) || "";
c60cae2000-02-02Johan Sundström  string log_index = sprintf("%d,%s,%s", errtype, reference, s); if(!error_log[log_index]) error_log[log_index] = ({ log_time });
c5e0961999-10-04Per Hedbor  else
c60cae2000-02-02Johan Sundström  error_log[log_index] += ({ log_time });
e99fd41999-11-17Per Hedbor  if( mod ) { if( !mod->error_log ) mod->error_log = ([]);
c60cae2000-02-02Johan Sundström  mod->error_log[log_index] += ({ log_time });
e99fd41999-11-17Per Hedbor  } if( conf ) { if( !conf->error_log ) conf->error_log = ([]);
c60cae2000-02-02Johan Sundström  conf->error_log[log_index] += ({ log_time });
e99fd41999-11-17Per Hedbor  }
c60cae2000-02-02Johan Sundström  if(errtype >= 1)
81f8af1999-12-20Martin Nilsson  report_debug( s );
b1fca01996-11-12Per Hedbor } // When was Roxen started?
2ff8461999-09-02Per Hedbor int boot_time =time(); int start_time =time();
b1fca01996-11-12Per Hedbor  string version() {
daff902000-02-23Martin Nilsson #ifdef SERIOUS
71a11e1997-08-13Henrik Grubbström (Grubba)  return QUERY(default_ident)?real_version:QUERY(ident);
daff902000-02-23Martin Nilsson #else multiset choices=(<>); string version=QUERY(default_ident)?real_version:QUERY(ident);
0893642000-02-25Martin Nilsson  return version+", "+ ({ "Applier of Templates", "Beautifier of Layouts", "Conqueror of Comdex", "Deliverer of Documents", "Enhancer of Abilities", "Freer of Webmasters", "Generator of Logs", "Helper of Users", "Interpreter of Scripts", "Juggler of Java-code", "Keeper of Databases", "Locator of Keywords", "Manipulator of Data", "Negatiator of Protocols", "Operator of Sites", "Provider of Contents", "Quintessence of Quality", "Responder to Connections", "Server of Webs", "Translator of Texts", "Unifier of Interfaces", "Valet of Visitors", "Watcher for Requests", "Xylem of Services", "Yielder of Information", "Zenith of Extensibility" })[random(26)];
daff902000-02-23Martin Nilsson #endif
b1fca01996-11-12Per Hedbor }
81f8af1999-12-20Martin Nilsson public void log(mapping file, RequestID request_id)
b1fca01996-11-12Per Hedbor {
81f8af1999-12-20Martin Nilsson  if(!request_id->conf) return;
14179b1997-01-29Per Hedbor  request_id->conf->log(file, request_id);
b1fca01996-11-12Per Hedbor }
81f8af1999-12-20Martin Nilsson // Support for unique user id's
b1fca01996-11-12Per Hedbor private object current_user_id_file; private int current_user_id_number, current_user_id_file_last_mod; private void restore_current_user_id_number() { if(!current_user_id_file) current_user_id_file = open(configuration_dir + "LASTUSER~", "rwc"); if(!current_user_id_file) { call_out(restore_current_user_id_number, 2); return;
81f8af1999-12-20Martin Nilsson  }
b1fca01996-11-12Per Hedbor  current_user_id_number = (int)current_user_id_file->read(100); current_user_id_file_last_mod = current_user_id_file->stat()[2];
81f8af1999-12-20Martin Nilsson  report_debug("Restoring unique user ID information. (" + current_user_id_number + ")\n");
3235691998-03-26Per Hedbor #ifdef FD_DEBUG
c31f7b1998-10-10Henrik Grubbström (Grubba)  mark_fd(current_user_id_file->query_fd(), LOCALE->unique_uid_logfile());
3235691998-03-26Per Hedbor #endif
b1fca01996-11-12Per Hedbor }
f6d62d1997-03-26Per Hedbor 
b1fca01996-11-12Per Hedbor int increase_id() { if(!current_user_id_file) { restore_current_user_id_number(); return current_user_id_number+time(); } if(current_user_id_file->stat()[2] != current_user_id_file_last_mod) restore_current_user_id_number(); current_user_id_number++;
81f8af1999-12-20Martin Nilsson  //werror("New unique id: "+current_user_id_number+"\n");
b1fca01996-11-12Per Hedbor  current_user_id_file->seek(0); current_user_id_file->write((string)current_user_id_number); current_user_id_file_last_mod = current_user_id_file->stat()[2]; return current_user_id_number; } public string full_status() { int tmp; string res=""; array foo = ({0.0, 0.0, 0.0, 0.0, 0}); if(!sizeof(configurations))
c31f7b1998-10-10Henrik Grubbström (Grubba)  return LOCALE->no_servers_enabled();
81f8af1999-12-20Martin Nilsson 
5281751997-11-26Henrik Grubbström (Grubba)  foreach(configurations, object conf)
b1fca01996-11-12Per Hedbor  {
88e1cb1996-12-07David Hedbor  if(!conf->sent ||!conf->received ||!conf->hsent) continue;
48315a1999-11-23Per Hedbor  foo[0] += conf->sent/(1024.0*1024.0)/(float)(time(1)-start_time+1); foo[1] += conf->sent/(1024.0*1024.0); foo[2] += conf->hsent/(1024.0*1024.0); foo[3] += conf->received/(1024.0*1024.0);
5281751997-11-26Henrik Grubbström (Grubba)  foo[4] += conf->requests;
b1fca01996-11-12Per Hedbor  }
5281751997-11-26Henrik Grubbström (Grubba) 
b1fca01996-11-12Per Hedbor  for(tmp = 1; tmp < 4; tmp ++) {
c31f7b1998-10-10Henrik Grubbström (Grubba)  // FIXME: LOCALE?
81f8af1999-12-20Martin Nilsson  if(foo[tmp] < 1024.0)
27b0e11996-11-26Per Hedbor  foo[tmp] = sprintf("%.2f MB", foo[tmp]);
b1fca01996-11-12Per Hedbor  else
27b0e11996-11-26Per Hedbor  foo[tmp] = sprintf("%.2f GB", foo[tmp]/1024.0);
b1fca01996-11-12Per Hedbor  }
60ecef1998-06-13Henrik Grubbström (Grubba)  int uptime = time()-start_time; int days = uptime/(24*60*60); int hrs = uptime/(60*60); int min = uptime/60 - hrs*60; hrs -= days*24;
053e9a1998-08-20Per Hedbor  tmp=(int)((foo[4]*600.0)/(uptime+1));
b1fca01996-11-12Per Hedbor 
20b07e2000-02-02Per Hedbor  return(LOCALE->full_status(real_version, start_time,
c31f7b1998-10-10Henrik Grubbström (Grubba)  days, hrs, min, uptime%60, foo[1], foo[0] * 8192.0, foo[2], foo[4], (float)tmp/(float)10, foo[3]));
b1fca01996-11-12Per Hedbor }
ee8b201998-07-13David Hedbor static int abs_started;
6ca8f61998-10-13Per Hedbor 
81f8af1999-12-20Martin Nilsson void restart_if_stuck (int force)
6ca8f61998-10-13Per Hedbor {
ee8b201998-07-13David Hedbor  remove_call_out(restart_if_stuck); if (!(QUERY(abs_engage) || force))
edc9af1998-07-11David Hedbor  return;
81f8af1999-12-20Martin Nilsson  if(!abs_started)
6ca8f61998-10-13Per Hedbor  {
ee8b201998-07-13David Hedbor  abs_started = 1;
81f8af1999-12-20Martin Nilsson  report_debug("Anti-Block System Enabled.\n");
ee8b201998-07-13David Hedbor  } call_out (restart_if_stuck,10);
6ca8f61998-10-13Per Hedbor  signal(signum("SIGALRM"), lambda( int n ) {
81f8af1999-12-20Martin Nilsson  report_debug("**** %s: ABS engaged!\n" "Trying to dump backlog: \n", ctime(time()) - "\n");
b0659e1999-07-20Henrik Grubbström (Grubba)  catch { // Catch for paranoia reasons. describe_all_threads(); };
81f8af1999-12-20Martin Nilsson  report_debug("**** %s: ABS exiting roxen!\n\n", ctime(time()));
6ca8f61998-10-13Per Hedbor  _exit(1); // It might now quit correctly otherwise, if it's // locked up });
ee8b201998-07-13David Hedbor  alarm (60*QUERY(abs_timeout)+10);
edc9af1998-07-11David Hedbor }
52c0fa2000-03-01Per Hedbor // Settings used by the various configuration interface modules etc.
c5e0961999-10-04Per Hedbor class ConfigIFCache { string dir;
4f2d5f2000-03-13Per Hedbor  void create( string name, int|void settings )
c5e0961999-10-04Per Hedbor  {
4f2d5f2000-03-13Per Hedbor  if( settings ) dir = configuration_dir + "_configinterface/" + name + "/"; else dir = "../var/"+roxen_version()+"/config_caches/" + name + "/";
52c0fa2000-03-01Per Hedbor  mkdirhier( dir );
c5e0961999-10-04Per Hedbor  } mixed set( string name, mixed to ) {
4f2d5f2000-03-13Per Hedbor  Stdio.File f; if(!(f=open( dir + replace( name, "/", "-" ), "wct" )))
c5e0961999-10-04Per Hedbor  { mkdirhier( dir+"/foo" ); if(!f->open( dir + replace( name, "/", "-" ), "wct" )) { report_error("Failed to create configuration interface cache file ("+ dir + replace( name, "/", "-" )+") "+ strerror( errno() )+"\n"); return to; } }
ca594e2000-03-01Per Hedbor  f->write( #"<?XML version=\"1.0\" encoding=\"UTF-8\"?> " + string_to_utf8(encode_mixed( to, this_object() ) ));
c5e0961999-10-04Per Hedbor  return to; }
81f8af1999-12-20Martin Nilsson 
c5e0961999-10-04Per Hedbor  mixed get( string name ) {
4f2d5f2000-03-13Per Hedbor  Stdio.File f;
52c0fa2000-03-01Per Hedbor  mapping q = ([]);
4f2d5f2000-03-13Per Hedbor  f=open( dir + replace( name, "/", "-" ), "r" ); if(!f) return 0;
ca594e2000-03-01Per Hedbor  decode_variable( 0, ([ "name":"res" ]), utf8_to_string(f->read()), q );
52c0fa2000-03-01Per Hedbor  return q->res;
c5e0961999-10-04Per Hedbor  }
6b34861999-11-15Per Hedbor  array list() {
4f2d5f2000-03-13Per Hedbor  return r_get_dir( dir );
6b34861999-11-15Per Hedbor  }
c5e0961999-10-04Per Hedbor  void delete( string name ) {
4f2d5f2000-03-13Per Hedbor  r_rm( dir + replace( name, "/", "-" ) );
c5e0961999-10-04Per Hedbor  } }
753a831999-08-30Per Hedbor 
2ff8461999-09-02Per Hedbor class ImageCache { string name; string dir; function draw_function; mapping data_cache = ([]); // not normally used. mapping meta_cache = ([]);
0f8b2f1999-03-27Henrik Grubbström (Grubba) 
34d3fa1999-04-22Per Hedbor 
2ff8461999-09-02Per Hedbor  static mapping meta_cache_insert( string i, mapping what ) { return meta_cache[i] = what; }
81f8af1999-12-20Martin Nilsson 
2ff8461999-09-02Per Hedbor  static string data_cache_insert( string i, string what ) { return data_cache[i] = what; }
753a831999-08-30Per Hedbor 
2ff8461999-09-02Per Hedbor  static mixed frommapp( mapping what )
753a831999-08-30Per Hedbor  {
2ff8461999-09-02Per Hedbor  if( what[""] ) return what[""]; return what;
753a831999-08-30Per Hedbor  }
2ff8461999-09-02Per Hedbor  static void draw( string name, RequestID id ) { mixed args = Array.map( Array.map( name/"$", argcache->lookup, id->client ), frommapp); mapping meta; string data;
37ecea2000-02-21Per Hedbor 
2ff8461999-09-02Per Hedbor  mixed reply = draw_function( @copy_value(args), id );
b1fca01996-11-12Per Hedbor 
2ff8461999-09-02Per Hedbor  if( arrayp( args ) ) args = args[0];
b1fca01996-11-12Per Hedbor 
37ecea2000-02-21Per Hedbor  if( arrayp( reply ) ) // layers. reply = Image.lay( reply ); if( objectp( reply ) && reply->image ) // layer. { reply = ([ "img":reply->image(), "alpha":reply->alpha(), ]); }
b1fca01996-11-12Per Hedbor 
2ff8461999-09-02Per Hedbor  if( objectp( reply ) || (mappingp(reply) && reply->img) )
b1fca01996-11-12Per Hedbor  {
2ff8461999-09-02Per Hedbor  int quant = (int)args->quant; string format = lower_case(args->format || "gif"); string dither = args->dither; Image.Colortable ct;
e9d7c51999-11-02Per Hedbor  Image.Color.Color bgcolor;
2ff8461999-09-02Per Hedbor  object alpha;
81f8af1999-12-20Martin Nilsson  int true_alpha;
b1fca01996-11-12Per Hedbor 
2ff8461999-09-02Per Hedbor  if( args->fs || dither == "fs" ) dither = "floyd_steinberg";
b1fca01996-11-12Per Hedbor 
2ff8461999-09-02Per Hedbor  if( dither == "random" ) dither = "random_dither";
b1fca01996-11-12Per Hedbor 
81f8af1999-12-20Martin Nilsson  if( format == "jpg" )
2ff8461999-09-02Per Hedbor  format = "jpeg";
b1fca01996-11-12Per Hedbor 
112b1c2000-02-02Per Hedbor  if( dither ) dither = replace( dither, "-", "_" );
2ff8461999-09-02Per Hedbor  if(mappingp(reply)) { alpha = reply->alpha; reply = reply->img;
93ebdd1999-03-11Martin Stjernholm  }
81f8af1999-12-20Martin Nilsson 
2ff8461999-09-02Per Hedbor  if( args->gamma ) reply = reply->gamma( (float)args->gamma );
b79be21999-06-11Per Hedbor 
c3a53d1999-06-25Per Hedbor  if( args["true-alpha"] ) true_alpha = 1;
e7e6031999-11-05Per Hedbor  if( args["background"] || args["background-color"]) bgcolor = Image.Color( (args["background"]||args["background-color"]) );
e9d7c51999-11-02Per Hedbor 
b79be21999-06-11Per Hedbor  if( args["opaque-value"] ) {
c3a53d1999-06-25Per Hedbor  true_alpha = 1;
b79be21999-06-11Per Hedbor  int ov = (int)(((float)args["opaque-value"])*2.55); if( ov < 0 ) ov = 0; else if( ov > 255 ) ov = 255; if( alpha ) {
2537c32000-02-14Per Hedbor  Image.Image i = Image.Image( reply->xsize(), reply->ysize(), ov,ov,ov );
e9d7c51999-11-02Per Hedbor  i = i->paste_alpha( alpha, ov );
b79be21999-06-11Per Hedbor  alpha = i; } else {
2537c32000-02-14Per Hedbor  alpha = Image.Image( reply->xsize(), reply->ysize(), ov,ov,ov );
b79be21999-06-11Per Hedbor  } }
c526921999-05-18Per Hedbor 
3cbd0d2000-01-31Per Hedbor  int x0, y0, x1, y1; if( args["x-offset"] || args["xoffset"] ) x0 = (int)(args["x-offset"]||args["xoffset"]); if( args["y-offset"] || args["yoffset"] ) y0 = (int)(args["y-offset"]||args["yoffset"]); if( args["width"] || args["x-size"] ); x1 = (int)(args["x-size"]||args["width"]); if( args["height"] || args["y-size"] ); y1 = (int)(args["y-size"]||args["height"]); if( args->crop ) { sscanf( args->crop, "%d,%d-%d,%d", x0, y0, x1, y1 ); x1 -= x0; y1 -= y0; } if( x0 || x1 || y0 || y1 ) { if( !x1 ) x1 = reply->xsize()-x0; if( !y1 ) y1 = reply->ysize()-y0; reply = reply->copy( x0,y0,x1-1,y1-1 ); if( alpha ) alpha = alpha->copy( x0,y0,x1-1,y1-1 ); }
c526921999-05-18Per Hedbor  if( args->scale ) { int x, y; if( sscanf( args->scale, "%d,%d", x, y ) == 2) { reply = reply->scale( x, y ); if( alpha ) alpha = alpha->scale( x, y ); }
3255b11999-05-19Per Hedbor  else if( (float)args->scale < 3.0)
c526921999-05-18Per Hedbor  {
3255b11999-05-19Per Hedbor  reply = reply->scale( ((float)args->scale) );
c526921999-05-18Per Hedbor  if( alpha )
3255b11999-05-19Per Hedbor  alpha = alpha->scale( ((float)args->scale) );
c526921999-05-18Per Hedbor  } }
81f8af1999-12-20Martin Nilsson  if( args->maxwidth || args->maxheight ||
e7e6031999-11-05Per Hedbor  args["max-width"] || args["max-height"])
c526921999-05-18Per Hedbor  {
e7e6031999-11-05Per Hedbor  int x = (int)args->maxwidth||(int)args["max-width"]; int y = (int)args->maxheight||(int)args["max-height"];
c526921999-05-18Per Hedbor  if( x && reply->xsize() > x ) { reply = reply->scale( x, 0 ); if( alpha ) alpha = alpha->scale( x, 0 ); } if( y && reply->ysize() > y ) { reply = reply->scale( 0, y ); if( alpha ) alpha = alpha->scale( 0, y ); } }
112b1c2000-02-02Per Hedbor  if( args["rotate-cw"] || args["rotate-ccw"]) { float degree = (float)(args["rotate-cw"] || args["rotate-ccw"]); switch( args["rotate-unit"] ) { case "r": degree = (degree / 2*3.1415) * 360; break; case "d": break; case "n": degree = (degree / 400) * 360; break; } if( args["rotate-ccw"] ) degree = -degree; if( alpha ) { reply = reply->rotate_expand( degree ); alpha = alpha->rotate( degree, 0,0,0 ); } else reply = reply->rotate( degree )->autocrop(); } if( args["mirror-x"] ) { if( alpha ) alpha = alpha->mirrorx(); reply = reply->mirrorx(); } if( args["mirror-y"] ) { if( alpha ) alpha = alpha->mirrory(); reply = reply->mirrory(); } if( args["cs-rgb-hsv"] )reply = reply->rgb_to_hsv(); if( args["cs-grey"] ) reply = reply->grey(); if( args["cs-invert"] ) reply = reply->invert(); if( args["cs-hsv-rgb"] )reply = reply->hsv_to_rgb();
e7e6031999-11-05Per Hedbor  if( bgcolor && alpha ) { reply = Image.Image( reply->xsize(), reply->ysize(), bgcolor ) ->paste_mask( reply, alpha ); }
69a8691999-05-18Per Hedbor  if( quant || (format=="gif") ) {
e9d7c51999-11-02Per Hedbor  int ncols = quant||id->misc->defquant||32;
7ed2ef1999-05-25Peter Bortas  if( ncols > 250 )
000c781999-05-25Per Hedbor  ncols = 250; ct = Image.Colortable( reply, ncols );
69a8691999-05-18Per Hedbor  if( dither )
000c781999-05-25Per Hedbor  if( ct[ dither ] ) ct[ dither ]();
69a8691999-05-18Per Hedbor  else ct->ordered(); }
81f8af1999-12-20Martin Nilsson  if(!Image[upper_case( format )]
3760171999-06-27Per Hedbor  || !Image[upper_case( format )]->encode )
69a8691999-05-18Per Hedbor  error("Image format "+format+" unknown\n"); mapping enc_args = ([]); if( ct ) enc_args->colortable = ct; if( alpha ) enc_args->alpha = alpha;
c526921999-05-18Per Hedbor  foreach( glob( "*-*", indices(args)), string n ) if(sscanf(n, "%*[^-]-%s", string opt ) == 2) enc_args[opt] = (int)args[n];
69a8691999-05-18Per Hedbor  switch(format) { case "gif":
c3a53d1999-06-25Per Hedbor  if( alpha && true_alpha )
b79be21999-06-11Per Hedbor  {
81f8af1999-12-20Martin Nilsson  Image.Colortable bw=Image.Colortable( ({ ({ 0,0,0 }), ({ 255,255,255 }) }) );
e9d7c51999-11-02Per Hedbor  bw->floyd_steinberg(); alpha = bw->map( alpha );
b79be21999-06-11Per Hedbor  }
000c781999-05-25Per Hedbor  if( catch { if( alpha ) data = Image.GIF.encode_trans( reply, ct, alpha ); else data = Image.GIF.encode( reply, ct ); }) data = Image.GIF.encode( reply ); break;
e9d7c51999-11-02Per Hedbor 
69a8691999-05-18Per Hedbor  case "png":
e9d7c51999-11-02Per Hedbor  if( ct ) enc_args->palette = ct;
69a8691999-05-18Per Hedbor  m_delete( enc_args, "colortable" );
e9d7c51999-11-02Per Hedbor  if( !enc_args->alpha ) m_delete( enc_args, "alpha" );
81f8af1999-12-20Martin Nilsson 
69a8691999-05-18Per Hedbor  default: data = Image[upper_case( format )]->encode( reply, enc_args ); }
81f8af1999-12-20Martin Nilsson  meta = ([
69a8691999-05-18Per Hedbor  "xsize":reply->xsize(), "ysize":reply->ysize(), "type":"image/"+format, ]);
c526921999-05-18Per Hedbor  }
81f8af1999-12-20Martin Nilsson  else if( mappingp(reply) )
69a8691999-05-18Per Hedbor  { meta = reply->meta; data = reply->data; if( !meta || !data ) error("Invalid reply mapping.\n" "Should be ([ \"meta\": ([metadata]), \"data\":\"data\" ])\n"); } store_meta( name, meta ); store_data( name, data ); } static void store_meta( string id, mapping meta ) { meta_cache_insert( id, meta ); string data = encode_value( meta );
4f2d5f2000-03-13Per Hedbor  Stdio.File f; if(!(f=open(dir+id+".i", "wct" )))
69a8691999-05-18Per Hedbor  { report_error( "Failed to open image cache persistant cache file "+ dir+id+".i: "+strerror( errno() )+ "\n" ); return; } f->write( data ); } static void store_data( string id, string data ) {
4f2d5f2000-03-13Per Hedbor  Stdio.File f; if(!(f = open(dir+id+".d", "wct" )))
69a8691999-05-18Per Hedbor  { data_cache_insert( id, data ); report_error( "Failed to open image cache persistant cache file "+
3760171999-06-27Per Hedbor  dir+id+".d: "+strerror( errno() )+ "\n" );
69a8691999-05-18Per Hedbor  return; } f->write( data ); } static mapping restore_meta( string id ) { Stdio.File f; if( meta_cache[ id ] ) return meta_cache[ id ];
4f2d5f2000-03-13Per Hedbor  if( !(f=open(dir+id+".i", "r" ) ) )
69a8691999-05-18Per Hedbor  return 0; return meta_cache_insert( id, decode_value( f->read() ) ); }
4f2d5f2000-03-13Per Hedbor  void flush(int|void age) {
1f58d02000-01-02Martin Nilsson  report_debug("Flushing "+name+" image cache.\n");
4f2d5f2000-03-13Per Hedbor  foreach(r_get_dir(dir), string f) if(f[-2]=='.' && (f[-1]=='i' || f[-1]=='d') && (!age || age>r_file_stat(dir+f)[2])) r_rm(dir+f);
1f58d02000-01-02Martin Nilsson  } array status(int|void age) { int files=0, size=0, aged=0; array stat;
4f2d5f2000-03-13Per Hedbor  foreach(r_get_dir(dir), string f)
1f58d02000-01-02Martin Nilsson  if(f[-2]=='.' && (f[-1]=='i' || f[-1]=='d')) { files++;
4f2d5f2000-03-13Per Hedbor  stat=r_file_stat(dir+f,1);
1f58d02000-01-02Martin Nilsson  if(stat[1]>0) size+=stat[1]; if(age<stat[2]) aged++; } return ({files, size, aged}); }
69a8691999-05-18Per Hedbor  static mapping restore( string id ) {
37ecea2000-02-21Per Hedbor  mixed f;
69a8691999-05-18Per Hedbor  mapping m;
37ecea2000-02-21Per Hedbor 
69a8691999-05-18Per Hedbor  if( data_cache[ id ] ) f = data_cache[ id ];
81f8af1999-12-20Martin Nilsson  else
4f2d5f2000-03-13Per Hedbor  if(!(f = open( dir+id+".d", "r" )))
37ecea2000-02-21Per Hedbor  return 0;
69a8691999-05-18Per Hedbor  m = restore_meta( id );
81f8af1999-12-20Martin Nilsson 
69a8691999-05-18Per Hedbor  if(!m) return 0; if( stringp( f ) )
0fe69d2000-03-19Martin Nilsson  return Roxen.http_string_answer( f, m->type||("image/gif") ); return Roxen.http_file_answer( f, m->type||("image/gif") );
69a8691999-05-18Per Hedbor  } string data( string|mapping args, RequestID id, int|void nodraw ) { string na = store( args, id ); mixed res; if(!( res = restore( na )) ) { if(nodraw) return 0; draw( na, id ); res = restore( na ); } if( res->file ) return res->file->read(); return res->data; }
81f8af1999-12-20Martin Nilsson  mapping http_file_answer( string|mapping data, RequestID id,
c3a53d1999-06-25Per Hedbor  int|void nodraw )
69a8691999-05-18Per Hedbor  { string na = store( data,id ); mixed res; if(!( res = restore( na )) ) { if(nodraw) return 0; draw( na, id ); res = restore( na ); } return res; }
2ff8461999-09-02Per Hedbor  mapping metadata( string|mapping data, RequestID id, int|void nodraw ) { string na = store( data,id ); if(!restore_meta( na )) { if(nodraw) return 0; draw( na, id ); return restore_meta( na ); } return restore_meta( na ); } mapping tomapp( mixed what ) { if( mappingp( what )) return what; return ([ "":what ]); } string store( array|string|mapping data, RequestID id ) { string ci; if( mappingp( data ) ) ci = argcache->store( data ); else if( arrayp( data ) ) ci = Array.map( Array.map( data, tomapp ), argcache->store )*"$"; else ci = data; return ci; } void set_draw_function( function to ) { draw_function = to; } void create( string id, function draw_func, string|void d ) {
3590742000-03-08Martin Nilsson  if(!d) d = roxenp()->query("argument_cache_dir");
2ff8461999-09-02Per Hedbor  if( d[-1] != '/' ) d+="/"; d += id+"/"; mkdirhier( d+"foo"); dir = d; name = id; draw_function = draw_func; } } class ArgCache { static string name; static string path; static int is_db;
43665d1999-12-19Martin Nilsson  static Sql.sql db;
2ff8461999-09-02Per Hedbor  #define CACHE_VALUE 0 #define CACHE_SKEY 1 #define CACHE_SIZE 600 #define CLEAN_SIZE 100 #ifdef THREADS static Thread.Mutex mutex = Thread.Mutex(); # define LOCK() object __key = mutex->lock() #else
81f8af1999-12-20Martin Nilsson # define LOCK()
2ff8461999-09-02Per Hedbor #endif static mapping (string:mixed) cache = ([ ]);
b870ac1999-09-03Henrik Grubbström (Grubba)  static void setup_table()
2ff8461999-09-02Per Hedbor  { if(catch(db->query("select id from "+name+" where id=-1"))) if(catch(db->query("create table "+name+" (" "id int auto_increment primary key, " "lkey varchar(80) not null default '', " "contents blob not null default '', " "atime bigint not null default 0)"))) throw("Failed to create table in database\n"); }
81f8af1999-12-20Martin Nilsson  void create( string _name, string _path,
2ff8461999-09-02Per Hedbor  int _is_db ) { name = _name; path = _path; is_db = _is_db; if(is_db) { db = Sql.sql( path ); if(!db) error("Failed to connect to database for argument cache\n"); setup_table( ); } else { if(path[-1] != '/' && path[-1] != '\\') path += "/"; path += replace(name, "/", "_")+"/"; mkdirhier( path + "/tmp" );
4f2d5f2000-03-13Per Hedbor  Stdio.File test; if (!(test = open (path + "/.testfile", "wc"))) error ("Can't create files in the argument cache directory " + path + #if constant(strerror) " ("+strerror(errno())+ #endif "\n"); // else // { // rm (path + "/.testfile"); // It is better not to remove it, // this way permission problems are detected rather early. // }
2ff8461999-09-02Per Hedbor  } } static string read_args( string id ) { if( is_db ) {
43665d1999-12-19Martin Nilsson  array res = db->query("select contents from "+name+" where id='"+id+"'");
2ff8461999-09-02Per Hedbor  if( sizeof(res) ) {
4f2d5f2000-03-13Per Hedbor  db->query("update "+name+" set atime='"+time()+"' where id='"+id+"'");
2ff8461999-09-02Per Hedbor  return res[0]->contents; } return 0; } else {
4f2d5f2000-03-13Per Hedbor  Stdio.File f; if( search( id, "/" )<0 && (f = open(path+"/"+id, "r"))) return f->read();
2ff8461999-09-02Per Hedbor  } return 0; } static string create_key( string long_key ) { if( is_db ) {
43665d1999-12-19Martin Nilsson  array data = db->query(sprintf("select id,contents from %s where lkey='%s'",
2ff8461999-09-02Per Hedbor  name,long_key[..79])); foreach( data, mapping m ) if( m->contents == long_key ) return m->id; db->query( sprintf("insert into %s (contents,lkey,atime) values "
81f8af1999-12-20Martin Nilsson  "('%s','%s','%d')",
2ff8461999-09-02Per Hedbor  name, long_key, long_key[..79], time() )); return create_key( long_key ); } else { string _key=MIME.encode_base64(Crypto.md5()->update(long_key)->digest(),1); _key = replace(_key-"=","/","="); string short_key = _key[0..1];
4f2d5f2000-03-13Per Hedbor  Stdio.File f; while( f = open( path+short_key, "r" ) )
2ff8461999-09-02Per Hedbor  {
4f2d5f2000-03-13Per Hedbor  if( f->read() == long_key )
2ff8461999-09-02Per Hedbor  return short_key; short_key = _key[..strlen(short_key)]; if( strlen(short_key) >= strlen(_key) ) short_key += "."; // Not very likely... }
4f2d5f2000-03-13Per Hedbor  f = open( path+short_key, "wct" );
2ff8461999-09-02Per Hedbor  f->write( long_key ); return short_key; } } int key_exists( string key ) { LOCK();
4f2d5f2000-03-13Per Hedbor  if( !is_db ) return !!open( path+key, "r" );
2ff8461999-09-02Per Hedbor  return !!read_args( key ); } string store( mapping args )
69a8691999-05-18Per Hedbor  {
2ff8461999-09-02Per Hedbor  LOCK(); array b = values(args), a = sort(indices(args),b); string data = MIME.encode_base64(encode_value(({a,b})),1); if( cache[ data ] ) return cache[ data ][ CACHE_SKEY ];
8693b22000-01-08Martin Stjernholm  if( sizeof( cache ) >= CACHE_SIZE ) { array i = indices(cache); while( sizeof(cache) > CACHE_SIZE-CLEAN_SIZE ) { string idx=i[random(sizeof(i))]; if(arrayp(cache[idx])) { m_delete( cache, cache[idx][CACHE_SKEY] ); m_delete( cache, idx ); } else { m_delete( cache, cache[idx] ); m_delete( cache, idx ); } } }
2ff8461999-09-02Per Hedbor  string id = create_key( data ); cache[ data ] = ({ 0, 0 }); cache[ data ][ CACHE_VALUE ] = copy_value( args ); cache[ data ][ CACHE_SKEY ] = id; cache[ id ] = data; return id;
69a8691999-05-18Per Hedbor  }
56b7fc1999-12-21Per Hedbor  mapping lookup( string id, array|void client )
c3a53d1999-06-25Per Hedbor  {
2ff8461999-09-02Per Hedbor  LOCK();
c5e0961999-10-04Per Hedbor  if(cache[id] && cache[ cache[id] ] )
2ff8461999-09-02Per Hedbor  return cache[cache[id]][CACHE_VALUE]; string q = read_args( id );
bfb4d41999-12-28Martin Nilsson  if(!q)
56b7fc1999-12-21Per Hedbor  if( client ) error("Key does not exist! (Thinks "+ (client*"") +")\n"); else error("Requesting unknown key\n");
2ff8461999-09-02Per Hedbor  mixed data = decode_value(MIME.decode_base64( q )); data = mkmapping( data[0],data[1] ); cache[ q ] = ({0,0}); cache[ q ][ CACHE_VALUE ] = data; cache[ q ][ CACHE_SKEY ] = id; cache[ id ] = q; return data;
c3a53d1999-06-25Per Hedbor  }
2ff8461999-09-02Per Hedbor  void delete( string id )
69a8691999-05-18Per Hedbor  {
2ff8461999-09-02Per Hedbor  LOCK(); if(cache[id]) { m_delete( cache, cache[id] ); m_delete( cache, id ); } if( is_db ) db->query( "delete from "+name+" where id='"+id+"'" );
69a8691999-05-18Per Hedbor  else
4f2d5f2000-03-13Per Hedbor  r_rm( path+id );
69a8691999-05-18Per Hedbor  }
2ff8461999-09-02Per Hedbor }
69a8691999-05-18Per Hedbor 
95b69e1999-09-05Per Hedbor mapping cached_decoders = ([]); string decode_charset( string charset, string data ) {
808e171999-09-05Henrik Grubbström (Grubba)  // FIXME: This code is probably not thread-safe!
95b69e1999-09-05Per Hedbor  if( charset == "iso-8859-1" ) return data; if( !cached_decoders[ charset ] ) cached_decoders[ charset ] = Locale.Charset.decoder( charset ); data = cached_decoders[ charset ]->feed( data )->drain();
dc3a471999-12-15Marcus Comstedt  cached_decoders[ charset ]->clear();
95b69e1999-09-05Per Hedbor  return data; }
2ff8461999-09-02Per Hedbor void create() {
2537c32000-02-14Per Hedbor  SET_LOCALE(default_locale);
cde8d62000-02-16Per Hedbor 
2ff8461999-09-02Per Hedbor  // Dump some programs (for speed)
a40c152000-02-16Per Hedbor  dump( "etc/roxen_master.pike" );
cde8d62000-02-16Per Hedbor  dump( "etc/modules/Dims.pmod" );
27008b2000-03-20Martin Stjernholm  dump( "etc/modules/RXML.pmod/module.pmod" ); foreach( glob("*.p???",get_dir( "etc/modules/RXML.pmod/")), string q ) if( q != "PXml.pike" ) dump( "etc/modules/RXML.pmod/"+ q ); dump( "etc/modules/Roxen.pmod" ); // This is currently needed to resolve the circular references in // RXML.pmod correctly. :P master()->resolv ("RXML.refs");
cde8d62000-02-16Per Hedbor  dump( "base_server/disk_cache.pike" );
2537c32000-02-14Per Hedbor  foreach( glob("*.pmod",get_dir( "etc/modules/RoxenLocale.pmod/")), string q )
4cf7832000-02-16Per Hedbor  if( q != "Modules.pmod" ) dump( "etc/modules/RoxenLocale.pmod/"+ q );
2537c32000-02-14Per Hedbor  dump( "base_server/roxen.pike" );
7e596b2000-02-13Per Hedbor  dump( "base_server/roxenlib.pike" );
6f72d42000-02-08Per Hedbor  dump( "base_server/basic_defvar.pike" );
2ff8461999-09-02Per Hedbor  dump( "base_server/newdecode.pike" ); dump( "base_server/read_config.pike" ); dump( "base_server/global_variables.pike" ); dump( "base_server/module_support.pike" ); dump( "base_server/http.pike" ); dump( "base_server/socket.pike" ); dump( "base_server/cache.pike" ); dump( "base_server/supports.pike" ); dump( "base_server/hosts.pike"); dump( "base_server/language.pike");
76c94e2000-01-05Martin Stjernholm  dump( "base_server/configuration.pike" );
69a8691999-05-18Per Hedbor 
95b69e1999-09-05Per Hedbor #ifndef __NT__
640cc41999-11-29Per Hedbor  if(!getuid())
95b69e1999-09-05Per Hedbor  add_constant("Privs", Privs);
640cc41999-11-29Per Hedbor  else
95b69e1999-09-05Per Hedbor #endif /* !__NT__ */
eb6ce92000-01-03Martin Stjernholm  add_constant("Privs", class { void create(string reason, int|string|void uid, int|string|void gid) {} });
69a8691999-05-18Per Hedbor 
855c391999-11-29Per Hedbor 
2ff8461999-09-02Per Hedbor  // for module encoding stuff
d3b98e1999-11-28Per Hedbor 
95b69e1999-09-05Per Hedbor  add_constant( "ArgCache", ArgCache );
27008b2000-03-20Martin Stjernholm  //add_constant( "roxen.load_image", load_image );
2ff8461999-09-02Per Hedbor 
95b69e1999-09-05Per Hedbor  add_constant( "roxen", this_object());
27008b2000-03-20Martin Stjernholm  //add_constant( "roxen.decode_charset", decode_charset);
855c391999-11-29Per Hedbor 
95b69e1999-09-05Per Hedbor  add_constant( "RequestID", RequestID);
855c391999-11-29Per Hedbor  add_constant( "RoxenModule", RoxenModule);
67c7491999-12-27Martin Stjernholm  add_constant( "ModuleInfo", ModuleInfo );
855c391999-11-29Per Hedbor 
95b69e1999-09-05Per Hedbor  add_constant( "load", load); add_constant( "Roxen.set_locale", set_locale );
2537c32000-02-14Per Hedbor  add_constant( "roxen.locale", locale );
27008b2000-03-20Martin Stjernholm  //add_constant( "roxen.ImageCache", ImageCache );
2537c32000-02-14Per Hedbor 
2ff8461999-09-02Per Hedbor  // compatibility
a40c152000-02-16Per Hedbor // int s = gethrtime();
cde8d62000-02-16Per Hedbor  add_constant( "roxen.fonts", (fonts = ((program)"base_server/fonts.pike")()) );
a40c152000-02-16Per Hedbor // report_debug( "[fonts: %.2fms] ", (gethrtime()-s)/1000.0);
cde8d62000-02-16Per Hedbor  dump( "base_server/fonts.pike" );
855c391999-11-29Per Hedbor 
a40c152000-02-16Per Hedbor // int s = gethrtime();
7e596b2000-02-13Per Hedbor  Configuration = (program)"configuration"; dump( "base_server/configuration.pike" ); dump( "base_server/rxmlhelp.pike" ); add_constant( "Configuration", Configuration );
a40c152000-02-16Per Hedbor // report_debug( "[Configuration: %.2fms] ", (gethrtime()-s)/1000.0);
69a8691999-05-18Per Hedbor }
2ff8461999-09-02Per Hedbor // Set the uid and gid to the ones requested by the user. If the sete* // functions are available, and the define SET_EFFECTIVE is enabled, // the euid and egid is set. This might be a minor security hole, but // it will enable roxen to start CGI scripts with the correct // permissions (the ones the owner of that script have).
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor int set_u_and_gid() { #ifndef __NT__ string u, g; int uid, gid; array pw;
81f8af1999-12-20Martin Nilsson 
2ff8461999-09-02Per Hedbor  u=QUERY(User); sscanf(u, "%s:%s", u, g); if(strlen(u)) { if(getuid()) { report_error ("It is only possible to change uid and gid if the server " "is running as root.\n"); } else { if (g) { #if constant(getgrnam) pw = getgrnam (g); if (!pw) if (sscanf (g, "%d", gid)) pw = getgrgid (gid), g = (string) gid; else report_error ("Couldn't resolve group " + g + ".\n"), g = 0; if (pw) g = pw[0], gid = pw[2];
a22f6f1999-05-12Per Hedbor #else
2ff8461999-09-02Per Hedbor  if (!sscanf (g, "%d", gid)) report_warning ("Can't resolve " + g + " to gid on this system; " "numeric gid required.\n");
a22f6f1999-05-12Per Hedbor #endif
2ff8461999-09-02Per Hedbor  }
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor  pw = getpwnam (u); if (!pw) if (sscanf (u, "%d", uid)) pw = getpwuid (uid), u = (string) uid; else { report_error ("Couldn't resolve user " + u + ".\n"); return 0; } if (pw) { u = pw[0], uid = pw[2]; if (!g) gid = pw[3]; }
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor #ifdef THREADS object mutex_key; catch { mutex_key = euid_egid_lock->lock(); }; object threads_disabled = _disable_threads(); #endif
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor #if constant(seteuid) if (geteuid() != getuid()) seteuid (getuid()); #endif
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor #if constant(initgroups) catch { initgroups(pw[0], gid); // Doesn't always work - David. }; #endif if (QUERY(permanent_uid)) { #if constant(setuid) if (g) { # if constant(setgid) setgid(gid); if (getgid() != gid) report_error ("Failed to set gid.\n"), g = 0; # else report_warning ("Setting gid not supported on this system.\n"); g = 0; # endif } setuid(uid); if (getuid() != uid) report_error ("Failed to set uid.\n"), u = 0; if (u) report_notice(LOCALE->setting_uid_gid_permanently (uid, gid, u, g)); #else report_warning ("Setting uid not supported on this system.\n"); u = g = 0; #endif }
b84a161999-06-07Martin Stjernholm  else {
2ff8461999-09-02Per Hedbor #if constant(seteuid) if (g) { # if constant(setegid) setegid(gid); if (getegid() != gid) report_error ("Failed to set effective gid.\n"), g = 0; # else report_warning ("Setting effective gid not supported on this system.\n"); g = 0; # endif } seteuid(uid); if (geteuid() != uid) report_error ("Failed to set effective uid.\n"), u = 0; if (u) report_notice(LOCALE->setting_uid_gid (uid, gid, u, g)); #else report_warning ("Setting effective uid not supported on this system.\n"); u = g = 0; #endif
b84a161999-06-07Martin Stjernholm  }
2ff8461999-09-02Per Hedbor  return !!u;
a22f6f1999-05-12Per Hedbor  } }
2ff8461999-09-02Per Hedbor #endif return 0; }
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor void reload_all_configurations() { object conf; array (object) new_confs = ({}); mapping config_cache = ([]); int modified; configs = ([]); setvars(retrieve("Variables", 0)); foreach(list_all_configurations(), string config)
a22f6f1999-05-12Per Hedbor  {
2ff8461999-09-02Per Hedbor  array err, st;
4cf7832000-02-16Per Hedbor  conf = find_configuration( config );
2ff8461999-09-02Per Hedbor  if(!(st = config_is_modified(config))) { if(conf) { config_cache[config] = config_stat_cache[config]; new_confs += ({ conf });
a22f6f1999-05-12Per Hedbor  }
2ff8461999-09-02Per Hedbor  continue;
a22f6f1999-05-12Per Hedbor  }
2ff8461999-09-02Per Hedbor  modified = 1; config_cache[config] = st;
4cf7832000-02-16Per Hedbor  if(conf) {
2ff8461999-09-02Per Hedbor  conf->stop(); conf->invalidate_cache(); conf->create(conf->name);
a22f6f1999-05-12Per Hedbor  } else {
2ff8461999-09-02Per Hedbor  if(err = catch
a22f6f1999-05-12Per Hedbor  {
2ff8461999-09-02Per Hedbor  conf = enable_configuration(config); }) { report_error(LOCALE-> error_enabling_configuration(config, describe_backtrace(err))); continue;
a22f6f1999-05-12Per Hedbor  } }
2ff8461999-09-02Per Hedbor  if(err = catch { conf->start(); conf->enable_all_modules(); }) { report_error(LOCALE-> error_enabling_configuration(config, describe_backtrace(err))); continue; } new_confs += ({ conf });
a22f6f1999-05-12Per Hedbor  }
81f8af1999-12-20Martin Nilsson 
2ff8461999-09-02Per Hedbor  foreach(configurations - new_confs, conf)
a22f6f1999-05-12Per Hedbor  {
2ff8461999-09-02Per Hedbor  modified = 1; report_notice(LOCALE->disabling_configuration(conf->name));
acf0fa2000-02-29David Hedbor  // Array.map(values(conf->server_ports), lambda(object o) { destruct(o); });
2ff8461999-09-02Per Hedbor  conf->stop(); destruct(conf); } if(modified) { configurations = new_confs; config_stat_cache = config_cache;
a22f6f1999-05-12Per Hedbor  }
2ff8461999-09-02Per Hedbor }
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor object enable_configuration(string name) {
15635b1999-10-10Per Hedbor  object cf = Configuration( name );
2ff8461999-09-02Per Hedbor  configurations += ({ cf }); return cf; }
a22f6f1999-05-12Per Hedbor 
2ff8461999-09-02Per Hedbor // Enable all configurations void enable_configurations() { array err; configurations = ({});
15635b1999-10-10Per Hedbor 
2ff8461999-09-02Per Hedbor  foreach(list_all_configurations(), string config)
1d7d6d2000-02-16Per Hedbor  { int t = gethrtime(); report_debug("\nEnabling the configuration "+config+" ...\n");
15635b1999-10-10Per Hedbor  if(err=catch( enable_configuration(config)->start() ))
1d7d6d2000-02-16Per Hedbor  report_error("\nError while loading configuration "+config+":\n"+
15635b1999-10-10Per Hedbor  describe_backtrace(err)+"\n");
1d7d6d2000-02-16Per Hedbor  report_debug("Enabled "+config+" in %.1fms\n", (gethrtime()-t)/1000.0 ); }
2ff8461999-09-02Per Hedbor }
a22f6f1999-05-12Per Hedbor 
1d7d6d2000-02-16Per Hedbor int all_modules_loaded;
2ff8461999-09-02Per Hedbor void enable_configurations_modules() {
4cf7832000-02-16Per Hedbor  if( all_modules_loaded++ ) return;
2ff8461999-09-02Per Hedbor  foreach(configurations, object config)
4cf7832000-02-16Per Hedbor  if(mixed err=catch( config->enable_all_modules() ))
15635b1999-10-10Per Hedbor  report_error("Error while loading modules in configuration "+ config->name+":\n"+describe_backtrace(err)+"\n");
a22f6f1999-05-12Per Hedbor }
d681842000-02-08Per Hedbor mapping low_decode_image(string data, void|mixed tocolor)
a22f6f1999-05-12Per Hedbor {
56b7fc1999-12-21Per Hedbor  return Image._decode( data, tocolor );
a22f6f1999-05-12Per Hedbor }
d681842000-02-08Per Hedbor array(Image.Layer) decode_layers(string data, void|mixed tocolor) { return Image.decode_layers( data, tocolor ); }
81f8af1999-12-20Martin Nilsson mapping low_load_image(string f, RequestID id)
a22f6f1999-05-12Per Hedbor { string data;
81f8af1999-12-20Martin Nilsson  Stdio.File file; if(id->misc->_load_image_called < 5)
69a8691999-05-18Per Hedbor  {
3ffe061999-05-16David Hedbor  // We were recursing very badly with the demo module here... id->misc->_load_image_called++;
c526921999-05-18Per Hedbor  if(!(data=id->conf->try_get_file(f, id))) {
3ffe061999-05-16David Hedbor  file=Stdio.File();
c526921999-05-18Per Hedbor  if(!file->open(f,"r") || !(data=file->read()))
56b7fc1999-12-21Per Hedbor  catch { data = Protocols.HTTP.get_url_nice( f )[1]; }; if( !data )
3ffe061999-05-16David Hedbor  return 0; } } id->misc->_load_image_called = 0;
56b7fc1999-12-21Per Hedbor  if(!data) return 0;
a22f6f1999-05-12Per Hedbor  return low_decode_image( data ); }
d681842000-02-08Per Hedbor array(Image.Layer) load_layers(string f, RequestID id) { string data; Stdio.File file; if(id->misc->_load_image_called < 5) { // We were recursing very badly with the demo module here... id->misc->_load_image_called++; if(!(data=id->conf->try_get_file(f, id))) { file=Stdio.File(); if(!file->open(f,"r") || !(data=file->read())) catch { data = Protocols.HTTP.get_url_nice( f )[1]; }; if( !data ) return 0; } } id->misc->_load_image_called = 0; if(!data) return 0; return decode_layers( data ); }
a22f6f1999-05-12Per Hedbor 
2537c32000-02-14Per Hedbor Image.Image load_image(string f, RequestID id)
a22f6f1999-05-12Per Hedbor { mapping q = low_load_image( f, id ); if( q ) return q->img; return 0; }
b1fca01996-11-12Per Hedbor // do the chroot() call. This is not currently recommended, since // roxen dynamically loads modules, all module files must be // available at the new location. private void fix_root(string to) {
c79b261998-02-05Johan Schön #ifndef __NT__
b1fca01996-11-12Per Hedbor  if(getuid()) {
81f8af1999-12-20Martin Nilsson  report_debug("It is impossible to chroot() if the server is not run as root.\n");
b1fca01996-11-12Per Hedbor  return; } if(!chroot(to)) {
81f8af1999-12-20Martin Nilsson  report_debug("Roxen: Cannot chroot to "+to+": ");
b1fca01996-11-12Per Hedbor #if efun(real_perror) real_perror(); #endif return; }
81f8af1999-12-20Martin Nilsson  report_debug("Root is now "+to+".\n");
c79b261998-02-05Johan Schön #endif
b1fca01996-11-12Per Hedbor } void create_pid_file(string where) {
c79b261998-02-05Johan Schön #ifndef __NT__
b1fca01996-11-12Per Hedbor  if(!where) return;
81f8af1999-12-20Martin Nilsson  where = replace(where, ({ "$pid", "$uid" }),
b1fca01996-11-12Per Hedbor  ({ (string)getpid(), (string)getuid() }));
4f2d5f2000-03-13Per Hedbor  r_rm(where);
5e89211997-02-13Per Hedbor  if(catch(Stdio.write_file(where, sprintf("%d\n%d", getpid(), getppid()))))
81f8af1999-12-20Martin Nilsson  report_debug("I cannot create the pid file ("+where+").\n");
c79b261998-02-05Johan Schön #endif
b1fca01996-11-12Per Hedbor }
95b69e1999-09-05Per Hedbor program pipe;
ccffe71999-03-05Wilhelm Köhler object shuffle(object from, object to, object|void to2, function(:void)|void callback)
14179b1997-01-29Per Hedbor {
beaca01998-02-20Per Hedbor #if efun(spider.shuffle) if(!to2)
5bc1991997-01-29Per Hedbor  {
95b69e1999-09-05Per Hedbor  if(!pipe) pipe = ((program)"smartpipe"); object p = pipe( );
beaca01998-02-20Per Hedbor  p->input(from);
95e2b41997-05-25Wilhelm Köhler  p->set_done_callback(callback);
beaca01998-02-20Per Hedbor  p->output(to);
ccffe71999-03-05Wilhelm Köhler  return p;
a60c4c1997-07-03Henrik Grubbström (Grubba)  } else {
beaca01998-02-20Per Hedbor #endif // 'smartpipe' does not support multiple outputs. object p = Pipe.pipe(); if (callback) p->set_done_callback(callback); p->output(to);
33b7701998-03-20Johan Schön  if(to2) p->output(to2);
beaca01998-02-20Per Hedbor  p->input(from);
ccffe71999-03-05Wilhelm Köhler  return p;
beaca01998-02-20Per Hedbor #if efun(spider.shuffle)
b1fca01996-11-12Per Hedbor  }
beaca01998-02-20Per Hedbor #endif
b1fca01996-11-12Per Hedbor }
3aaaa71997-06-12Wilhelm Köhler 
4f4bc11998-02-04Per Hedbor 
b1fca01996-11-12Per Hedbor static private int _recurse;
a9d8111998-09-01Henrik Grubbström (Grubba) // FIXME: Ought to use the shutdown code.
b1fca01996-11-12Per Hedbor void exit_when_done() {
81f8af1999-12-20Martin Nilsson  report_debug("Interrupt request received. Exiting,\n");
4f4bc11998-02-04Per Hedbor  die_die_die=1;
c5e0961999-10-04Per Hedbor 
b1fca01996-11-12Per Hedbor  if(++_recurse > 4)
38dca81996-12-10Per Hedbor  {
81f8af1999-12-20Martin Nilsson  report_debug("Exiting roxen (spurious signals received).\n");
c5e0961999-10-04Per Hedbor  configurations->stop();
1f79ba1998-09-01Marcus Comstedt #ifdef THREADS stop_handler_threads(); #endif /* THREADS */
3835ca1998-01-16Henrik Grubbström (Grubba)  exit(-1); // Restart.
38dca81996-12-10Per Hedbor  }
81f8af1999-12-20Martin Nilsson  report_debug("Exiting roxen.\n");
c5e0961999-10-04Per Hedbor  configurations->stop();
1f79ba1998-09-01Marcus Comstedt #ifdef THREADS
c5e0961999-10-04Per Hedbor  stop_handler_threads();
1f79ba1998-09-01Marcus Comstedt #endif /* THREADS */
c5e0961999-10-04Per Hedbor  exit(-1); // Restart.
b1fca01996-11-12Per Hedbor } void exit_it() {
81f8af1999-12-20Martin Nilsson  report_debug("Recursive signals.\n");
3835ca1998-01-16Henrik Grubbström (Grubba)  exit(-1); // Restart.
b1fca01996-11-12Per Hedbor }
7c92b91998-11-19Per Hedbor void set_locale( string to ) { if( to == "standard" ) SET_LOCALE( default_locale );
2537c32000-02-14Per Hedbor  SET_LOCALE( RoxenLocale[ to ] || default_locale );
7c92b91998-11-19Per Hedbor }
a22f6f1999-05-12Per Hedbor 
1c9d081999-07-19Henrik Grubbström (Grubba) // Dump all threads to the debug log. void describe_all_threads() { array(mixed) all_backtraces; #if constant(all_threads) all_backtraces = all_threads()->backtrace(); #else /* !constant(all_threads) */ all_backtraces = ({ backtrace() }); #endif /* constant(all_threads) */
81f8af1999-12-20Martin Nilsson  report_debug("Describing all threads:\n");
1c9d081999-07-19Henrik Grubbström (Grubba)  int i; for(i=0; i < sizeof(all_backtraces); i++) {
81f8af1999-12-20Martin Nilsson  report_debug("Thread %d:\n" "%s\n", i+1, describe_backtrace(all_backtraces[i]));
1c9d081999-07-19Henrik Grubbström (Grubba)  } }
753a831999-08-30Per Hedbor  void dump( string file ) {
dde8331999-11-15Per Hedbor  if( file[0] != '/' ) file = getcwd() +"/"+ file;
81f8af1999-12-20Martin Nilsson 
dde8331999-11-15Per Hedbor  program p = master()->programs[ replace(file, "//", "/" ) ];
753a831999-08-30Per Hedbor  array q;
2bb9241999-11-24Per Hedbor 
753a831999-08-30Per Hedbor  if(!p)
2ff8461999-09-02Per Hedbor  { #ifdef DUMP_DEBUG
81f8af1999-12-20Martin Nilsson  werror(file+" not loaded, and thus cannot be dumped.\n");
2ff8461999-09-02Per Hedbor #endif
753a831999-08-30Per Hedbor  return;
2ff8461999-09-02Per Hedbor  }
753a831999-08-30Per Hedbor 
2bb9241999-11-24Per Hedbor  string ofile = master()->make_ofilename( replace(file, "//", "/") ); if(!file_stat( ofile ) || (file_stat( ofile )[ ST_MTIME ] < file_stat(file)[ ST_MTIME ]))
2ff8461999-09-02Per Hedbor  {
2bb9241999-11-24Per Hedbor  if(q=catch( master()->dump_program( replace(file, "//", "/"), p ) ) ) report_debug("** Cannot encode "+file+": "+describe_backtrace(q)+"\n");
2ff8461999-09-02Per Hedbor #ifdef DUMP_DEBUG
2bb9241999-11-24Per Hedbor  else
84cf742000-01-30Per Hedbor  werror( file+" dumped successfully to "+ofile+"\n" );
2ff8461999-09-02Per Hedbor #endif } #ifdef DUMP_DEBUG else
81f8af1999-12-20Martin Nilsson  werror(file+" already dumped (and up to date)\n");
2ff8461999-09-02Per Hedbor #endif
753a831999-08-30Per Hedbor }
a577791999-11-24Per Hedbor program slowpipe, fastpipe;
1d7d6d2000-02-16Per Hedbor void initiate_argcache() { int t = gethrtime(); report_debug( "Initiating argument cache ... "); int id; string cp = QUERY(argument_cache_dir), na = "args"; if( QUERY(argument_cache_in_db) ) { id = 1; cp = QUERY(argument_cache_db_path); na = "argumentcache"; } mixed e; e = catch( argcache = ArgCache(na,cp,id) ); if( e ) { report_error( "Failed to initialize the global argument cache:\n" + (describe_backtrace( e )/"\n")[0]+"\n"); report_debug( describe_backtrace( e ) ); } add_constant( "roxen.argcache", argcache ); report_debug("Done [%.2fms]\n", (gethrtime()-t)/1000.0); }
7339a02000-02-10Per Hedbor int main(int argc, array tmp)
b1fca01996-11-12Per Hedbor {
7339a02000-02-10Per Hedbor  array argv = tmp; tmp = 0;
a577791999-11-24Per Hedbor  slowpipe = ((program)"slowpipe"); fastpipe = ((program)"fastpipe");
753a831999-08-30Per Hedbor  call_out( lambda() {
2537c32000-02-14Per Hedbor  foreach(glob("*.pmod",get_dir( "etc/modules/RoxenLocale.pmod/")), string q ) dump( "etc/modules/RoxenLocale.pmod/"+ q );
4cf7832000-02-16Per Hedbor  (program)"module";
95b69e1999-09-05Per Hedbor  dump( "protocols/http.pike"); dump( "protocols/ftp.pike"); dump( "protocols/https.pike");
753a831999-08-30Per Hedbor  dump( "base_server/state.pike" );
2ff8461999-09-02Per Hedbor  dump( "base_server/highlight_pike.pike");
753a831999-08-30Per Hedbor  dump( "base_server/wizard.pike" ); dump( "base_server/proxyauth.pike" ); dump( "base_server/html.pike" ); dump( "base_server/module.pike" );
95b69e1999-09-05Per Hedbor  dump( "base_server/throttler.pike" ); dump( "base_server/smartpipe.pike" ); dump( "base_server/slowpipe.pike" ); dump( "base_server/fastpipe.pike" );
753a831999-08-30Per Hedbor  }, 9); switch(getenv("LANG")) { case "sv":
2537c32000-02-14Per Hedbor  default_locale = RoxenLocale["svenska"];
753a831999-08-30Per Hedbor  break; case "jp":
2537c32000-02-14Per Hedbor  default_locale = RoxenLocale["nihongo"];
753a831999-08-30Per Hedbor  break;
e6f83d2000-03-06Peter Bortas  case "de": default_locale = RoxenLocale["deutsch"]; break;
753a831999-08-30Per Hedbor  }
59912f1998-10-15Henrik Grubbström (Grubba)  SET_LOCALE(default_locale);
c245691997-10-25Per Hedbor  initiate_languages();
cde8d62000-02-16Per Hedbor  dump( "languages/abstract.pike" );
b1fca01996-11-12Per Hedbor  mixed tmp;
81f8af1999-12-20Martin Nilsson 
b1fca01996-11-12Per Hedbor  mark_fd(0, "Stdin"); mark_fd(1, "Stdout"); mark_fd(2, "Stderr");
51643e1997-08-21Per Hedbor  configuration_dir =
6ca8f61998-10-13Per Hedbor  Getopt.find_option(argv, "d",({"config-dir","configuration-directory" }),
51643e1997-08-21Per Hedbor  ({ "ROXEN_CONFIGDIR", "CONFIGURATIONS" }), "../configurations");
b1fca01996-11-12Per Hedbor 
a92b951997-08-05Martin Stjernholm  if(configuration_dir[-1] != '/')
b1fca01996-11-12Per Hedbor  configuration_dir += "/";
14179b1997-01-29Per Hedbor  // Dangerous...
6ca8f61998-10-13Per Hedbor  if(tmp = Getopt.find_option(argv, "r", "root")) fix_root(tmp);
b1fca01996-11-12Per Hedbor  argv -= ({ 0 });
51643e1997-08-21Per Hedbor  argc = sizeof(argv);
b1fca01996-11-12Per Hedbor  define_global_variables(argc, argv);
95b69e1999-09-05Per Hedbor 
b796b51998-11-18Per Hedbor  object o;
2537c32000-02-14Per Hedbor  if(QUERY(locale) != "standard" && (o = RoxenLocale[QUERY(locale)]))
b796b51998-11-18Per Hedbor  { default_locale = o; SET_LOCALE(default_locale); }
b1fca01996-11-12Per Hedbor #if efun(syslog) init_logger(); #endif init_garber(); initiate_supports();
1d7d6d2000-02-16Per Hedbor  initiate_argcache();
b84a161999-06-07Martin Stjernholm  enable_configurations();
95b69e1999-09-05Per Hedbor  set_u_and_gid(); // Running with the right [e]uid:[e]gid from this point on.
b84a161999-06-07Martin Stjernholm  create_pid_file(Getopt.find_option(argv, "p", "pid-file", "ROXEN_PID_FILE") || QUERY(pidfile));
1766be2000-02-16Per Hedbor  if( Getopt.find_option( argv, 0, "no-delayed-load" ) ) enable_configurations_modules();
11f1922000-02-16Per Hedbor  else foreach( configurations, object c ) if( c->query( "no_delayed_load" ) ) c->enable_all_modules();
81f8af1999-12-20Martin Nilsson 
b1fca01996-11-12Per Hedbor  call_out(update_supports_from_roxen_com, QUERY(next_supports_update)-time());
81f8af1999-12-20Martin Nilsson 
48fa361997-04-05Per Hedbor #ifdef THREADS start_handler_threads();
4f4bc11998-02-04Per Hedbor  catch( this_thread()->set_name("Backend") );
34d3fa1999-04-22Per Hedbor  backend_thread = this_thread();
34fbbc1998-02-05Henrik Grubbström (Grubba) #endif /* THREADS */
990cbb1997-08-12David Hedbor 
3835ca1998-01-16Henrik Grubbström (Grubba)  // Signals which cause a restart (exitcode != 0)
15635b1999-10-10Per Hedbor  foreach( ({ "SIGINT", "SIGTERM" }), string sig) catch( signal(signum(sig), exit_when_done) ); catch( signal(signum("SIGHUP"), reload_all_configurations) );
1c9d081999-07-19Henrik Grubbström (Grubba)  // Signals which cause Roxen to dump the thread state
15635b1999-10-10Per Hedbor  foreach( ({ "SIGUSR1", "SIGUSR2", "SIGTRAP" }), string sig) catch( signal(signum(sig), describe_all_threads) );
0f28da1997-08-13Per Hedbor 
4f4bc11998-02-04Per Hedbor #ifdef __RUN_TRACE trace(1); #endif
08152b1998-04-24Per Hedbor  start_time=time(); // Used by the "uptime" info later on.
4cf7832000-02-16Per Hedbor  if (QUERY(suicide_engage)) call_out (restart,60*60*24*QUERY(suicide_timeout)); restart_if_stuck( 0 );
b1fca01996-11-12Per Hedbor  return -1; }
7a61de1998-03-26Per Hedbor 
edc9af1998-07-11David Hedbor // Called from the configuration interface.
ee8b201998-07-13David Hedbor string check_variable(string name, mixed value)
edc9af1998-07-11David Hedbor { switch(name) {
ee8b201998-07-13David Hedbor  case "abs_engage": if (value) restart_if_stuck(1);
81f8af1999-12-20Martin Nilsson  else
ee8b201998-07-13David Hedbor  remove_call_out(restart_if_stuck); break; case "suicide_engage":
81f8af1999-12-20Martin Nilsson  if (value)
ee8b201998-07-13David Hedbor  call_out(restart,60*60*24*QUERY(suicide_timeout)); else remove_call_out(restart); break;
b796b51998-11-18Per Hedbor  case "locale": object o;
280e2b2000-03-04Henrik Grubbström (Grubba)  if(o = RoxenLocale[value])
b796b51998-11-18Per Hedbor  { default_locale = o; SET_LOCALE(default_locale);
280e2b2000-03-04Henrik Grubbström (Grubba)  } else { return sprintf("No such locale: %O\n", value);
b796b51998-11-18Per Hedbor  } break;
edc9af1998-07-11David Hedbor  } }
9fd61c1999-02-16Per Hedbor  mapping config_cache = ([ ]); mapping host_accuracy_cache = ([]); int is_ip(string s) {
1f58d02000-01-02Martin Nilsson  return (sscanf(s,"%*d.%*d.%*d.%*d")==4 && s[-1]>47 && s[-1]<58);
9fd61c1999-02-16Per Hedbor }
8b64e82000-01-03Martin Nilsson 
c616962000-01-18Martin Nilsson array configuration_auth=({});
b5595b2000-01-07Martin Nilsson mapping configuration_perm=([]);
2f74c32000-01-21Per Hedbor  void add_permission(string name, mapping desc) { configuration_perm[ name ]=desc; configuration_auth->add_permission( name, desc );
c616962000-01-18Martin Nilsson }
2f74c32000-01-21Per Hedbor  void remove_configuration_auth(RoxenModule o) {
c616962000-01-18Martin Nilsson  configuration_auth-=({o}); }
2f74c32000-01-21Per Hedbor  void add_configuration_auth(RoxenModule o) { configuration_auth|=({o}); } string configuration_authenticate(RequestID id, string what) { if(!id->realauth) return 0;
c616962000-01-18Martin Nilsson  array auth; RoxenModule o;
2f74c32000-01-21Per Hedbor  foreach(configuration_auth, o) {
c616962000-01-18Martin Nilsson  auth=o->auth( ({"",id->realauth}), id); if(auth) break; }
2f74c32000-01-21Per Hedbor  if(!auth) return 0; if(!auth[0]) return 0; if( o->find_admin_user( auth[1] )->auth( what ) )
c616962000-01-18Martin Nilsson  return auth[1]; return 0;
b5595b2000-01-07Martin Nilsson }
2f74c32000-01-21Per Hedbor  array(object) get_config_users( string uname ) { return configuration_auth->find_admin_user( uname ); }
4cf7832000-02-16Per Hedbor array(string|object) list_config_users(string uname, string|void required_auth)
2f74c32000-01-21Per Hedbor { array users = `+( ({}), configuration_auth->list_admin_users( ) ); if( !required_auth ) return users; array res = ({ }); foreach( users, string q ) { foreach( get_config_users( q ), object o ) if( o->auth( required_auth ) ) res += ({ o }); } return res; }