Happy new year
[yazproxy-moved-to-github.git] / src / t-server.cpp
1 /* This file is part of YAZ proxy
2    Copyright (C) 1998-2009 Index Data
3
4 YAZ proxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include <stdlib.h>
20 #include <pthread.h>
21 #include <yaz/log.h>
22 #include <yaz/diagbib1.h>
23 #include <yaz/options.h>
24 #include "msg-thread.h"
25 #include <yazpp/z-assoc.h>
26 #include <yazpp/pdu-assoc.h>
27 #include <yazpp/gdu.h>
28 #include <yazpp/gduqueue.h>
29 #include <yazpp/socket-manager.h>
30
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 using namespace yazpp_1;
36
37 class MyServer;
38
39 class Auth_Msg : public IMsg_Thread {
40 public:
41     int m_close_flag;
42     GDU *m_gdu;
43     GDU *m_output;
44     MyServer *m_front;
45     IMsg_Thread *handle();
46     void result();
47     Auth_Msg(GDU *gdu, MyServer *front);
48     virtual ~Auth_Msg();
49 };
50
51 Auth_Msg::Auth_Msg(GDU *gdu, MyServer *front)
52 {
53     m_front = front;
54     m_output = 0;
55     m_gdu = gdu;
56     m_close_flag = 0;
57 }
58
59 Auth_Msg::~Auth_Msg()
60 {
61     delete m_output;
62     delete m_gdu;
63 }
64     
65 IMsg_Thread *Auth_Msg::handle()
66 {
67     ODR odr = odr_createmem(ODR_ENCODE);
68     yaz_log(YLOG_LOG, "Auth_Msg:handle begin");
69     Z_GDU *z_gdu = m_gdu->get();
70     if (z_gdu->which == Z_GDU_Z3950)
71     {
72         Z_APDU *apdu = 0;
73         switch(z_gdu->u.z3950->which)
74         {
75         case Z_APDU_initRequest:
76             apdu = zget_APDU(odr, Z_APDU_initResponse);
77             ODR_MASK_SET(apdu->u.initResponse->options, Z_Options_triggerResourceCtrl);
78             ODR_MASK_SET(apdu->u.initResponse->options, Z_Options_search);
79             ODR_MASK_SET(apdu->u.initResponse->options, Z_Options_present);
80             break;
81         case Z_APDU_searchRequest:
82 #if HAVE_UNISTD_H
83             sleep(5);
84 #endif
85             apdu = zget_APDU(odr, Z_APDU_searchResponse);
86             break;
87         case Z_APDU_triggerResourceControlRequest:
88             break;
89         default:
90             apdu = zget_APDU(odr, Z_APDU_close);
91             m_close_flag = 1;
92             break;
93         }
94         if (apdu)
95             m_output = new GDU(apdu);
96     }
97     yaz_log(YLOG_LOG, "Auth_Msg:handle end");
98     odr_destroy(odr);
99     return this;
100 }
101
102 class MyServer : public Z_Assoc {
103 public:
104     ~MyServer();
105     MyServer(IPDU_Observable *the_PDU_Observable,
106              Msg_Thread *m_my_thread
107         );
108     IPDU_Observer* sessionNotify(IPDU_Observable *the_PDU_Observable,
109                                  int fd);
110
111     void recv_GDU(Z_GDU *apdu, int len);
112
113     void failNotify();
114     void timeoutNotify();
115     void connectNotify();
116
117     int m_no_requests;
118     int m_delete_flag;
119 private:
120     yazpp_1::GDUQueue m_in_queue;
121     Msg_Thread *m_my_thread;
122 };
123
124 void Auth_Msg::result()
125 {
126     m_front->m_no_requests--;
127     if (!m_front->m_delete_flag)
128     {
129         if (m_output)
130         {
131             int len;
132             m_front->send_GDU(m_output->get(), &len);
133         }
134         if (m_close_flag)
135         {
136             m_front->close();
137             m_front->m_delete_flag = 1;
138         }
139     }
140     if (m_front->m_delete_flag && m_front->m_no_requests == 0)
141         delete m_front;
142     delete this;
143 }
144
145 MyServer::MyServer(IPDU_Observable *the_PDU_Observable,
146                    Msg_Thread *my_thread
147 )
148     :  Z_Assoc(the_PDU_Observable)
149 {
150     m_my_thread = my_thread;
151     m_no_requests = 0;
152     m_delete_flag = 0;
153     yaz_log(YLOG_LOG, "Construct Myserver=%p", this);
154 }
155
156 IPDU_Observer *MyServer::sessionNotify(IPDU_Observable
157                                        *the_PDU_Observable, int fd)
158 {
159     MyServer *my = new MyServer(the_PDU_Observable, m_my_thread);
160     yaz_log(YLOG_LOG, "New session %s", the_PDU_Observable->getpeername());
161     return my;
162 }
163
164 MyServer::~MyServer()
165 {
166     yaz_log(YLOG_LOG, "Destroy Myserver=%p", this);
167 }
168
169 void MyServer::recv_GDU(Z_GDU *apdu, int len)
170 {
171     GDU *gdu = new GDU(apdu);
172     Auth_Msg *m = new Auth_Msg(gdu, this);
173     m_no_requests++;
174     m_my_thread->put(m);    
175 }
176
177 void MyServer::failNotify()
178 {
179     m_delete_flag = 1;
180     if (m_no_requests == 0)
181         delete this;
182     
183 }
184
185 void MyServer::timeoutNotify()
186 {
187     m_delete_flag = 1;
188     if (m_no_requests == 0)
189         delete this;
190 }
191
192 void MyServer::connectNotify()
193 {
194
195 }
196
197 void usage(const char *prog)
198 {
199     fprintf (stderr, "%s: [-a log] [-v level] [-T] @:port\n", prog);
200     exit (1);
201 }
202
203 int main(int argc, char **argv)
204 {
205     char *arg;
206     char *prog = *argv;
207     int thread_flag = 0;
208     int ret;
209     const char *addr = "tcp:@:9999";
210     char *apdu_log = 0;
211     int no_threads = 1;
212
213     while ((ret = options("n:a:v:T", argv, argc, &arg)) != -2)
214     {
215         switch (ret)
216         {
217         case 0:
218             addr = xstrdup(arg);
219             break;
220         case 'n':
221             no_threads = atoi(arg);
222             break;
223         case 'a':
224             apdu_log = xstrdup(arg);
225             break;
226         case 'v':
227             yaz_log_init_level (yaz_log_mask_str(arg));
228             break;
229         case 'T':
230             thread_flag = 1;
231             break;
232         default:
233             usage(prog);
234             return 1;
235         }
236     }
237
238     SocketManager mySocketManager;
239
240     PDU_Assoc *my_PDU_Assoc = 0;
241     
242     MyServer *z = 0;
243
244     Msg_Thread *my_thread = new Msg_Thread(&mySocketManager, no_threads);
245
246 #if YAZ_POSIX_THREADS
247     if (thread_flag)
248         my_PDU_Assoc = new PDU_AssocThread(&mySocketManager);
249     else
250         my_PDU_Assoc = new PDU_Assoc(&mySocketManager);
251 #else
252     my_PDU_Assoc = new PDU_Assoc(&mySocketManager);
253 #endif
254     
255     z = new MyServer(my_PDU_Assoc, my_thread);
256     z->server(addr);
257     if (apdu_log)
258     {
259         yaz_log (YLOG_LOG, "set_APDU_log %s", apdu_log);
260         z->set_APDU_log(apdu_log);
261     }
262
263     while (mySocketManager.processEvent() > 0)
264         ;
265     delete z;
266     delete my_thread;
267     return 0;    
268 }
269 /*
270  * Local variables:
271  * c-basic-offset: 4
272  * indent-tabs-mode: nil
273  * End:
274  * vim: shiftwidth=4 tabstop=8 expandtab
275  */
276