7 #define WIN32_LEAN_AND_MEAN
11 static WSADATA wsaData;
13 #elif defined(__unix__) || defined(__APPLE__)
21 #include <netinet/in.h>
23 #include <sys/socket.h>
25 #include <sys/types.h>
27 #include <arpa/inet.h>
33 typedef struct hostent HOSTENT;
34 typedef struct sockaddr SOCKADDR;
35 typedef struct sockaddr_in SOCKADDR_IN;
36 typedef struct in_addr IN_ADDR;
37 #define closesocket(s) close(s)
43 #define GETLEDWORD(b) (uint32)(((b)[3] << 24) | ((b)[2] << 16) | ((b)[1] << 8) | (b)[0])
45 #define PUTLEDWORD(b, d) \
46 (b)[3] = (byte)(((d) >> 24) & 0xFF); \
47 (b)[2] = (byte)(((d) >> 16) & 0xFF); \
48 (b)[1] = (byte)(((d) >> 8) & 0xFF); \
49 (b)[0] = (byte)( (d) & 0xFF);
51 public enum SocketType { tcp, udp };
52 public enum DisconnectCode { remoteLost = 1, remoteClosed = 2, resolveFailed = 3, connectFailed = 4 };
54 public class Packet : struct
60 static class SocketConnectThread : Thread
67 HOSTENT * host = gethostbyname(socket.address);
74 socket.a.sin_addr = *((IN_ADDR *)host->h_addr);
75 network.mutex.Release();
76 if(socket.type == udp ||
77 !connect(socket.s,(SOCKADDR *)&socket.a,sizeof(socket.a)))
80 strcpy(socket.inetAddress, inet_ntoa(socket.a.sin_addr));
81 socket.inetPort = ntohs(socket.a.sin_port);
82 network.mutex.Release();
84 if(socket.OnEstablishConnection((int)socket.s))
92 socket.disconnectCode = connectFailed;
98 socket.disconnectCode = connectFailed;
103 socket.disconnectCode = resolveFailed;
106 Log("[C] Signaling connect event (%X)\n", socket);
108 if(result && !socket.destroyed)
109 socket._connected = 1;
111 socket._connected = -1;
114 Log("[C] Getting out of connect thread (%X)\n", socket);
116 network.connectEvent = true;
118 guiApp.SignalEvent();
119 network.mutex.Release();
128 property Service service
136 int addrLen = sizeof(a);
138 value.accepted = true;
139 s = accept(value.s,(SOCKADDR *)&a, &addrLen);
145 value.sockets.Add(this);
148 setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&sendsize, (int)sizeof(sendsize));
149 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&recvsize, (int)sizeof(recvsize));
156 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
157 inetPort = ntohs(a.sin_port);
160 connectThread = null;
161 disconnectCode = (DisconnectCode)-1;
162 disconnected = false;
164 network.mutex.Wait();
165 FD_SET(s, &network.exceptSet);
166 FD_SET(s, &network.readSet);
169 network.ns = (int)(s+1);
170 network.socketsSemaphore.Release();
172 network.mutex.Release();
180 get { return this ? service : null; }
183 property char * inetAddress { get { return (char *)inetAddress; } };
184 property int inetPort { get { return inetPort; } }
185 property Socket next { get { return next; } };
186 property bool connected { get { return _connected == 1 || _connected == -2; } };
187 property bool processAlone { get { return processAlone; } set { processAlone = value; } };
189 virtual void OnConnect(void);
190 virtual uint OnReceive(const byte * buffer, uint count)
192 if(count >= sizeof(class Packet))
194 Packet packet = (Packet)buffer;
195 uint size = GETLEDWORD((byte *)&packet.size);
198 byte * tempBuffer = null;
203 tempBuffer = new byte[size];
204 packet = (Packet)tempBuffer;
205 memcpy(tempBuffer, buffer, size);
206 memmove(recvBuffer, recvBuffer + size, recvBytes - size);
210 OnReceivePacket(packet);
218 virtual void OnDisconnect(int code);
219 virtual void OnReceivePacket(Packet packet);
221 bool Connect(char * address, int port)
224 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
225 SOCKET s = socket(AF_INET,SOCK_STREAM,0);
227 Log("\n[P] [NConnect]\n");
231 result = _Connect(s, address, port);
237 void Disconnect(DisconnectCode code)
241 bool wasDisconnected = disconnected;
242 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
246 Logf("[P] [NDisconnect (%X, %x)]\n", this, this.s);
248 network.mutex.Wait();
249 disconnectCode = code;
258 ((_connected == -1) ? network.connectSockets : network.sockets).Remove(this);
262 service.sockets.Remove(this);
266 network.mutex.Release();
267 OnDisconnect(disconnectCode);
268 network.mutex.Wait();
271 if(s == network.ns - 1)
272 Network_DetermineMaxSocket();
276 FD_CLR(s, &network.readSet);
277 FD_CLR(s, &network.writeSet);
278 FD_CLR(s, &network.exceptSet);
280 // 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...
281 // Trying >= 1 instead of > 1
292 network.mutex.Release();
298 bool Send(void * buffer, int size)
300 #if defined(__WIN32__) || defined(__unix__) || defined(__APPLE__)
307 if(s != -1 && ((type == tcp && (count = SendData(buffer, size, 0))) ||
308 (type == udp && (count = (int)sendto(s, buffer, size,0, (SOCKADDR *)&a, sizeof(a))))))
310 #if defined(__WIN32__)
311 int error = WSAGetLastError();
317 #if defined(__WIN32__)
324 // This is what was making eCom jam...
325 // select(s+1, null, &ws, &es, null);
333 bool SendPacket(Packet packet)
338 uint size = packet.size;
339 PUTLEDWORD((byte *)&packet.size, size);
340 result = Send(packet, size);
347 bool SendString(char * string)
349 return Send(string, (int)strlen(string));
352 bool Sendf(char * format, ...)
356 char string[MAX_F_STRING];
357 va_start(args, format);
358 vsnprintf(string, sizeof(string), format, args);
359 string[sizeof(string)-1] = 0;
360 result = Send(string, (int)strlen(string));
365 bool DatagramConnect(char * sendAddress, int port)
367 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
370 _Connect(s, sendAddress, port);
377 bool DatagramHost(int port)
379 SOCKET s = socket(AF_INET,SOCK_DGRAM,0);
380 if(s != -1 && !_connected)
384 a.sin_family=AF_INET;
385 a.sin_port = htons((uint16)port);
386 a.sin_addr.s_addr=INADDR_ANY;
387 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
388 if(!bind(s,(SOCKADDR *)&a, sizeof(a)))
390 network.mutex.Wait();
393 network.sockets.Add(this);
396 disconnectCode = (DisconnectCode)-1;
399 FD_CLR(s, &network.writeSet);
400 FD_SET(s, &network.readSet);
401 FD_SET(s, &network.exceptSet);
404 network.ns = (int)(s+1);
405 network.socketsSemaphore.Release();
407 network.mutex.Release();
415 virtual int ReceiveData(byte * buffer, int count, uint flags)
417 return (int)recv(s, buffer, count, flags);
419 virtual int SendData(byte * buffer, int count, uint flags)
421 return (int)send(s, buffer, count, flags);
423 virtual bool OnEstablishConnection(int s);
428 Network_Initialize();
440 void Free(bool mustLock)
444 if(mustLock) network.mutex.Wait();
445 if(!service && _connected)
447 (_connected == -1 ? network.connectSockets : network.sockets).Remove(this);
454 network.mutex.Release();
456 OnDisconnect(disconnectCode);
457 // if(_refCount > 1) _refCount--;
459 network.mutex.Wait();
464 service.sockets.Remove(this);
469 if(s != -1) { closesocket(s); this.s = -1; }
479 FD_CLR(s, &network.readSet);
480 FD_CLR(s, &network.writeSet);
481 FD_CLR(s, &network.exceptSet);
486 // COMMENTED THIS OUT SINCE IT WAS INVALIDATING PROTECTION FOR HTTP FILE CONNECTION REUSE...
487 // WATCH FOR LEAKS IN OTHER PROJECTS?
488 //if(_refCount > 1) _refCount--;
489 if(mustLock) network.mutex.Release();
492 void _Disconnect(DisconnectCode code)
495 network.mutex.Wait();
497 disconnectCode = code;
502 if(s == network.ns - 1)
503 Network_DetermineMaxSocket();
504 network.mutex.Release();
507 bool _Connect(SOCKET s, char * address, int port)
513 a.sin_family = AF_INET;
514 a.sin_port = htons((uint16)port);
516 network.mutex.Wait();
522 this.address = new char[strlen(address)+1];
523 strcpy(this.address, address);
527 disconnected = false;
528 disconnectCode = (DisconnectCode)-1;
529 connectThread = null;
532 FD_SET(s, &network.writeSet);
533 if(s >= network.ns && !processAlone)
535 network.ns = (int)(s+1);
536 network.socketsSemaphore.Release();
538 connectThread = SocketConnectThread { socket = this };
540 if(OnConnect == Socket::OnConnect)
544 network.mutex.Release();
545 connectThread.Main();
546 network.mutex.Wait();
548 if(_connected == -1 || destroyed)
552 if(s == network.ns - 1)
553 Network_DetermineMaxSocket();
555 if(this.disconnectCode == resolveFailed)
556 Logf("Error resolving address %s\n", this.address);
562 else if(_connected == 1)
564 FD_CLR(s, &network.writeSet);
565 FD_SET(s, &network.readSet);
566 FD_SET(s, &network.exceptSet);
567 network.sockets.Add(this);
575 delete connectThread;
579 network.connectSockets.Add(this);
581 incref connectThread;
582 connectThread.Create();
588 network.mutex.Release();
592 #define MAX_RECEIVE 65536
594 bool ProcessSocket(fd_set * rs, fd_set * ws, fd_set * es)
601 // network.mutex.Wait();
603 if(FD_ISSET(s, rs) || leftOver)
608 if((int)recvBufferSize - recvBytes < MAX_RECEIVE)
610 recvBuffer = renew recvBuffer byte[recvBufferSize + MAX_RECEIVE];
611 recvBufferSize += MAX_RECEIVE;
614 if(FD_ISSET(s, rs) && disconnectCode == (DisconnectCode)-1)
616 if(type == tcp /*|| _connected*/)
617 count = ReceiveData(recvBuffer + recvBytes, recvBufferSize - recvBytes, 0);
621 count = (int)recvfrom(s, recvBuffer + recvBytes,
622 recvBufferSize - recvBytes, 0, (SOCKADDR *)&a, &len);
623 strcpy(inetAddress, inet_ntoa(this.a.sin_addr));
624 inetPort = ntohs((uint16)a.sin_port);
629 disconnectCode = remoteClosed;
634 printf("Errno is %d", errno);*/
635 disconnectCode = remoteLost;
641 if(count > 0 || (leftOver && !count))
646 for(flushCount = 0; flushCount < recvBytes; )
648 uint recvCount = OnReceive(recvBuffer + flushCount, recvBytes - flushCount);
653 network.leftOverBytes = true;
656 flushCount += recvCount;
659 if(flushCount < recvBytes)
663 memmove(recvBuffer, recvBuffer + flushCount, recvBytes - flushCount);
664 recvBytes -= flushCount;
668 // If nothing was acknowledged, clear socket so that OnReceive doesn't keep getting called
669 if(disconnectCode > -1)
677 else if(FD_ISSET(s, es))
681 Logf("Remote Lost %s\n", (void *)inet_ntoa(a.sin_addr));
684 _Disconnect(remoteLost);
687 // Disconnect it here
688 if(!recvBytes && disconnectCode > -1 && _connected)
693 Logf("Disconnected (%d) %s\n", disconnectCode, (void *)inet_ntoa(a.sin_addr));
696 _Disconnect(disconnectCode);
698 // network.mutex.Release();
706 public bool Process()
708 return ProcessTimeOut(0);
711 public bool ProcessTimeOut(Seconds timeOut)
713 bool gotEvent = false;
714 struct timeval tv = {0, 0};
715 struct timeval tvTO = {(uint)timeOut, (uint)((timeOut -(uint)timeOut)* 1000000)};
719 if(disconnectCode > 0 && !leftOver) return false;
728 selectResult = select((int)(s+1), &rs, &ws, &es, leftOver ? &tv : (timeOut ? &tvTO : null));
730 if(s != -1 && _refCount && (leftOver || selectResult))
732 gotEvent |= ProcessSocket(&rs, &ws, &es);
742 char inetAddress[20];
749 Thread connectThread;
750 DisconnectCode disconnectCode;