]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socketengines/socketengine_iocp.cpp
Fix Extend usage and a few other things for latest API. Compiles but not tested.
[user/henk/code/inspircd.git] / src / socketengines / socketengine_iocp.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /*       +------------------------------------+
15  *       | Inspire Internet Relay Chat Daemon |
16  *       +------------------------------------+
17  *
18  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
19  * See: http://wiki.inspircd.org/Credits
20  *
21  * This program is free but copyrighted software; see
22  *          the file COPYING for details.
23  *
24  * ---------------------------------------------------
25  */
26
27 #ifndef __SOCKETENGINE_IOCP__
28 #define __SOCKETENGINE_IOCP__
29
30 #define READ_BUFFER_SIZE 600
31 #define USING_IOCP 1
32
33 #include "inspircd_config.h"
34 #include "inspircd_win32wrapper.h"
35 #include "inspircd.h"
36 #include "socketengine.h"
37
38 /** Socket overlapped event types
39  */
40 enum SocketIOEvent
41 {
42         /** Read ready */
43         SOCKET_IO_EVENT_READ_READY                      = 0,
44         /** Write ready */
45         SOCKET_IO_EVENT_WRITE_READY                     = 1,
46         /** Accept ready */
47         SOCKET_IO_EVENT_ACCEPT                          = 2,
48         /** Error occured */
49         SOCKET_IO_EVENT_ERROR                           = 3,
50         /** Number of events */
51         NUM_SOCKET_IO_EVENTS                            = 4,
52 };
53
54 /** Represents a windows overlapped IO event
55  */
56 class Overlapped
57 {
58  public:
59         /** Overlap event */
60         OVERLAPPED m_overlap;
61         /** Type of event */
62         SocketIOEvent m_event;
63 #ifdef WIN64
64         /** Parameters */
65         unsigned __int64 m_params;
66 #else
67         /** Parameters */
68         unsigned long m_params;
69 #endif
70         /** Create an overlapped event
71          */
72         Overlapped(SocketIOEvent ev, int params) : m_event(ev), m_params(params)
73         {
74                 memset(&m_overlap, 0, sizeof(OVERLAPPED));
75         }
76 };
77
78 /** Specific to UDP sockets with overlapped IO
79  */
80 struct udp_overlap
81 {
82         unsigned char udp_buffer[600];
83         unsigned long udp_len;
84         sockaddr udp_sockaddr[2];
85         unsigned long udp_sockaddr_len;
86 };
87
88 /** Specific to accepting sockets with overlapped IO
89  */
90 struct accept_overlap
91 {
92         int socket;
93         char buf[1024];
94 };
95
96 /** Implementation of SocketEngine that implements windows IO Completion Ports
97  */
98 class IOCPEngine : public SocketEngine
99 {
100         /** Creates a "fake" file descriptor for use with an IOCP socket.
101          * This is a little slow, but it isnt called too much. We'll fix it
102          * in a future release.
103          * @return -1 if there are no free slots, and an integer if it finds one.
104          */
105         __inline int GenerateFd(int RealFd)
106         {
107                 int index_hash = RealFd % MAX_DESCRIPTORS;
108                 if(ref[index_hash] == 0)
109                         return index_hash;
110                 else
111                 {
112                         register int i = 0;
113                         for(; i < MAX_DESCRIPTORS; ++i)
114                                 if(ref[i] == 0)
115                                         return i;
116                 }
117                 return -1;
118         }
119
120         /** Global I/O completion port that sockets attach to.
121          */
122         HANDLE m_completionPort;
123
124         /** This is kinda shitty... :/ for getting an address from a real fd.
125          */
126         std::map<int, EventHandler*> m_binding;
127
128         LocalIntExt fdExt;
129         LocalIntExt readExt;
130         LocalIntExt writeExt;
131         LocalIntExt acceptExt;
132
133 public:
134         /** Holds the preallocated buffer passed to WSARecvFrom
135          * function. Yes, I know, it's a dirty hack.
136          */
137         udp_overlap * udp_ov;
138
139         /** Creates an IOCP Socket Engine
140          * @param Instance The creator of this object
141          */
142         IOCPEngine();
143
144         /** Deletes an IOCP socket engine and all the attached sockets
145          */
146         ~IOCPEngine();
147
148         /** Adds an event handler to the completion port, and sets up initial events.
149          * @param eh EventHandler to add
150          * @return True if success, false if no room
151          */
152         bool AddFd(EventHandler* eh, int event_mask);
153
154         /** Gets the maximum number of file descriptors that this engine can handle.
155          * @return The number of file descriptors
156          */
157         __inline int GetMaxFds() { return MAX_DESCRIPTORS; }
158
159         /** Gets the number of free/remaining file descriptors under this engine.
160          * @return Remaining count
161          */
162         __inline int GetRemainingFds()
163         {
164                 register int count = 0;
165                 register int i = 0;
166                 for(; i < MAX_DESCRIPTORS; ++i)
167                         if(ref[i] == 0)
168                                 ++count;
169                 return count;
170         }
171
172         /** Removes a file descriptor from the set, preventing it from receiving any more events
173          * @return True if remove was successful, false otherwise
174          */
175         bool DelFd(EventHandler* eh, bool force = false);
176
177         /** Called every loop to handle input/output events for all sockets under this engine
178          * @return The number of "changed" sockets.
179          */
180         int DispatchEvents();
181
182         /** Gets the name of this socket engine as a string.
183          * @return string of socket engine name
184          */
185         std::string GetName();
186
187         void OnSetEvent(EventHandler* eh, int old_mask, int new_mask);
188
189         /** Posts a completion event on the specified socket.
190          * @param eh EventHandler for message
191          * @param type Event Type
192          * @param param Event Parameter
193          * @return True if added, false if not
194          */
195         bool PostCompletionEvent(EventHandler* eh, SocketIOEvent type, int param);
196
197         /** Posts a read event on the specified socket
198          * @param eh EventHandler (socket)
199          */
200         void PostReadEvent(EventHandler* eh);
201
202         /** Posts an accept event on the specified socket
203          * @param eh EventHandler (socket)
204          */
205         void PostAcceptEvent(EventHandler* eh);
206
207         /** Returns the EventHandler attached to a specific fd.
208          * If the fd isnt in the socketengine, returns NULL.
209          * @param fd The event handler to look for
210          * @return A pointer to the event handler, or NULL
211          */
212         EventHandler* GetRef(int fd);
213
214         /** Returns true if a file descriptor exists in
215          * the socket engine's list.
216          * @param fd The event handler to look for
217          * @return True if this fd has an event handler
218          */
219         bool HasFd(int fd);
220
221         /** Returns the EventHandler attached to a specific fd.
222          * If the fd isnt in the socketengine, returns NULL.
223          * @param fd The event handler to look for
224          * @return A pointer to the event handler, or NULL
225          */
226         EventHandler* GetIntRef(int fd);
227
228         bool BoundsCheckFd(EventHandler* eh);
229
230         virtual int Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen);
231
232         virtual int RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
233
234         virtual int Blocking(int fd);
235
236         virtual int NonBlocking(int fd);
237
238         virtual int GetSockName(EventHandler* fd, sockaddr *name, socklen_t* namelen);
239
240         virtual int Close(int fd);
241
242         virtual int Close(EventHandler* fd);
243 };
244
245 #endif
246
247 #include "exitcodes.h"
248 #include <mswsock.h>
249
250 IOCPEngine::IOCPEngine()
251 : fdExt("internal_fd", NULL),
252   readExt("windows_readevent", NULL),
253   writeExt("windows_writeevent", NULL),
254   acceptExt("windows_acceptevent", NULL)
255 {
256         MAX_DESCRIPTORS = 10240;
257
258         /* Create completion port */
259         m_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0);
260
261         if (!m_completionPort)
262         {
263                 ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.");
264                 ServerInstance->Logs->Log("SOCKET",DEFAULT, "ERROR: this is a fatal error, exiting now.");
265                 printf("ERROR: Could not initialize socket engine. Your kernel probably does not have the proper features.\n");
266                 printf("ERROR: this is a fatal error, exiting now.\n");
267                 ServerInstance->Exit(EXIT_STATUS_SOCKETENGINE);
268         }
269
270         /* Null variables out. */
271         CurrentSetSize = 0;
272         MAX_DESCRIPTORS = 10240;
273         ref = new EventHandler* [10240];
274         memset(ref, 0, sizeof(EventHandler*) * MAX_DESCRIPTORS);
275 }
276
277 IOCPEngine::~IOCPEngine()
278 {
279         /* Clean up winsock and close completion port */
280         CloseHandle(m_completionPort);
281         WSACleanup();
282         delete[] ref;
283 }
284
285 bool IOCPEngine::AddFd(EventHandler* eh, int event_mask)
286 {
287         /* Does it at least look valid? */
288         if (!eh)
289                 return false;
290
291         int* fake_fd = new int(GenerateFd(eh->GetFd()));
292         int is_accept = 0;
293         int opt_len = sizeof(int);
294
295         /* In range? */
296         if ((*fake_fd < 0) || (*fake_fd > MAX_DESCRIPTORS))
297         {
298                 delete fake_fd;
299                 return false;
300         }
301
302         /* Already an entry here */
303         if (ref[*fake_fd])
304         {
305                 delete fake_fd;
306                 return false;
307         }
308
309         /* are we a listen socket? */
310         getsockopt(eh->GetFd(), SOL_SOCKET, SO_ACCEPTCONN, (char*)&is_accept, &opt_len);
311
312         /* set up the read event so the socket can actually receive data :P */
313         fdExt.set(eh, *fake_fd);
314
315         unsigned long completion_key = (ULONG_PTR)*fake_fd;
316         /* assign the socket to the completion port */
317         if (!CreateIoCompletionPort((HANDLE)eh->GetFd(), m_completionPort, completion_key, 0))
318                 return false;
319
320         /* setup initial events */
321         if(is_accept)
322                 PostAcceptEvent(eh);
323         else
324                 PostReadEvent(eh);
325
326         /* log message */
327         ServerInstance->Logs->Log("SOCKET",DEBUG, "New fake fd: %u, real fd: %u, address 0x%p", *fake_fd, eh->GetFd(), eh);
328
329         /* post a write event if there is data to be written */
330         if (event_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE))
331                 OnSetEvent(eh, event_mask, event_mask);
332
333         /* we're all good =) */
334         try
335         {
336                 m_binding.insert( std::map<int, EventHandler*>::value_type( eh->GetFd(), eh ) );
337         }
338         catch (...)
339         {
340                 /* Ohshi-, map::insert failed :/ */
341                 return false;
342         }
343
344         ++CurrentSetSize;
345         SocketEngine::SetEventMask(eh, event_mask);
346         ref[*fake_fd] = eh;
347
348         return true;
349 }
350
351 bool IOCPEngine::DelFd(EventHandler* eh, bool force /* = false */)
352 {
353         if (!eh)
354                 return false;
355
356         int* fake_fd = (int*)fdExt.get(eh);
357
358         if (!fake_fd)
359                 return false;
360
361         int fd = eh->GetFd();
362
363         void* m_readEvent = (void*)readExt.get(eh);
364         void* m_writeEvent = (void*)writeExt.get(eh);
365         void* m_acceptEvent = (void*)acceptExt.get(eh);
366
367         ServerInstance->Logs->Log("SOCKET",DEBUG, "Removing fake fd %u, real fd %u, address 0x%p", *fake_fd, eh->GetFd(), eh);
368
369         /* Cancel pending i/o operations. */
370         if (CancelIo((HANDLE)fd) == FALSE)
371                 return false;
372
373         /* Free the buffer, and delete the event. */
374         if (m_readEvent)
375         {
376                 if(((Overlapped*)m_readEvent)->m_params != 0)
377                         delete ((udp_overlap*)((Overlapped*)m_readEvent)->m_params);
378
379                 delete ((Overlapped*)m_readEvent);
380                 readExt.free(eh);
381         }
382
383         if(m_writeEvent)
384         {
385                 delete ((Overlapped*)m_writeEvent);
386                 writeExt.free(eh);
387         }
388
389         if(m_acceptEvent)
390         {
391                 delete ((accept_overlap*)((Overlapped*)m_acceptEvent)->m_params);
392                 delete ((Overlapped*)m_acceptEvent);
393                 acceptExt.free(eh);
394         }
395
396         /* Clear binding */
397         ref[*fake_fd] = 0;
398         m_binding.erase(eh->GetFd());
399
400         delete fake_fd;
401         fdExt.free(eh);
402
403         /* decrement set size */
404         --CurrentSetSize;
405
406         /* success */
407         return true;
408 }
409
410 void IOCPEngine::OnSetEvent(EventHandler* eh, int old_mask, int new_mask)
411 {
412         if (!eh)
413                 return;
414
415         void* m_writeEvent = (void*)writeExt.get(eh);
416
417         int* fake_fd = (int*)fdExt.get(eh);
418         if (!fake_fd)
419                 return;
420
421         /* Post event - write begin */
422         if((new_mask & (FD_WANT_POLL_WRITE | FD_WANT_FAST_WRITE | FD_WANT_SINGLE_WRITE)) && !m_writeEvent)
423         {
424                 ULONG_PTR completion_key = (ULONG_PTR)*fake_fd;
425                 Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_WRITE_READY, 0);
426                 writeExt.free(eh);
427                 writeExt.set(eh, (intptr_t)ov);
428                 PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);
429         }
430 }
431
432 bool IOCPEngine::PostCompletionEvent(EventHandler * eh, SocketIOEvent type, int param)
433 {
434         if (!eh)
435                 return false;
436
437         int* fake_fd = (int*)fdExt.get(eh);
438         if (!fake_fd)
439                 return false;
440
441         Overlapped * ov = new Overlapped(type, param);
442         ULONG_PTR completion_key = (ULONG_PTR)*fake_fd;
443         return PostQueuedCompletionStatus(m_completionPort, 0, completion_key, &ov->m_overlap);
444 }
445
446 void IOCPEngine::PostReadEvent(EventHandler * eh)
447 {
448         if (!eh)
449                 return;
450
451         Overlapped * ov = new Overlapped(SOCKET_IO_EVENT_READ_READY, 0);
452         DWORD flags = 0;
453         DWORD r_length = 0;
454         WSABUF buf;
455
456         /* by passing a null buffer pointer, we can have this working in the same way as epoll..
457          * its slower, but it saves modifying all network code.
458          */
459         buf.buf = 0;
460         buf.len = 0;
461
462         /* determine socket type. */
463         DWORD sock_type;
464         int sock_len = sizeof(DWORD);
465         if(getsockopt(eh->GetFd(), SOL_SOCKET, SO_TYPE, (char*)&sock_type, &sock_len) == -1)
466         {
467                 /* wtfhax? */
468                 PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
469                 delete ov;
470                 return;
471         }
472         switch(sock_type)
473         {
474                 case SOCK_DGRAM:                        /* UDP Socket */
475                 {
476                         udp_overlap * uv = new udp_overlap;
477                         uv->udp_sockaddr_len = sizeof(sockaddr);
478                         buf.buf = (char*)uv->udp_buffer;
479                         buf.len = sizeof(uv->udp_buffer);
480                         ov->m_params = (unsigned long)uv;
481                         if(WSARecvFrom(eh->GetFd(), &buf, 1, &uv->udp_len, &flags, uv->udp_sockaddr, (LPINT)&uv->udp_sockaddr_len, &ov->m_overlap, 0))
482                         {
483                                 int err = WSAGetLastError();
484                                 if(err != WSA_IO_PENDING)
485                                 {
486                                         delete ov;
487                                         PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
488                                         return;
489                                 }
490                         }
491                 }
492                 break;
493
494                 case SOCK_STREAM:                       /* TCP Socket */
495                 {
496                         if(WSARecv(eh->GetFd(), &buf, 1, &r_length, &flags, &ov->m_overlap, 0) == SOCKET_ERROR)
497                         {
498                                 if(WSAGetLastError() != WSA_IO_PENDING)
499                                 {
500                                         delete ov;
501                                         PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, 0);
502                                         return;
503                                 }
504                         }
505                 }
506                 break;
507
508                 default:
509                 {
510                         printf("unknwon socket type: %u\n", sock_type);
511                         return;
512                 }
513                 break;
514         }
515         readExt.set(eh, (intptr_t)ov);
516 }
517
518 int IOCPEngine::DispatchEvents()
519 {
520         DWORD len;
521         LPOVERLAPPED overlap;
522         Overlapped * ov;
523         EventHandler * eh;
524         ULONG_PTR intfd;
525         int ret;
526         unsigned long bytes_recv;
527
528         while (GetQueuedCompletionStatus(m_completionPort, &len, &intfd, &overlap, 1000))
529         {
530                 if (intfd > (unsigned long)MAX_DESCRIPTORS)
531                         continue;
532
533                 // woot, we got an event on a socket :P
534                 eh = ref[intfd];
535                 ov = CONTAINING_RECORD(overlap, Overlapped, m_overlap);
536
537                 if (eh == 0)
538                         continue;
539
540                 TotalEvents++;
541
542                 switch(ov->m_event)
543                 {
544                         case SOCKET_IO_EVENT_WRITE_READY:
545                         {
546                                 WriteEvents++;
547                                 writeExt.free(eh);
548                                 SetEventMask(eh, eh->GetEventMask() & ~FD_WRITE_WILL_BLOCK);
549                                 eh->HandleEvent(EVENT_WRITE, 0);
550                         }
551                         break;
552
553                         case SOCKET_IO_EVENT_READ_READY:
554                         {
555                                 ReadEvents++;
556                                 SetEventMask(eh, eh->GetEventMask() & ~FD_READ_WILL_BLOCK);
557                                 if(ov->m_params)
558                                 {
559                                         // if we had params, it means we are a udp socket with a udp_overlap pointer in this long.
560                                         udp_overlap * uv = (udp_overlap*)ov->m_params;
561                                         uv->udp_len = len;
562                                         this->udp_ov = uv;
563                                         readExt.free(eh);
564                                         eh->HandleEvent(EVENT_READ, 0);
565                                         this->udp_ov = 0;
566                                         delete uv;
567                                         PostReadEvent(eh);
568                                 }
569                                 else
570                                 {
571                                         ret = ioctlsocket(eh->GetFd(), FIONREAD, &bytes_recv);
572                                         readExt.free(eh);
573                                         if(ret != 0 || bytes_recv == 0)
574                                         {
575                                                 /* end of file */
576                                                 PostCompletionEvent(eh, SOCKET_IO_EVENT_ERROR, EIO); /* Old macdonald had an error, EIEIO. */
577                                         }
578                                         else
579                                         {
580                                                 eh->HandleEvent(EVENT_READ, 0);
581                                                 PostReadEvent(eh);
582                                         }
583                                 }
584                         }
585                         break;
586
587                         case SOCKET_IO_EVENT_ACCEPT:
588                         {
589                                 /* this is kinda messy.. :/ */
590                                 ReadEvents++;
591                                 eh->HandleEvent(EVENT_READ, ov->m_params);
592                                 delete ((accept_overlap*)ov->m_params);
593                                 acceptExt.free(eh);
594                                 PostAcceptEvent(eh);
595                         }
596                         break;
597
598                         case SOCKET_IO_EVENT_ERROR:
599                         {
600                                 ErrorEvents++;
601                                 eh->HandleEvent(EVENT_ERROR, ov->m_params);
602                         }
603                         break;
604                 }
605
606                 delete ov;
607         }
608
609         return 0;
610 }
611
612 void IOCPEngine::PostAcceptEvent(EventHandler * eh)
613 {
614         if (!eh)
615                 return;
616
617         int on = 1;
618         u_long arg = 1;
619         struct linger linger = { 0 };
620
621         int fd = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, WSA_FLAG_OVERLAPPED);
622
623         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
624         /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */
625         linger.l_onoff = 1;
626         linger.l_linger = 1;
627         setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&linger,sizeof(linger));
628         ioctlsocket(fd, FIONBIO, &arg);
629
630         int len = sizeof(sockaddr_in) + 16;
631         DWORD dwBytes;
632         accept_overlap* ao = new accept_overlap;
633         memset(ao->buf, 0, 1024);
634         ao->socket = fd;
635
636         Overlapped* ov = new Overlapped(SOCKET_IO_EVENT_ACCEPT, (int)ao);
637         acceptExt.set(eh, (intptr_t)ov);
638
639         if(AcceptEx(eh->GetFd(), fd, ao->buf, 0, len, len, &dwBytes, &ov->m_overlap) == FALSE)
640         {
641                 int err = WSAGetLastError();
642                 if(err != WSA_IO_PENDING)
643                 {
644                         printf("PostAcceptEvent err: %d\n", err);
645                 }
646         }
647 }
648
649
650 std::string IOCPEngine::GetName()
651 {
652         return "iocp";
653 }
654
655 EventHandler * IOCPEngine::GetRef(int fd)
656 {
657         std::map<int, EventHandler*>::iterator itr = m_binding.find(fd);
658         return (itr == m_binding.end()) ? 0 : itr->second;
659 }
660
661 bool IOCPEngine::HasFd(int fd)
662 {
663         return (GetRef(fd) != 0);
664 }
665
666 bool IOCPEngine::BoundsCheckFd(EventHandler* eh)
667 {
668         int* internal_fd = (int*)fdExt.get(eh);
669         if (!eh || eh->GetFd() < 0)
670                 return false;
671
672         if(!internal_fd)
673                 return false;
674
675         if(*internal_fd > MAX_DESCRIPTORS)
676                 return false;
677
678         return true;
679 }
680
681 EventHandler * IOCPEngine::GetIntRef(int fd)
682 {
683         if(fd < 0 || fd > MAX_DESCRIPTORS)
684                 return 0;
685         return ref[fd];
686 }
687
688 int IOCPEngine::Accept(EventHandler* fd, sockaddr *addr, socklen_t *addrlen)
689 {
690         //SOCKET s = fd->GetFd();
691
692         Overlapped* acceptevent = (Overlapped*)acceptExt.get(fd);
693         if (!acceptevent)
694                 /* Shit, no accept event on this socket! :( */
695                 return -1;
696
697         Overlapped* ovl = acceptevent;
698         accept_overlap* ov = (accept_overlap*)ovl->m_params;
699
700         //sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];
701         sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];
702
703         memcpy(addr, client_address, sizeof(sockaddr_in));
704         *addrlen = sizeof(sockaddr_in);
705
706         return ov->socket;
707 }
708
709 int IOCPEngine::GetSockName(EventHandler* fd, sockaddr *name, socklen_t* namelen)
710 {
711         Overlapped* ovl = (Overlapped*)acceptExt.get(fd);
712
713         if (!ovl)
714                 return -1;
715
716         accept_overlap* ov = (accept_overlap*)ovl->m_params;
717
718         sockaddr_in* server_address = (sockaddr_in*)&ov->buf[10];
719         //sockaddr_in* client_address = (sockaddr_in*)&ov->buf[38];
720
721         memcpy(name, server_address, sizeof(sockaddr_in));
722         *namelen = sizeof(sockaddr_in);
723
724         return 0;
725 }
726
727 int IOCPEngine::RecvFrom(EventHandler* fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)
728 {
729         this->UpdateStats(len, 0);
730         udp_overlap* ov = (udp_overlap*)readExt.get(fd);
731         if (!ov)
732                 return -1;
733         memcpy(buf, ov->udp_buffer, ov->udp_len);
734         memcpy(from, ov->udp_sockaddr, *fromlen);
735         return ov->udp_len;
736 }
737
738 int IOCPEngine::Blocking(int fd)
739 {
740         unsigned long opt = 0;
741         return ioctlsocket(fd, FIONBIO, &opt);
742 }
743
744 int IOCPEngine::NonBlocking(int fd)
745 {
746         unsigned long opt = 1;
747         return ioctlsocket(fd, FIONBIO, &opt);
748 }
749
750 int IOCPEngine::Close(int fd)
751 {
752         return closesocket(fd);
753 }
754
755 int IOCPEngine::Close(EventHandler* fd)
756 {
757         return this->Close(fd->GetFd());
758 }
759
760 SocketEngine* CreateSocketEngine()
761 {
762         return new IOCPEngine;
763 }