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