Updated license
[anna.git] / include / anna / ldap / Session.hpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_ldap_Session_hpp
38 #define anna_ldap_Session_hpp
39
40 #include <string>
41
42 #include <anna/core/util/SortedVector.hpp>
43
44 #include <anna/comm/Handler.hpp>
45
46 #include <anna/ldap/defines.hpp>
47 #include <anna/ldap/ClassCode.hpp>
48
49 namespace anna {
50
51 namespace xml {
52 class Node;
53 }
54
55 namespace ldap {
56
57 class Request;
58 class Response;
59 class Timer;
60 class Engine;
61 class ResultCode;
62
63 /**
64    Modela la conexion realizada contra una servidor LDAP.
65 */
66 class Session : public comm::Handler {
67 public:
68   /**
69      Define los estados en los que puede estar una sesion LDAP.
70      \see ldap::Session::getState
71   */
72   struct State {
73     enum _v {
74       Closed, /**< Cerrada */
75       WaitingBind, /**< Pendiente de confirmacion de conexion */
76       Bound /**< Conectada al servidor LDAP */
77     };
78   };
79
80   /**
81      Opciones disponibles para ajustar el comporamiento de nuestra sesion.
82      \see ldap::Session
83   */
84   struct Option {
85     /**
86        Modos de interpretar las referencias.
87        \see ldap::Session
88     */
89     struct Defer {
90       enum _v {
91         Never, /**< Valor por defecto */
92         Searching, /**< Indica que los valores son interpretados durante la busqueda, pero no cuando localiza el objeto base de la misma */
93         Finding, /**< Indica que los valores son interpretados cuando se localiza el objeto base, pero no durante la busqueda */
94         Always
95       };
96     };
97     /**
98        Determina si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias retornadas
99        por los servidores LDAP.
100        \see ldap::Session
101     */
102     struct Referral { enum _v { Off, On }; };
103   };
104
105   /**
106    * Periodo de espera por defecto para cada una de las peticiones de esta sesión.
107    */
108   static const Millisecond DefaultTimeout;
109
110   /**
111      Devuelve la direccion del servidor LDAP. Coincidira con la indicada en ldap::Engine::createSession.
112      \return La direccion del servidor LDAP. Coincidira con la indicada en ldap::Engine::createSession.
113   */
114   const std::string& getURL() const throw() { return a_url; }
115
116   /**
117      Devuelve el usuario de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
118      \return El usuario de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
119   */
120   const std::string& getUser() const throw() { return a_user; }
121
122   /**
123      Devuelve el password de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
124      \return El password de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
125   */
126   const std::string& getPassword() const throw() { return a_password; }
127
128   /**
129      Devuelve la categoria de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
130      \return La categoria de esta sesion. Coincidira con la indicada en ldap::Engine::createSession.
131   */
132   int getCategory() const throw() { return a_category; }
133
134   /**
135    * Devuelve la clave externa con la que fué creada esta sesión.
136    */
137   int getExternalID() const throw() { return a_externalID; }
138
139   /**
140      Devuelve el manejador usado para conectar con el servidor LDAP.
141      \warning Exclusivamente uso interno.
142   */
143   void* getLDAP() throw() { return a_ldap; }
144
145   /**
146    * Devuelve el fd asociado a esta sesión de LDAP.
147    * \return el fd asociado a esta sesión de LDAP.
148    * \warning Las operaciones sobre este fd podrían influir negativamente en el sistema.
149    */
150   int getDangerousFileDescriptor() const throw(RuntimeException);
151
152   /**
153      Devuelve el modo de interpretar las referencias establecido en esta sesion.
154      \return El modo de interpretar las referencias establecido en esta sesion.
155   */
156   Option::Defer::_v getDefer() const throw() { return a_defer; }
157
158   /**
159      Devuelve \em true si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias
160      retornadas por los servidores LDAP o \em false en otro caso.
161      \return \em true si la biblioteca LDAP realiza de forma automatica el siguimiento de las referencias
162      retornadas por los servidores LDAP o \em false en otro caso.
163   */
164   Option::Referral::_v getReferral() const throw() { return a_referral; }
165
166   /**
167      Devuelve el estado de esta sesion.
168      \return El estado de esta sesion.
169   */
170   State::_v getState() const throw() { return a_state; }
171
172   /**
173    * Devuelve el periodo de espera establecido para las peticiones del tipo \em v.
174    * \return el periodo de espera establecido para las peticiones del tipo \em v.
175    */
176   const Millisecond &getTimeout(const ClassCode::_v v) const throw() { return a_timeouts [v]; }
177
178   /**
179    * Devuelve el valor establecido en #setNetworkTimeout
180    * \return Los miligundos establecidos por #setNetworkTimeout.
181    * \warning El valor retornado sólo tendrá valided si #hasNetworkTimeout devolvió \em true.
182    */
183   Millisecond getNetworkTimeout() const throw() {
184     Millisecond result(1000 * a_networkTimeout.tv_sec);
185     return Millisecond(result + a_networkTimeout.tv_usec / 1000);
186   }
187
188   /**
189    * Devuelve \em true si se estableció el tiempo de espera de conexión o \em false en otro caso.
190    * \return \em true si se estableció el tiempo de espera de conexión o \em false en otro caso.
191    */
192   bool hasNetworkTimeout() const throw() { return a_networkTimeout.tv_sec != -1; }
193
194   /**
195      Solicita la conexion al servidor asociado a esta sesion.
196
197      \warning Solo deberia invocarse directamente este metodo en caso de que el #eventResponse
198      notifique no ha sido posible contactar con el servidor indicado.
199   */
200   void bind() throw(RuntimeException);
201
202   /**
203      Devuelve \em true si la sesion esta conectada al servidor LDAP o \em false en otro caso.
204      \return \em true si la sesion esta conectada al servidor LDAP o \em false en otro caso.
205   */
206   bool isBound() const throw() { return a_state == State::Bound; }
207
208   /**
209      Establece el modo de interpretar las referencias.
210      \param defer Indica el modo de interpretar las referencias.
211   */
212   void setOption(const Option::Defer::_v defer) throw() { a_defer = defer; }
213
214   /**
215      Establece el modo en que la biblioteca LDAP actua a la hora de realizar el siguimiento de las referencias.
216      \param referral Indica el modo de realizar el seguimiento de las referncias.
217   */
218   void setOption(const Option::Referral::_v referral) throw() { a_referral = referral; }
219
220   /**
221    * Establece el periodo de tiempo máximo que esperará la conexión a un servidor LDAP antes de considerar que
222    * éste no es alcanzable.
223    *
224    * \param timeout Milisegundos que esperará la conexión a un servidor LDAP antes de considerar que no es alcanzable.
225    *
226    * \see http://manpages.courier-mta.org/htmlman3/ldap_get_option.3.html
227    * \warning Sólo tiene efecto antes de invocar al #bind, por lo que habrá que desactivar la auto conexión, para establecer el valor.
228    */
229   void setNetworkTimeout(const Millisecond &timeout) throw() { a_networkTimeout.tv_sec = timeout / 1000; a_networkTimeout.tv_usec = (timeout % 1000) * 1000; }
230
231   /**
232    * Elimina el tiempo asignado en #setNetworkTimeout.
233    *
234    * \see http://manpages.courier-mta.org/htmlman3/ldap_get_option.3.html
235    * \warning Sólo tiene efecto antes de invocar al #bind
236    */
237   void clearNetworkTimeout() throw() { a_networkTimeout.tv_sec = -1; a_networkTimeout.tv_usec = 0; }
238
239   /**
240      Establece el tiempo de espera maximo antes de considerar fallida una peticion LDAP.
241      \param v Tipo de peticion LDAP.
242      \param millisecond Milisegundos esperados antes de considerar fallida la peticion LDAP.
243
244      Los temporizadores correspondientes las peticiones LDAP se activaran automaticamente al
245      invocar a los distintos métodos de esta clase.
246   */
247   void setTimeout(const ClassCode::_v v, const Millisecond &millisecond) throw() { a_timeouts [v] = millisecond;  }
248
249   /**
250      Envia la peticion recibida como parametro al servidor con el que estamos conectados mediante esta
251      sesion LDAP.
252
253      Una vez enviada la peticion se activara automaticamente un temporizador. Si este llegara a caducar
254      se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido
255      un error de temporización. La duracion del temporizador sera la establecida por
256      ldap::TimerManager::setTimeout o el valor defecto.
257
258      \param request Peticion a enviar al servidor LDAP con el que estamos conectados.
259      \return La instancia de la respuesta LDAP asociada la peticion realizada.
260      \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true.
261   */
262   const Response* send(const Request* request) throw(RuntimeException);
263
264   /**
265      Envia la peticion recibida como parametro al servidor con el que estamos conectados mediante esta
266      sesion LDAP.
267
268      Una vez enviada la peticion se activara automaticamente un temporizador. Si este llegara a caducar
269      se cancelara la busqueda y se invocara al metodo Session::eventResponse indicado que se ha producido
270      un error de temporización. La duracion del temporizador sera la establecida por
271      ldap::TimerManager::setTimeout o el valor defecto.
272
273      \param request Peticion a enviar al servidor LDAP con el que estamos conectados.
274      \return La instancia de la respuesta LDAP asociada la peticion realizada.
275      \warning Solo se podra hacer uso de este metodo cuando el metodo #isBound devuelva \em true.
276   */
277   const Response* send(const Request& request) throw(RuntimeException) { return send(&request); }
278
279   /**
280    * Desconecta este cliente LDAP del servidor LDAP.
281    * Se notifica la terminación de cada una de las peticiones pendientes invocando al método Session::eventResponse
282    * indicando un error y se cancelan en el servidor LDAP.
283    * \warning Después de invocar a este método habría que volver a invocar a ldap::Session::bind y esperar la conexión
284    * antes de volver a usar esta sessión.
285    */
286   void unbind() throw(RuntimeException);
287
288   /**
289      Devuelve una cadena con la informacion relevante sobre esta instancia.
290      \return Una cadena con la informacion relevante sobre esta instancia.
291   */
292   std::string asString() const throw();
293
294   /**
295      Devuelve un documento XML con la informacion relevante sobre esta instancia.
296      \param parent Nodo XML del que colgar la informacion referente a esta instancia.
297      \return Un documento XML con la informacion relevante sobre esta instancia.
298   */
299   xml::Node* asXML(xml::Node* parent) const throw();
300
301 protected:
302   /**
303      Constructor.
304      \see ldap::Engine::createSession
305   */
306   Session();
307
308   /**
309      Metodo-manejador que informa de que el servidor LDAP con el que estaba conectado esta sesion
310      ha dejado de dar servicio.
311
312      Una vez que se ha notificado la caida de la sesion, el nucleo de ANNA.ldap genera un
313      ldap::Session::eventResponse para cada una de las peticiones que hay pendientes de contestar.
314   */
315   virtual void eventServerShutdown() throw() {;}
316
317   /**
318      Metodo-manejador de las respuestas provenientes del servidor LDAP.
319
320      \param response Objeto que contiene la respuesta correspondiente a la peticion LDAP realizada.
321   */
322   virtual void eventResponse(const Response& response) throw(RuntimeException) = 0;
323
324   /**
325      Metodo-manejador de los errores provenientes del servidor LDAP.
326      \param resultCode Instancia que contiene la información sobre el error recibido.
327      \param disconnect Incicador que informa al nivel de aplicación sobre cómo actuará la ANNA.ldap
328      para recuperar este error, si vale \em true la conexión se cerrará o \em false en otro caso.
329   */
330   virtual void eventResponseError(const ResultCode& resultCode, const bool disconnect) throw() {;}
331
332   /**
333    * Método-manejador que se invoca cuando alguno de los mensajes intermedios requeridos para formar
334    * la contestación completa no se puede interpretar correctamente.
335    *
336      \param response Objeto que contiene la respuesta correspondiente a la peticion LDAP realizada.
337    */
338   virtual void eventIntermediateResponseError(const Response& response) throw() {;}
339
340 private:
341   struct SortById {
342     static IdMessage value(const Response*) throw();
343   };
344   typedef SortedVector <Response, SortById, IdMessage> response_container;
345   typedef response_container::iterator response_iterator;
346   typedef response_container::const_iterator const_response_iterator;
347
348   typedef void* HandleLDAP;
349   typedef void* HandleMessage;
350
351   int a_category;
352   HandleLDAP a_ldap;
353   State::_v a_state;
354   std::string a_url;
355   std::string a_user;
356   std::string a_password;
357   Option::Defer::_v a_defer;
358   Option::Referral::_v a_referral;
359   response_container a_responses;
360   int a_externalID;
361   Millisecond a_timeouts [ClassCode::Max];
362   struct timeval a_networkTimeout;
363
364   /* Dependiendo de cómo se cree la sesión este miembro puede ser una copia de a_user
365    * o el identificador numérico que pasaron como parámetro al crear la sesión
366    */
367   std::string a_keymap;
368
369   void apply() throw(RuntimeException);
370   void receiveBind(const IdMessage, HandleMessage) throw(RuntimeException);
371   void receiveEntry(const IdMessage, HandleMessage) throw(RuntimeException);
372   void receiveReference(const IdMessage, HandleMessage) throw(RuntimeException);
373   void receiveResult(const IdMessage, HandleMessage) throw(RuntimeException);
374   void expireResponse(Response*) throw();
375
376   void finalize() throw();
377
378   response_iterator response_begin() throw() { return a_responses.begin(); }
379   response_iterator response_end() throw() { return a_responses.end(); }
380   void response_add(Response* response) throw();
381   void response_erase(Response* response) throw();
382   Response* response_find(const IdMessage idMessage) throw(RuntimeException);
383
384   static Response* response(response_iterator ii) throw() { return response_container::data(ii); }
385
386   const_response_iterator response_begin() const throw() { return a_responses.begin(); }
387   const_response_iterator response_end() const throw() { return a_responses.end(); }
388   static const Response* response(const_response_iterator ii) throw() { return response_container::data(ii); }
389
390   static const char* asText(const State::_v) throw();
391
392   friend class Timer;
393   friend class Engine;
394 };
395
396 }
397 }
398
399 #endif
400