7 #define WIN32_LEAN_AND_MEAN
11 #define SOCKLEN_TYPE int
13 #elif defined(__unix__) || defined(__APPLE__)
16 #define SOCKLEN_TYPE socklen_t
22 #include <netinet/in.h>
24 #include <sys/socket.h>
26 #include <sys/types.h>
28 #include <arpa/inet.h>
34 typedef struct hostent HOSTENT;
35 typedef struct sockaddr SOCKADDR;
36 typedef struct sockaddr_in SOCKADDR_IN;
37 typedef struct in_addr IN_ADDR;
38 #define closesocket(s) close(s)
52 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
54 #define PUTLEDWORD(b, d) \
55 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
56 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
57 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
58 (b)[0] = (byte)( (d) & 0xFF);
60 public enum SocketType { tcp, udp };
61 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
63 public class Packet : struct
69 static class SocketConnectThread : Thread
76 HOSTENT * host = gethostbyname(socket.address);
83 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
84 network.mutex.Release();
85 if(socket.type == udp ||
86 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
89 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
90 socket.inetPort = ntohs(socket.a.sin_port);
91 network.mutex.Release();
93 if(socket.OnEstablishConnection((int)socket.s))
100 network.mutex.Wait();
101 socket.disconnectCode = connectFailed;
106 network.mutex.Wait();
107 socket.disconnectCode = connectFailed;
112 socket.disconnectCode = resolveFailed;
115 Log("[C] Signaling connect event (%X)\n", socket);
117 if(result && !socket.destroyed)
118 socket._connected = 1;
119 else if(socket._connected == -2)
120 socket._connected = -1;
123 Log("[C] Getting out of connect thread (%X)\n", socket);
125 network.connectEvent = true;
127 guiApp.SignalEvent();
128 network.mutex.Release();
137 property Service service
145 SOCKLEN_TYPE addrLen = sizeof(a);
147 value.accepted = true;
148 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
154 value.sockets.Add(this);
157 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
158 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
165 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
166 inetPort = ntohs(a.sin_port);
169 connectThread = null;
170 disconnectCode = (DisconnectCode)-1;
171 disconnected = false;
173 network.mutex.Wait();
174 FD_SET(s, &network.exceptSet);
175 FD_SET(s, &network.readSet);
178 network.ns = (int)(s+1);
179 network.socketsSemaphore.Release();
181 network.mutex.Release();
189 get { return this ? service : null; }
192 property const char * inetAddress { get { return (char *)inetAddress; } };
193 property int inetPort { get { return inetPort; } }
194 property Socket next { get { return next; } };
195 property bool connected { get { return _connected == 1 || _connected == -2; } };
196 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
198 virtual void OnConnect(void);
199 virtual uint OnReceive(const byte * buffer, uint count)
201 if(count >= sizeof(class Packet))
203 Packet packet = (Packet)buffer;
204 uint size = GETLEDWORD((byte *)&packet.size);
207 byte * tempBuffer = null;
212 tempBuffer = new byte[size];
213 packet = (Packet)tempBuffer;
214 memcpy(tempBuffer, buffer, size);
215 memmove(recvBuffer, recvBuffer + size, recvBytes - size);
219 OnReceivePacket(packet);
227 virtual void OnDisconnect(int code);
228 virtual void OnReceivePacket(Packet packet);
230 bool Connect(const char * address, int port)
233 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
234 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
236 Log("\n[P] [NConnect]\n");
240 result = _Connect(s, address, port);
246 void Disconnect(DisconnectCode code)
250 bool wasDisconnected = disconnected;
251 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
255 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
257 network.mutex.Wait();
258 disconnectCode = code;
263 if(_connected == -2 && connectThread)
266 network.mutex.Release();
267 connectThread.Wait();
268 delete connectThread;
269 network.mutex.Wait();
276 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
280 service.sockets.Remove(this);
284 network.mutex.Release();
285 OnDisconnect(disconnectCode);
286 network.mutex.Wait();
289 if(s == network.ns - 1)
290 Network_DetermineMaxSocket();
294 FD_CLR(s, &network.readSet);
295 FD_CLR(s, &network.writeSet);
296 FD_CLR(s, &network.exceptSet);
298 // 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...
299 // Trying >= 1 instead of > 1
310 network.mutex.Release();
316 bool Send(const void * buffer, int size)
318 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
325 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
326 (type == udp && (count = (int)sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
328 #if defined(__WIN32__)
329 int error = WSAGetLastError();
335 #if defined(__WIN32__)
342 // This is what was making eCom jam...
343 // 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);
446 Network_Initialize();
458 void Free(bool mustLock)
462 if(mustLock) network.mutex.Wait();
464 if(!service && _connected)
466 ((_connected == -1 || _connected == -2) ? network.connectSockets : network.sockets).Remove(this);
473 network.mutex.Release();
475 OnDisconnect(disconnectCode);
476 // if(_refCount > 1) _refCount--;
478 network.mutex.Wait();
483 service.sockets.Remove(this);
488 if(s != -1) { closesocket(s); this.s = -1; }
498 FD_CLR(s, &network.readSet);
499 FD_CLR(s, &network.writeSet);
500 FD_CLR(s, &network.exceptSet);
505 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
506 // WATCH FOR LEAKS IN OTHER PROJECTS?
507 //if(_refCount > 1) _refCount--;
508 if(mustLock) network.mutex.Release();
511 void _Disconnect(DisconnectCode code)
514 network.mutex.Wait();
516 disconnectCode = code;
521 if(s == network.ns - 1)
522 Network_DetermineMaxSocket();
523 network.mutex.Release();
526 bool _Connect(SOCKET s, const char * address, int port)
532 a.sin_family = AF_INET;
533 a.sin_port = htons((uint16)port);
535 network.mutex.Wait();
541 this.address = new char[strlen(address)+1];
542 strcpy(this.address, address);
546 disconnected = false;
547 disconnectCode = (DisconnectCode)-1;
548 connectThread = null;
551 FD_SET(s, &network.writeSet);
552 if(s >= network.ns && !processAlone)
554 network.ns = (int)(s+1);
555 network.socketsSemaphore.Release();
557 connectThread = SocketConnectThread { socket = this };
559 if(OnConnect == Socket::OnConnect)
563 network.mutex.Release();
564 connectThread.Main();
565 network.mutex.Wait();
567 if(_connected == -1 || destroyed)
571 if(s == network.ns - 1)
572 Network_DetermineMaxSocket();
574 if(this.disconnectCode == resolveFailed)
575 Logf("Error resolving address %s\n", this.address);
581 else if(_connected == 1)
583 FD_CLR(s, &network.writeSet);
584 FD_SET(s, &network.readSet);
585 FD_SET(s, &network.exceptSet);
586 network.sockets.Add(this);
594 delete connectThread;
598 network.connectSockets.Add(this);
600 incref connectThread;
601 connectThread.Create();
607 network.mutex.Release();
611 #define MAX_RECEIVE 65536
613 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
620 // network.mutex.Wait();
622 if(FD_ISSET(s, rs) || leftOver)
627 if((int)recvBufferSize - recvBytes < MAX_RECEIVE)
629 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
630 recvBufferSize += MAX_RECEIVE;
633 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
635 if(type == tcp /*|| _connected*/)
636 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
639 SOCKLEN_TYPE len = sizeof(a);
640 count = (int)recvfrom(s, (char *)recvBuffer + recvBytes,
641 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
642 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
643 inetPort = ntohs((uint16)a.sin_port);
648 disconnectCode = remoteClosed;
653 printf("Errno is %d", errno);*/
654 disconnectCode = remoteLost;
660 if(count > 0 || (leftOver && !count))
665 for(flushCount = 0; flushCount < recvBytes; )
667 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
672 network.leftOverBytes = true;
675 flushCount += recvCount;
678 if(flushCount < recvBytes)
682 memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
683 recvBytes -= flushCount;
687 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
688 if(disconnectCode > -1)
696 else if(FD_ISSET(s, es))
700 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
703 _Disconnect(remoteLost);
706 // Disconnect it here
707 if(!recvBytes && disconnectCode > -1 && _connected)
712 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
715 _Disconnect(disconnectCode);
717 // network.mutex.Release();
725 public bool Process()
727 return ProcessTimeOut(0);
730 public bool ProcessTimeOut(Seconds timeOut)
732 bool gotEvent = false;
733 struct timeval tv = {0, 0};
734 struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
738 if(disconnectCode > 0 && !leftOver) return false;
747 selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
749 if(s != -1 && _refCount && (leftOver || selectResult))
751 gotEvent |= ProcessSocket(&rs, &ws, &es);
761 char inetAddress[20];
768 Thread connectThread;
769 DisconnectCode disconnectCode;
771 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