7 #define WIN32_LEAN_AND_MEAN
12 #elif defined(__unix__) || defined(__APPLE__)
20 #include <netinet/in.h>
22 #include <sys/socket.h>
24 #include <sys/types.h>
26 #include <arpa/inet.h>
32 typedef struct hostent HOSTENT;
33 typedef struct sockaddr SOCKADDR;
34 typedef struct sockaddr_in SOCKADDR_IN;
35 typedef struct in_addr IN_ADDR;
36 #define closesocket(s) close(s)
42 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
44 #define PUTLEDWORD(b, d) \
45 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
46 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
47 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
48 (b)[0] = (byte)( (d) & 0xFF);
50 public enum SocketType { tcp, udp };
51 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
53 public class Packet : struct
59 static class SocketConnectThread : Thread
66 HOSTENT * host = gethostbyname(socket.address);
73 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
74 network.mutex.Release();
75 if(socket.type == udp ||
76 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
79 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
80 socket.inetPort = ntohs(socket.a.sin_port);
81 network.mutex.Release();
83 if(socket.OnEstablishConnection((int)socket.s))
91 socket.disconnectCode = connectFailed;
97 socket.disconnectCode = connectFailed;
102 socket.disconnectCode = resolveFailed;
105 Log("[C] Signaling connect event (%X)\n", socket);
107 if(result && !socket.destroyed)
108 socket._connected = 1;
109 else if(socket._connected == -2)
110 socket._connected = -1;
113 Log("[C] Getting out of connect thread (%X)\n", socket);
115 network.connectEvent = true;
117 guiApp.SignalEvent();
118 network.mutex.Release();
127 property Service service
135 uint addrLen = sizeof(a);
137 value.accepted = true;
138 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
144 value.sockets.Add(this);
147 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
148 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
155 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
156 inetPort = ntohs(a.sin_port);
159 connectThread = null;
160 disconnectCode = (DisconnectCode)-1;
161 disconnected = false;
163 network.mutex.Wait();
164 FD_SET(s, &network.exceptSet);
165 FD_SET(s, &network.readSet);
168 network.ns = (int)(s+1);
169 network.socketsSemaphore.Release();
171 network.mutex.Release();
179 get { return this ? service : null; }
182 property const char * inetAddress { get { return (char *)inetAddress; } };
183 property int inetPort { get { return inetPort; } }
184 property Socket next { get { return next; } };
185 property bool connected { get { return _connected == 1 || _connected == -2; } };
186 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
188 virtual void OnConnect(void);
189 virtual uint OnReceive(const byte * buffer, uint count)
191 if(count >= sizeof(class Packet))
193 Packet packet = (Packet)buffer;
194 uint size = GETLEDWORD((byte *)&packet.size);
197 byte * tempBuffer = null;
202 tempBuffer = new byte[size];
203 packet = (Packet)tempBuffer;
204 memcpy(tempBuffer, buffer, size);
205 memmove(recvBuffer, recvBuffer + size, recvBytes - size);
209 OnReceivePacket(packet);
217 virtual void OnDisconnect(int code);
218 virtual void OnReceivePacket(Packet packet);
220 bool Connect(const char * address, int port)
223 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
224 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
226 Log("\n[P] [NConnect]\n");
230 result = _Connect(s, address, port);
236 void Disconnect(DisconnectCode code)
240 bool wasDisconnected = disconnected;
241 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
245 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
247 network.mutex.Wait();
248 disconnectCode = code;
253 if(_connected == -2 && connectThread)
256 network.mutex.Release();
257 connectThread.Wait();
258 delete connectThread;
259 network.mutex.Wait();
266 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
270 service.sockets.Remove(this);
274 network.mutex.Release();
275 OnDisconnect(disconnectCode);
276 network.mutex.Wait();
279 if(s == network.ns - 1)
280 Network_DetermineMaxSocket();
284 FD_CLR(s, &network.readSet);
285 FD_CLR(s, &network.writeSet);
286 FD_CLR(s, &network.exceptSet);
288 // 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...
289 // Trying >= 1 instead of > 1
300 network.mutex.Release();
306 bool Send(const void * buffer, int size)
308 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
315 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
316 (type == udp && (count = (int)sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
318 #if defined(__WIN32__)
319 int error = WSAGetLastError();
325 #if defined(__WIN32__)
332 // This is what was making eCom jam...
333 // select(s+1, null, &ws, &es, null);
341 bool SendPacket(Packet packet)
346 uint size = packet.size;
347 PUTLEDWORD((byte *)&packet.size, size);
348 result = Send(packet, size);
355 bool SendString(const char * string)
357 return Send(string, (int)strlen(string));
360 bool Sendf(const char * format, ...)
364 char string[MAX_F_STRING];
365 va_start(args, format);
366 vsnprintf(string, sizeof(string), format, args);
367 string[sizeof(string)-1] = 0;
368 result = Send(string, (int)strlen(string));
373 bool DatagramConnect(const char * sendAddress, int port)
375 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
378 _Connect(s, sendAddress, port);
385 bool DatagramHost(int port)
387 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
388 if(s != -1 && !_connected)
392 a.sin_family=AF_INET;
393 a.sin_port = htons((uint16)port);
394 a.sin_addr.s_addr=INADDR_ANY;
395 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
396 if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
398 network.mutex.Wait();
401 network.sockets.Add(this);
404 disconnectCode = (DisconnectCode)-1;
407 FD_CLR(s, &network.writeSet);
408 FD_SET(s, &network.readSet);
409 FD_SET(s, &network.exceptSet);
412 network.ns = (int)(s+1);
413 network.socketsSemaphore.Release();
415 network.mutex.Release();
423 virtual int ReceiveData(byte * buffer, int count, uint flags)
425 return (int)recv(s, (char *)buffer, count, flags);
427 virtual int SendData(const byte * buffer, int count, uint flags)
429 return (int)send(s, (const char *)buffer, count, flags);
431 virtual bool OnEstablishConnection(int s);
436 Network_Initialize();
448 void Free(bool mustLock)
452 if(mustLock) network.mutex.Wait();
454 if(!service && _connected)
456 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
463 network.mutex.Release();
465 OnDisconnect(disconnectCode);
466 // if(_refCount > 1) _refCount--;
468 network.mutex.Wait();
473 service.sockets.Remove(this);
478 if(s != -1) { closesocket(s); this.s = -1; }
488 FD_CLR(s, &network.readSet);
489 FD_CLR(s, &network.writeSet);
490 FD_CLR(s, &network.exceptSet);
495 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
496 // WATCH FOR LEAKS IN OTHER PROJECTS?
497 //if(_refCount > 1) _refCount--;
498 if(mustLock) network.mutex.Release();
501 void _Disconnect(DisconnectCode code)
504 network.mutex.Wait();
506 disconnectCode = code;
511 if(s == network.ns - 1)
512 Network_DetermineMaxSocket();
513 network.mutex.Release();
516 bool _Connect(SOCKET s, const char * address, int port)
522 a.sin_family = AF_INET;
523 a.sin_port = htons((uint16)port);
525 network.mutex.Wait();
531 this.address = new char[strlen(address)+1];
532 strcpy(this.address, address);
536 disconnected = false;
537 disconnectCode = (DisconnectCode)-1;
538 connectThread = null;
541 FD_SET(s, &network.writeSet);
542 if(s >= network.ns && !processAlone)
544 network.ns = (int)(s+1);
545 network.socketsSemaphore.Release();
547 connectThread = SocketConnectThread { socket = this };
549 if(OnConnect == Socket::OnConnect)
553 network.mutex.Release();
554 connectThread.Main();
555 network.mutex.Wait();
557 if(_connected == -1 || destroyed)
561 if(s == network.ns - 1)
562 Network_DetermineMaxSocket();
564 if(this.disconnectCode == resolveFailed)
565 Logf("Error resolving address %s\n", this.address);
571 else if(_connected == 1)
573 FD_CLR(s, &network.writeSet);
574 FD_SET(s, &network.readSet);
575 FD_SET(s, &network.exceptSet);
576 network.sockets.Add(this);
584 delete connectThread;
588 network.connectSockets.Add(this);
590 incref connectThread;
591 connectThread.Create();
597 network.mutex.Release();
601 #define MAX_RECEIVE 65536
603 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
610 // network.mutex.Wait();
612 if(FD_ISSET(s, rs) || leftOver)
617 if((int)recvBufferSize - recvBytes < MAX_RECEIVE)
619 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
620 recvBufferSize += MAX_RECEIVE;
623 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
625 if(type == tcp /*|| _connected*/)
626 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
629 uint len = sizeof(a);
630 count = (int)recvfrom(s, (char *)recvBuffer + recvBytes,
631 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
632 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
633 inetPort = ntohs((uint16)a.sin_port);
638 disconnectCode = remoteClosed;
643 printf("Errno is %d", errno);*/
644 disconnectCode = remoteLost;
650 if(count > 0 || (leftOver && !count))
655 for(flushCount = 0; flushCount < recvBytes; )
657 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
662 network.leftOverBytes = true;
665 flushCount += recvCount;
668 if(flushCount < recvBytes)
672 memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
673 recvBytes -= flushCount;
677 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
678 if(disconnectCode > -1)
686 else if(FD_ISSET(s, es))
690 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
693 _Disconnect(remoteLost);
696 // Disconnect it here
697 if(!recvBytes && disconnectCode > -1 && _connected)
702 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
705 _Disconnect(disconnectCode);
707 // network.mutex.Release();
715 public bool Process()
717 return ProcessTimeOut(0);
720 public bool ProcessTimeOut(Seconds timeOut)
722 bool gotEvent = false;
723 struct timeval tv = {0, 0};
724 struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
728 if(disconnectCode > 0 && !leftOver) return false;
737 selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
739 if(s != -1 && _refCount && (leftOver || selectResult))
741 gotEvent |= ProcessSocket(&rs, &ws, &es);
751 char inetAddress[20];
758 Thread connectThread;
759 DisconnectCode disconnectCode;
761 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