7 #define WIN32_LEAN_AND_MEAN
9 static WSADATA wsaData;
11 #elif defined(__unix__) || defined(__APPLE__)
18 #include <netinet/in.h>
20 #include <sys/socket.h>
22 #include <sys/types.h>
24 #include <arpa/inet.h>
29 typedef struct hostent HOSTENT;
30 typedef struct sockaddr SOCKADDR;
31 typedef struct sockaddr_in SOCKADDR_IN;
32 typedef struct in_addr IN_ADDR;
33 #define closesocket(s) close(s)
39 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
41 #define PUTLEDWORD(b, d) \
42 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
43 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
44 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
45 (b)[0] = (byte)( (d) & 0xFF);
47 public enum SocketType { tcp, udp };
48 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
50 public class Packet : struct
56 static class SocketConnectThread : Thread
63 HOSTENT * host = gethostbyname(socket.address);
70 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
71 network.mutex.Release();
72 if(socket.type == udp ||
73 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
76 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
77 socket.inetPort = ntohs(socket.a.sin_port);
78 network.mutex.Release();
80 if(socket.OnEstablishConnection(socket.s))
88 socket.disconnectCode = connectFailed;
94 socket.disconnectCode = connectFailed;
99 socket.disconnectCode = resolveFailed;
102 Log("[C] Signaling connect event (%X)\n", socket);
104 if(result && !socket.destroyed)
105 socket._connected = 1;
107 socket._connected = -1;
110 Log("[C] Getting out of connect thread (%X)\n", socket);
112 network.connectEvent = true;
114 guiApp.SignalEvent();
115 network.mutex.Release();
124 property Service service
132 int addrLen = sizeof(a);
134 value.accepted = true;
135 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
141 value.sockets.Add(this);
144 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
145 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
152 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
153 inetPort = ntohs(a.sin_port);
156 connectThread = null;
157 disconnectCode = (DisconnectCode)-1;
158 disconnected = false;
160 network.mutex.Wait();
161 FD_SET(s, &network.exceptSet);
162 FD_SET(s, &network.readSet);
166 network.socketsSemaphore.Release();
168 network.mutex.Release();
176 get { return this ? service : null; }
179 property char * inetAddress { get { return (char *)inetAddress; } };
180 property int inetPort { get { return inetPort; } }
181 property Socket next { get { return next; } };
182 property bool connected { get { return _connected == 1 || _connected == -2; } };
183 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
185 virtual void OnConnect(void);
186 virtual uint OnReceive(const byte * buffer, uint count)
188 if(count >= sizeof(class Packet))
190 Packet packet = (Packet)buffer;
191 uint size = GETLEDWORD((byte *)&packet.size);
196 CopyBytes(recvBuffer, recvBuffer + size, recvBytes - size);
199 OnReceivePacket(packet);
206 virtual void OnDisconnect(int code);
207 virtual void OnReceivePacket(Packet packet);
209 bool Connect(char * address, int port)
212 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
213 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
215 Log("\n[P] [NConnect]\n");
219 result = _Connect(s, address, port);
225 void Disconnect(DisconnectCode code)
229 bool wasDisconnected = disconnected;
230 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
234 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
236 network.mutex.Wait();
237 disconnectCode = code;
245 if(_connected == -1/* != 1*/)
247 network.connectSockets.Remove(this);
252 network.sockets.Remove(this);
258 service.sockets.Remove(this);
262 network.mutex.Release();
263 OnDisconnect(disconnectCode);
264 network.mutex.Wait();
267 if(s == network.ns - 1)
268 Network_DetermineMaxSocket();
272 FD_CLR(s, &network.readSet);
273 FD_CLR(s, &network.writeSet);
274 FD_CLR(s, &network.exceptSet);
276 // 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...
277 // Trying >= 1 instead of > 1
282 network.mutex.Release();
293 bool Send(void * buffer, int size)
295 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
302 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
303 (type == udp && (count = sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
305 #if defined(__WIN32__)
306 int error = WSAGetLastError();
312 #if defined(__WIN32__)
319 // This is what was making eCom jam...
320 // select(s+1, null, &ws, &es, null);
328 bool SendPacket(Packet packet)
333 uint size = packet.size;
334 PUTLEDWORD((byte *)&packet.size, size);
335 result = Send(packet, size);
342 bool SendString(char * string)
344 return Send(string, strlen(string));
347 bool Sendf(char * format, ...)
351 char string[MAX_F_STRING];
352 va_start(args, format);
353 vsprintf(string,format,args);
354 result = Send(string, strlen(string));
359 bool DatagramConnect(char * sendAddress, int port)
361 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
364 _Connect(s, sendAddress, port);
371 bool DatagramHost(int port)
373 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
378 a.sin_family=AF_INET;
379 a.sin_port = htons((uint16)port);
380 a.sin_addr.s_addr=INADDR_ANY;
381 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
382 if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
384 network.mutex.Wait();
387 network.sockets.Add(this);
390 disconnectCode = (DisconnectCode)-1;
393 FD_CLR(s, &network.writeSet);
394 FD_SET(s, &network.readSet);
395 FD_SET(s, &network.exceptSet);
399 network.socketsSemaphore.Release();
401 network.mutex.Release();
409 virtual int ReceiveData(byte * buffer, int count, uint flags)
411 return (int)recv(s, buffer, count, flags);
413 virtual int SendData(byte * buffer, int count, uint flags)
415 return (int)send(s, buffer, count, flags);
417 virtual bool OnEstablishConnection(int s);
422 Network_Initialize();
434 void Free(bool mustLock)
438 if(mustLock) network.mutex.Wait();
441 if(_connected == -1/* != 1*/)
443 network.connectSockets.Remove(this);
448 network.sockets.Remove(this);
456 network.mutex.Release();
458 OnDisconnect(disconnectCode);
459 // if(_refCount > 1) _refCount--;
461 network.mutex.Wait();
466 service.sockets.Remove(this);
471 if(s != -1) { closesocket(s); this.s = -1; }
481 FD_CLR(s, &network.readSet);
482 FD_CLR(s, &network.writeSet);
483 FD_CLR(s, &network.exceptSet);
488 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
489 // WATCH FOR LEAKS IN OTHER PROJECTS?
490 //if(_refCount > 1) _refCount--;
491 if(mustLock) network.mutex.Release();
494 void _Disconnect(DisconnectCode code)
497 network.mutex.Wait();
499 disconnectCode = code;
504 if(s == network.ns - 1)
505 Network_DetermineMaxSocket();
506 network.mutex.Release();
509 bool _Connect(SOCKET s, char * address, int port)
515 a.sin_family = AF_INET;
516 a.sin_port = htons((uint16)port);
518 network.mutex.Wait();
524 this.address = new char[strlen(address)+1];
525 strcpy(this.address, address);
529 disconnected = false;
530 disconnectCode = (DisconnectCode)-1;
531 connectThread = null;
534 FD_SET(s, &network.writeSet);
535 if(s >= network.ns && !processAlone)
538 network.socketsSemaphore.Release();
540 connectThread = SocketConnectThread { socket = this };
542 if(OnConnect == Socket::OnConnect)
546 network.mutex.Release();
547 connectThread.Main();
548 network.mutex.Wait();
550 if(_connected == -1 || destroyed)
554 if(s == network.ns - 1)
555 Network_DetermineMaxSocket();
557 if(this.disconnectCode == resolveFailed)
558 Logf("Error resolving address %s\n", this.address);
564 else if(_connected == 1)
566 FD_CLR(s, &network.writeSet);
567 FD_SET(s, &network.readSet);
568 FD_SET(s, &network.exceptSet);
569 network.sockets.Add(this);
577 delete connectThread;
581 network.connectSockets.Add(this);
583 incref connectThread;
584 connectThread.Create();
590 network.mutex.Release();
594 #define MAX_RECEIVE 65536
596 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
603 // network.mutex.Wait();
605 if(FD_ISSET(s, rs) || leftOver)
610 if(recvBufferSize - recvBytes < MAX_RECEIVE)
612 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
613 recvBufferSize += MAX_RECEIVE;
616 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
618 if(type == tcp /*|| _connected*/)
619 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
623 count = recvfrom(s, recvBuffer + recvBytes,
624 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
625 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
626 inetPort = ntohs((uint16)a.sin_port);
631 disconnectCode = remoteClosed;
636 printf("Errno is %d", errno);*/
637 disconnectCode = remoteLost;
643 if(count > 0 || leftOver)
648 for(flushCount = 0; flushCount < recvBytes; )
650 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
655 network.leftOverBytes = true;
658 flushCount += recvCount;
661 if(flushCount < recvBytes)
665 CopyBytes(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
666 recvBytes -= flushCount;
670 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
671 if(disconnectCode > -1)
679 else if(FD_ISSET(s, es))
683 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
686 _Disconnect(remoteLost);
689 // Disconnect it here
690 if(!recvBytes && disconnectCode > -1 && _connected)
695 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
698 _Disconnect(disconnectCode);
700 // network.mutex.Release();
708 public bool Process()
710 bool gotEvent = false;
711 struct timeval tv = {0, 0};
715 if(disconnectCode > 0) return false;
723 selectResult = select(s+1, &rs, &ws, &es, leftOver ? &tv : null);
725 if(s != -1 && _refCount && (leftOver || selectResult))
727 gotEvent |= ProcessSocket(&rs, &ws, &es);
736 char inetAddress[20];
743 Thread connectThread;
744 DisconnectCode disconnectCode;