diff options
author | brianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-12-05 02:53:33 +0000 |
---|---|---|
committer | brianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-12-05 02:53:33 +0000 |
commit | 60a426c0742b3e7d8c5b557c7578df6eeeea377b (patch) | |
tree | 5d01f9ccc2798309f9b13f07c0096ed97c6a85c8 /src/common/network.c | |
parent | 621db2441f69736a6c8f10d26bf966d5414fac74 (diff) | |
download | hercules-60a426c0742b3e7d8c5b557c7578df6eeeea377b.tar.gz hercules-60a426c0742b3e7d8c5b557c7578df6eeeea377b.tar.bz2 hercules-60a426c0742b3e7d8c5b557c7578df6eeeea377b.tar.xz hercules-60a426c0742b3e7d8c5b557c7578df6eeeea377b.zip |
- Undid r16968: SVN Replaced with source:/trunk/src/@16966 (tid:74924).
[16969:16991/trunk/src/] will be re-committed in the next 24 hours.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16992 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/common/network.c')
-rw-r--r-- | src/common/network.c | 1809 |
1 files changed, 900 insertions, 909 deletions
diff --git a/src/common/network.c b/src/common/network.c index 1c968200d..1f1621363 100644 --- a/src/common/network.c +++ b/src/common/network.c @@ -51,1020 +51,1011 @@ static bool onSend(int32 fd); #define _network_free_netbuf_async( buf ) add_timer( 0, _network_async_free_netbuf_proc, 0, (intptr_t) buf) -static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data) -{ - // netbuf is in data - netbuffer_put((netbuf)data); +static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, intptr_t data){ + // netbuf is in data + netbuffer_put( (netbuf)data ); - return 0; + return 0; }//end: _network_async_free_netbuf_proc() -void network_init() -{ - SESSION *s; - int32 i; - - memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN)); - - for (i = 0; i < MAXCONN; i++) { - s = &g_Session[i]; - - s->type = NST_FREE; - s->disconnect_in_progress = false; - - } - - // Initialize the correspondig event dispatcher - evdp_init(); - - // - add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); - +void network_init(){ + SESSION *s; + int32 i; + + memset(g_Session, 0x00, (sizeof(SESSION) * MAXCONN) ); + + for(i = 0; i < MAXCONN; i++){ + s = &g_Session[i]; + + s->type = NST_FREE; + s->disconnect_in_progress = false; + + } + + // Initialize the correspondig event dispatcher + evdp_init(); + + // + add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc"); + }//end: network_init() -void network_final() -{ - - // @TODO: - // .. disconnect and cleanup everything! +void network_final(){ - evdp_final(); + // @TODO: + // .. disconnect and cleanup everything! + + evdp_final(); }//end: network_final() -void network_do() -{ - struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; - register struct EVDP_EVENT *ev; - register int n, nfds; - register SESSION *s; - - nfds = evdp_wait(l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() - - for (n = 0; n < nfds; n++) { - ev = &l_events[n]; - s = &g_Session[ ev->fd ]; - - if (ev->events & EVDP_EVENT_HUP) { - network_disconnect(ev->fd); - continue; // no further event processing. - }// endif vent is HUP (disconnect) - - - if (ev->events & EVDP_EVENT_IN) { - - if (s->onRecv != NULL) { - if (false == s->onRecv(ev->fd)) { - network_disconnect(ev->fd); - continue; // .. - } - } else { - ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - - }// endif event is IN (recv) - - - if (ev->events & EVDP_EVENT_OUT) { - if (s->onSend != NULL) { - if (false == s->onSend(ev->fd)) { - network_disconnect(ev->fd); - continue; - } - } else { - ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); - network_disconnect(ev->fd); - continue; - } - }// endif event is OUT (send) - - }//endfor - +void network_do(){ + struct EVDP_EVENT l_events[EVENTS_PER_CYCLE]; + register struct EVDP_EVENT *ev; + register int n, nfds; + register SESSION *s; + + nfds = evdp_wait( l_events, EVENTS_PER_CYCLE, 1000); // @TODO: timer_getnext() + + for(n = 0; n < nfds; n++){ + ev = &l_events[n]; + s = &g_Session[ ev->fd ]; + + if(ev->events & EVDP_EVENT_HUP){ + network_disconnect( ev->fd ); + continue; // no further event processing. + }// endif vent is HUP (disconnect) + + + if(ev->events & EVDP_EVENT_IN){ + + if(s->onRecv != NULL){ + if( false == s->onRecv(ev->fd) ){ + network_disconnect(ev->fd); + continue; // .. + } + }else{ + ShowError("network_do: fd #%u has no onRecv proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + + }// endif event is IN (recv) + + + if(ev->events & EVDP_EVENT_OUT){ + if(s->onSend != NULL){ + if( false == s->onSend(ev->fd) ){ + network_disconnect(ev->fd); + continue; + } + }else{ + ShowError("network_do: fd #%u has no onSend proc set. - disconnecting\n", ev->fd); + network_disconnect(ev->fd); + continue; + } + }// endif event is OUT (send) + + }//endfor + }//end: network_do() -static bool _setnonblock(int32 fd) -{ - int flags = fcntl(fd, F_GETFL, 0); - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) - return false; +static bool _setnonblock(int32 fd){ + int flags = fcntl(fd, F_GETFL, 0); + if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) + return false; - return true; + return true; }//end: _setnonblock() -static bool _network_accept(int32 fd) -{ - SESSION *listener = &g_Session[fd]; - SESSION *s; - union { - struct sockaddr_in v4; +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; + 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) { + } _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 { + if(listener->v6 == true){ + addrlen = sizeof(_addr.v6); + addr = (struct sockaddr*)&_addr.v6; + }else{ #endif - addrlen = sizeof(_addr.v4); - addr = (struct sockaddr *)&_addr.v4; + addrlen = sizeof(_addr.v4); + addr = (struct sockaddr*)&_addr.v4; #ifdef ENABLE_IPV6 - } + } #endif #ifdef HAVE_ACCEPT4 - newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); + newfd = accept4(fd, addr, &addrlen, SOCK_NONBLOCK); #else - newfd = accept(fd, addr, &addrlen); + 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("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); + 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("_network_accept: accept() returned error. closing listener. (errno: %u / %s)\n", errno, strerror(errno)); - return false; // will call disconnect after return. - //break; - } + 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("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); - close(newfd); - continue; - } + if(_setnonblock(newfd) == false){ + ShowError("_network_accept: failed to set newly accepted connection nonblocking (errno: %u / %s). - disconnecting.\n", errno, strerror(errno)); + close(newfd); + continue; + } #endif - // Check connection limits. - if (newfd >= MAXCONN) { - ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", 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("_network_accept: failed to accept connection - event subsystem returned an error.\n"); - 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; + // Check connection limits. + if(newfd >= MAXCONN){ + ShowError("_network_accept: failed to accept connection - MAXCONN (%u) exceeded.\n", 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("_network_accept: failed to accept connection - event subsystem returned an error.\n"); + 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() -void network_disconnect(int32 fd) -{ - SESSION *s = &g_Session[fd]; - netbuf b, bn; - - // Prevent recursive calls - // by wrong implemented on disconnect handlers.. and such.. - if (s->disconnect_in_progress == true) - return; - - s->disconnect_in_progress = true; - - - // Disconnect Todo: - // - Call onDisconnect Handler - // - Release all Assigned buffers. - // - remove from event system (notifications) - // - cleanup session structure - // - close connection. - // - - if (s->onDisconnect != NULL && - s->type != NST_LISTENER) { - - s->onDisconnect(fd); - } - - // Read Buffer - if (s->read.buf != NULL) { - netbuffer_put(s->read.buf); - s->read.buf = NULL; - } - - // Write Buffer(s) - b = s->write.buf; - while (1) { - if (b == NULL) break; - - bn = b->next; - - netbuffer_put(b); - - b = bn; - } - s->write.buf = NULL; - s->write.buf_last = NULL; - - s->write.n_outstanding = 0; - s->write.max_outstanding = 0; - - - // Remove from event system. - evdp_remove(fd, &s->evdp_data); - - // Cleanup Session Structure. - s->type = NST_FREE; - s->data = NULL; // no application level data assigned - s->disconnect_in_progress = false; - - - // Close connection - close(fd); - +void network_disconnect(int32 fd){ + SESSION *s = &g_Session[fd]; + netbuf b, bn; + + // Prevent recursive calls + // by wrong implemented on disconnect handlers.. and such.. + if(s->disconnect_in_progress == true) + return; + + s->disconnect_in_progress = true; + + + // Disconnect Todo: + // - Call onDisconnect Handler + // - Release all Assigned buffers. + // - remove from event system (notifications) + // - cleanup session structure + // - close connection. + // + + if(s->onDisconnect != NULL && + s->type != NST_LISTENER){ + + s->onDisconnect( fd ); + } + + // Read Buffer + if(s->read.buf != NULL){ + netbuffer_put(s->read.buf); + s->read.buf = NULL; + } + + // Write Buffer(s) + b = s->write.buf; + while(1){ + if(b == NULL) break; + + bn = b->next; + + netbuffer_put(b); + + b = bn; + } + s->write.buf = NULL; + s->write.buf_last = NULL; + + s->write.n_outstanding = 0; + s->write.max_outstanding = 0; + + + // Remove from event system. + evdp_remove(fd, &s->evdp_data); + + // Cleanup Session Structure. + s->type = NST_FREE; + s->data = NULL; // no application level data assigned + s->disconnect_in_progress = false; + + + // Close connection + close(fd); + }//end: network_disconnect() -int32 network_addlistener(bool v6, const char *addr, uint16 port) -{ - SESSION *s; - int optval, fd; +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; - } + 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 + 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 + 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 { + 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); + 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. + // 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)); + optval=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); #endif - // Bind + // 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 { + 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; - } + 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; + 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() -static bool _network_connect_establishedHandler(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - int val; - socklen_t val_len; - - if (s->type == NST_FREE) - return true; // due to multiple non coalesced event notifications - // this can happen .. when a previous handled event has already disconnected the connection - // within the same cycle.. - - val = -1; - val_len = sizeof(val); - getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); - - if (val != 0) { - // :( .. cleanup session.. - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we CANT return false, - // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. - } else { - // ok - if (s->onConnect(fd) == false) { - // onConnect handler has refused the connection .. - // cleanup .. and ok - s->type = NST_FREE; - s->onSend = NULL; - s->onConnect = NULL; - s->onDisconnect = NULL; - - evdp_remove(fd, &s->evdp_data); - close(fd); - - return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. - } - - // connection established ! - // - if (evdp_outgoingconnection_established(fd, &s->evdp_data) == false) { - return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. - } - - s->onSend = NULL; - - ShowStatus("#%u connection successfull!\n", fd); - } - - return true; +static bool _network_connect_establishedHandler(int32 fd){ + register SESSION *s = &g_Session[fd]; + int val; + socklen_t val_len; + + if(s->type == NST_FREE) + return true; // due to multiple non coalesced event notifications + // this can happen .. when a previous handled event has already disconnected the connection + // within the same cycle.. + + val = -1; + val_len = sizeof(val); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &val_len); + + if(val != 0){ + // :( .. cleanup session.. + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we CANT return false, + // becuase the normal disconnect procedure would execute the ondisconnect handler, which we dont want .. in this case. + }else{ + // ok + if(s->onConnect(fd) == false) { + // onConnect handler has refused the connection .. + // cleanup .. and ok + s->type = NST_FREE; + s->onSend = NULL; + s->onConnect = NULL; + s->onDisconnect = NULL; + + evdp_remove(fd, &s->evdp_data); + close(fd); + + return true; // we dnot want the ondisconnect handler to be executed, so its okay to handle this by ourself. + } + + // connection established ! + // + if( evdp_outgoingconnection_established(fd, &s->evdp_data) == false ){ + return false; // we want the normal disconnect procedure.. with call to ondisconnect handler. + } + + s->onSend = NULL; + + ShowStatus("#%u connection successfull!\n", fd); + } + + return true; }//end: _network_connect_establishedHandler() 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; + 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; + struct sockaddr_in6 ip6; #endif #ifdef ENABLE_IPV6 - if (v6 == true) - fd = socket(AF_INET6, SOCK_STREAM, 0); - else + if(v6 == true) + fd = socket(AF_INET6, SOCK_STREAM, 0); + else #endif - fd = socket(AF_INET, SOCK_STREAM, 0); + 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; - } + // 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)); + // 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 - - } - - - // 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); + 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; + // 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 + 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; - } + 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 + 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; + 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 _onSend(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - register netbuf buf, buf_next; - register uint32 szNeeded; - register int wLen; - - if (s->type == NST_FREE) - return true; // Possible due to multipl non coalsced event notifications - // so onSend gets called after disconnect caused by an previous vent. - // we can ignore the call to onSend, then. - - buf = s->write.buf; - while (1) { - if (buf == NULL) - break; - - buf_next = buf->next; - - - szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. - - // try to write. - wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); - if (wLen == 0) { - return false; // eof. - } else if (wLen == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) - return true; // dont disconnect / try again later. - - // all other errors. . - return false; - } - - // Wrote data.. => - szNeeded -= wLen; - if (szNeeded > 0) { - // still data left .. - // - s->write.dataPos += wLen; // fix offset. - return true; - } else { - // this buffer has been written successfully - // could be returned to pool. - netbuffer_put(buf); - s->write.n_outstanding--; // When threadsafe -> Interlocked here. - s->write.dataPos = 0; - } - - - buf = buf_next; - } - - // okay, - // reaching this part means: - // while interrupted by break - - // which means all buffers are written, nothing left - // - - s->write.buf_last = NULL; - s->write.buf = NULL; - s->write.n_outstanding = 0; - s->write.dataPos = 0; - - // Remove from event dispatcher (write notification) - // - evdp_writable_remove(fd, &s->evdp_data); - - return true; +static bool _onSend(int32 fd){ + register SESSION *s = &g_Session[fd]; + register netbuf buf, buf_next; + register uint32 szNeeded; + register int wLen; + + if(s->type == NST_FREE) + return true; // Possible due to multipl non coalsced event notifications + // so onSend gets called after disconnect caused by an previous vent. + // we can ignore the call to onSend, then. + + buf = s->write.buf; + while(1){ + if(buf == NULL) + break; + + buf_next = buf->next; + + + szNeeded = (buf->dataLen - s->write.dataPos); // using th session-local .dataPos member, due to shared write buffer support. + + // try to write. + wLen = write(fd, &buf->buf[s->write.dataPos], szNeeded); + if(wLen == 0){ + return false; // eof. + }else if(wLen == -1){ + if(errno == EAGAIN || errno == EWOULDBLOCK) + return true; // dont disconnect / try again later. + + // all other errors. . + return false; + } + + // Wrote data.. => + szNeeded -= wLen; + if(szNeeded > 0){ + // still data left .. + // + s->write.dataPos += wLen; // fix offset. + return true; + }else{ + // this buffer has been written successfully + // could be returned to pool. + netbuffer_put(buf); + s->write.n_outstanding--; // When threadsafe -> Interlocked here. + s->write.dataPos = 0; + } + + + buf = buf_next; + } + + // okay, + // reaching this part means: + // while interrupted by break - + // which means all buffers are written, nothing left + // + + s->write.buf_last = NULL; + s->write.buf = NULL; + s->write.n_outstanding = 0; + s->write.dataPos = 0; + + // Remove from event dispatcher (write notification) + // + evdp_writable_remove(fd, &s->evdp_data); + + return true; }//end: _onSend() -static bool _onRORecv(int32 fd) -{ - register SESSION *s = &g_Session[fd]; - register uint32 szNeeded; - register char *p; - register int rLen; - - if (s->type == NST_FREE) - return true; // Possible due to multiple non coalesced events by evdp. - // simply ignore this call returning positive result. - - // Initialize p and szNeeded depending on change - // - switch (s->read.state) { - case NRS_WAITOP: - szNeeded = s->read.head_left; - p = ((char *)&s->read.head[0]) + (2-szNeeded); - break; - - case NRS_WAITLEN: - szNeeded = s->read.head_left; - p = ((char *)&s->read.head[1]) + (2-szNeeded); - break; - - case NRS_WAITDATA: { - register netbuf buf = s->read.buf; - - szNeeded = (buf->dataLen - buf->dataPos); - p = (char *)&buf->buf[ buf->dataPos ]; - } - break; - - default: - // .. the impossible gets possible .. - ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - // - - rLen = read(fd, p, szNeeded); - if (rLen == 0) { - // eof.. - return false; - } else if (rLen == -1) { - - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) - return true; - } - - // an additional interesting case would be - // EINTR, this 'could' be handled .. but: - // posix says that its possible that data gets currupted during irq - // or data gor read and not reported.., so we'd have a data loss.. - // (which shouldnt happen with stream based protocols such as tcp) - // its better to disonnect the client in that case. - - return false; - } - - // - // Got Data: - // next action also depends on current state .. - // - szNeeded -= rLen; - switch (s->read.state) { - case NRS_WAITOP: - - if (szNeeded > 0) { - // still data missing .. - s->read.head_left = szNeeded; - return true; // wait for completion. - } else { - // complete .. - // next state depends on packet type. - - s->read.head[1] = ((uint16 *)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] - - if (s->read.head[1] == ROPACKET_UNKNOWN) { - // unknown packet - disconnect - ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); - return false; - } else if (s->read.head[1] == ROPACKET_DYNLEN) { - // dynamic length - // next state: requrie len. - s->read.state = NRS_WAITLEN; - s->read.head_left = 2; - return true; // - } else if (s->read.head[1] == 2) { - // packet has no data (only opcode) - register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = 2; - buf->next = NULL; - - // Back to initial state -> Need opcode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine here. - s->onPacketComplete(fd, s->read.head[0], 2, buf); - - return true; // done :) - } else { - // paket needs .. data .. - register netbuf buf = netbuffer_get(s->read.head[1]); - - NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. - buf->dataPos = 2; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach buffer. - s->read.buf = buf; - - // set state: - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (opcode read completed?) - - break; - - - case NRS_WAITLEN: - - if (szNeeded > 0) { - // incomplete .. - s->read.head_left = szNeeded; - return true; - } else { - - if (s->read.head[1] == 4) { - // packet has no data (only opcode + length) - register netbuf buf = netbuffer_get(4); - - NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = 4; - buf->next = NULL; - - // set initial state (need opcode) - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // call completion routine. - s->onPacketComplete(fd, s->read.head[0], 4, buf); - - return true; - } else if (s->read.head[1] < 4) { - // invalid header. - ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); - return false; - } else { - // Data needed - // next state -> waitdata! - register netbuf buf = netbuffer_get(s->read.head[1]); - - NBUFL(buf, 0) = *((uint32 *)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL - buf->dataPos = 4; - buf->dataLen = s->read.head[1]; - buf->next = NULL; - - // attach to session: - s->read.buf = buf; - s->read.state = NRS_WAITDATA; - - return true; - } - - }//endif: szNeeded > 0 (length read complete?) - - break; - - - case NRS_WAITDATA: - - if (szNeeded == 0) { - // Packet finished! - // compltion. - register netbuf buf = s->read.buf; - - // set initial state. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - s->read.buf = NULL; - - // Call completion routine. - s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); - - return true; - } else { - // still data needed - s->read.buf->dataPos += rLen; - - return true; - } - break; - - - // - default: - ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); - return false; - break; - } - - - return false; +static bool _onRORecv(int32 fd){ + register SESSION *s = &g_Session[fd]; + register uint32 szNeeded; + register char *p; + register int rLen; + + if(s->type == NST_FREE) + return true; // Possible due to multiple non coalesced events by evdp. + // simply ignore this call returning positive result. + + // Initialize p and szNeeded depending on change + // + switch(s->read.state){ + case NRS_WAITOP: + szNeeded = s->read.head_left; + p = ((char*)&s->read.head[0]) + (2-szNeeded); + break; + + case NRS_WAITLEN: + szNeeded = s->read.head_left; + p = ((char*)&s->read.head[1]) + (2-szNeeded); + break; + + case NRS_WAITDATA:{ + register netbuf buf = s->read.buf; + + szNeeded = (buf->dataLen - buf->dataPos); + p = (char*)&buf->buf[ buf->dataPos ]; + } + break; + + default: + // .. the impossible gets possible .. + ShowError("_onRORecv: fd #%u has unknown read.state (%d) - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + // + + rLen = read(fd, p, szNeeded); + if(rLen == 0){ + // eof.. + return false; + }else if(rLen == -1){ + + if(errno == EAGAIN || errno == EWOULDBLOCK){ + // try again later .. (this case shouldnt happen, because we're event trigered.. but .. sometimes it happens :) + return true; + } + + // an additional interesting case would be + // EINTR, this 'could' be handled .. but: + // posix says that its possible that data gets currupted during irq + // or data gor read and not reported.., so we'd have a data loss.. + // (which shouldnt happen with stream based protocols such as tcp) + // its better to disonnect the client in that case. + + return false; + } + + // + // Got Data: + // next action also depends on current state .. + // + szNeeded -= rLen; + switch(s->read.state){ + case NRS_WAITOP: + + if(szNeeded > 0){ + // still data missing .. + s->read.head_left = szNeeded; + return true; // wait for completion. + }else{ + // complete .. + // next state depends on packet type. + + s->read.head[1] = ((uint16*)s->netparser_data)[ s->read.head[0] ]; // store lenght of packet by opcode head[0] to head[1] + + if(s->read.head[1] == ROPACKET_UNKNOWN){ + // unknown packet - disconnect + ShowWarning("_onRORecv: fd #%u got unlnown packet 0x%04x - disconnecting.\n", fd, s->read.head[0]); + return false; + } + else if(s->read.head[1] == ROPACKET_DYNLEN){ + // dynamic length + // next state: requrie len. + s->read.state = NRS_WAITLEN; + s->read.head_left = 2; + return true; // + } + else if(s->read.head[1] == 2){ + // packet has no data (only opcode) + register netbuf buf = netbuffer_get(2); // :D whoohoo its giant! + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = 2; + buf->next = NULL; + + // Back to initial state -> Need opcode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine here. + s->onPacketComplete(fd, s->read.head[0], 2, buf); + + return true; // done :) + } + else{ + // paket needs .. data .. + register netbuf buf = netbuffer_get( s->read.head[1] ); + + NBUFW(buf, 0) = s->read.head[0]; // store opcode @ packet begin. + buf->dataPos = 2; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach buffer. + s->read.buf = buf; + + // set state: + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (opcode read completed?) + + break; + + + case NRS_WAITLEN: + + if(szNeeded > 0){ + // incomplete .. + s->read.head_left = szNeeded; + return true; + }else{ + + if(s->read.head[1] == 4){ + // packet has no data (only opcode + length) + register netbuf buf = netbuffer_get( 4 ); + + NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = 4; + buf->next = NULL; + + // set initial state (need opcode) + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // call completion routine. + s->onPacketComplete(fd, s->read.head[0], 4, buf); + + return true; + } + else if(s->read.head[1] < 4){ + // invalid header. + ShowWarning("_onRORecv: fd #%u invalid header - got packet 0x%04x, reported length < 4 - INVALID - disconnecting\n", fd, s->read.head[0]); + return false; + } + else{ + // Data needed + // next state -> waitdata! + register netbuf buf = netbuffer_get( s->read.head[1] ); + + NBUFL(buf, 0) = *((uint32*)&s->read.head[0]); // copy Opcode + length to netbuffer using MOVL + buf->dataPos = 4; + buf->dataLen = s->read.head[1]; + buf->next = NULL; + + // attach to session: + s->read.buf = buf; + s->read.state = NRS_WAITDATA; + + return true; + } + + }//endif: szNeeded > 0 (length read complete?) + + break; + + + case NRS_WAITDATA: + + if(szNeeded == 0){ + // Packet finished! + // compltion. + register netbuf buf = s->read.buf; + + // set initial state. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + s->read.buf = NULL; + + // Call completion routine. + s->onPacketComplete(fd, NBUFW(buf, 0), buf->dataLen, buf); + + return true; + }else{ + // still data needed + s->read.buf->dataPos += rLen; + + return true; + } + break; + + + // + default: + ShowError("_onRORecv: fd #%u has unknown read.state (%d) [2] - disconnecting\n", fd, s->read.state); + return false; + break; + } + + + return false; }//end: _onRORecv() -void network_send(int32 fd, netbuf buf) -{ - register SESSION *s = &g_Session[fd]; - +void network_send(int32 fd, netbuf buf){ + register SESSION *s = &g_Session[fd]; + #ifdef PARANOID_CHECKS - if (fd >= MAXCONN) { - ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); - _network_free_netbuf_async(buf); - return; - } + if(fd >= MAXCONN){ + ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd); + _network_free_netbuf_async(buf); + return; + } #endif - if (s->type == NST_FREE) - return; - - // Check Max Outstanding buffers limit. - if ((s->write.max_outstanding > 0) && - (s->write.n_outstanding >= s->write.max_outstanding)) { - - ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); - network_disconnect(fd); - // - _network_free_netbuf_async(buf); - return; - } - - - // Attach to the end: - buf->next = NULL; - if (s->write.buf_last != NULL) { - s->write.buf_last->next = buf; - s->write.buf_last = buf; - - } else { - // currently no buffer attached. - s->write.buf = s->write.buf_last = buf; - - // register @ evdp for writable notification. - evdp_writable_add(fd, &s->evdp_data); // - } - - - // - s->write.n_outstanding++; - + if(s->type == NST_FREE) + return; + + // Check Max Outstanding buffers limit. + if( (s->write.max_outstanding > 0) && + (s->write.n_outstanding >= s->write.max_outstanding) ){ + + ShowWarning("network_send: fd #%u max Outstanding buffers exceeded. - disconnecting.\n", fd); + network_disconnect(fd); + // + _network_free_netbuf_async(buf); + return; + } + + + // Attach to the end: + buf->next = NULL; + if(s->write.buf_last != NULL){ + s->write.buf_last->next = buf; + s->write.buf_last = buf; + + }else{ + // currently no buffer attached. + s->write.buf = s->write.buf_last = buf; + + // register @ evdp for writable notification. + evdp_writable_add(fd, &s->evdp_data); // + } + + + // + s->write.n_outstanding++; + }//end: network_send() void network_parser_set_ro(int32 fd, - int16 *packetlentable, - void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) - ) -{ - register SESSION *s = &g_Session[fd]; - register netbuf b, nb; // used for potential free attached buffers. - - if (s->type == NST_FREE) - return; - - s->onPacketComplete = onPacketCompleteProc; - - s->onRecv = _onRORecv; // .. - s->onSend = _onSend; // Using the normal generic netbuf based send function. - - s->netparser_data = packetlentable; - - // Initial State -> Need Packet OPCode. - s->read.state = NRS_WAITOP; - s->read.head_left = 2; - - - // Detach (if..) all buffers. - if (s->read.buf != NULL) { - _network_free_netbuf_async(s->read.buf); // - s->read.buf = NULL; - } - - if (s->write.buf != NULL) { - b = s->write.buf; - while (1) { - nb = b->next; - - _network_free_netbuf_async(b); - - b = nb; - } - - s->write.buf = NULL; - s->write.buf_last = NULL; - s->write.n_outstanding = 0; - } - - // not changing any limits on outstanding .. - // - + int16 *packetlentable, + void (*onPacketCompleteProc)(int32 fd, uint16 op, uint16 len, netbuf buf) + ){ + register SESSION *s = &g_Session[fd]; + register netbuf b, nb; // used for potential free attached buffers. + + if(s->type == NST_FREE) + return; + + s->onPacketComplete = onPacketCompleteProc; + + s->onRecv = _onRORecv; // .. + s->onSend = _onSend; // Using the normal generic netbuf based send function. + + s->netparser_data = packetlentable; + + // Initial State -> Need Packet OPCode. + s->read.state = NRS_WAITOP; + s->read.head_left = 2; + + + // Detach (if..) all buffers. + if(s->read.buf != NULL){ + _network_free_netbuf_async(s->read.buf); // + s->read.buf = NULL; + } + + if(s->write.buf != NULL){ + b = s->write.buf; + while(1){ + nb = b->next; + + _network_free_netbuf_async(b); + + b = nb; + } + + s->write.buf = NULL; + s->write.buf_last = NULL; + s->write.n_outstanding = 0; + } + + // not changing any limits on outstanding .. + // + }//end: network_parser_set_ro() |