9 #define WIN32_LEAN_AND_MEAN
10 #define String _String
13 #define SOCKLEN_TYPE int
15 #elif defined(__unix__) || defined(__APPLE__)
18 #define SOCKLEN_TYPE socklen_t
24 #include <netinet/in.h>
26 #include <sys/socket.h>
28 #include <sys/types.h>
30 #include <arpa/inet.h>
36 typedef struct hostent HOSTENT;
37 typedef struct sockaddr SOCKADDR;
38 typedef struct sockaddr_in SOCKADDR_IN;
39 typedef struct in_addr IN_ADDR;
40 #define closesocket(s) close(s)
46 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
48 #define PUTLEDWORD(b, d) \
49 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
50 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
51 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
52 (b)[0] = (byte)( (d) & 0xFF);
54 public enum SocketType { tcp, udp };
55 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
57 public class Packet : struct
63 static class SocketConnectThread : Thread
70 HOSTENT * host = gethostbyname(socket.address);
77 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
78 network.mutex.Release();
79 if(socket.type == udp ||
80 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
83 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
84 socket.inetPort = ntohs(socket.a.sin_port);
85 network.mutex.Release();
87 if(socket.OnEstablishConnection((int)socket.s))
95 socket.disconnectCode = connectFailed;
100 network.mutex.Wait();
101 socket.disconnectCode = connectFailed;
106 socket.disconnectCode = resolveFailed;
109 Log("[C] Signaling connect event (%X)\n", socket);
111 if(result && !socket.destroyed)
112 socket._connected = 1;
113 else if(socket._connected == -2)
114 socket._connected = -1;
117 Log("[C] Getting out of connect thread (%X)\n", socket);
119 network.connectEvent = true;
121 guiApp.SignalEvent();
122 network.mutex.Release();
131 property Service service
139 SOCKLEN_TYPE addrLen = sizeof(a);
141 value.accepted = true;
142 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
148 value.sockets.Add(this);
151 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
152 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
159 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
160 inetPort = ntohs(a.sin_port);
163 connectThread = null;
164 disconnectCode = (DisconnectCode)-1;
165 disconnected = false;
167 network.mutex.Wait();
168 FD_SET(s, &network.exceptSet);
169 FD_SET(s, &network.readSet);
172 network.ns = (int)(s+1);
173 network.socketsSemaphore.Release();
175 network.mutex.Release();
183 get { return this ? service : null; }
186 property const char * inetAddress { get { return (char *)inetAddress; } };
187 property int inetPort { get { return inetPort; } }
188 property Socket next { get { return next; } };
189 property bool connected { get { return _connected == 1 || _connected == -2; } };
190 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
192 virtual void OnConnect(void);
193 virtual uint OnReceive(const byte * buffer, uint count)
195 if(count >= sizeof(class Packet))
197 Packet packet = (Packet)buffer;
198 uint size = GETLEDWORD((byte *)&packet.size);
201 byte * tempBuffer = null;
206 tempBuffer = new byte[size];
207 packet = (Packet)tempBuffer;
208 memcpy(tempBuffer, buffer, size);
209 memmove(recvBuffer, recvBuffer + size, recvBytes - size);
213 OnReceivePacket(packet);
221 virtual void OnDisconnect(int code);
222 virtual void OnReceivePacket(Packet packet);
224 bool Connect(const char * address, int port)
227 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
228 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
230 Log("\n[P] [NConnect]\n");
234 result = _Connect(s, address, port);
240 void Disconnect(DisconnectCode code)
244 bool wasDisconnected = disconnected;
245 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
249 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
251 network.mutex.Wait();
252 disconnectCode = code;
257 if(_connected == -2 && connectThread)
260 network.mutex.Release();
261 connectThread.Wait();
262 delete connectThread;
263 network.mutex.Wait();
270 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
274 service.sockets.Remove(this);
278 network.mutex.Release();
279 OnDisconnect(disconnectCode);
280 network.mutex.Wait();
283 if(s == network.ns - 1)
284 Network_DetermineMaxSocket();
288 FD_CLR(s, &network.readSet);
289 FD_CLR(s, &network.writeSet);
290 FD_CLR(s, &network.exceptSet);
292 // Why wasn't this here? Don't want it here :) Hmm why don't we want it here? Service created socket not getting freed in DICOMTest...
293 // Trying >= 1 instead of > 1
304 network.mutex.Release();
310 bool Send(const void * buffer, int size)
312 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
321 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
322 (type == udp && (count = (int)sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
324 #if defined(__WIN32__)
325 int error = WSAGetLastError();
331 #if defined(__WIN32__)
338 // This is what was making eCom jam...
339 // select(s+1, null, &ws, &es, null);
351 bool SendPacket(Packet packet)
356 uint size = packet.size;
357 PUTLEDWORD((byte *)&packet.size, size);
358 result = Send(packet, size);
365 bool SendString(const char * string)
367 return Send(string, (int)strlen(string));
370 bool Sendf(const char * format, ...)
374 char string[MAX_F_STRING];
375 va_start(args, format);
376 vsnprintf(string, sizeof(string), format, args);
377 string[sizeof(string)-1] = 0;
378 result = Send(string, (int)strlen(string));
383 bool DatagramConnect(const char * sendAddress, int port)
385 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
388 _Connect(s, sendAddress, port);
395 bool DatagramHost(int port)
397 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
398 if(s != -1 && !_connected)
402 a.sin_family=AF_INET;
403 a.sin_port = htons((uint16)port);
404 a.sin_addr.s_addr=INADDR_ANY;
405 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
406 if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
408 network.mutex.Wait();
411 network.sockets.Add(this);
414 disconnectCode = (DisconnectCode)-1;
417 FD_CLR(s, &network.writeSet);
418 FD_SET(s, &network.readSet);
419 FD_SET(s, &network.exceptSet);
422 network.ns = (int)(s+1);
423 network.socketsSemaphore.Release();
425 network.mutex.Release();
433 virtual int ReceiveData(byte * buffer, int count, uint flags)
435 return (int)recv(s, (char *)buffer, count, flags);
437 virtual int SendData(const byte * buffer, int count, uint flags)
439 return (int)send(s, (const char *)buffer, count, flags);
441 virtual bool OnEstablishConnection(int s);
443 dllexport void safeIncRef()
450 dllexport void safeDecRef()
452 Mutex mutex = this.mutex;
461 Network_Initialize();
473 void Free(bool mustLock)
477 if(mustLock) network.mutex.Wait();
479 if(!service && _connected)
481 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
488 network.mutex.Release();
490 OnDisconnect(disconnectCode);
491 // if(_refCount > 1) _refCount--;
493 network.mutex.Wait();
498 service.sockets.Remove(this);
503 if(s != -1) { closesocket(s); this.s = -1; }
513 FD_CLR(s, &network.readSet);
514 FD_CLR(s, &network.writeSet);
515 FD_CLR(s, &network.exceptSet);
520 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
521 // WATCH FOR LEAKS IN OTHER PROJECTS?
522 //if(_refCount > 1) _refCount--;
523 if(mustLock) network.mutex.Release();
526 void _Disconnect(DisconnectCode code)
529 network.mutex.Wait();
531 disconnectCode = code;
536 if(s == network.ns - 1)
537 Network_DetermineMaxSocket();
538 network.mutex.Release();
541 bool _Connect(SOCKET s, const char * address, int port)
547 a.sin_family = AF_INET;
548 a.sin_port = htons((uint16)port);
550 network.mutex.Wait();
556 this.address = new char[strlen(address)+1];
557 strcpy(this.address, address);
561 disconnected = false;
562 disconnectCode = (DisconnectCode)-1;
563 connectThread = null;
566 FD_SET(s, &network.writeSet);
567 if(s >= network.ns && !processAlone)
569 network.ns = (int)(s+1);
570 network.socketsSemaphore.Release();
572 connectThread = SocketConnectThread { socket = this };
574 if(OnConnect == Socket::OnConnect)
578 network.mutex.Release();
579 connectThread.Main();
580 network.mutex.Wait();
582 if(_connected == -1 || destroyed)
586 if(s == network.ns - 1)
587 Network_DetermineMaxSocket();
589 if(this.disconnectCode == resolveFailed)
590 Logf("Error resolving address %s\n", this.address);
596 else if(_connected == 1)
598 FD_CLR(s, &network.writeSet);
599 FD_SET(s, &network.readSet);
600 FD_SET(s, &network.exceptSet);
601 network.sockets.Add(this);
609 delete connectThread;
613 network.connectSockets.Add(this);
615 incref connectThread;
616 connectThread.Create();
622 network.mutex.Release();
626 #define MAX_RECEIVE 65536
628 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
632 Mutex mutex = this.mutex;
636 // network.mutex.Wait();
638 if(FD_ISSET(s, rs) || leftOver)
643 if((int)recvBufferSize - recvBytes < MAX_RECEIVE)
645 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
646 recvBufferSize += MAX_RECEIVE;
649 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
651 if(type == tcp /*|| _connected*/)
652 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
655 SOCKLEN_TYPE len = sizeof(a);
656 count = (int)recvfrom(s, (char *)recvBuffer + recvBytes,
657 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
658 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
659 inetPort = ntohs((uint16)a.sin_port);
664 disconnectCode = remoteClosed;
669 printf("Errno is %d", errno);*/
670 disconnectCode = remoteLost;
676 if(count > 0 || (leftOver && !count))
681 for(flushCount = 0; flushCount < recvBytes; )
683 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
689 network.leftOverBytes = true;
692 flushCount += recvCount;
695 if(flushCount < recvBytes)
699 memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
700 recvBytes -= flushCount;
704 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
705 if(disconnectCode > -1)
713 else if(FD_ISSET(s, es))
717 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
720 _Disconnect(remoteLost);
723 // Disconnect it here
724 if(!recvBytes && disconnectCode > -1 && _connected)
729 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
732 _Disconnect(disconnectCode);
734 // network.mutex.Release();
742 public bool Process()
744 return ProcessTimeOut(0);
747 public bool ProcessTimeOut(Seconds timeOut)
749 bool gotEvent = false;
750 struct timeval tv = {0, 0};
751 struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
756 if(disconnectCode > 0 && !leftOver) return false;
768 selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
770 if(s != -1 && _refCount && (leftOver || selectResult))
772 gotEvent |= ProcessSocket(&rs, &ws, &es);
783 char inetAddress[20];
790 Thread connectThread;
791 DisconnectCode disconnectCode;
793 int _connected; // -2: Initial value when calling Connect(), -1: Disconnected or otherwise destroyed while connecting, 1: succesfully connected, 0: no longer in any connect/sockets list