6 #include "inspircd_config.h"
7 #include "configreader.h"
18 /* $ModDesc: Provides zlib link support for servers */
19 /* $LinkerFlags: -lz */
23 enum izip_status { IZIP_WAITFIRST, IZIP_OPEN, IZIP_CLOSED };
25 const unsigned int CHUNK = 16384;
27 /** Represents an ZIP user's extra data
29 class izip_session : public classbase
32 z_stream c_stream; /* compression stream */
33 z_stream d_stream; /* decompress stream */
38 class ModuleZLib : public Module
40 izip_session sessions[MAX_DESCRIPTORS];
44 ModuleZLib(InspIRCd* Me)
47 ServerInstance->PublishInterface("InspSocketHook", this);
54 virtual Version GetVersion()
56 return Version(1, 1, 0, 0, VF_VENDOR, API_VERSION);
59 void Implements(char* List)
61 List[I_OnRawSocketConnect] = List[I_OnRawSocketAccept] = List[I_OnRawSocketClose] = List[I_OnRawSocketRead] = List[I_OnRawSocketWrite] = 1;
62 List[I_OnRequest] = 1;
65 virtual char* OnRequest(Request* request)
67 ISHRequest* ISR = (ISHRequest*)request;
68 if (strcmp("IS_NAME", request->GetId()) == 0)
72 else if (strcmp("IS_HOOK", request->GetId()) == 0)
74 return ServerInstance->Config->AddIOHook((Module*)this, (InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
76 else if (strcmp("IS_UNHOOK", request->GetId()) == 0)
78 return ServerInstance->Config->DelIOHook((InspSocket*)ISR->Sock) ? (char*)"OK" : NULL;
80 else if (strcmp("IS_HSDONE", request->GetId()) == 0)
84 else if (strcmp("IS_ATTACH", request->GetId()) == 0)
92 virtual void OnRawSocketAccept(int fd, const std::string &ip, int localport)
94 izip_session* session = &sessions[fd];
96 /* allocate deflate state */
98 session->status = IZIP_WAITFIRST;
100 session->c_stream.zalloc = (alloc_func)0;
101 session->c_stream.zfree = (free_func)0;
102 session->c_stream.opaque = (voidpf)0;
104 if (deflateInit(&session->c_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
107 session->d_stream.zalloc = (alloc_func)0;
108 session->d_stream.zfree = (free_func)0;
109 session->d_stream.opaque = (voidpf)0;
111 if (deflateInit(&session->d_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
115 virtual void OnRawSocketConnect(int fd)
117 OnRawSocketAccept(fd, "", 0);
120 virtual void OnRawSocketClose(int fd)
122 CloseSession(&sessions[fd]);
125 virtual int OnRawSocketRead(int fd, char* buffer, unsigned int count, int &readresult)
127 izip_session* session = &sessions[fd];
129 if (session->status == IZIP_CLOSED)
133 if (read(fd, &size, sizeof(size)) != sizeof(size))
138 ServerInstance->Log(DEBUG,"Size of frame to read: %d", size);
140 unsigned char compr[size+1];
142 readresult = read(fd, compr, size);
144 if (readresult == size)
146 if(session->status == IZIP_WAITFIRST)
148 session->status = IZIP_OPEN;
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)
156 session->status = IZIP_OPEN;
158 while ((session->d_stream.total_out < count) && (session->d_stream.total_in < (unsigned int)readresult))
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)
165 inflateEnd(&session->d_stream);
167 readresult = session->d_stream.total_out;
169 buffer[readresult] = 0;
171 ServerInstance->Log(DEBUG,"DECOMPRESSED: '%s'", buffer);
175 /* XXX: We need to buffer here, really. */
176 if (readresult == -1)
178 ServerInstance->Log(DEBUG,"Error: %s", strerror(errno));
180 ServerInstance->Log(DEBUG,"(EAGAIN)");
182 ServerInstance->Log(DEBUG,"Didnt read whole frame, got %d bytes of %d!", readresult, size);
185 return (readresult > 0);
188 virtual int OnRawSocketWrite(int fd, const char* buffer, int count)
191 ServerInstance->Log(DEBUG,"Write event of %d uncompressed bytes: '%s'", count, buffer);
195 ServerInstance->Log(DEBUG,"Nothing to do!");
199 unsigned char compr[count*2+4];
201 izip_session* session = &sessions[fd];
203 if(session->status == IZIP_WAITFIRST)
205 session->status = IZIP_OPEN;
208 // Z_BEST_COMPRESSION
209 if (deflateInit(&session->c_stream, Z_BEST_COMPRESSION) != Z_OK)
211 ServerInstance->Log(DEBUG,"Deflate init failed");
214 if(session->status != IZIP_OPEN)
216 ServerInstance->Log(DEBUG,"State not open!");
217 CloseSession(session);
221 session->c_stream.next_in = (Bytef*)buffer;
222 session->c_stream.next_out = compr+4;
224 while ((session->c_stream.total_in < (unsigned int)count) && (session->c_stream.total_out < (unsigned int)count*2))
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)
229 ServerInstance->Log(DEBUG,"Couldnt deflate!");
230 CloseSession(session);
234 /* Finish the stream, still forcing small buffers: */
237 session->c_stream.avail_out = 1;
238 if (deflate(&session->c_stream, Z_FINISH) == Z_STREAM_END)
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);
247 deflateEnd(&session->c_stream);
252 void CloseSession(izip_session* session)
254 session->status = IZIP_CLOSED;
259 class ModuleZLibFactory : public ModuleFactory
270 virtual Module * CreateModule(InspIRCd* Me)
272 return new ModuleZLib(Me);
277 extern "C" void * init_module( void )
279 return new ModuleZLibFactory;