summaryrefslogtreecommitdiff
path: root/src/common/network.c
diff options
context:
space:
mode:
authorbrianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-12-05 02:53:33 +0000
committerbrianluau <brianluau@54d463be-8e91-2dee-dedb-b68131a5f0ec>2012-12-05 02:53:33 +0000
commit60a426c0742b3e7d8c5b557c7578df6eeeea377b (patch)
tree5d01f9ccc2798309f9b13f07c0096ed97c6a85c8 /src/common/network.c
parent621db2441f69736a6c8f10d26bf966d5414fac74 (diff)
downloadhercules-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.c1809
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()