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