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