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