]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/extra/m_ziplink.cpp
59ae89605fd2cf69959e8f61e448ed004c098ca1
[user/henk/code/inspircd.git] / src / modules / extra / m_ziplink.cpp
1 #include <string>
2 #include <vector>
3
4 #include "zlib.h"
5
6 #include "inspircd_config.h"
7 #include "configreader.h"
8 #include "users.h"
9 #include "channels.h"
10 #include "modules.h"
11
12 #include "socket.h"
13 #include "hashcomp.h"
14 #include "inspircd.h"
15
16 #include "ssl.h"
17
18 /* $ModDesc: Provides zlib link support for servers */
19 /* $LinkerFlags: -lz */
20 /* $ModDep: ssl.h */
21
22
23 enum izip_status { IZIP_WAITFIRST, IZIP_OPEN, IZIP_CLOSED };
24
25 const unsigned int CHUNK = 16384;
26
27 /** Represents an ZIP user's extra data
28  */
29 class izip_session : public classbase
30 {
31  public:
32         z_stream c_stream; /* compression stream */
33         z_stream d_stream; /* decompress stream */
34         izip_status status;
35         int fd;
36 };
37
38 class ModuleZLib : public Module
39 {
40         izip_session sessions[MAX_DESCRIPTORS];
41         
42  public:
43         
44         ModuleZLib(InspIRCd* Me)
45                 : Module::Module(Me)
46         {
47                 ServerInstance->PublishInterface("InspSocketHook", this);
48         }
49         
50         virtual ~ModuleZLib()
51         {
52         }
53
54         virtual Version GetVersion()
55         {
56                 return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
57         }
58
59         void Implements(char* List)
60         {
61                 List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1;
62                 List[I_OnRequest] = 1;
63         }
64
65         virtual char* OnRequest(Request* request)
66         {
67                 ISHRequest* ISR = (ISHRequest*)request;
68                 if (strcmp("IS_NAME", request->GetId()) == 0)
69                 {
70                         return "zip";
71                 }
72                 else if (strcmp("IS_HOOK", request->GetId()) == 0)
73                 {
74                         return ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
75                 }
76                 else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
77                 {
78                         return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
79                 }
80                 else if (strcmp("IS_HSDONE", request->GetId()) == 0)
81                 {
82                         return "OK";
83                 }
84                 else if (strcmp("IS_ATTACH", request->GetId()) == 0)
85                 {
86                         return NULL;
87                 }
88                 return NULL;
89         }
90
91
92         virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
93         {
94                 izip_session* session = &sessions[fd];
95         
96                 /* allocate deflate state */
97                 session->fd = fd;
98                 session->status = IZIP_WAITFIRST;
99
100                 session->c_stream.zalloc = (alloc_func)0;
101                 session->c_stream.zfree = (free_func)0;
102                 session->c_stream.opaque = (voidpf)0;
103
104                 if (deflateInit(&session->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
105                         return;
106
107                 session->d_stream.zalloc = (alloc_func)0;
108                 session->d_stream.zfree = (free_func)0;
109                 session->d_stream.opaque = (voidpf)0;
110
111                 if (deflateInit(&session->d_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
112                         return;
113         }
114
115         virtual void OnRawSocketConnect(int fd)
116         {
117                 OnRawSocketAccept(fd, "", 0);
118         }
119
120         virtual void OnRawSocketClose(int fd)
121         {
122                 CloseSession(&sessions[fd]);
123         }
124         
125         virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
126         {
127                 izip_session* session = &sessions[fd];
128
129                 if (session->status == IZIP_CLOSED)
130                         return 1;
131
132                 int size = 0;
133                 if (read(fd, &size, sizeof(size)) != sizeof(size))
134                         return 0;
135
136                 size = ntohl(size);
137
138                 ServerInstance->Log(DEBUG,"Size of frame to read: %d", size);
139
140                 unsigned char compr[size+1];
141
142                 readresult = read(fd, compr, size);
143
144                 if (readresult == size)
145                 {
146                         if(session->status == IZIP_WAITFIRST)
147                         {
148                                 session->status = IZIP_OPEN;
149                         }
150                                 
151                         session->d_stream.next_in  = (Bytef*)compr;
152                         session->d_stream.avail_in = 0;
153                         session->d_stream.next_out = (Bytef*)buffer;
154                         if (inflateInit(&session->d_stream) != Z_OK)
155                                 return -EBADF;
156                         session->status = IZIP_OPEN;
157
158                         while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)readresult))
159                         {
160                                 session->d_stream.avail_in = session->d_stream.avail_out = 1; /* force small buffers */
161                                 if (inflate(&session->d_stream, Z_NO_FLUSH) == Z_STREAM_END)
162                                         break;
163                         }
164
165                         inflateEnd(&session->d_stream);
166
167                         readresult = session->d_stream.total_out;
168
169                         buffer[readresult] = 0;
170
171                         ServerInstance->Log(DEBUG,"DECOMPRESSED: '%s'", buffer);
172                 }
173                 else
174                 {
175                         /* XXX: We need to buffer here, really. */
176                         if (readresult == -1)
177                         {
178                                 ServerInstance->Log(DEBUG,"Error: %s", strerror(errno));
179                                 if (errno == EAGAIN)
180                                         ServerInstance->Log(DEBUG,"(EAGAIN)");
181                         }
182                         ServerInstance->Log(DEBUG,"Didnt read whole frame, got %d bytes of %d!", readresult, size);
183                 }
184
185                 return (readresult > 0);
186         }
187
188         virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
189         {
190                 int ocount = count;
191                 ServerInstance->Log(DEBUG,"Write event of %d uncompressed bytes: '%s'", count, buffer);
192
193                 if (!count)
194                 {
195                         ServerInstance->Log(DEBUG,"Nothing to do!");
196                         return 1;
197                 }
198
199                 unsigned char compr[count*2+4];
200
201                 izip_session* session = &sessions[fd];
202
203                 if(session->status == IZIP_WAITFIRST)
204                 {
205                         session->status = IZIP_OPEN;
206                 }
207
208                 // Z_BEST_COMPRESSION
209                 if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)
210                 {
211                         ServerInstance->Log(DEBUG,"Deflate init failed");
212                 }
213
214                 if(session->status != IZIP_OPEN)
215                 {
216                         ServerInstance->Log(DEBUG,"State not open!");
217                         CloseSession(session);
218                         return 0;
219                 }
220
221                 session->c_stream.next_in  = (Bytef*)buffer;
222                 session->c_stream.next_out = compr+4;
223
224                 while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < (unsigned int)count*2))
225                 {
226                         session->c_stream.avail_in = session->c_stream.avail_out = 1; /* force small buffers */
227                         if (deflate(&session->c_stream, Z_NO_FLUSH) != Z_OK)
228                         {
229                                 ServerInstance->Log(DEBUG,"Couldnt deflate!");
230                                 CloseSession(session);
231                                 return 0;
232                         }
233                 }
234                 /* Finish the stream, still forcing small buffers: */
235                 for (;;)
236                 {
237                         session->c_stream.avail_out = 1;
238                         if (deflate(&session->c_stream, Z_FINISH) == Z_STREAM_END)
239                                 break;
240                 }
241
242                 ServerInstance->Log(DEBUG,"Write %d compressed bytes", session->c_stream.total_out);
243                 int x = htonl(session->c_stream.total_out);
244                 memcpy(compr, &x, sizeof(x));
245                 write(fd, compr, session->c_stream.total_out+4);
246
247                 deflateEnd(&session->c_stream);
248
249                 return ocount;
250         }
251         
252         void CloseSession(izip_session* session)
253         {
254                 session->status = IZIP_CLOSED;
255         }
256
257 };
258
259 class ModuleZLibFactory : public ModuleFactory
260 {
261  public:
262         ModuleZLibFactory()
263         {
264         }
265         
266         ~ModuleZLibFactory()
267         {
268         }
269         
270         virtual Module * CreateModule(InspIRCd* Me)
271         {
272                 return new ModuleZLib(Me);
273         }
274 };
275
276
277 extern "C" void * init_module( void )
278 {
279         return new ModuleZLibFactory;
280 }