#include "cygwin.h" #include "cSocket.h" #define TCP_ACK 40 size_t global_ul_count = 0; // Values important for the UL/DL Management size_t global_dl_count = 0; int ul_left = 0; int dl_left = 0; size_t ulSecond = 10 * 1024; size_t dlSecond = 80 * 1024; //struct in_addr my_ip; size_t cSocket::count = 0; extern bool running; extern time_t currentTime; void every_sec (void); #ifdef CDONKEY #include "donkey.h" extern struct sPref pref; #endif const char *txtType (const cSocket *list1) {{{ if (list1 == NULL) return "(NULL)"; switch(list1->Type) { case tNone : return "none "; case tSocket : return "socket "; case tServer : return "server "; case tSource : return "source "; case tGui : return "gui "; case tCommand : return "source "; case tKademlia : return "kademlia"; case tServerUDP : return "udp_port"; } return ""; }}} const char* GetSockTypeString( int type ) {{{ switch( type ) { case SOCK_STREAM: return "SOCK_STREAM"; // stream socket case SOCK_DGRAM: return "SOCK_DGRAM"; // datagram socket case SOCK_RAW: return "SOCK_RAW"; // raw-protocol interface case SOCK_RDM: return "SOCK_RDM"; // reliably-delivered message case SOCK_SEQPACKET: return "SOCK_SEQPACKET"; // sequenced packet stream default: return "UNKNOWN SOCK TYPE!"; } }}} void cSocket::resetAccept(void) {{{ printf("do not accept connection !!!\n"); printf("closing fd: %d\n", fd_new); closesocket(fd_new); fd_new =INVALID_SOCKET; }}} typedef std::map cSocketMap; cSocketMap g_SocketMap; cSocketList event_list; cSocketList timer_list; #undef HAVE_ASYNCIO #define HAVE_POLLIO 1 #ifdef _WIN32 #define GetErrno() WSAGetLastError() #define SOCKET_WOULD_BLOCK WSAEWOULDBLOCK #define SOCKET_RETRY WSAEWOULDBLOCK #define WAIT_EVENT 1 u_long read_avail = 0; // cSocket::do Read // {{{ HINSTANCE asyncIO_prc; HWND asyncIO_win; ATOM asyncIO; void Win32_PrintErrorString( int err ) {{{ char* msg; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &msg, 0, NULL ); printf( msg ); LocalFree( msg ); }}} char* GetWSAErrorString( int err ) {{{ // WINDOWS spezific char* pMsg; switch(err) { case WSAVERNOTSUPPORTED: pMsg = "WSAVERNOTSUPPORTED: version of WinSock not supported"; break; case WSASYSNOTREADY: pMsg = "WSASYSNOTREADY: WinSock not present or not responding"; break; case WSAEINVAL: pMsg = "WSAEINVAL: app version not supported by DLL"; break; case WSAHOST_NOT_FOUND: pMsg = "WSAHOST_NOT_FOUND: Authoritive: Host not found"; break; case WSATRY_AGAIN: pMsg = "WSATRY_AGAIN: Non-authoritive: host not found or server failure"; break; case WSANO_RECOVERY: pMsg = "WSANO_RECOVERY: Non-recoverable: refused or not implemented"; break; case WSANO_DATA: pMsg = "WSANO_DATA: Valid name, no data record for type"; break; case WSANOTINITIALISED: pMsg = "WSANOTINITIALISED: WSA Startup not initialized"; break; case WSAENETDOWN: pMsg = "WSAENETDOWN: Network subsystem failed"; break; case WSAEINPROGRESS: pMsg = "WSAEINPROGRESS: Blocking operation in progress"; break; case WSAEINTR: pMsg = "WSAEINTR: Blocking call cancelled"; break; case WSAEAFNOSUPPORT: pMsg = "WSAEAFNOSUPPORT: address family not supported"; break; case WSAEMFILE: pMsg = "WSAEMFILE: no file descriptors available"; break; case WSAENOBUFS: pMsg = "WSAENOBUFS: no buffer space available"; break; case WSAEPROTONOSUPPORT: pMsg = "WSAEPROTONOSUPPORT: specified protocol not supported"; break; case WSAEPROTOTYPE: pMsg = "WSAEPROTOTYPE: protocol wrong type for this socket"; break; case WSAESOCKTNOSUPPORT: pMsg = "WSAESOCKTNOSUPPORT: socket type not supported for address family"; break; case WSAENOTSOCK: pMsg = "WSAENOTSOCK: descriptor is not a socket"; break; case WSAEWOULDBLOCK: pMsg = "WSAEWOULDBLOCK: socket marked as non-blocking and SO_LINGER set not 0"; break; case WSAEADDRINUSE: pMsg = "WSAEADDRINUSE: address already in use"; break; case WSAECONNABORTED: pMsg = "WSAECONNABORTED: connection aborted"; break; case WSAECONNRESET: pMsg = "WSAECONNRESET: connection reset"; break; case WSAENOTCONN: pMsg = "WSAENOTCONN: not connected"; break; case WSAETIMEDOUT: pMsg = "WSAETIMEDOUT: connection timed out"; break; case WSAECONNREFUSED: pMsg = "WSAECONNREFUSED: connection refused"; break; case WSAEHOSTDOWN: pMsg = "WSAEHOSTDOWN: host down"; break; case WSAEHOSTUNREACH: pMsg = "WSAEHOSTUNREACH: host unreachable"; break; case WSAEADDRNOTAVAIL: pMsg = "WSAEADDRNOTAVAIL: address not available"; break; default: pMsg = "WSA UNKNOWN ERROR!"; break; } return pMsg; }}} void Win32_SocketEventToString( WORD ev, std::string& str ) {{{ if( ev & FD_ACCEPT ) str += "ACCEPT "; if( ev & FD_CONNECT ) str += "CONNECT "; if( ev & FD_OOB ) str += "OOB "; if( ev & FD_READ ) str += "READ "; if( ev & FD_WRITE ) str += "WRITE "; if( ev & FD_CLOSE ) str += "CLOSE "; // if( ev & FD_QOS ) str += "QOS "; // if( ev & FD_GROUP_QOS ) str += "GROUP_QOS "; }}} LRESULT CALLBACK handleSocket (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {{{ // WINDOWS spezific if (uMsg != WM_USER) return DefWindowProc(hwnd, uMsg, wParam, lParam); // not our async message int fd = (int)wParam; class cSocket *sock = NULL; cSocketMap::iterator so_it = g_SocketMap.find(fd); if (so_it != g_SocketMap.end()) sock = so_it->second; int event = 0; WORD win_event = LOWORD(lParam); int err = HIWORD(lParam); std::string strEvent; if( err || sock == NULL ) { Win32_SocketEventToString( win_event, strEvent ); printf( "handleSocket: fd = %i, event = %s\n", fd, strEvent.c_str() ); if( err ) printf( " ERRNO:%i => %s\n", err, GetWSAErrorString(err) ); if( sock == NULL ) printf( " Received event for an unregistered socket.\n" ); // else sock->last_err = err; return 0; } if( win_event & FD_CLOSE ) { delete sock; return 0; } if( win_event & (FD_ACCEPT | FD_READ) ) event |= 1; if( win_event & (FD_CONNECT | FD_OOB | FD_WRITE) ) event |= 2; if( event ) sock->doWork( event ); else { Win32_SocketEventToString( win_event, strEvent ); printf( "handleSocket: unhandled event = %s\n", strEvent.c_str() ); } return 0; }}} // TimerProc is called every second. VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) {{{ // *** call every_sec() here *** // printf("TimerProc: called every second. Time (ms) = %li\n", dwTime); }}} void cSocket::Start (void) {{{ // WINDOWS spezific cSocket::local_external_ip.s_addr = 0; cSocket::local_internal_ip.s_addr = 0; const char name[] = "asyncio"; WNDCLASS wc; // Hidden window for async-io message tracking wc.style=0; wc.lpfnWndProc=(WNDPROC)handleSocket; wc.cbClsExtra=0; wc.cbWndExtra=0; wc.hIcon=0; wc.hCursor=0; wc.hbrBackground=0; wc.lpszMenuName=(LPSTR)0; wc.lpszClassName= name; asyncIO_prc = (HINSTANCE) wc.hInstance = GetModuleHandle(NULL); if (!(asyncIO = RegisterClass(&wc))) { printf("RegisterClass failed :-(\n"); exit(0); } if (!(asyncIO_win = CreateWindow(name,"win-io",WS_POPUP,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,asyncIO_prc,0))) { printf("CreateWindow failed :-(\n"); exit(0); } WSADATA wsadata; if (0 == SetTimer(asyncIO_win, 1, 1000, TimerProc)) { // TimerProc is called once every second printf("Timer failed\n"); exit(0); } if (WSAStartup(0x0101, &wsadata)) { WSACleanup(); printf("WSAStartup failed\n"); exit(0); } if (wsadata.wVersion < 0x0101) { WSACleanup(); printf("Wrong winsock version\n"); exit(0); } }}} void cSocket::doUnblock (void) {{{ // WINDOWS spezific if (fd == INVALID_SOCKET) return; u_long command = 1; int ret = ioctlsocket (fd, FIONBIO, &command); // Redirect events and set non-blocking mode if(ret != 0) { printf("Seting socket to nonblocking failed ERR: %i\n", ret); } if (WSAAsyncSelect(fd, asyncIO_win, WM_USER, FD_READ|FD_WRITE|FD_ACCEPT|FD_CLOSE|FD_OOB) < 0) { printf("ERROR: WSAAsyncSelect failed\n"); exit(0); } }}} const char* cSocket::Strerror (int err) { return GetWSAErrorString(err); } void cSocket::printError (int err) {{{ // WINDOWS spezific printf("ERRNO %u => %s\n", err, cSocket::Strerror(err) ); printf(" fd %i, port %u, peer %s:%u\n", fd, this_port, inet_ntoa(peer_ip), peer_port ); }}} void cSocket::doBlock(void) { } // }}} #else #define GetErrno() errno #define SOCKET_WOULD_BLOCK EINPROGRESS #define SOCKET_RETRY EAGAIN size_t read_avail = 0; // cSocket::do Read // {{{ #ifdef HAVE_ASYNCIO # define USE_SIGNAL (SIGRTMIN+5) # define WAIT_EVENT 4 void handleSocket (int, siginfo_t *, void *) { printf("handleSocket\n"); } void handlePipe (int, siginfo_t *, void *) { printf("handlePipe \n"); } // SIGPIPE void handleIO (int, siginfo_t *info, void *) { printf("handleIO\n"); printf("info->si_signo => %i\n", info->si_signo); printf("info->si_errno => %i\n", info->si_errno); printf("info->si_code => %i\n", info->si_code); } // SIGIO void handleSEGV (int, siginfo_t *, void *) { printf("handleSEGV \n"); } void handleFPE (int, siginfo_t *, void *) { printf("handleFPE \n"); } void handleILL (int, siginfo_t *, void *) { printf("handleILL \n"); } void handleBUS (int, siginfo_t *, void *) { printf("handleBUS \n"); } #elif HAVE_POLLIO # define WAIT_EVENT 3 #else # define WAIT_EVENT 2 #endif #ifdef HAVE_ASYNCIO typedef void (*action_hdl)(int, siginfo_t *, void *); static void SigAction(int signum, action_hdl action) {{{ struct sigaction act; bzero (&act, sizeof(act)); sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; act.sa_sigaction = action; if (0 != sigaction(signum, &act, NULL)) { printf("sigaction(%i,*) => %i : %s\n", signum, errno, cSocket::Strerror(errno)); abort(); } }}} void cSocket::doUnblock (void) {{{ // LINUX spezific if (fd == INVALID_SOCKET) return; int opt = 1; // sec to wait for data int async = O_ASYNC | O_NONBLOCK; if (0 != fcntl (fd, F_SETOWN, getpid())) {{{ // abort printf("fcntl (fd, F_SETOWN, getpid()) => %i : %s\n", errno, cSocket::Strerror(errno)); abort(); }}} if (0 != fcntl (fd, F_SETSIG, USE_SIGNAL)) {{{ // abort printf("fcntl (fd, F_SETSIG, USE_SIGNAL) => %i : %s\n", errno, cSocket::Strerror(errno)); abort(); }}} if (0 != fcntl (fd, F_SETFL , async | fcntl (fd, F_GETFL, 0))) {{{ // abort printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno)); abort(); }}} if (type != SOCK_DGRAM) if (0 != setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(int))) { printf("setsockopt(fd, SOL_TCP, TCP_NODELAY, [1], 4) => %i : %s\n", errno, cSocket::Strerror(errno)); } struct pollfd check; check.fd = fd; check.events = POLLIN | POLLOUT | POLLERR; if (0 < poll (&check, 1, 0)) { mask &= 32; if (check.revents & POLLIN ) mask |= 1; if (check.revents & POLLOUT) mask |= 2; if (check.revents & POLLERR) mask |= 4; } }}} void cSocket::doBlock (void) {{{ int async = O_ASYNC | O_NONBLOCK; if (0 != fcntl (fd, F_SETFL , (~async) & fcntl (fd, F_GETFL, 0))) { printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno)); } }}} #else void cSocket::doUnblock (void) {{{ // LINUX spezific int async = O_NONBLOCK; if (fd == INVALID_SOCKET) return; int opt = 1; // sec to wait for data if (0 != fcntl (fd, F_SETFL , async | fcntl (fd, F_GETFL, 0))) {{{ // abort printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno)); abort(); }}} if (type == SOCK_DGRAM) return; if (0 != setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(int))) { printf("setsockopt(fd, SOL_TCP, TCP_NODELAY, [1], 4) => %i : %s\n", errno, cSocket::Strerror(errno)); } }}} void cSocket::doBlock(void) { } #endif void cSocket::Start (void) {{{ // LINUX spezific cSocket::local_external_ip.s_addr = 0; cSocket::local_internal_ip.s_addr = 0; #ifdef HAVE_ASYNCIO SigAction (USE_SIGNAL, handleSocket); SigAction (SIGPIPE , handlePipe ); SigAction (SIGIO , handleIO ); // SigAction (SIGSEGV , handleSEGV ); // These can cause big trouble SigAction (SIGFPE , handleFPE ); SigAction (SIGILL , handleILL ); SigAction (SIGBUS , handleBUS ); // Block "USE_SIGNAL" so we can dequeue it in the wait process sigset_t block_rtmin; sigemptyset (&block_rtmin); sigaddset (&block_rtmin, USE_SIGNAL); sigaddset (&block_rtmin, SIGALRM ); sigprocmask (SIG_BLOCK, &block_rtmin, NULL); struct itimerval cur_timer; struct itimerval old_timer; cur_timer.it_interval.tv_sec = 1; cur_timer.it_interval.tv_usec = 0; cur_timer.it_value .tv_sec = 1; cur_timer.it_value .tv_usec = 0; setitimer(ITIMER_REAL, &cur_timer, &old_timer); #endif }}} const char* cSocket::Strerror (int err) { return strerror(err); } void cSocket::printError (int err) {{{ // LINUX spezific ASSERT(err != 11); // EAGAIN ASSERT(err != 13); // ASSERT(err != 22); // EINVAL ASSERT(err != SOCKET_WOULD_BLOCK); printf("%15s:%5u ERRNO %5u => %s\n", inet_ntoa(peer_ip), peer_port, err , cSocket::Strerror(err)); }}} // }}} #endif #if WAIT_EVENT == 1 void cSocket::waitEvent (int ) {{{ // Windows version MSG msg; BOOL bRet; if ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { // Main message loop: if (bRet == -1) { printf( "GetMessage error: " ); Win32_PrintErrorString( GetLastError() ); } else { TranslateMessage(&msg); DispatchMessage(&msg); // cSocket::hdlEvent(); } } }}} #elif WAIT_EVENT == 2 void cSocket::waitEvent (int usec) {{{ // Select Version struct timeval timeout; timeout.tv_sec = (usec / 1000000); // Set timeout for the select() timeout.tv_usec = (usec % 1000000); fd_set fd_1; fd_set fd_2; fd_set fd_4; FD_ZERO(&fd_1); FD_ZERO(&fd_2); FD_ZERO(&fd_4); int max = 0; for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) { class cSocket *akt = so_it->second; if (akt == NULL) continue; if (akt->fd < 0) continue; if (akt->fd > 1023) continue; if (akt->fd > max) max = akt->fd + 1; FD_SET(akt->fd, &fd_1); if (akt->send_len > 0) FD_SET(akt->fd, &fd_2); if (akt->connected == 0) FD_SET(akt->fd, &fd_2); FD_SET(akt->fd, &fd_4); } int cnt = select (max + 1, &fd_1, &fd_2, &fd_4, &timeout); if (cnt <= 0) { if (cnt < 0) ; // printf("Error %i in select()\n", errno); return; } for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) { class cSocket *akt = so_it->second; if (akt == NULL) continue; if (akt->fd < 0) continue; if (akt->fd > 1023) continue; if (cnt <= 0) continue; if (FD_ISSET(akt->fd, &fd_1)) { akt->addEvent(1); cnt--; } if (FD_ISSET(akt->fd, &fd_2)) { akt->addEvent(2); cnt--; } if (FD_ISSET(akt->fd, &fd_4)) { akt->addEvent(4); cnt--; } } }}} #elif WAIT_EVENT == 3 #define POLL_LIMIT 8192 void cSocket::waitEvent (int usec) {{{ // Poll Version usec = usec / 1000; struct pollfd poll_fds[POLL_LIMIT]; // limited file descriptors! cSocket *sockets[POLL_LIMIT]; unsigned int num, i = 0; cSocketMap::iterator so_it; for (so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) { class cSocket *akt = so_it->second; if (akt == NULL) continue; poll_fds[i].fd = akt->fd; poll_fds[i].events = POLLIN | POLLERR | POLLHUP | POLLNVAL; if (akt->send_len > 0) poll_fds[i].events |= POLLOUT; if (akt->connected == 0) poll_fds[i].events |= POLLOUT; poll_fds[i].revents = 0; sockets[i] = akt; if (++i >= POLL_LIMIT) break; // should crash here?!? } num = i; int cnt = poll (poll_fds, i, usec); if (cnt <= 0) { if (cnt == 0) return; // Timeout if (errno == EINTR) return; // A signal occurred before any requested event. printf("poll ([poll_fds], %u, %i) => %4i = %s\n", i, usec, errno, strerror(errno)); return; } i = 0; for (i = 0; i < num && cnt > 0; i++) { class cSocket *akt = sockets[i]; if (akt == NULL) continue; if ( poll_fds[i].revents == 0) continue; // Here we handle only sockets with new events, // Other there handled each seconed cnt--; // cnt more events to handle int m = akt->mask; akt->mask &= 32; if ((poll_fds[i].revents & POLLIN ) != 0) m |= 1; if ((poll_fds[i].revents & POLLPRI ) != 0) { m |= 16; printf("urgent data\n"); } if ((poll_fds[i].revents & POLLOUT ) != 0) m |= 2; if ((poll_fds[i].revents & POLLERR ) != 0) m |= 4; if ((poll_fds[i].revents & POLLHUP ) != 0) if (akt->connected != 2 && akt->connected != 3) m |= 16; // This does not close listen sockets if ((poll_fds[i].revents & POLLNVAL) != 0) m |= 16; if (m == 0) continue; // Listen socket, wich was not closed if ((m & 16) == 0) akt->doWork(m); if (((m | akt->mask) & 16) != 0) { log(1, "cSocket::waitEvent delete %x\n", akt); for (int j=i+1;jsecond; if (sock == NULL) { // printf("Unhandeld socket %4i code %i\n", info.si_fd ,info.si_code); /* I (thomas) checked that unhandeld socket result from events that happen after close the socket and remove the handler. That mean they should cause no problem. Please do not remove the comment, from time to time it can make sense to check if there was no code error. */ continue; } info.si_code |= sock->mask; sock->mask &= 32; if ( 4 == (info.si_code & 4)) sock->last_err = info.si_errno; if ( 0 == (info.si_code & 16)) sock->doWork(info.si_code); // ORDER IS IMPORTANT if (16 == (info.si_code & 16)) { log(1, "cSocket::waitEventASYNC delete %x\n", sock); delete sock; } continue; } printf("SIGNAL %i unhandeld\n", info.si_signo); } // while (running) }}} #else #error "Undefined Socket waiting" #endif void cSocket::Stop (void) {{{ size_t safe = g_SocketMap.size(); for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it = g_SocketMap.begin()) { log(1, "cSocket::Stop delete %x\n", so_it->second); delete so_it->second; // ~cSocket delete itself from g_SocketMap size_t check = g_SocketMap.size(); ASSERT(check < safe); safe = check; } #ifdef _WIN32 WSACleanup(); DestroyWindow(asyncIO_win); UnregisterClass((LPCTSTR) MAKEINTATOM(asyncIO), asyncIO_prc); #endif }}} void cSocket::Init0 (void) {{{ last_err = 0; Type = tNone; event = NULL; mask = 0; prio = 1; fd_new = INVALID_SOCKET; event = NULL; send_buf = NULL; send_len = 0; read_buf = NULL; read_len = 0; last_read = 0; last_send = 0; since = currentTime; work_last = currentTime; timer = NULL; destr_callback = NULL; }}} cSocket :: cSocket (class cSocket *FD) {{{ printf("(create.1) cSocket %p\n", this); count++; Init0(); fd = FD->fd_new; if (fd == INVALID_SOCKET) { printf("ERROR %s %i\n", __FILE__, __LINE__); addEvent(16); return; } g_SocketMap[fd] = this; doUnblock(); timer = timer_list.add_back (this); FD->fd_new = INVALID_SOCKET; type = SOCK_STREAM; connected = 1; ready_send = 1; dl_count = ul_count = 0 ; struct sockaddr_in addr; socklen_t len = sizeof(addr); getpeername(fd, reinterpret_cast(&addr), &len); this_ip.s_addr = 0; this_port = FD->this_port; peer_port = 0; peer_ip = addr.sin_addr; peer_port = addr.sin_port; last_conn = currentTime; if (!guessSocketLocalIP()) addEvent(16); // if op. failed, there's something wrong with the socket anyway }}} cSocket :: cSocket (unsigned int IP, uint16_t PORT, int TYPE) {{{ printf("(create.2) cSocket %p\n", this); count++; Init0(); type = TYPE; if (PORT == 0 || (type != SOCK_STREAM && type != SOCK_DGRAM)) { printf("ERROR %s %i\n", __FILE__, __LINE__); addEvent(16); return; } // {{{ Create Socket, aktivate Handling fd = socket (AF_INET, type, 0); if (fd == INVALID_SOCKET) {{{ last_err = GetErrno(); printf("cSocket::cSocket(IP,PORT,TYPE) :"); printError (last_err); addEvent(16); if (EMFILE == last_err) { if (TCP_CLIENT_COUNT > cSocket::count) TCP_CLIENT_COUNT = cSocket::count - 10; else TCP_CLIENT_COUNT -= 10; return; } assert(0); return; }}} g_SocketMap[fd] = this; timer = timer_list.add_back (this); doUnblock(); // }}} struct sockaddr_in srv_addr; srv_addr.sin_family = AF_INET; srv_addr.sin_addr = cSocket::getLocalInternalIP (); srv_addr.sin_port = htons(0); if (0 != bind(fd, reinterpret_cast(&srv_addr), sizeof(srv_addr))) {{{ int err = GetErrno(); printf("bind(%i, %15s:%5u <%u>, %u) => %s\n", fd, inet_ntoa(srv_addr.sin_addr), htons(srv_addr.sin_port), type, sizeof(srv_addr),cSocket::Strerror(err)); addEvent(16); assert(0); return; }}} dl_count = ul_count = 0 ; this_ip.s_addr = 0; this_port = 0; peer_port = PORT; peer_ip.s_addr = IP; struct sockaddr_in server_addr; bzero (&server_addr, sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = IP; server_addr.sin_port = htons (PORT); int ret = connect(fd, reinterpret_cast(&server_addr), sizeof(server_addr)); if (ret == -1) {{{ // Erro happened maybe only deffered connection int err = GetErrno(); if (err != SOCKET_WOULD_BLOCK) { printf ("BIND "); printError (err); addEvent(16); return; } }}} if (!guessSocketLocalIP()) addEvent(16); // if op. failed, there's something wrong with the socket anyway connected = (ret == 0); ready_send = (ret == 0); }}} cSocket :: cSocket (unsigned short PORT, int TYPE) {{{ printf("(create.3) cSocket %p\n", this); count++; Init0(); if (TYPE == SOCK_STREAM) connected = 2; else connected = 3; dl_count = ul_count = 0 ; peer_port = 0; peer_ip.s_addr = 0; last_err = 0; type = TYPE; if (PORT == 0 || (type != SOCK_STREAM && type != SOCK_DGRAM)) { printf("ERROR %s %i\n", __FILE__, __LINE__); addEvent(16); return; } fd = socket (AF_INET, type, 0); if (fd == INVALID_SOCKET) {{{ printf("cSocket::cSocket(PORT,TYPE) :"); printError (GetErrno()); addEvent(16); return; }}} g_SocketMap[fd] = this; doUnblock(); timer = timer_list.add_back (this); this_ip.s_addr = 0; struct sockaddr_in client_addr; bzero (&client_addr, sizeof client_addr); // clear sin_zero client_addr.sin_family = AF_INET; client_addr.sin_addr = cSocket::getLocalInternalIP (); client_addr.sin_port = htons(PORT); #ifndef _WIN32 int opt = 1; // sec to wait for data setsockopt(fd, SOL_SOCKET, SO_REUSEADDR , &opt, sizeof(int)); #endif if (0 != bind(fd, reinterpret_cast(&client_addr), sizeof(client_addr))) { int err = GetErrno(); printf("bind(%i, %15s:%5u <%u>, %u) => %s\n", fd, inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port), type, sizeof(client_addr),cSocket::Strerror(err)); addEvent(16); return; } bzero (&client_addr, sizeof client_addr); socklen_t len = sizeof(client_addr); getsockname(fd, reinterpret_cast(&client_addr), &len); this_port = htons(client_addr.sin_port); printf("Listen on %15s:%5u (Proto: %u) ", inet_ntoa( client_addr.sin_addr), this_port, type); if (type == SOCK_STREAM)printf("(TCP) "); else if (type == SOCK_DGRAM )printf("(UDP) "); else printf("(Proto %u) ", type); #ifdef CDONKEY if (this_port == pref.ports.server ) printf("eDonkey-Server (should be forwarded)\n"); else if (this_port == pref.ports.client ) printf("eDonkey-Client (should be forwarded)\n"); else if (this_port == pref.ports.emule ) printf("eDonkey-UDP (should be forwarded)\n"); else if (this_port == pref.ports.kademlia) printf("Overnet-UDP (should be forwarded)\n"); else if (this_port == pref.ports.gui ) printf("eDonkey-Gui (password protected, should not be forwarded)\n"); else if (this_port == pref.ports.clc ) printf("eDonkey-CLC (password protected, should not be forwarded)\n"); else if (this_port == pref.ports.web ) printf("eDonkey-Web (password protected, should not be forwarded)\n"); else if (this_port == this_port ) printf("TODO: Document it!\n"); #endif if (type == SOCK_STREAM) listen(fd,64); }}} cSocket ::~cSocket () {{{ // ASSERT(connected != 2); count--; if (event != NULL) delete event; if (timer != NULL) delete timer; doBlock (); shutdown (fd, 2); if (fd != INVALID_SOCKET) g_SocketMap.erase(fd); if (g_SocketMap.size() != count) printf("WARNING: SocketMap: %d count: %d\n", g_SocketMap.size(),count); ASSERT (fd != -1); printf("(destr.)closing fd: %u this: %p:\n", fd, this); closesocket(fd); if (send_buf != NULL) free (send_buf); if (read_buf != NULL) free (read_buf); if (destr_callback != NULL) (*destr_callback)(this); }}} void cSocket::Close (void) {{{ ASSERT(connected != 2); addEvent(16); // let safely delete hdl event this }}} void cSocket::setDestructorCallback(void (*callback)(cSocket *)) {{{ if (callback != NULL) destr_callback = callback; }}} void cSocket::doAccept (void) {{{ do { if (fd_new != INVALID_SOCKET) { printf("cSocket::doAccept: ERROR! An accepted connection was left dangling.\n"); printf(" this_port=%u, fd_new=%u\n", this_port, fd_new); printf(" CLOSING SOCKET!\n"); printf("(doAcc) closing fd: %d\n", fd_new); closesocket(fd_new); } struct sockaddr_in addr; socklen_t len = sizeof (addr); do {{{ fd_new = accept(fd, reinterpret_cast(&addr), &len); if (fd_new != INVALID_SOCKET) break; last_err = GetErrno(); if (last_err == EINTR) continue; if (last_err == SOCKET_RETRY) return; printf("accept()"); printError(last_err); }}} while (true); if (fd_new == INVALID_SOCKET) return; peer_ip = addr.sin_addr; peer_port = htons(addr.sin_port); Work(); } while (true); // Handle multiple connects // hl: Doesn't seem wise to me, // Maybe some upper limit? }}} void cSocket::doSend (void) {{{ mask = mask & (~2); if (type == SOCK_DGRAM ) return; if (fd == INVALID_SOCKET) return; if (connected == 2) { doAccept (); return; } if (connected == 0) {{{ // maintain connection state last_conn = currentTime; connected = 1; ready_send = 1; socklen_t len = sizeof(last_err); getsockopt (fd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&last_err), &len); if (last_err == ECONNREFUSED) { addEvent(16); return; } if (last_err == EHOSTUNREACH) { addEvent(16); return; } if (last_err) printf("ERR 666 => %i\n", last_err); }}} if (send_len == 0) return; int done = 0; do {{{ done = send (fd, send_buf, send_len, 0); if (done > 0) break; ready_send = 0; last_err = GetErrno(); if (last_err == EINTR ) continue; if (last_err == SOCKET_RETRY ) return; if (last_err == SOCKET_WOULD_BLOCK ) return; addEvent(16); if (last_err == ECONNREFUSED ) return; if (last_err == EHOSTUNREACH ) return; if (last_err == 104 ) return; if (last_err == 32) return; // EPIPE printf("675 err "); printError(last_err); return; }}} while (true); last_send = currentTime; if (done <= 0) return; if (prio != 0) {{{ // Handle traffic accounting global_dl_count += TCP_ACK; //we do only count all finished bytes of that file //dl_count += TCP_ACK; global_ul_count += TCP_ACK + done; //ul_count += TCP_ACK + done ; dl_left -= TCP_ACK; ul_left -= TCP_ACK + done; }}} send_len -= done; if (send_len > 0) { memcpy (send_buf, send_buf + done, send_len); // send_buf = (char*)REALLOC(send_buf, send_len); // become smaller (leave it safe time and fragmention } else { // free (send_buf); // become smaller (leave it safe time and fragmention // send_buf = NULL; } ready_send = (send_len == 0); }}} void cSocket::doRead (void) {{{ if (16 == (16 & mask)) return; if (fd == INVALID_SOCKET) { addEvent(16); return; } int done = 0; int err = 0; if (connected == 2) { doAccept (); return; } do {{{ done = ioctlsocket(fd, FIONREAD, &read_avail); if (done == 0) break; err = GetErrno(); if (err == EINTR) continue; printf("ioctlsocket %15s", inet_ntoa(peer_ip)); printError(err); addEvent(16); return; }}} while(true); if (type == SOCK_DGRAM ) {{{ // return if (read_avail == 0) return; last_read = currentTime; struct sockaddr_in addr; do { if (read_buf == NULL) { read_buf = reinterpret_cast(MALLOC (read_avail)); read_buf_length = read_avail; } else { if (read_buf_length < read_avail) { read_buf = reinterpret_cast(REALLOC(read_buf, read_avail)); read_buf_length = read_avail; } } socklen_t s_len = sizeof(addr); do {{{ done = recvfrom(fd, read_buf, read_avail, 0, reinterpret_cast(&addr), &s_len); if (done >= 0) break; err = GetErrno(); if (err != EINTR) break; }}} while(true); if (done <= 0) {{{ // return // if (read_buf != NULL) free (read_buf); // become smaller (leave it safe time and fragmention // read_buf = NULL; return; }}} if (prio != 0) {{{ // count the traffic //global_dl_count += TCP_ACK + done; //dl_count += TCP_ACK + done; dl_left -= TCP_ACK + done; }}} peer_ip = addr.sin_addr; peer_port = htons(addr.sin_port); read_len = done; doRead_high(); // if (read_buf != NULL) free (read_buf); // become smaller (leave it safe time and fragmention // read_buf = NULL; read_avail -= done; last_read = currentTime; } while (read_avail > 0); return; }}} if (read_avail <= 0) read_avail = 4; if (type == SOCK_STREAM) {{{ // return if (read_buf == NULL) { read_buf = reinterpret_cast(MALLOC (read_len + read_avail)); read_buf_length = read_len + read_avail; } else { if (read_buf_length < read_len + read_avail) { read_buf = reinterpret_cast(REALLOC(read_buf, read_len + read_avail)); read_buf_length = read_len + read_avail; } } do {{{ done = recv (fd, read_buf + read_len, read_avail, 0); if (done == 0) { // free (read_buf); // deleted in destructor // read_buf = NULL; read_avail = 0; read_len = 0; addEvent(16); return; } int done_old = done; if (done > 0) break; err = GetErrno(); if (err == EINTR) continue; done = 0; if (err == SOCKET_RETRY ) break; if (err == SOCKET_WOULD_BLOCK) break; addEvent(16); // free (read_buf); // read_buf = NULL; // deleted in destructor read_avail = 0; read_len = 0; if (err == ECONNREFUSED ) return; if (err == 0 ) return; if (err == ENOTCONN ) return; // 107 notconnected if (err == ECONNRESET ) return; // 104 connection reset by peer if (err == EHOSTUNREACH ) return; // 113 connection reset by peer if (err == ETIMEDOUT ) return; // 110 ETIMEDOUT if (err == 10054 ) return; if (done_old == 0 && read_avail > 0) return; printf("%5i %s recv () = %i\n", __LINE__, __FILE__, done_old); printError(err); return; }}} while (true); if (done > 0) {{{ // we have realy read someting if (connected == 0) { connected = 1; ready_send = 1; last_conn = currentTime; } read_len += done; last_read = currentTime; if (prio != 0) {{{ // count traffic global_ul_count += TCP_ACK; //ul_count += TCP_ACK; global_dl_count += TCP_ACK + done; //dl_count += TCP_ACK + done ; ul_left -= TCP_ACK; dl_left -= TCP_ACK + done; }}} }}} if (read_len != 0) { if (read_buf_length < read_len) { read_buf = reinterpret_cast(REALLOC (read_buf, read_len)); read_buf_length = read_len; } } return; }}} }}} bool cSocket::Write (const unsigned char *buf, size_t len) {{{ ASSERT(fd != INVALID_SOCKET); ASSERT(fd < 100000); if (type == SOCK_DGRAM) {{{ // Handle UDP sending struct sockaddr_in addr; bzero (&addr, sizeof(addr)); socklen_t addr_len = sizeof(addr); addr.sin_addr = peer_ip; addr.sin_port = htons(peer_port); addr.sin_family = AF_INET; last_send = currentTime; ASSERT(buf[0] != 0x07); int ret = 0; const char *c_buf = reinterpret_cast(buf); ret = sendto (fd, c_buf, len, 0 , reinterpret_cast(&addr), addr_len); size_t RET = ret; if (ret < 0) {{{ // display error int err = GetErrno(); if (err == 22) return false; if (err == 11) return false; if (err == 101) { printf("UNREACHABLE %s\n", inet_ntoa(addr.sin_addr)); return false; } printf("IP 13 %s\n", inet_ntoa(addr.sin_addr)); printf("LEN %i\n", len); if (err == 13) printf("IP 13 %s\n", inet_ntoa(addr.sin_addr)); printf("fd: %u this %p:\n", fd, this); printError(err); return false; }}} if (prio != 0) {{{ // count traffic global_ul_count += TCP_ACK + ret; //ul_count += TCP_ACK + ret ; ul_left -= TCP_ACK + ret; }}} return RET == len; }}} if (fd == INVALID_SOCKET) return false; if (send_buf == NULL) {{{ send_buf = reinterpret_cast(MALLOC (send_len + len)); send_buf_length = send_len + len; }}} else {{{ if (send_buf_length < send_len + len) { send_buf = reinterpret_cast(REALLOC (send_buf, send_len + len)); send_buf_length = send_len + len; } }}} memcpy (send_buf + send_len, buf, len); send_len += len; if (0 == (mask & 2)) addEvent(2); return (ready_send == 1); }} } size_t cSocket::Read (unsigned char *buf, size_t len) {{{ if (fd == INVALID_SOCKET) return 0; if (read_len < len) len = read_len; if (len == 0) return 0; ASSERT(read_len > 0 ); ASSERT(read_buf != NULL); memmove (buf, read_buf, len); read_len -= len; if (read_len == 0) { // free (read_buf); // become smaller (leave it safe time and fragmention // read_buf = NULL; } else { memmove (read_buf, read_buf + len, read_len); // read_buf = (char*)REALLOC(read_buf, read_len); // become smaller (leave it safe time and fragmention } return len; }}} bool cSocket::doInternal(int Event) {{{ ASSERT (fd != INVALID_SOCKET); if (4 == (4 & Event)) { // Error socklen_t len = sizeof(last_err); getsockopt (fd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&last_err), &len); // Error happend if (last_err != 0) { // printError(last_err); addEvent(16); // error's should not be able to recover if (last_err == 0 ) return false; if (last_err == ECONNREFUSED ) return false; // 111 if (last_err == ECONNRESET ) return false; // 104 if (last_err == EHOSTUNREACH ) return false; // 113 if (last_err == 32 ) return false; // EPIPE because read ignore read len = 0 return false; } } ASSERT (fd != INVALID_SOCKET); if (2 == (2 & Event)) doSend (); // Send data if posible if (send_len == 0 && 32 == (mask & 32)) mask = 16; ASSERT (fd != INVALID_SOCKET); if (mask & 16) return false; if (1 == (1 & Event)) doRead (); ASSERT (fd != INVALID_SOCKET); if (16 == (mask & 16)) return false; if (fd != INVALID_SOCKET) return false; if (type == SOCK_DGRAM) return false; return (send_len == 0 || read_len > 0); }}} void cSocket::doWork (int Event) {{{ ASSERT((mask&16)==0); ASSERT (fd != INVALID_SOCKET); if (mask & 16) return; Event = Event | mask; mask &= 32; bool work = (8 == (8 & Event)); ASSERT (fd != INVALID_SOCKET); if (connected == 0) work = true; doInternal (Event); if (16 == (mask & 16)) return; if (connected == 2) return; if (!work && (read_len == 0) && (send_len > 0)) return; // NOTE: if there's no 1 event, // doInternal might not have done any reading // and doRead_high might kill the whole thing // (because read_buf == NULL) bool worked = false; while (read_len > 0 && fd != INVALID_SOCKET) { if (mask & 16) return; doRead_high(); if (mask & 16) return; if (!canWork()) break; readWork(); mask = mask & (~8); Work(); work = false; worked = true; } if (work) { ASSERT((mask&16)==0); Work (); worked = true; } if (worked) { work_last = currentTime; if (timer != NULL) delete timer; timer = timer_list.add_back (this); } else { if (timer == NULL) timer = timer_list.add_back (this); } if (mask & 2) { mask = mask & (~2); doSend(); } if (send_len == 0 && 32 == (mask & 32)) mask = 16; }}} void cSocket::addEvent (int Event) {{{ if (Event == 0) return; mask |= Event; if (event != NULL) return; if (prio == 0) event = event_list.add_front(this); else event = event_list.add_back (this); }}} void cSocket::hdlEvent (void ) {{{ class cSocket *stop = NULL; while (!event_list.empty() && ul_left > 0 && dl_left > 0) { class cSocket *akt = event_list.peek(); if (stop == akt) return; cSocketList::remove(&akt->event); unsigned mask_tmp = akt->mask; akt->mask &= 32; if (!akt->validSocket()) mask_tmp = 16; if (mask_tmp == 0) continue; if (0 == (16 & mask_tmp)) akt->doWork(mask_tmp); if (mask_tmp & 16) { log(1, "cSocket::hdlEvent delete %x\n", akt); delete akt; } else if (akt->event != NULL && stop == NULL) stop = akt; } }}} // // utility funtions for IP handling // #define MAX_HOSTNAME_LENGTH 256 struct in_addr cSocket::local_internal_ip; bool cSocket::local_internal_ip_forced = false; struct in_addr cSocket::local_external_ip; bool cSocket::local_external_ip_forced = false; int cSocket::local_external_ip_repeats = 0; // is an IP in private address space (in general) (swiped from gtk-gnutella) bool cSocket::isPrivateIP(struct in_addr addr) {{{ uint32_t ip = ntohl(addr.s_addr); // 10.0.0.0 -- (10/8 prefix) if ((ip & 0xff000000) == 0xa000000) return true; // 172.16.0.0 -- (172.16/12 prefix) if ((ip & 0xfff00000) == 0xac100000) return true; // 169.254.0.0 -- (169.254/16 prefix) -- since Jan 2001 if ((ip & 0xffff0000) == 0xa9fe0000) return true; // 192.168.0.0 -- (192.168/16 prefix) if ((ip & 0xffff0000) == 0xc0a80000) return true; return false; }}} // is an IP in the same LAN as our internal address (swiped from gtk-gnutella) bool cSocket::isInternalIP(struct in_addr addr) {{{ uint32_t ip = ntohl(addr.s_addr); uint32_t local_ip = ntohl(local_internal_ip.s_addr); return ip == local_ip || // quick check (ip & 0xffffff00) == (local_ip & 0xffffff00) || // same LAN/24 (ip & 0xff000000) == 0x7f000000; // loopback 127.xxx }}} // try to set our local LAN address void cSocket::setLocalInternalIP(struct in_addr new_addr) {{{ if (!local_internal_ip_forced) local_internal_ip.s_addr = new_addr.s_addr; }}} // set our local LAN address by forcing it, also set forcing on // when forcing=true calls that don't have forcing parameter shall // not set the address void cSocket::setLocalInternalIP(struct in_addr new_addr, bool forcing) {{{ local_internal_ip.s_addr = new_addr.s_addr; local_internal_ip_forced = forcing; }}} // try to set our local externally visible address void cSocket::setLocalExternalIP(struct in_addr new_addr) {{{ static struct in_addr last_ip_seen; static int same_ip_count = 0; if (new_addr.s_addr != last_ip_seen.s_addr) { last_ip_seen.s_addr = new_addr.s_addr; same_ip_count = 1; return; } if (++same_ip_count < (local_external_ip_repeats+1)) return; last_ip_seen.s_addr = 0; same_ip_count = 0; local_external_ip.s_addr = new_addr.s_addr; log(1, "local_external_ip changed to %s\n", inet_ntoa(local_external_ip)); }}} // set our local externally visible address void cSocket::setLocalExternalIP(struct in_addr new_addr, bool forcing) {{{ local_external_ip.s_addr = new_addr.s_addr; local_external_ip_forced = forcing; }}} // how many repeats (in all: one time + repeats) are required before IP change void cSocket::setLocalExternalIPRepeatCount(int repeats) {{{ if (repeats >= 0) local_external_ip_repeats = repeats; }}} struct in_addr cSocket::getLocalInternalIP () {{{ return local_internal_ip; }}} struct in_addr cSocket::getLocalExternalIP () {{{ return local_external_ip; }}} // find out local IP struct in_addr cSocket::hostIP(const char *bind_to) {{{ struct in_addr addr; if ((bind_to == NULL) || (strcmp(bind_to,"0") == 0)) { // if there's no bind_to specified, find hostip by ourselves char name[MAX_HOSTNAME_LENGTH]; addr.s_addr = 0; if (-1 == gethostname(name, MAX_HOSTNAME_LENGTH)) log(1, "cSocket::localInterfaceIP: couldn't get hostname (%d)\n", errno); else { struct hostent *he = gethostbyname(name); if (he != 0) addr.s_addr = *(uint32_t *)(he->h_addr_list[0]); } } else addr.s_addr = inet_addr(bind_to); return addr; }}} // guess the local-end IP of this socket // updates socket.this_ip bool cSocket::guessSocketLocalIP(void) {{{ if ((this_ip.s_addr != 0) && (!connected)) return true; struct sockaddr_in sa; socklen_t sa_len = sizeof (sa); if (0 != getsockname (fd, reinterpret_cast(&sa), &sa_len)) return false; // logic: // if peer_ip is on local network -> use ip from here // if peer_ip is not on local network -> use local_external_ip // is peer_ip is not known (= 0) -> use ip from here if ((peer_ip.s_addr == 0) || isInternalIP(peer_ip)) { this_ip.s_addr = sa.sin_addr.s_addr; //log(1, "guessSocketIP: setting to private: %p %s\n", this, inet_ntoa(this_ip)); } else { this_ip = getLocalExternalIP(); //log(1, "guessSocketIP: setting to public: %p %s\n", this, inet_ntoa(this_ip)); } return true; }}} off_t FD_LSEEK (int fd, off_t offset, int whence) {{{ off_t err = FD_lseek (fd, offset, whence); if (err == offset - 1) { printf("lseek failes %4i %s\n", errno, cSocket::Strerror(errno)); ASSERT(0); } return err; }}} bool FD_READ2 (int fd, unsigned char *buf, size_t len) {{{ while (len > 0) { int err = FD_read (fd, buf, len); if (err > 0) { len -= err; buf += err; continue; } if (err == 0) { printf("read over file end\n"); fflush(stdout); return false; } if (errno == EINTR ) continue; if (errno == EAGAIN) continue; printf("READ error %4i %s\n", errno, cSocket::Strerror(errno)); assert(0); ASSERT(0); } return true; }}} void FD_WRITE2 (int fd, const unsigned char *buf, size_t len) {{{ while (len > 0) { int err = FD_write (fd, buf, len); if (err > 0) { len -= err; buf += err; continue; } if (errno == EAGAIN) continue; if (errno == EINTR ) continue; if (errno == ENOSPC) { printf("Disk full\n"); sleep (1); continue; } printf("WRITE error %4i %s\n", errno, cSocket::Strerror(errno)); ASSERT(0); } }}} unsigned char *file(const char *name, size_t *ret_size) {{{ int src_fd = -1; int size = 0; if (-1 == (src_fd = FD_open (name, O_RDONLY | O_BINARY))) return NULL; size = FD_LSEEK (src_fd, 0, SEEK_END); if (size == 0) { *ret_size = 0; return NULL; } FD_LSEEK (src_fd, 0, SEEK_SET); unsigned char *INPUT = reinterpret_cast(MALLOC(size+1)); INPUT[size] = 0; if (!FD_READ2(src_fd, INPUT, size)) { free (INPUT); *ret_size = 0; return NULL; } *ret_size = size; goto ende_0; if(INPUT == NULL) free(INPUT); INPUT = NULL; ende_0: if(src_fd != -1) FD_close(src_fd); return INPUT; }}}