version 0.1.3
[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                                 }\r
80                         }\r
81                 }\r
82 \r
83                 // check for any non-running connection threads that we can delete\r
84                 for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); )\r
85                 {\r
86                         if((*i)->IsRunning()==false)\r
87                         {\r
88                                 delete (*i);\r
89                                 i=m_connectionthreads.erase(i);\r
90                         }\r
91                         if(i!=m_connectionthreads.end())\r
92                         {\r
93                                 i++;\r
94                         }\r
95                 }\r
96 \r
97         //}while(!ZThread::Thread::interrupted() && m_listensockets.size()>0);\r
98         }while(!IsCancelled() && m_listensockets.size()>0);\r
99 \r
100         // see if any threads are still running - just calling interrupt without check would cause assert in debug mode\r
101         /*\r
102         if(m_connections.wait(1)==false)\r
103         {\r
104                 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run interrupting connection threads and waiting 60 seconds for exit.");\r
105                 try\r
106                 {\r
107                         m_connections.interrupt();\r
108                 }\r
109                 catch(...)\r
110                 {\r
111                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run caught unhandled exception.");\r
112                 }\r
113                 if(m_connections.wait(60000)==false)\r
114                 {\r
115                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run connection threads did not exit after 60 seconds.");\r
116                 }\r
117         }\r
118         */\r
119         for(std::vector<PThread::Thread *>::iterator i=m_connectionthreads.begin(); i!=m_connectionthreads.end(); i++)\r
120         {\r
121                 if((*i)->IsRunning())\r
122                 {\r
123                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::Run waiting for connection thread to exit.");\r
124                         (*i)->Cancel();\r
125                         (*i)->Join();\r
126                 }\r
127                 delete (*i);\r
128         }\r
129 \r
130         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
131         {\r
132                 #ifdef _WIN32\r
133                 closesocket((*listeni));\r
134                 #else\r
135                 close((*listeni));\r
136                 #endif\r
137         }\r
138         m_listensockets.clear();\r
139 \r
140 }\r
141 \r
142 void NNTPListener::StartListen()\r
143 {\r
144         \r
145         std::string bindaddresses;\r
146         std::vector<std::string> listenaddresses;\r
147         std::string nntpport;\r
148         if(Option::Instance()->Get("NNTPListenPort",nntpport)==false)\r
149         {\r
150                 nntpport="1119";\r
151                 Option::Instance()->Set("NNTPListenPort",nntpport);\r
152         }\r
153         if(Option::Instance()->Get("NNTPBindAddresses",bindaddresses)==false)\r
154         {\r
155                 bindaddresses="127.0.0.1";\r
156                 Option::Instance()->Set("NNTPBindAddresses",bindaddresses);\r
157         }\r
158         StringFunctions::Split(bindaddresses,",",listenaddresses);\r
159         \r
160         for(std::vector<std::string>::iterator i=listenaddresses.begin(); i!=listenaddresses.end(); i++)\r
161         {\r
162                 SOCKET sock;\r
163                 int rval;\r
164                 struct addrinfo hint,*result,*current;\r
165                 result=current=NULL;\r
166                 memset(&hint,0,sizeof(hint));\r
167                 hint.ai_socktype=SOCK_STREAM;\r
168                 hint.ai_protocol=IPPROTO_TCP;\r
169                 hint.ai_flags=AI_PASSIVE;\r
170                 \r
171                 rval=getaddrinfo((*i).c_str(),nntpport.c_str(),&hint,&result);\r
172                 if(rval==0)\r
173                 {\r
174                         for(current=result; current!=NULL; current=current->ai_next)\r
175                         {\r
176                                 sock=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
177                                 if(sock!=INVALID_SOCKET)\r
178                                 {\r
179                                         if(bind(sock,current->ai_addr,current->ai_addrlen)==0)\r
180                                         {\r
181                                                 if(listen(sock,10)==0)\r
182                                                 {\r
183                                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::StartListen started listening at "+(*i)+":"+nntpport);\r
184                                                         m_listensockets.push_back(sock);\r
185                                                 }\r
186                                                 else\r
187                                                 {\r
188                                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket listen failed");\r
189                                                         #ifdef _WIN32\r
190                                                         closesocket(sock);\r
191                                                         #else\r
192                                                         close(sock);\r
193                                                         #endif\r
194                                                 }\r
195                                         }\r
196                                         else\r
197                                         {\r
198                                                 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket bind failed");\r
199                                                 #ifdef _WIN32\r
200                                                 closesocket(sock);\r
201                                                 #else\r
202                                                 close(sock);\r
203                                                 #endif\r
204                                         }\r
205                                 }\r
206                                 else\r
207                                 {\r
208                                         LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen couldn't create socket");\r
209                                 }\r
210                         }\r
211                 }\r
212                 if(result)\r
213                 {\r
214                         freeaddrinfo(result);\r
215                 }\r
216         }\r
217         if(m_listensockets.size()==0)\r
218         {\r
219                 LogFile::Instance()->WriteLog(LogFile::LOGLEVEL_FATAL,"NNTPListener::StartListen couldn't start listening on any sockets");\r
220         }\r
221 }\r