Add to git.
[monolith.git] / src / monolith.h
1 /* Monolith core code.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: monolith.h,v 1.19 2003/02/22 15:34:32 rich Exp $
19  */
20
21 #ifndef MONOLITH_H
22 #define MONOLITH_H
23
24 #include <pool.h>
25 #include <vector.h>
26 #include <pthr_pseudothread.h>
27 #include <pthr_cgi.h>
28 #include <pthr_dbi.h>
29 #include <rws_request.h>
30
31 #include <stdlib.h>             /* For size_t */
32
33 /* Just like the semi-standard "offsetof" function. */
34 #ifdef offsetof
35 #define ml_offsetof(type,member) offset(type,member)
36 #else
37 #define ml_offsetof(type,member) ((size_t) &((type *)0)->member)
38 #endif
39
40 #include <sys/socket.h>
41
42 #include <ml_window.h>
43
44 /* Session object. */
45 struct ml_session;
46 typedef struct ml_session *ml_session;
47
48 /* Function: ml_entry_point - entry point into monolith from handle_request
49  *
50  * @code{ml_entry_point} is the entry point into the monolith core
51  * library code, called from @code{handle_request}. The application's
52  * @code{handle_request} function should contain just a single
53  * call to @code{ml_entry_point} like this:
54  *
55  * @code{return ml_entry_point (rq, app_main);}
56  *
57  * where @code{rq} is the @code{rws_request} object passed by the
58  * web server, and @code{app_main} is the application's main function.
59  *
60  * See @code{examples/01_label_and_button.c} for a simple monolith
61  * application.
62  *
63  * See also: @ref{ml_session_pool(3)},
64  * @ref{rws_request_pool(3)}, @ref{new_ml_window(3)},
65  * @ref{ml_cfg_get_string(3)}.
66  */
67 extern int ml_entry_point (rws_request rq, void (*app_main) (ml_session));
68
69 /* Function: ml_session_pool - get monolith per-session information
70  * Function: ml_session_args
71  * Function: ml_session_sessionid
72  * Function: ml_session_host_header
73  * Function: ml_session_canonical_path
74  * Function: ml_session_script_name
75  * Function: ml_session_user_agent
76  * Function: ml_session_set_main_window
77  * Function: ml_session_get_main_window
78  * Function: ml_session_get_peername
79  * Function: ml_session_get_peernamestr
80  *
81  * These functions extract the information from the opaque @code{ml_session}
82  * object passed to most application functions and callbacks. Each separate
83  * user session is tied to a separate @code{ml_session} object which
84  * contains standard fields.
85  *
86  * @code{ml_session_pool} returns the session pool, which is a pool which
87  * has the lifetime of the whole session.
88  *
89  * @code{ml_session_args} returns the arguments (a @code{cgi} object) which
90  * were passed to the application when it started running. This is kind of
91  * equivalent to @code{argc} and @code{argv} for a traditional application.
92  *
93  * @code{ml_session_sessionid} returns the session ID, a 32 character
94  * string of random hex digits which also happens to be the cookie
95  * passed by the browser.
96  *
97  * @code{ml_session_host_header} returns the Host: header of the
98  * monolith application. For example @code{www.annexia.org}.
99  *
100  * @code{ml_session_canonical_path} returns the canonical path of the
101  * monolith application, that is, the full path of the application as
102  * it appears to the browser. For example @code{/so-bin/app.so}.
103  *
104  * @code{ml_session_script_name} returns just the name of the application
105  * as it appears to the browser. For example @code{app.so}.
106  *
107  * @code{ml_session_user_agent} returns the identifying string for
108  * the browser, sent in the HTTP @code{User-Agent} header. This can
109  * be @code{NULL}.
110  *
111  * @code{ml_session_(set|get)_main_window} are a pair of esoteric
112  * functions which you will not need to use in most applications. They
113  * are useful, however, when you are building a website. They nominate
114  * a particular window which will be the window displayed if the user
115  * types the URL of the application directly into their browser
116  * location bar, without the normally mandatory @code{ml_window}
117  * parameter.
118  *
119  * @code{ml_session_get_peername} returns the peer address of the
120  * socket. The peer address is the IP address of the user's browser
121  * or proxy. This function returns @code{0} on success or @code{-1}
122  * on failure (with the appropriate error code in @code{errno}).
123  * @code{ml_session_get_peernamestr} returns the same
124  * converted to a string, normally in "dotted quad" format, for example:
125  * @code{"10.0.0.137"}. On failure, @code{ml_session_get_peernamestr}
126  * returns @code{NULL}.
127  *
128  * See also: @ref{ml_entry_point(3)}, @ref{ml_die(3)}, @ref{new_cgi(3)}
129  */
130 extern pool ml_session_pool (ml_session);
131 extern cgi ml_session_args (ml_session);
132 extern const char *ml_session_sessionid (ml_session);
133 extern const char *ml_session_host_header (ml_session);
134 extern const char *ml_session_canonical_path (ml_session);
135 extern const char *ml_session_script_name (ml_session);
136 extern const char *ml_session_user_agent (ml_session);
137 extern void ml_session_set_main_window (ml_session, ml_window);
138 extern ml_window ml_session_get_main_window (ml_session);
139 extern int ml_session_get_peername (ml_session, struct sockaddr *name, socklen_t *namelen);
140 extern const char *ml_session_get_peernamestr (ml_session);
141
142 /* Function: ml_session_release_lock
143  * Function: ml_session_acquire_lock
144  *
145  * These are advanced functions which you will probably never need to use.
146  *
147  * Monolith maintains a single session structure for each session. If
148  * the browser were to try and fetch two pages with the same session ID
149  * at the same time, then rws could create two threads running at the
150  * same time, and these two threads could access the same session
151  * structure. The result of this, under some circumstances, would be
152  * that the session structure would be corrupted. There is obviously
153  * potential for malicious abuse here, but this can also happen under
154  * normal conditions, particularly in framesets (the browser fetches
155  * each frame at the same time).
156  *
157  * To avoid this situation, monolith maintains a mutex lock on each
158  * session structure, so that no two threads can try to access the
159  * same session structure at the same time. (Different sessions can
160  * execute concurrently, of course).
161  *
162  * Monolith's session locking is normally transparent to programmers
163  * and users, but these functions allow you to bypass the session
164  * lock under certain circumstances. Of course, when a programmer
165  * does this, they can no longer rely on monolith to keep the session
166  * structure consistent, and must instead guarantee this themselves.
167  *
168  * @code{ml_session_release_lock} releases the session lock. This
169  * potentially allows other threads to run, overwriting parts of the
170  * session structure.
171  *
172  * @code{ml_session_acquire_lock} reacquires the session lock, possibly
173  * sleeping to do so. This does not restore the session structure which
174  * will still be in a semi-corrupted state.
175  *
176  * In future we will add functions to allow @code{ml_session_acquire_lock}
177  * to restore the session structure to a non-corrupt state, perhaps by
178  * having a stack of session structures (or some parts of the session
179  * structure).
180  *
181  * See also: @ref{new_pseudothread(3)}, @ref{new_mutex(3)}.
182  */
183 extern void ml_session_release_lock (ml_session);
184 extern void ml_session_acquire_lock (ml_session);
185
186 /* Function: ml_session_login - user authentication, log in, log out
187  * Function: ml_session_logout
188  * Function: ml_session_userid
189  *
190  * These functions provide a low-level, database-independent,
191  * authentication-method-agnostic way to handle the problem
192  * of user authentication in monolith applications.
193  *
194  * All of these functions require the schema in
195  * @code{sql/monolith_auth_create.sql}. This schema contains a
196  * table which stores a mapping from cookies to user IDs. The
197  * @code{rws} configuration file must contain a line which allows
198  * monolith to find the database containing this table:
199  *
200  * @code{monolith user database: CONNINFO}
201  *
202  * (@code{CONNINFO} is the PostgreSQL connection info string).
203  *
204  * Each user must be identified by a unique numeric userid >= 1.
205  *
206  * Once a user has logged in, a cookie (@code{ml_auth}) is sent back
207  * to their browser. The reason for sending back a cookie, rather than
208  * just storing the userid in the session state, is that it might be
209  * necessary for the user to be automatically logged in to other
210  * applications on the same server. By sending the cookie back to,
211  * say, the @code{/} path, a user effectively logs into all
212  * applications whenever they log into any one application. Also,
213  * by controlling the expiry time of the cookie, it is possible
214  * to allow a user to remain logged in across several browser
215  * sessions.
216  *
217  * The session stores the currently logged in user (as a userid)
218  * or @code{0} if no user is currently logged in. @code{ml_session_userid}
219  * retrieves the currently logged in userid or @code{0}. Note that
220  * the currently logged in user can change unexpectedly, so you
221  * must NOT stash the userid away. Call @code{ml_session_userid}
222  * every time you want to check the currently logged in user. See
223  * below for more details.
224  *
225  * When a user logs in to a particular application, the application
226  * should call @code{ml_session_login}. The actual method of login
227  * is not defined at this level (but monolith provides some higher-level
228  * widgets which you may use). The @code{userid} parameter is the
229  * user who has logged in. The @code{path} and @code{expires} parameters
230  * are used to control the @code{ml_auth} cookie sent back to the
231  * browser. If @code{path} is @code{NULL}, then the cookie only applies
232  * to the current application. If @code{path} is @code{"/"}, then the
233  * user will be automatically logged into all applications running
234  * at the same address. Other @code{path}s may also be specified to
235  * restrict authentication to some subset of the path space. If
236  * @code{expires} is @code{NULL}, then the cookie will expire at
237  * the end of the current browser session (when the user closes their
238  * browser). This means that the next time they visit the site, they
239  * will need to log in again, if they have closed their browser in
240  * the meantime. @code{expires} may also be set to a date in
241  * RFC 2616 compliant format, or to a relative time such as
242  * @code{"+1y"} (meaning 1 year from now). Relative times are
243  * specified in exactly the same way as the @code{rws} @code{expires}
244  * configuration option.
245  *
246  * There are various browser-related problems which mean that you
247  * should not mix and match different @code{path}s unless you really
248  * know what you are doing. In general, you should always set @code{path}
249  * to either @code{"/"} everywhere, or to @code{NULL} everywhere. The
250  * simplest thing is to always set @code{path} to @code{"/"} everywhere.
251  *
252  * If @code{path} is not @code{NULL}, then calling @code{ml_session_login}
253  * may also cause other monolith applications to become logged in.
254  * This is because they notice the @code{ml_auth} cookie, verify it
255  * against the database, and if it is verified, change their state
256  * to logged in. For this reason, applications should not stash away
257  * the result of @code{ml_session_userid}, but should check it each
258  * time they need it, because it can change unexpectedly.
259  *
260  * @code{ml_session_logout} logs the current user out. @code{path} should
261  * be the same as above.
262  *
263  * As before, if @code{path} is not @code{NULL}, then calling
264  * @code{ml_session_logout} may cause other monolith applications to
265  * become logged out (@code{ml_session_userid} will start to return
266  * @code{0}). This is because monolith overwrites the @code{ml_auth}
267  * cookie with a "poisoned" cookie which other applications may notice.
268  */
269 extern void ml_session_login (ml_session, int userid, const char *path, const char *expires);
270 extern void ml_session_logout (ml_session, const char *path);
271 extern int ml_session_userid (ml_session);
272
273 /* Function: ml_cfg_get_string - get values from the configuration file
274  * Function: ml_cfg_get_int
275  * Function: ml_cfg_get_bool
276  *
277  * @code{rws_request_cfg_get_string} returns the configuration file
278  * string for @code{key}. If there is no entry in the configuration
279  * file, this returns @code{default_value}.
280  *
281  * @code{rws_request_cfg_get_int} returns the string converted to
282  * an integer.
283  *
284  * @code{rws_request_cfg_get_bool} returns the string converted to
285  * a boolean.
286  *
287  * See also: @ref{ml_entry_point(3)}, @ref{rws_request_cfg_get_string(3)}.
288  *
289  */
290 extern const char *ml_cfg_get_string (ml_session, const char *key, const char *default_value);
291 extern int ml_cfg_get_int (ml_session, const char *key, int default_value);
292 extern int ml_cfg_get_bool (ml_session, const char *key, int default_value);
293
294 /* Function: ml_register_action - register callbacks
295  * Function: ml_unregister_action
296  *
297  * Widgets such as buttons may register actions (callback functions)
298  * to be run when a user clicks a button or submits a form. Each
299  * action is associated with a unique action ID (a string). A separate
300  * set of actions is registered within each session. The callback
301  * function is invoked as @code{void callback_fn (ml_session
302  * session, void *data)}.
303  *
304  * @code{ml_register_action} registers an action within a given
305  * session and returns the action ID string.
306  *
307  * @code{ml_unregister_action} unregisters an action.
308  *
309  * See also: @ref{new_ml_button(3)}.
310  */
311 extern const char *ml_register_action (ml_session session, void (*callback_fn) (ml_session, void *), void *data);
312 extern void ml_unregister_action (ml_session session, const char *action_id);
313
314 /* Private function used by forms to get the arguments passed just to
315  * this request. The returned value is on the short-lived thread pool,
316  * so interesting stuff must be copied to the session pool.
317  */
318 extern cgi _ml_session_submitted_args (ml_session);
319
320 /* Private function used by ml_window to register the current window. */
321 extern void _ml_session_set_current_window (ml_session, ml_window, const char *windowid);
322
323 /* Some private functions used by the stats package to inspect the internals
324  * of monolith. These functions are subject to change and should not be used
325  * in ordinary applications.
326  */
327 extern const vector _ml_get_sessions (pool);
328 extern ml_session _ml_get_session (const char *sessionid);
329 extern int _ml_session_get_hits (ml_session);
330 extern reactor_time_t _ml_session_get_last_access (ml_session);
331 extern reactor_time_t _ml_session_get_created (ml_session);
332 extern struct sockaddr_in _ml_session_get_original_ip (ml_session);
333 extern void *_ml_session_get_app_main (ml_session);
334 extern const vector _ml_session_get_windows (ml_session, pool);
335 extern ml_window _ml_session_get_window (ml_session, const char *windowid);
336 extern const vector _ml_session_get_actions (ml_session, pool);
337 extern int _ml_session_get_action (ml_session, const char *actionid, void **fn_rtn, void **data_rtn);
338
339 #endif /* MONOLITH_H */