7 #define WIN32_LEAN_AND_MEAN
9 static WSADATA wsaData;
11 #elif defined(__unix__) || defined(__APPLE__)
19 #include <netinet/in.h>
21 #include <sys/socket.h>
23 #include <sys/types.h>
25 #include <arpa/inet.h>
31 typedef struct hostent HOSTENT;
32 typedef struct sockaddr SOCKADDR;
33 typedef struct sockaddr_in SOCKADDR_IN;
34 typedef struct in_addr IN_ADDR;
35 #define closesocket(s) close(s)
41 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
43 #define PUTLEDWORD(b, d) \
44 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
45 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
46 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
47 (b)[0] = (byte)( (d) & 0xFF);
49 public enum SocketType { tcp, udp };
50 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
52 public class Packet : struct
58 static class SocketConnectThread : Thread
65 HOSTENT * host = gethostbyname(socket.address);
72 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
73 network.mutex.Release();
74 if(socket.type == udp ||
75 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
78 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
79 socket.inetPort = ntohs(socket.a.sin_port);
80 network.mutex.Release();
82 if(socket.OnEstablishConnection(socket.s))
90 socket.disconnectCode = connectFailed;
96 socket.disconnectCode = connectFailed;
101 socket.disconnectCode = resolveFailed;
104 Log("[C] Signaling connect event (%X)\n", socket);
106 if(result && !socket.destroyed)
107 socket._connected = 1;
109 socket._connected = -1;
112 Log("[C] Getting out of connect thread (%X)\n", socket);
114 network.connectEvent = true;
116 guiApp.SignalEvent();
117 network.mutex.Release();
126 property Service service
134 int addrLen = sizeof(a);
136 value.accepted = true;
137 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
143 value.sockets.Add(this);
146 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
147 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
154 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
155 inetPort = ntohs(a.sin_port);
158 connectThread = null;
159 disconnectCode = (DisconnectCode)-1;
160 disconnected = false;
162 network.mutex.Wait();
163 FD_SET(s, &network.exceptSet);
164 FD_SET(s, &network.readSet);
168 network.socketsSemaphore.Release();
170 network.mutex.Release();
178 get { return this ? service : null; }
181 property char * inetAddress { get { return (char *)inetAddress; } };
182 property int inetPort { get { return inetPort; } }
183 property Socket next { get { return next; } };
184 property bool connected { get { return _connected == 1 || _connected == -2; } };
185 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
187 virtual void OnConnect(void);
188 virtual uint OnReceive(const byte * buffer, uint count)
190 if(count >= sizeof(class Packet))
192 Packet packet = (Packet)buffer;
193 uint size = GETLEDWORD((byte *)&packet.size);
196 byte * tempBuffer = null;
201 tempBuffer = new byte[size];
202 packet = (Packet)tempBuffer;
203 memcpy(tempBuffer, buffer, size);
204 memmove(recvBuffer, recvBuffer + size, recvBytes - size);
208 OnReceivePacket(packet);
216 virtual void OnDisconnect(int code);
217 virtual void OnReceivePacket(Packet packet);
219 bool Connect(char * address, int port)
222 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
223 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
225 Log("\n[P] [NConnect]\n");
229 result = _Connect(s, address, port);
235 void Disconnect(DisconnectCode code)
239 bool wasDisconnected = disconnected;
240 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
244 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
246 network.mutex.Wait();
247 disconnectCode = code;
256 ((_connected == -1) ? network.connectSockets : network.sockets).Remove(this);
260 service.sockets.Remove(this);
264 network.mutex.Release();
265 OnDisconnect(disconnectCode);
266 network.mutex.Wait();
269 if(s == network.ns - 1)
270 Network_DetermineMaxSocket();
274 FD_CLR(s, &network.readSet);
275 FD_CLR(s, &network.writeSet);
276 FD_CLR(s, &network.exceptSet);
278 // 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...
279 // Trying >= 1 instead of > 1
290 network.mutex.Release();
296 bool Send(void * buffer, int size)
298 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
305 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
306 (type == udp && (count = sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
308 #if defined(__WIN32__)
309 int error = WSAGetLastError();
315 #if defined(__WIN32__)
322 // This is what was making eCom jam...
323 // select(s+1, null, &ws, &es, null);
331 bool SendPacket(Packet packet)
336 uint size = packet.size;
337 PUTLEDWORD((byte *)&packet.size, size);
338 result = Send(packet, size);
345 bool SendString(char * string)
347 return Send(string, strlen(string));
350 bool Sendf(char * format, ...)
354 char string[MAX_F_STRING];
355 va_start(args, format);
356 vsprintf(string,format,args);
357 result = Send(string, strlen(string));
362 bool DatagramConnect(char * sendAddress, int port)
364 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
367 _Connect(s, sendAddress, port);
374 bool DatagramHost(int port)
376 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
381 a.sin_family=AF_INET;
382 a.sin_port = htons((uint16)port);
383 a.sin_addr.s_addr=INADDR_ANY;
384 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
385 if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
387 network.mutex.Wait();
390 network.sockets.Add(this);
393 disconnectCode = (DisconnectCode)-1;
396 FD_CLR(s, &network.writeSet);
397 FD_SET(s, &network.readSet);
398 FD_SET(s, &network.exceptSet);
402 network.socketsSemaphore.Release();
404 network.mutex.Release();
412 virtual int ReceiveData(byte * buffer, int count, uint flags)
414 return (int)recv(s, buffer, count, flags);
416 virtual int SendData(byte * buffer, int count, uint flags)
418 return (int)send(s, buffer, count, flags);
420 virtual bool OnEstablishConnection(int s);
425 Network_Initialize();
437 void Free(bool mustLock)
441 if(mustLock) network.mutex.Wait();
442 if(!service && _connected)
444 (_connected == -1 ? network.connectSockets : network.sockets).Remove(this);
451 network.mutex.Release();
453 OnDisconnect(disconnectCode);
454 // if(_refCount > 1) _refCount--;
456 network.mutex.Wait();
461 service.sockets.Remove(this);
466 if(s != -1) { closesocket(s); this.s = -1; }
476 FD_CLR(s, &network.readSet);
477 FD_CLR(s, &network.writeSet);
478 FD_CLR(s, &network.exceptSet);
483 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
484 // WATCH FOR LEAKS IN OTHER PROJECTS?
485 //if(_refCount > 1) _refCount--;
486 if(mustLock) network.mutex.Release();
489 void _Disconnect(DisconnectCode code)
492 network.mutex.Wait();
494 disconnectCode = code;
499 if(s == network.ns - 1)
500 Network_DetermineMaxSocket();
501 network.mutex.Release();
504 bool _Connect(SOCKET s, char * address, int port)
510 a.sin_family = AF_INET;
511 a.sin_port = htons((uint16)port);
513 network.mutex.Wait();
519 this.address = new char[strlen(address)+1];
520 strcpy(this.address, address);
524 disconnected = false;
525 disconnectCode = (DisconnectCode)-1;
526 connectThread = null;
529 FD_SET(s, &network.writeSet);
530 if(s >= network.ns && !processAlone)
533 network.socketsSemaphore.Release();
535 connectThread = SocketConnectThread { socket = this };
537 if(OnConnect == Socket::OnConnect)
541 network.mutex.Release();
542 connectThread.Main();
543 network.mutex.Wait();
545 if(_connected == -1 || destroyed)
549 if(s == network.ns - 1)
550 Network_DetermineMaxSocket();
552 if(this.disconnectCode == resolveFailed)
553 Logf("Error resolving address %s\n", this.address);
559 else if(_connected == 1)
561 FD_CLR(s, &network.writeSet);
562 FD_SET(s, &network.readSet);
563 FD_SET(s, &network.exceptSet);
564 network.sockets.Add(this);
572 delete connectThread;
576 network.connectSockets.Add(this);
578 incref connectThread;
579 connectThread.Create();
585 network.mutex.Release();
589 #define MAX_RECEIVE 65536
591 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
598 // network.mutex.Wait();
600 if(FD_ISSET(s, rs) || leftOver)
605 if(recvBufferSize - recvBytes < MAX_RECEIVE)
607 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
608 recvBufferSize += MAX_RECEIVE;
611 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
613 if(type == tcp /*|| _connected*/)
614 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
618 count = recvfrom(s, recvBuffer + recvBytes,
619 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
620 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
621 inetPort = ntohs((uint16)a.sin_port);
626 disconnectCode = remoteClosed;
631 printf("Errno is %d", errno);*/
632 disconnectCode = remoteLost;
638 if(count > 0 || (leftOver && !count))
643 for(flushCount = 0; flushCount < recvBytes; )
645 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
650 network.leftOverBytes = true;
653 flushCount += recvCount;
656 if(flushCount < recvBytes)
660 memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
661 recvBytes -= flushCount;
665 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
666 if(disconnectCode > -1)
674 else if(FD_ISSET(s, es))
678 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
681 _Disconnect(remoteLost);
684 // Disconnect it here
685 if(!recvBytes && disconnectCode > -1 && _connected)
690 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
693 _Disconnect(disconnectCode);
695 // network.mutex.Release();
703 public bool Process()
708 public bool ProcessTimeOut(Seconds timeOut)
710 bool gotEvent = false;
711 struct timeval tv = {0, 0};
712 struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
716 if(disconnectCode > 0) return false;
724 selectResult = select(s+1, &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
726 if(s != -1 && _refCount && (leftOver || selectResult))
728 gotEvent |= ProcessSocket(&rs, &ws, &es);
737 char inetAddress[20];
744 Thread connectThread;
745 DisconnectCode disconnectCode;