int32 network_addlistener(bool v6, const char *addr, uint16 port) { SESSION *s; int optval, fd; #if !defined(ENABLE_IPV6) if(v6 == true) { ShowError(read_message("Source.common.network_addlistener"), (v6==true?'t':'f'), addr, port); return -1; } #endif #ifdef ENABLE_IPV6 if(v6 == true) fd = socket(AF_INET6, SOCK_STREAM, 0); else #endif fd = socket(AF_INET, SOCK_STREAM, 0); // Error? if(fd == -1) { ShowError(read_message("Source.common.network_addlistener2"), (v6==true?'t':'f'), addr, port, errno, strerror(errno)); return -1; } // Too many connections? if(fd >= MAXCONN) { ShowError(read_message("Source.common.network_addlistener3"), (v6==true?'t':'f'), addr, port, MAXCONN); close(fd); return -1; } s = &g_Session[fd]; if(s->type != NST_FREE) { // additional checks.. :) ShowError(read_message("Source.common.network_addlistener4"), (v6==true?'t':'f'), addr, port, fd); close(fd); return -1; } // Fill ip addr structs #ifdef ENABLE_IPV6 if(v6 == true) { memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); s->addr.v6.sin6_family = AF_INET6; s->addr.v6.sin6_port = htons(port); if(inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1) { ShowError(read_message("Source.common.network_addlistener5"), (v6==true?'t':'f'), addr, port); close(fd); return -1; } } else { #endif memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); s->addr.v4.sin_family = AF_INET; s->addr.v4.sin_port = htons(port); s->addr.v4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 } #endif // if OS has support for SO_REUSEADDR, apply the flag // so the address could be used when there're still time_wait sockets outstanding from previous application run. #ifdef SO_REUSEADDR optval=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif // Bind #ifdef ENABLE_IPV6 if(v6 == true) { if(bind(fd, (struct sockaddr *)&s->addr.v6, sizeof(s->addr.v6)) == -1) { ShowError(read_message("Source.common.add_listener6"), (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } } else { #endif if(bind(fd, (struct sockaddr *)&s->addr.v4, sizeof(s->addr.v4)) == -1) { ShowError(read_message("Source.common.add_listener6"), (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } #ifdef ENABLE_IPV6 } #endif if(listen(fd, l_ListenBacklog) == -1) { ShowError(read_message("Source.common.add_listener7"), (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } // Set to nonblock! if(_setnonblock(fd) == false) { ShowError(read_message("Source.common.addlistener8"), (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } // Rgister @ evdp. if(evdp_addlistener(fd, &s->evdp_data) != true) { ShowError(read_message("Source.common.addlistener9"), (v6==true?'t':'f'), addr, port); close(fd); return -1; } // Apply flags on Session array for this conneciton. if(v6 == true) s->v6 = true; else s->v6 = false; s->type = NST_LISTENER; s->onRecv = _network_accept; ShowStatus(read_message("Source.common.add_listener10"), addr, port, (v6==true ? "(ipv6)":"(ipv4)")); return fd; }//end: network_addlistener()
int32 network_connect(bool v6, const char *addr, uint16 port, const char *from_addr, uint16 from_port, bool (*onConnectionEstablishedHandler)(int32 fd), void (*onConnectionLooseHandler)(int32 fd) ){ register SESSION *s; int32 fd, optval, ret; struct sockaddr_in ip4; #ifdef ENABLE_IPV6 struct sockaddr_in6 ip6; #endif #ifdef ENABLE_IPV6 if(v6 == true) fd = socket(AF_INET6, SOCK_STREAM, 0); else #endif fd = socket(AF_INET, SOCK_STREAM, 0); #ifndef ENABLE_IPV6 // check.. if(v6 == true){ ShowError("network_connect(%c, '%s', %u...): tried to create an ipv6 connection, IPV6 is not supported in this release.\n", (v6==true?'t':'f'), addr, port); return -1; } #endif // check connection limits. if(fd >= MAXCONN){ ShowError("network_connect(%c, '%s', %u...): cannot create new connection, exceeeds more than supported connections (%u)\n", (v6==true?'t':'f'), addr, port ); close(fd); return -1; } // Originating IP/Port pair given ? if(from_addr != NULL && *from_addr != 0){ //.. #ifdef SO_REUSEADDR optval=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif #ifdef ENABLE_IPV6 if(v6 == true){ memset(&ip6, 0x00, sizeof(ip6)); ip6.sin6_family = AF_INET6; ip6.sin6_port = htons(from_port); if(inet_pton(AF_INET6, from_addr, &ip6.sin6_addr) != 1){ ShowError("network_connect(%c, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } ret = bind(fd, (struct sockaddr*)&ip6, sizeof(ip6)); }else{ #endif memset(&ip4, 0x00, sizeof(ip4)); ip4.sin_family = AF_INET; ip4.sin_port = htons(from_port); ip4.sin_addr.s_addr = inet_addr(from_addr); ret = bind(fd, (struct sockaddr*)&ip4, sizeof(ip4)); #ifdef ENABLE_IPV6 } #endif } // Set non block if(_setnonblock(fd) == false){ ShowError("network_connect(%c, '%s', %u...): cannot set socket to nonblocking (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } // Create ip addr block to connect to .. #ifdef ENABLE_IPV6 if(v6 == true){ memset(&ip6, 0x00, sizeof(ip6)); ip6.sin6_family = AF_INET6; ip6.sin6_port = htons(port); if(inet_pton(AF_INET6, addr, &ip6.sin6_addr) != 1){ ShowError("network_connect(%c, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } }else{ #endif memset(&ip4, 0x00, sizeof(ip4)); ip4.sin_family = AF_INET; ip4.sin_port = htons(port); ip4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 } #endif // Assign Session.. s = &g_Session[fd]; s->type = NST_OUTGOING; s->v6 = v6; s->onConnect = onConnectionEstablishedHandler; s->onDisconnect = onConnectionLooseHandler; s->onRecv = NULL; s->onSend = _network_connect_establishedHandler; #ifdef ENABLE_IPV6 if(v6 == true) memcpy(&s->addr.v6, &ip6, sizeof(ip6)); else #endif memcpy(&s->addr.v4, &ip4, sizeof(ip4)); // Register @ EVDP. as outgoing (see doc of the function) if(evdp_addconnecting(fd, &s->evdp_data) == false){ ShowError("network_connect(%c, '%s', %u...): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); // cleanup session x.x.. s->type = NST_FREE; s->onConnect = NULL; s->onDisconnect = NULL; s->onSend = NULL; // close, return error code. close(fd); return -1; } #ifdef ENABLE_IPV6 if(v6 == true) ret = connect(fd, (struct sockaddr*)&ip6, sizeof(ip6)); else #endif ret = connect(fd, (struct sockaddr*)&ip4, sizeof(ip4)); // if(ret != 0 && errno != EINPROGRESS){ ShowWarning("network_connect(%c, '%s', %u...): connection failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); // Cleanup session .. s->type = NST_FREE; s->onConnect = NULL; s->onDisconnect = NULL; s->onSend = NULL; // .. remove from evdp and close fd. evdp_remove(fd, &s->evdp_data); close(fd); return -1; } // ! The Info Message :~D ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port); return fd; }//end: network_connect()
static bool _network_accept(int32 fd) { SESSION *listener = &g_Session[fd]; SESSION *s; union { struct sockaddr_in v4; #ifdef ENABLE_IPV6 struct sockaddr_in6 v6; #endif } _addr; int newfd; socklen_t addrlen; struct sockaddr *addr; // Accept until OS returns - nothing to accept anymore // - this is required due to our EVDP abstraction. (which handles on listening sockets similar to epoll's EPOLLET flag.) while(1) { #ifdef ENABLE_IPV6 if(listener->v6 == true) { addrlen = sizeof(_addr.v6); addr = (struct sockaddr *)&_addr.v6; } else { #endif addrlen = sizeof(_addr.v4); addr = (struct sockaddr *)&_addr.v4; #ifdef ENABLE_IPV6 } #endif #ifdef HAVE_ACCEPT4 newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); #else newfd = accept(fd, addr, &addrlen); #endif if(newfd == -1) { if(errno == EAGAIN || errno == EWOULDBLOCK) break; // this is fully valid & whished., se explaination on top of while(1) // Otherwis .. we have serious problems :( seems tahat our listner has gone away.. // @TODO handle this .. ShowError(read_message("Source.common.network_accept"), errno, strerror(errno)); return false; // will call disconnect after return. //break; } #ifndef HAVE_ACCEPT4 // no accept4 means, we have to set nonblock by ourself. .. if(_setnonblock(newfd) == false) { ShowError(read_message("Source.common.network_accept2"), errno, strerror(errno)); close(newfd); continue; } #endif // Check connection limits. if(newfd >= MAXCONN) { ShowError(read_message("network_accept3"), MAXCONN); close(newfd); continue; // we have to loop over the events (and disconnect them too ..) but otherwise we would leak event notifications. } // Create new Session. s = &g_Session[newfd]; s->type = NST_CLIENT; // The new connection inherits listenr's handlers. s->onDisconnect = listener->onDisconnect; s->onConnect = listener->onConnect; // maybe useless but .. fear the future .. :~ // Register the new connection @ EVDP if(evdp_addclient(newfd, &s->evdp_data) == false) { ShowError(read_message("Source.common.network_accept3")); close(newfd); s->type = NST_FREE; } // Call the onConnect handler on the listener. if(listener->onConnect(newfd) == false) { // Resfused by onConnect handler.. evdp_remove(newfd, &s->evdp_data); close(newfd); s->type = NST_FREE; s->data = NULL; // be on the safe side ~ ! continue; } } return true; }//end: _network_accept()
int32 network_addlistener(bool v6, const char *addr, uint16 port){ SESSION *s; int optval, fd; #if !defined(ENABLE_IPV6) if(v6 == true){ ShowError("network_addlistener(%c, '%s', %u): this release has no IPV6 support.\n", (v6==true?'t':'f'), addr, port); return -1; } #endif #ifdef ENABLE_IPV6 if(v6 == true) fd = socket(AF_INET6, SOCK_STREAM, 0); else #endif fd = socket(AF_INET, SOCK_STREAM, 0); // Error? if(fd == -1){ ShowError("network_addlistener(%c, '%s', %u): socket() failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); return -1; } // Too many connections? if(fd >= MAXCONN){ ShowError("network_addlistener(%c, '%s', %u): cannot create listener, exceeds more than supported connections (%u).\n", (v6==true?'t':'f'), addr, port, MAXCONN); close(fd); return -1; } s = &g_Session[fd]; if(s->type != NST_FREE){ // additional checks.. :) ShowError("network_addlistener(%c, '%s', %u): failed, got fd #%u which is already in use in local session table?!\n", (v6==true?'t':'f'), addr, port, fd); close(fd); return -1; } // Fill ip addr structs #ifdef ENABLE_IPV6 if(v6 == true){ memset(&s->addr.v6, 0x00, sizeof(s->addr.v6)); s->addr.v6.sin6_family = AF_INET6; s->addr.v6.sin6_port = htons(port); if(inet_pton(AF_INET6, addr, &s->addr.v6.sin6_addr) != 1){ ShowError("network_addlistener(%c, '%s', %u): failed to parse the given IPV6 address.\n", (v6==true?'t':'f'), addr, port); close(fd); return -1; } }else{ #endif memset(&s->addr.v4, 0x00, sizeof(s->addr.v4)); s->addr.v4.sin_family = AF_INET; s->addr.v4.sin_port = htons(port); s->addr.v4.sin_addr.s_addr = inet_addr(addr); #ifdef ENABLE_IPV6 } #endif // if OS has support for SO_REUSEADDR, apply the flag // so the address could be used when there're still time_wait sockets outstanding from previous application run. #ifdef SO_REUSEADDR optval=1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif // Bind #ifdef ENABLE_IPV6 if(v6 == true){ if( bind(fd, (struct sockaddr*)&s->addr.v6, sizeof(s->addr.v6)) == -1) { ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } }else{ #endif if( bind(fd, (struct sockaddr*)&s->addr.v4, sizeof(s->addr.v4)) == -1) { ShowError("network_addlistener(%c, '%s', %u): bind failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } #ifdef ENABLE_IPV6 } #endif if( listen(fd, l_ListenBacklog) == -1){ ShowError("network_addlistener(%c, '%s', %u): listen failed (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } // Set to nonblock! if(_setnonblock(fd) == false){ ShowError("network_addlistener(%c, '%s', %u): cannot set to nonblock (errno: %u / %s)\n", (v6==true?'t':'f'), addr, port, errno, strerror(errno)); close(fd); return -1; } // Rgister @ evdp. if( evdp_addlistener(fd, &s->evdp_data) != true){ ShowError("network_addlistener(%c, '%s', %u): eventdispatcher subsystem returned an error.\n", (v6==true?'t':'f'), addr, port); close(fd); return -1; } // Apply flags on Session array for this conneciton. if(v6 == true) s->v6 = true; else s->v6 = false; s->type = NST_LISTENER; s->onRecv = _network_accept; ShowStatus("Added Listener on '%s':%u\n", addr, port, (v6==true ? "(ipv6)":"(ipv4)") ); return fd; }//end: network_addlistener()