version 0.1.2
[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         StartListen();\r
39 \r
40         do\r
41         {\r
42                 // reset values\r
43                 highsocket=0;\r
44                 tv.tv_sec=1;\r
45                 tv.tv_usec=0;\r
46 \r
47                 // clear fd set\r
48                 FD_ZERO(&readfs);\r
49 \r
50                 // put all listen sockets on the fd set\r
51                 for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
52                 {\r
53                         FD_SET((*listeni),&readfs);\r
54                         if((*listeni)>highsocket)\r
55                         {\r
56                                 highsocket=(*listeni);\r
57                         }\r
58                 }\r
59 \r
60                 // see if any connections are waiting\r
61                 rval=select(highsocket+1,&readfs,0,0,&tv);\r
62 \r
63                 // check for new connections\r
64                 if(rval>0)\r
65                 {\r
66                         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
67                         {\r
68                                 if(FD_ISSET((*listeni),&readfs))\r
69                                 {\r
70                                         SOCKET newsock;\r
71                                         struct sockaddr_storage addr;\r
72                                         int addrlen=sizeof(addr);\r
73                                         newsock=accept((*listeni),(struct sockaddr *)&addr,&addrlen);\r
74                                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::run NNTP client connected");\r
75                                         m_connections.execute(new NNTPConnection(newsock));\r
76                                 }\r
77                         }\r
78                 }\r
79 \r
80         }while(!ZThread::Thread::interrupted() && m_listensockets.size()>0);\r
81 \r
82         // see if any threads are still running - just calling interrupt without check would cause assert in debug mode\r
83         if(m_connections.wait(1)==false)\r
84         {\r
85                 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run interrupting connection threads and waiting 60 seconds for exit.");\r
86                 try\r
87                 {\r
88                         m_connections.interrupt();\r
89                 }\r
90                 catch(...)\r
91                 {\r
92                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run caught unhandled exception.");\r
93                 }\r
94                 if(m_connections.wait(60)==false)\r
95                 {\r
96                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_DEBUG,"NNTPListener::run connection threads did not exit after 60 seconds.");\r
97                 }\r
98         }\r
99 \r
100         for(listeni=m_listensockets.begin(); listeni!=m_listensockets.end(); listeni++)\r
101         {\r
102                 #ifdef _WIN32\r
103                 closesocket((*listeni));\r
104                 #else\r
105                 close((*listeni));\r
106                 #endif\r
107         }\r
108         m_listensockets.clear();\r
109 \r
110 }\r
111 \r
112 void NNTPListener::StartListen()\r
113 {\r
114         \r
115         std::string bindaddresses;\r
116         std::vector<std::string> listenaddresses;\r
117         std::string nntpport;\r
118         if(Option::instance()->Get("NNTPListenPort",nntpport)==false)\r
119         {\r
120                 nntpport="1119";\r
121                 Option::instance()->Set("NNTPListenPort",nntpport);\r
122         }\r
123         if(Option::instance()->Get("NNTPBindAddresses",bindaddresses)==false)\r
124         {\r
125                 bindaddresses="127.0.0.1";\r
126                 Option::instance()->Set("NNTPBindAddresses",bindaddresses);\r
127         }\r
128         StringFunctions::Split(bindaddresses,",",listenaddresses);\r
129         \r
130         for(std::vector<std::string>::iterator i=listenaddresses.begin(); i!=listenaddresses.end(); i++)\r
131         {\r
132                 SOCKET sock;\r
133                 int rval;\r
134                 struct addrinfo hint,*result,*current;\r
135                 result=current=NULL;\r
136                 memset(&hint,0,sizeof(hint));\r
137                 hint.ai_socktype=SOCK_STREAM;\r
138                 hint.ai_protocol=IPPROTO_TCP;\r
139                 hint.ai_flags=AI_PASSIVE;\r
140                 \r
141                 rval=getaddrinfo((*i).c_str(),nntpport.c_str(),&hint,&result);\r
142                 if(rval==0)\r
143                 {\r
144                         for(current=result; current!=NULL; current=current->ai_next)\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                                         if(bind(sock,current->ai_addr,current->ai_addrlen)==0)\r
150                                         {\r
151                                                 if(listen(sock,10)==0)\r
152                                                 {\r
153                                                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_INFO,"NNTPListener::StartListen started listening at "+(*i)+":"+nntpport);\r
154                                                         m_listensockets.push_back(sock);\r
155                                                 }\r
156                                                 else\r
157                                                 {\r
158                                                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket listen failed");\r
159                                                         #ifdef _WIN32\r
160                                                         closesocket(sock);\r
161                                                         #else\r
162                                                         close(sock);\r
163                                                         #endif\r
164                                                 }\r
165                                         }\r
166                                         else\r
167                                         {\r
168                                                 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen socket bind failed");\r
169                                                 #ifdef _WIN32\r
170                                                 closesocket(sock);\r
171                                                 #else\r
172                                                 close(sock);\r
173                                                 #endif\r
174                                         }\r
175                                 }\r
176                                 else\r
177                                 {\r
178                                         LogFile::instance()->WriteLog(LogFile::LOGLEVEL_ERROR,"NNTPListener::StartListen couldn't create socket");\r
179                                 }\r
180                         }\r
181                 }\r
182                 if(result)\r
183                 {\r
184                         freeaddrinfo(result);\r
185                 }\r
186         }\r
187         if(m_listensockets.size()==0)\r
188         {\r
189                 LogFile::instance()->WriteLog(LogFile::LOGLEVEL_FATAL,"NNTPListener::StartListen couldn't start listening on any sockets");\r
190         }\r
191 }\r