version 0.3.29
[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/global.h"\r
5 #include "../../include/stringfunctions.h"\r
6 \r
7 #include <Poco/Net/SocketAddress.h>\r
8 \r
9 #include <cstring>\r
10 \r
11 #ifdef _WIN32\r
12         #include <winsock2.h>\r
13         #include <ws2tcpip.h>\r
14 #else\r
15         #include <netinet/in.h>  // gcc - IPPROTO_ consts\r
16         #include <netdb.h>       // gcc - addrinfo\r
17 #endif\r
18 \r
19 #ifdef XMEM\r
20         #include <xmem.h>\r
21 #endif\r
22 \r
23 NNTPListener::NNTPListener()\r
24 {\r
25 \r
26 }\r
27 \r
28 NNTPListener::~NNTPListener()\r
29 {\r
30 \r
31 }\r
32 \r
33 void NNTPListener::run()\r
34 {\r
35         int rval;\r
36         fd_set readfs;\r
37         struct timeval tv;\r
38         std::vector<SOCKET>::iterator listeni;\r
39         SOCKET highsocket;\r
40 \r
41         m_log->debug("NNTPListener::run thread started.");\r
42 \r
43         LoadDatabase();\r
44 \r
45         StartListen();\r
46 \r
47         do\r
48         {\r
49                 // reset values\r
50                 highsocket=0;\r
51                 tv.tv_sec=1;\r
52                 tv.tv_usec=0;\r
53 \r
54                 // clear fd set\r
55                 FD_ZERO(&readfs);\r
56 \r
57                 // put all listen sockets on the fd set\r
58                 for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
59                 {\r
60                         FD_SET((*listeni),&readfs);\r
61                         if((*listeni)>highsocket)\r
62                         {\r
63                                 highsocket=(*listeni);\r
64                         }\r
65                 }\r
66 \r
67                 // see if any connections are waiting\r
68                 rval=select(highsocket+1,&readfs,0,0,&tv);\r
69 \r
70                 // check for new connections\r
71                 if(rval>0)\r
72                 {\r
73                         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
74                         {\r
75                                 if(FD_ISSET((*listeni),&readfs))\r
76                                 {\r
77                                         SOCKET newsock;\r
78                                         struct sockaddr_storage addr;\r
79                                         socklen_t addrlen=sizeof(addr);\r
80                                         newsock=accept((*listeni),(struct sockaddr *)&addr,&addrlen);\r
81                                         m_log->information("NNTPListener::run NNTP client connected");\r
82                                         m_connections.Start(new NNTPConnection(newsock));\r
83                                 }\r
84                         }\r
85                 }\r
86 \r
87         }while(!IsCancelled() && m_listensockets.size()>0);\r
88 \r
89         m_connections.Cancel();\r
90         m_connections.Join();\r
91 \r
92         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
93         {\r
94                 #ifdef _WIN32\r
95                 closesocket((*listeni));\r
96                 #else\r
97                 close((*listeni));\r
98                 #endif\r
99         }\r
100         m_listensockets.clear();\r
101 \r
102         m_log->debug("NNTPListener::run thread exiting.");\r
103 \r
104 }\r
105 \r
106 void NNTPListener::StartListen()\r
107 {\r
108         \r
109         std::vector<std::string> listenaddresses;\r
110         std::string bindaddresses;      \r
111         std::string nntpport;\r
112         Option option(m_db);\r
113 \r
114         if(option.Get("NNTPListenPort",nntpport)==false)\r
115         {\r
116                 nntpport="1119";\r
117                 option.Set("NNTPListenPort",nntpport);\r
118         }\r
119         if(option.Get("NNTPBindAddresses",bindaddresses)==false)\r
120         {\r
121                 bindaddresses="127.0.0.1";\r
122                 option.Set("NNTPBindAddresses",bindaddresses);\r
123         }\r
124 \r
125         StringFunctions::Split(bindaddresses,",",listenaddresses);\r
126         \r
127         for(std::vector<std::string>::iterator i=listenaddresses.begin(); i!=listenaddresses.end(); i++)\r
128         {\r
129                 SOCKET sock;\r
130                 int rval;\r
131                 struct addrinfo hint,*result,*current;\r
132                 result=current=NULL;\r
133                 memset(&hint,0,sizeof(hint));\r
134                 hint.ai_socktype=SOCK_STREAM;\r
135                 hint.ai_protocol=IPPROTO_TCP;\r
136                 hint.ai_flags=AI_PASSIVE;\r
137 \r
138                 m_log->trace("NNTPListener::StartListen getting address info for "+(*i));\r
139                 \r
140                 rval=getaddrinfo((*i).c_str(),nntpport.c_str(),&hint,&result);\r
141                 if(rval==0)\r
142                 {\r
143                         for(current=result; current!=NULL; current=current->ai_next)\r
144                         {\r
145                                 try\r
146                                 {\r
147                                         Poco::Net::SocketAddress sa(current->ai_addr,current->ai_addrlen);\r
148 \r
149                                         m_log->debug("NNTPListener::StartListen trying to create socket, bind, and listen on "+sa.toString());\r
150 \r
151                                         sock=socket(current->ai_family,current->ai_socktype,current->ai_protocol);\r
152                                         if(sock!=INVALID_SOCKET)\r
153                                         {\r
154                                                 #ifndef _WIN32\r
155                                                 const char optval='1';\r
156                                                 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));\r
157                                                 #endif\r
158                                                 if(bind(sock,current->ai_addr,current->ai_addrlen)==0)\r
159                                                 {\r
160                                                         if(listen(sock,10)==0)\r
161                                                         {\r
162                                                                 m_log->information("NNTPListener::StartListen started listening on "+sa.toString());\r
163                                                                 m_listensockets.push_back(sock);\r
164                                                         }\r
165                                                         else\r
166                                                         {\r
167                                                                 m_log->error("NNTPListener::StartListen socket listen failed on "+sa.toString());\r
168                                                                 #ifdef _WIN32\r
169                                                                 closesocket(sock);\r
170                                                                 #else\r
171                                                                 close(sock);\r
172                                                                 #endif\r
173                                                         }\r
174                                                 }\r
175                                                 else\r
176                                                 {\r
177                                                         m_log->error("NNTPListener::StartListen socket bind failed on "+sa.toString());\r
178                                                         #ifdef _WIN32\r
179                                                         closesocket(sock);\r
180                                                         #else\r
181                                                         close(sock);\r
182                                                         #endif\r
183                                                 }\r
184                                         }\r
185                                         else\r
186                                         {\r
187                                                 m_log->error("NNTPListener::StartListen couldn't create socket on "+sa.toString());\r
188                                         }\r
189                                 }\r
190                                 catch(Poco::Exception &e)\r
191                                 {\r
192                                         m_log->error("NNTPListener::StartListen caught "+e.displayText());\r
193                                         continue;\r
194                                 }\r
195                                 catch(...)\r
196                                 {\r
197                                         m_log->error("NNTPListener::StartListen caught unknown exception");\r
198                                         continue;\r
199                                 }\r
200                         }\r
201                 }\r
202                 if(result)\r
203                 {\r
204                         freeaddrinfo(result);\r
205                 }\r
206         }\r
207         if(m_listensockets.size()==0)\r
208         {\r
209                 m_log->fatal("NNTPListener::StartListen couldn't start listening on any interfaces");\r
210         }\r
211 }\r