su  1.12.11
su_port.h
00001 /*
00002  * This file is part of the Sofia-SIP package
00003  *
00004  * Copyright (C) 2005 Nokia Corporation.
00005  *
00006  * Contact: Pekka Pessi <pekka.pessi@nokia-email.address.hidden>
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA
00022  *
00023  */
00024 
00025 #ifndef SU_PORT_H
00026 
00027 #define SU_PORT_H
00028 
00040 #ifndef SU_MSG_ARG_T
00041 #define SU_MSG_ARG_T union { char anoymous[4]; }
00042 #endif
00043 
00044 #ifndef SU_WAIT_H
00045 #include "sofia-sip/su_wait.h"
00046 #endif
00047 
00048 #ifndef SU_MODULE_DEBUG_H
00049 #include "su_module_debug.h"
00050 #endif
00051 
00052 #ifndef SU_ALLOC_H
00053 #include <sofia-sip/su_alloc.h>
00054 #endif
00055 
00056 #include <assert.h>
00057 
00058 #define SU_WAIT_MIN    (16)
00059 
00060 SOFIA_BEGIN_DECLS
00061 
00063 struct su_msg_s {
00064   size_t         sum_size;
00065   su_msg_t      *sum_next;
00066   su_task_r      sum_to;
00067   su_task_r      sum_from;
00068   su_msg_f       sum_func;
00069   su_msg_f       sum_report;
00070   su_msg_deinit_function *sum_deinit;
00071   su_msg_arg_t   sum_data[1];           /* minimum size, may be extended */
00072 };
00073 
00074 struct _GSource;
00075 
00077 struct su_root_s {
00078   int              sur_size;
00079   su_root_magic_t *sur_magic;
00080   su_root_deinit_f sur_deinit;
00081   su_task_r        sur_task;
00082   su_task_r        sur_parent;
00083   unsigned         sur_threading : 1;
00084   unsigned         sur_deiniting : 1;
00085 };
00086 
00087 #define SU_ROOT_MAGIC(r) ((r) ? (r)->sur_magic : NULL)
00088 
00089 enum su_port_thread_op {
00090   su_port_thread_op_is_obtained,
00091   su_port_thread_op_release,
00092   su_port_thread_op_obtain
00093 };
00094 
00096 typedef struct su_port_vtable {
00097   unsigned su_vtable_size;
00098   void (*su_port_lock)(su_port_t *port, char const *who);
00099   void (*su_port_unlock)(su_port_t *port, char const *who);
00100   void (*su_port_incref)(su_port_t *port, char const *who);
00101   void (*su_port_decref)(su_port_t *port, int block, char const *who);
00102   struct _GSource *(*su_port_gsource)(su_port_t *port);
00103   int (*su_port_send)(su_port_t *self, su_msg_r rmsg);
00104   int (*su_port_register)(su_port_t *self,
00105                           su_root_t *root,
00106                           su_wait_t *wait,
00107                           su_wakeup_f callback,
00108                           su_wakeup_arg_t *arg,
00109                           int priority);
00110   int (*su_port_unregister)(su_port_t *port,
00111                             su_root_t *root,
00112                             su_wait_t *wait,
00113                             su_wakeup_f callback,
00114                             su_wakeup_arg_t *arg);
00115   int (*su_port_deregister)(su_port_t *self, int i);
00116   int (*su_port_unregister_all)(su_port_t *self,
00117                              su_root_t *root);
00118   int (*su_port_eventmask)(su_port_t *self, int index, int socket, int events);
00119   void (*su_port_run)(su_port_t *self);
00120   void (*su_port_break)(su_port_t *self);
00121   su_duration_t (*su_port_step)(su_port_t *self, su_duration_t tout);
00122 
00123   /* Reused slot */
00124   int (*su_port_thread)(su_port_t *port, enum su_port_thread_op op);
00125 
00126   int (*su_port_add_prepoll)(su_port_t *port,
00127                              su_root_t *root,
00128                              su_prepoll_f *,
00129                              su_prepoll_magic_t *);
00130 
00131   int (*su_port_remove_prepoll)(su_port_t *port,
00132                                 su_root_t *root);
00133 
00134   su_timer_queue_t *(*su_port_timers)(su_port_t *port);
00135 
00136   int (*su_port_multishot)(su_port_t *port, int multishot);
00137 
00138   /* Extension from >= 1.12.4 */
00139   int (*su_port_wait_events)(su_port_t *port, su_duration_t timeout);
00140   int (*su_port_getmsgs)(su_port_t *port);
00141   /* Extension from >= 1.12.5 */
00142   int (*su_port_getmsgs_from)(su_port_t *port, su_port_t *cloneport);
00143   char const *(*su_port_name)(su_port_t const *port);
00144   int (*su_port_start_shared)(su_root_t *root,
00145                               su_clone_r return_clone,
00146                               su_root_magic_t *magic,
00147                               su_root_init_f init,
00148                               su_root_deinit_f deinit);
00149   void (*su_port_wait)(su_clone_r rclone);
00150   int (*su_port_execute)(su_task_r const task,
00151                          int (*function)(void *), void *arg,
00152                          int *return_value);
00153 
00154   /* >= 1.12.11 */
00155   su_timer_queue_t *(*su_port_deferrable)(su_port_t *port);
00156   int (*su_port_max_defer)(su_port_t *port,
00157                            su_duration_t *return_duration,
00158                            su_duration_t *set_duration);
00159   int (*su_port_wakeup)(su_port_t *port);
00160   int (*su_port_is_running)(su_port_t const *port);
00161 } su_port_vtable_t;
00162 
00163 SOFIAPUBFUN su_port_t *su_port_create(void)
00164      __attribute__((__malloc__));
00165 
00166 /* Extension from >= 1.12.5 */
00167 
00168 SOFIAPUBFUN void su_msg_delivery_report(su_msg_r msg);
00169 SOFIAPUBFUN su_duration_t su_timer_next_expires(su_timer_queue_t const *timers,
00170                                                 su_time_t now);
00171 SOFIAPUBFUN su_root_t *su_root_create_with_port(su_root_magic_t *magic,
00172                                                 su_port_t *port)
00173   __attribute__((__malloc__));
00174 
00175 /* Extension from >= 1.12.6 */
00176 
00177 SOFIAPUBFUN char const *su_port_name(su_port_t const *port);
00178 
00179 SOFIAPUBFUN int su_timer_reset_all(su_timer_queue_t *, su_task_r );
00180 
00181 /* ---------------------------------------------------------------------- */
00182 
00183 /* React to multiple events per one poll() to make sure
00184  * that high-priority events can never completely mask other events.
00185  * Enabled by default on all platforms except WIN32 */
00186 #if !defined(WIN32)
00187 #define SU_ENABLE_MULTISHOT_POLL 1
00188 #else
00189 #define SU_ENABLE_MULTISHOT_POLL 0
00190 #endif
00191 
00192 /* ---------------------------------------------------------------------- */
00193 /* Virtual functions */
00194 
00195 typedef struct su_virtual_port_s {
00196   su_home_t        sup_home[1];
00197   su_port_vtable_t const *sup_vtable;
00198 } su_virtual_port_t;
00199 
00200 su_inline
00201 su_home_t *su_port_home(su_port_t const *self)
00202 {
00203   return (su_home_t *)self;
00204 }
00205 
00206 su_inline
00207 void su_port_lock(su_port_t *self, char const *who)
00208 {
00209   su_virtual_port_t *base = (su_virtual_port_t *)self;
00210   base->sup_vtable->su_port_lock(self, who);
00211 }
00212 
00213 su_inline
00214 void su_port_unlock(su_port_t *self, char const *who)
00215 {
00216   su_virtual_port_t *base = (su_virtual_port_t *)self;
00217   base->sup_vtable->su_port_unlock(self, who);
00218 }
00219 
00220 su_inline
00221 void su_port_incref(su_port_t *self, char const *who)
00222 {
00223   su_virtual_port_t *base = (su_virtual_port_t *)self;
00224   base->sup_vtable->su_port_incref(self, who);
00225 }
00226 
00227 su_inline
00228 void su_port_decref(su_port_t *self, char const *who)
00229 {
00230   su_virtual_port_t *base = (su_virtual_port_t *)self;
00231   base->sup_vtable->su_port_decref(self, 0, who);
00232 }
00233 
00234 su_inline
00235 void su_port_zapref(su_port_t *self, char const *who)
00236 {
00237   su_virtual_port_t *base = (su_virtual_port_t *)self;
00238   base->sup_vtable->su_port_decref(self, 1, who);
00239 }
00240 
00241 su_inline
00242 struct _GSource *su_port_gsource(su_port_t *self)
00243 {
00244   su_virtual_port_t *base = (su_virtual_port_t *)self;
00245   return base->sup_vtable->su_port_gsource(self);
00246 }
00247 
00248 su_inline
00249 int su_port_send(su_port_t *self, su_msg_r rmsg)
00250 {
00251   su_virtual_port_t *base = (su_virtual_port_t *)self;
00252   return base->sup_vtable->su_port_send(self, rmsg);
00253 }
00254 
00255 su_inline
00256 int su_port_wakeup(su_port_t *self)
00257 {
00258   su_virtual_port_t *base = (su_virtual_port_t *)self;
00259   return base->sup_vtable->su_port_wakeup(self);
00260 }
00261 
00262 su_inline
00263 int su_port_register(su_port_t *self,
00264                      su_root_t *root,
00265                      su_wait_t *wait,
00266                      su_wakeup_f callback,
00267                      su_wakeup_arg_t *arg,
00268                      int priority)
00269 {
00270   su_virtual_port_t *base = (su_virtual_port_t *)self;
00271   return base->sup_vtable->
00272     su_port_register(self, root, wait, callback, arg, priority);
00273 }
00274 
00275 su_inline
00276 int su_port_unregister(su_port_t *self,
00277                        su_root_t *root,
00278                        su_wait_t *wait,
00279                        su_wakeup_f callback,
00280                        su_wakeup_arg_t *arg)
00281 {
00282   su_virtual_port_t *base = (su_virtual_port_t *)self;
00283   return base->sup_vtable->
00284     su_port_unregister(self, root, wait, callback, arg);
00285 }
00286 
00287 su_inline
00288 int su_port_deregister(su_port_t *self, int i)
00289 {
00290   su_virtual_port_t *base = (su_virtual_port_t *)self;
00291   return base->sup_vtable->
00292     su_port_deregister(self, i);
00293 }
00294 
00295 su_inline
00296 int su_port_unregister_all(su_port_t *self,
00297                            su_root_t *root)
00298 {
00299   su_virtual_port_t *base = (su_virtual_port_t *)self;
00300   return base->sup_vtable->
00301     su_port_unregister_all(self, root);
00302 }
00303 
00304 su_inline
00305 int su_port_eventmask(su_port_t *self, int index, int socket, int events)
00306 {
00307   su_virtual_port_t *base = (su_virtual_port_t *)self;
00308   return base->sup_vtable->
00309     su_port_eventmask(self, index, socket, events);
00310 }
00311 
00312 su_inline
00313 int su_port_wait_events(su_port_t *self, su_duration_t timeout)
00314 {
00315   su_virtual_port_t *base = (su_virtual_port_t *)self;
00316   if (base->sup_vtable->su_port_wait_events == NULL)
00317     return errno = ENOSYS, -1;
00318   return base->sup_vtable->
00319     su_port_wait_events(self, timeout);
00320 }
00321 
00322 su_inline
00323 void su_port_run(su_port_t *self)
00324 {
00325   su_virtual_port_t *base = (su_virtual_port_t *)self;
00326   base->sup_vtable->su_port_run(self);
00327 }
00328 
00329 su_inline
00330 void su_port_break(su_port_t *self)
00331 {
00332   su_virtual_port_t *base = (su_virtual_port_t *)self;
00333   base->sup_vtable->su_port_break(self);
00334 }
00335 
00336 su_inline
00337 su_duration_t su_port_step(su_port_t *self, su_duration_t tout)
00338 {
00339   su_virtual_port_t *base = (su_virtual_port_t *)self;
00340   return base->sup_vtable->su_port_step(self, tout);
00341 }
00342 
00343 
00344 su_inline
00345 int su_port_own_thread(su_port_t const *self)
00346 {
00347   su_virtual_port_t const *base = (su_virtual_port_t *)self;
00348   return base->sup_vtable->
00349     su_port_thread((su_port_t *)self, su_port_thread_op_is_obtained) == 2;
00350 }
00351 
00352 su_inline int su_port_has_thread(su_port_t *self)
00353 {
00354   su_virtual_port_t *base = (su_virtual_port_t *)self;
00355   return base->sup_vtable->su_port_thread(self, su_port_thread_op_is_obtained);
00356 }
00357 
00358 su_inline int su_port_release(su_port_t *self)
00359 {
00360   su_virtual_port_t *base = (su_virtual_port_t *)self;
00361   return base->sup_vtable->su_port_thread(self, su_port_thread_op_release);
00362 }
00363 
00364 su_inline int su_port_obtain(su_port_t *self)
00365 {
00366   su_virtual_port_t *base = (su_virtual_port_t *)self;
00367   return base->sup_vtable->su_port_thread(self, su_port_thread_op_obtain);
00368 }
00369 
00370 su_inline
00371 int su_port_add_prepoll(su_port_t *self,
00372                         su_root_t *root,
00373                         su_prepoll_f *prepoll,
00374                         su_prepoll_magic_t *magic)
00375 {
00376   su_virtual_port_t *base = (su_virtual_port_t *)self;
00377   return base->sup_vtable->su_port_add_prepoll(self, root, prepoll, magic);
00378 }
00379 
00380 su_inline
00381 int su_port_remove_prepoll(su_port_t *self,
00382                            su_root_t *root)
00383 {
00384   su_virtual_port_t *base = (su_virtual_port_t *)self;
00385   return base->sup_vtable->su_port_remove_prepoll(self, root);
00386 }
00387 
00388 su_inline
00389 su_timer_queue_t *su_port_timers(su_port_t *self)
00390 {
00391   su_virtual_port_t *base = (su_virtual_port_t *)self;
00392   return base->sup_vtable->su_port_timers(self);
00393 }
00394 
00395 su_inline
00396 int su_port_multishot(su_port_t *self, int multishot)
00397 {
00398   su_virtual_port_t *base = (su_virtual_port_t *)self;
00399   return base->sup_vtable->su_port_multishot(self, multishot);
00400 }
00401 
00402 su_inline
00403 int su_port_getmsgs(su_port_t *self)
00404 {
00405   su_virtual_port_t *base = (su_virtual_port_t *)self;
00406   return base->sup_vtable->su_port_getmsgs(self);
00407 }
00408 
00409 su_inline
00410 int su_port_getmsgs_from(su_port_t *self, su_port_t *cloneport)
00411 {
00412   su_virtual_port_t *base = (su_virtual_port_t *)self;
00413   return base->sup_vtable->su_port_getmsgs_from(self, cloneport);
00414 }
00415 
00418 su_inline
00419 su_timer_queue_t *su_port_deferrable(su_port_t *self)
00420 {
00421   su_virtual_port_t *base = (su_virtual_port_t *)self;
00422 
00423   if (base == NULL) {
00424     errno = EFAULT;
00425     return NULL;
00426   }
00427 
00428   return base->sup_vtable->su_port_deferrable(self);
00429 }
00430 
00431 su_inline
00432 int su_port_max_defer(su_port_t *self,
00433                       su_duration_t *return_duration,
00434                       su_duration_t *set_duration)
00435 {
00436   su_virtual_port_t *base = (su_virtual_port_t *)self;
00437 
00438   if (base == NULL)
00439     return (errno = EFAULT), -1;
00440 
00441   return base->sup_vtable->su_port_max_defer(self,
00442                                              return_duration,
00443                                              set_duration);
00444 }
00445 
00446 su_inline
00447 int su_port_is_running(su_port_t const *self)
00448 {
00449   su_virtual_port_t *base = (su_virtual_port_t *)self;
00450   return base && base->sup_vtable->su_port_is_running(self);
00451 }
00452 
00453 SOFIAPUBFUN void su_port_wait(su_clone_r rclone);
00454 
00455 SOFIAPUBFUN int su_port_execute(su_task_r const task,
00456                                 int (*function)(void *), void *arg,
00457                                 int *return_value);
00458 
00459 /* ---------------------------------------------------------------------- */
00460 
00466 typedef struct su_base_port_s {
00467   su_home_t        sup_home[1];
00468   su_port_vtable_t const *sup_vtable;
00469 
00470   /* Implementation may vary stuff below, too. */
00471 
00472   /* Pre-poll callback */
00473   su_prepoll_f    *sup_prepoll;
00474   su_prepoll_magic_t *sup_pp_magic;
00475   su_root_t       *sup_pp_root;
00476 
00477   /* Message list - this is protected by su_port_lock()/su_port_unlock() */
00478   su_msg_t        *sup_head, **sup_tail;
00479 
00480   /* Timer list */
00481   su_timer_queue_t sup_timers, sup_deferrable;
00482 
00483   su_duration_t    sup_max_defer; 
00485   unsigned         sup_running;   
00486 } su_base_port_t;
00487 
00488 /* Base methods */
00489 
00490 SOFIAPUBFUN int su_base_port_init(su_port_t *, su_port_vtable_t const *);
00491 SOFIAPUBFUN void su_base_port_deinit(su_port_t *self);
00492 
00493 SOFIAPUBFUN void su_base_port_lock(su_port_t *self, char const *who);
00494 SOFIAPUBFUN void su_base_port_unlock(su_port_t *self, char const *who);
00495 
00496 SOFIAPUBFUN int su_base_port_thread(su_port_t const *self,
00497                                     enum su_port_thread_op op);
00498 
00499 SOFIAPUBFUN void su_base_port_incref(su_port_t *self, char const *who);
00500 SOFIAPUBFUN int su_base_port_decref(su_port_t *self,
00501                                     int blocking,
00502                                     char const *who);
00503 
00504 SOFIAPUBFUN struct _GSource *su_base_port_gsource(su_port_t *self);
00505 
00506 SOFIAPUBFUN su_socket_t su_base_port_mbox(su_port_t *self);
00507 SOFIAPUBFUN int su_base_port_send(su_port_t *self, su_msg_r rmsg);
00508 SOFIAPUBFUN int su_base_port_getmsgs(su_port_t *self);
00509 SOFIAPUBFUN int su_base_port_getmsgs_from(su_port_t *self,
00510                                            su_port_t *from);
00511 
00512 SOFIAPUBFUN void su_base_port_run(su_port_t *self);
00513 SOFIAPUBFUN void su_base_port_break(su_port_t *self);
00514 SOFIAPUBFUN su_duration_t su_base_port_step(su_port_t *self,
00515                                             su_duration_t tout);
00516 
00517 SOFIAPUBFUN int su_base_port_add_prepoll(su_port_t *self,
00518                                          su_root_t *root,
00519                                          su_prepoll_f *,
00520                                          su_prepoll_magic_t *);
00521 
00522 SOFIAPUBFUN int su_base_port_remove_prepoll(su_port_t *self, su_root_t *root);
00523 
00524 SOFIAPUBFUN su_timer_queue_t *su_base_port_timers(su_port_t *self);
00525 
00526 SOFIAPUBFUN int su_base_port_multishot(su_port_t *self, int multishot);
00527 
00528 SOFIAPUBFUN int su_base_port_start_shared(su_root_t *parent,
00529                                           su_clone_r return_clone,
00530                                           su_root_magic_t *magic,
00531                                           su_root_init_f init,
00532                                           su_root_deinit_f deinit);
00533 SOFIAPUBFUN void su_base_port_wait(su_clone_r rclone);
00534 
00535 SOFIAPUBFUN su_timer_queue_t *su_base_port_deferrable(su_port_t *self);
00536 
00537 SOFIAPUBFUN int su_base_port_max_defer(su_port_t *self,
00538                                        su_duration_t *return_duration,
00539                                        su_duration_t *set_duration);
00540 
00541 SOFIAPUBFUN int su_base_port_is_running(su_port_t const *self);
00542 
00543 /* ---------------------------------------------------------------------- */
00544 
00545 #if SU_HAVE_PTHREADS
00546 
00547 #include <pthread.h>
00548 
00550 typedef struct su_pthread_port_s {
00551   su_base_port_t   sup_base[1];
00552   struct su_pthread_port_waiting_parent
00553                   *sup_waiting_parent;
00554   pthread_t        sup_tid;
00555   pthread_mutex_t  sup_obtained[1];
00556 
00557 #if 0                           /* Pausing and resuming are not used */
00558   pthread_mutex_t  sup_runlock[1];
00559   pthread_cond_t   sup_resume[1];
00560   short            sup_paused;  
00561 #endif
00562   short            sup_thread;  
00563 } su_pthread_port_t;
00564 
00565 /* Pthread methods */
00566 
00567 SOFIAPUBFUN int su_pthread_port_init(su_port_t *, su_port_vtable_t const *);
00568 SOFIAPUBFUN void su_pthread_port_deinit(su_port_t *self);
00569 
00570 SOFIAPUBFUN void su_pthread_port_lock(su_port_t *self, char const *who);
00571 SOFIAPUBFUN void su_pthread_port_unlock(su_port_t *self, char const *who);
00572 
00573 SOFIAPUBFUN int su_pthread_port_thread(su_port_t *self,
00574                                        enum su_port_thread_op op);
00575 
00576 #if 0                           /* not yet  */
00577 SOFIAPUBFUN int su_pthread_port_send(su_port_t *self, su_msg_r rmsg);
00578 
00579 SOFIAPUBFUN su_port_t *su_pthread_port_create(void);
00580 SOFIAPUBFUN su_port_t *su_pthread_port_start(su_root_t *parent,
00581                                              su_clone_r return_clone,
00582                                              su_root_magic_t *magic,
00583                                              su_root_init_f init,
00584                                              su_root_deinit_f deinit);
00585 #endif
00586 
00587 SOFIAPUBFUN int su_pthreaded_port_start(su_port_create_f *create,
00588                                         su_root_t *parent,
00589                                         su_clone_r return_clone,
00590                                         su_root_magic_t *magic,
00591                                         su_root_init_f init,
00592                                         su_root_deinit_f deinit);
00593 
00594 SOFIAPUBFUN void su_pthread_port_wait(su_clone_r rclone);
00595 SOFIAPUBFUN int su_pthread_port_execute(su_task_r const task,
00596                                         int (*function)(void *), void *arg,
00597                                         int *return_value);
00598 
00599 #if 0
00600 SOFIAPUBFUN int su_pthread_port_pause(su_port_t *self);
00601 SOFIAPUBFUN int su_pthread_port_resume(su_port_t *self);
00602 #endif
00603 
00604 #else
00605 
00606 typedef su_base_port_t su_pthread_port_t;
00607 
00608 #define su_pthread_port_init   su_base_port_init
00609 #define su_pthread_port_deinit su_base_port_deinit
00610 #define su_pthread_port_lock   su_base_port_lock
00611 #define su_pthread_port_unlock su_base_port_unlock
00612 #define su_pthread_port_thread su_base_port_thread
00613 #define su_pthread_port_wait   su_base_port_wait
00614 #define su_pthread_port_execute  su_base_port_execute
00615 
00616 #endif
00617 
00618 /* ====================================================================== */
00619 /* Mailbox port using sockets */
00620 
00621 #define SU_MBOX_SIZE 2
00622 
00623 typedef struct su_socket_port_s {
00624   su_pthread_port_t sup_base[1];
00625   int               sup_mbox_index;
00626   su_socket_t       sup_mbox[SU_MBOX_SIZE];
00627 } su_socket_port_t;
00628 
00629 SOFIAPUBFUN int su_socket_port_init(su_socket_port_t *,
00630                                     su_port_vtable_t const *);
00631 SOFIAPUBFUN void su_socket_port_deinit(su_socket_port_t *self);
00632 SOFIAPUBFUN int su_socket_port_send(su_port_t *self, su_msg_r rmsg);
00633 SOFIAPUBFUN int su_socket_port_wakeup(su_port_t *self);
00634 
00635 SOFIA_END_DECLS
00636 
00637 #endif /* SU_PORT_H */
 All Data Structures Files Functions Variables Typedefs Enumerator Defines

Sofia-SIP 1.12.11 - Copyright (C) 2006 Nokia Corporation. All rights reserved. Licensed under the terms of the GNU Lesser General Public License.