version 0.1.9
[fms.git] / src / nntp / nntplistener.cpp
1 #include "../../include/nntp/nntplistener.h"\r
2 #include "../../include/nntp/nntpconnection.h"\r
3 #include "../../include/option.h"\r
4 #include "../../include/logfile.h"\r
5 #include "../../include/global.h"\r
6 #include "../../include/stringfunctions.h"\r
7 \r
8 #ifdef _WIN32\r
9         #include <winsock2.h>\r
10         #include <ws2tcpip.h>\r
11 #else\r
12         #include <netinet/in.h>  // gcc - IPPROTO_ consts\r
13         #include <netdb.h>       // gcc - addrinfo\r
14 #endif\r
15 \r
16 #ifdef XMEM\r
17         #include <xmem.h>\r
18 #endif\r
19 \r
20 NNTPListener::NNTPListener()\r
21 {\r
22 \r
23 }\r
24 \r
25 NNTPListener::~NNTPListener()\r
26 {\r
27 \r
28 }\r
29 \r
30 void NNTPListener::Run()\r
31 {\r
32         int rval;\r
33         fd_set readfs;\r
34         struct timeval tv;\r
35         std::vector<SOCKET>::iterator listeni;\r
36         SOCKET highsocket;\r
37 \r
38         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run thread started.");\r
39 \r
40         StartListen();\r
41 \r
42         do\r
43         {\r
44                 // reset values\r
45                 highsocket=0;\r
46                 tv.tv_sec=1;\r
47                 tv.tv_usec=0;\r
48 \r
49                 // clear fd set\r
50                 FD_ZERO(&readfs);\r
51 \r
52                 // put all listen sockets on the fd set\r
53                 for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
54                 {\r
55                         FD_SET((*listeni),&readfs);\r
56                         if((*listeni)>highsocket)\r
57                         {\r
58                                 highsocket=(*listeni);\r
59                         }\r
60                 }\r
61 \r
62                 // see if any connections are waiting\r
63                 rval=select(highsocket+1,&readfs,0,0,&tv);\r
64 \r
65                 // check for new connections\r
66                 if(rval>0)\r
67                 {\r
68                         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
69                         {\r
70                                 if(FD_ISSET((*listeni),&readfs))\r
71                                 {\r
72                                         SOCKET newsock;\r
73                                         struct sockaddr_storage addr;\r
74                                         socklen_t addrlen=sizeof(addr);\r
75                                         newsock=accept((*listeni),(struct sockaddr *)&addr,&addrlen);\r
76                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::run NNTP client connected");\r
77                                         //m_connections.execute(new NNTPConnection(newsock));\r
78                                         //m_connectionthreads.push_back(new PThread::Thread(new NNTPConnection(newsock)));\r
79                                         m_connections.Execute(new NNTPConnection(newsock));\r
80                                 }\r
81                         }\r
82                 }\r
83 /*\r
84                 // check for any non-running connection threads that we can delete\r
85                 for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); )\r
86                 {\r
87                         if((*i)->IsRunning()==false)\r
88                         {\r
89                                 delete (*i);\r
90                                 i=m_connectionthreads.erase(i);\r
91                         }\r
92                         if(i!=m_connectionthreads.end())\r
93                         {\r
94                                 i++;\r
95                         }\r
96                 }\r
97 */\r
98 \r
99         //}while(!ZThread::Thread::interrupted() && m_listensockets.size()>0);\r
100         }while(!IsCancelled() && m_listensockets.size()>0);\r
101 \r
102         // see if any threads are still running - just calling interrupt without check would cause assert in debug mode\r
103         /*\r
104         if(m_connections.wait(1)==false)\r
105         {\r
106                 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run interrupting connection threads and waiting 60 seconds for exit.");\r
107                 try\r
108                 {\r
109                         m_connections.interrupt();\r
110                 }\r
111                 catch(...)\r
112                 {\r
113                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run caught unhandled exception.");\r
114                 }\r
115                 if(m_connections.wait(60000)==false)\r
116                 {\r
117                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run connection threads did not exit after 60 seconds.");\r
118                 }\r
119         }\r
120         */\r
121         /*\r
122         for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); i++)\r
123         {\r
124                 if((*i)->IsRunning())\r
125                 {\r
126                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::Run waiting for connection thread to exit.");\r
127                         (*i)->Cancel();\r
128                         (*i)->Join();\r
129                 }\r
130                 delete (*i);\r
131         }\r
132         */\r
133         m_connections.Cancel();\r
134         m_connections.Join();\r
135 \r
136         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
137         {\r
138                 #ifdef _WIN32\r
139                 closesocket((*listeni));\r
140                 #else\r
141                 close((*listeni));\r
142                 #endif\r
143         }\r
144         m_listensockets.clear();\r
145 \r
146         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run thread exiting.");\r
147 \r
148 }\r
149 \r
150 void NNTPListener::StartListen()\r
151 {\r
152         \r
153         std::string bindaddresses;\r
154         std::vector<std::string> listenaddresses;\r
155         std::string nntpport;\r
156         if(Option::Instance()->Get("NNTPListenPort",nntpport)==false)\r
157         {\r
158                 nntpport="1119";\r
159                 Option::Instance()->Set("NNTPListenPort",nntpport);\r
160         }\r
161         if(Option::Instance()->Get("NNTPBindAddresses",bindaddresses)==false)\r
162         {\r
163                 bindaddresses="127.0.0.1";\r
164                 Option::Instance()->Set("NNTPBindAddresses",bindaddresses);\r
165         }\r
166         StringFunctions::Split(bindaddresses,",",listenaddresses);\r
167         \r
168         for(std::vector<std::string>::iterator i=listenaddresses.begin(); i!=listenaddresses.end(); i++)\r
169         {\r
170                 SOCKET sock;\r
171                 int rval;\r
172                 struct addrinfo hint,*result,*current;\r
173                 result=current=NULL;\r
174                 memset(&hint,0,sizeof(hint));\r
175                 hint.ai_socktype=SOCK_STREAM;\r
176                 hint.ai_protocol=IPPROTO_TCP;\r
177                 hint.ai_flags=AI_PASSIVE;\r
178                 \r
179                 rval=getaddrinfo((*i).c_str(),nntpport.c_str(),&hint,&result);\r
180                 if(rval==0)\r
181                 {\r
182                         for(current=result; current!=NULL; current=current->ai_next)\r
183                         {\r
184                                 sock=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
185                                 if(sock!=INVALID_SOCKET)\r
186                                 {\r
187                                         if(bind(sock,current->ai_addr,current->ai_addrlen)==0)\r
188                                         {\r
189                                                 if(listen(sock,10)==0)\r
190                                                 {\r
191                                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::StartListen started listening at "+(*i)+":"+nntpport);\r
192                                                         m_listensockets.push_back(sock);\r
193                                                 }\r
194                                                 else\r
195                                                 {\r
196                                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket listen failed");\r
197                                                         #ifdef _WIN32\r
198                                                         closesocket(sock);\r
199                                                         #else\r
200                                                         close(sock);\r
201                                                         #endif\r
202                                                 }\r
203                                         }\r
204                                         else\r
205                                         {\r
206                                                 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket bind failed");\r
207                                                 #ifdef _WIN32\r
208                                                 closesocket(sock);\r
209                                                 #else\r
210                                                 close(sock);\r
211                                                 #endif\r
212                                         }\r
213                                 }\r
214                                 else\r
215                                 {\r
216                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen couldn't create socket");\r
217                                 }\r
218                         }\r
219                 }\r
220                 if(result)\r
221                 {\r
222                         freeaddrinfo(result);\r
223                 }\r
224         }\r
225         if(m_listensockets.size()==0)\r
226         {\r
227                 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_FATAL,"NNTPListener::StartListen couldn't start listening on any sockets");\r
228         }\r
229 }\r