|
@@ -43,22 +43,22 @@ static int _network_async_free_netbuf_proc(int tid, unsigned int tick, int id, i
|
|
|
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 corresponding event dispatcher
|
|
|
evdp_init();
|
|
|
|
|
|
//
|
|
|
add_timer_func_list(_network_async_free_netbuf_proc, "_network_async_free_netbuf_proc");
|
|
|
-
|
|
|
+
|
|
|
}//end: network_init()
|
|
|
|
|
|
|
|
@@ -66,7 +66,7 @@ void network_final(){
|
|
|
|
|
|
// @TODO:
|
|
|
// .. disconnect and cleanup everything!
|
|
|
-
|
|
|
+
|
|
|
evdp_final();
|
|
|
|
|
|
}//end: network_final()
|
|
@@ -77,21 +77,21 @@ void network_do(){
|
|
|
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 );
|
|
|
+ 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);
|
|
@@ -101,11 +101,11 @@ void network_do(){
|
|
|
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) ){
|
|
@@ -118,9 +118,9 @@ void network_do(){
|
|
|
continue;
|
|
|
}
|
|
|
}// endif event is OUT (send)
|
|
|
-
|
|
|
+
|
|
|
}//endfor
|
|
|
-
|
|
|
+
|
|
|
}//end: network_do()
|
|
|
|
|
|
|
|
@@ -135,7 +135,7 @@ static bool _setnonblock(int32 fd){
|
|
|
|
|
|
static bool _network_accept(int32 fd){
|
|
|
SESSION *listener = &g_Session[fd];
|
|
|
- SESSION *s;
|
|
|
+ SESSION *s;
|
|
|
union{
|
|
|
struct sockaddr_in v4;
|
|
|
#ifdef ENABLE_IPV6
|
|
@@ -156,7 +156,7 @@ static bool _network_accept(int32 fd){
|
|
|
}else{
|
|
|
#endif
|
|
|
addrlen = sizeof(_addr.v4);
|
|
|
- addr = (struct sockaddr*)&_addr.v4;
|
|
|
+ addr = (struct sockaddr*)&_addr.v4;
|
|
|
#ifdef ENABLE_IPV6
|
|
|
}
|
|
|
#endif
|
|
@@ -170,9 +170,9 @@ static bool _network_accept(int32 fd){
|
|
|
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 ..
|
|
|
+ // @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.
|
|
@@ -183,7 +183,7 @@ static bool _network_accept(int32 fd){
|
|
|
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;
|
|
|
+ continue;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -198,31 +198,31 @@ static bool _network_accept(int32 fd){
|
|
|
// 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 .. :~
|
|
|
-
|
|
|
+ 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;
|
|
@@ -232,30 +232,30 @@ static bool _network_accept(int32 fd){
|
|
|
void network_disconnect(int32 fd){
|
|
|
SESSION *s = &g_Session[fd];
|
|
|
netbuf b, bn;
|
|
|
-
|
|
|
- // Prevent recursive calls
|
|
|
+
|
|
|
+ // Prevent recursive calls
|
|
|
// by wrong implemented on disconnect handlers.. and such..
|
|
|
if(s->disconnect_in_progress == true)
|
|
|
- return;
|
|
|
-
|
|
|
+ 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.
|
|
|
+ // - close connection.
|
|
|
//
|
|
|
-
|
|
|
- if(s->onDisconnect != NULL &&
|
|
|
+
|
|
|
+ if(s->onDisconnect != NULL &&
|
|
|
s->type != NST_LISTENER){
|
|
|
-
|
|
|
+
|
|
|
s->onDisconnect( fd );
|
|
|
}
|
|
|
|
|
|
- // Read Buffer
|
|
|
+ // Read Buffer
|
|
|
if(s->read.buf != NULL){
|
|
|
netbuffer_put(s->read.buf);
|
|
|
s->read.buf = NULL;
|
|
@@ -267,30 +267,30 @@ void network_disconnect(int32 fd){
|
|
|
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);
|
|
|
-
|
|
|
+ // Close connection
|
|
|
+ close(fd);
|
|
|
+
|
|
|
}//end: network_disconnect()
|
|
|
|
|
|
|
|
@@ -320,7 +320,7 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port){
|
|
|
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);
|
|
@@ -377,7 +377,7 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port){
|
|
|
ShowError("network_addlistener(f, '%s', %u): bind failed (errno: %u / %s)\n", addr, port, errno, strerror(errno));
|
|
|
close(fd);
|
|
|
return -1;
|
|
|
- }
|
|
|
+ }
|
|
|
#ifdef ENABLE_IPV6
|
|
|
}
|
|
|
#endif
|
|
@@ -387,14 +387,14 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port){
|
|
|
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){
|
|
@@ -406,7 +406,7 @@ int32 network_addlistener(bool v6, const char *addr, uint16 port){
|
|
|
// 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;
|
|
|
|
|
@@ -420,16 +420,16 @@ 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;
|
|
@@ -439,37 +439,37 @@ static bool _network_connect_establishedHandler(int32 fd){
|
|
|
|
|
|
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
|
|
|
+ // ok
|
|
|
if(s->onConnect(fd) == false) {
|
|
|
- // onConnect handler has refused the connection ..
|
|
|
+ // 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 !
|
|
|
- //
|
|
|
+
|
|
|
+ // 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);
|
|
|
+
|
|
|
+ ShowStatus("#%u connection successfull!\n", fd);
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
+ return true;
|
|
|
}//end: _network_connect_establishedHandler()
|
|
|
|
|
|
|
|
@@ -515,7 +515,7 @@ int32 network_connect(bool v6,
|
|
|
|
|
|
// 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));
|
|
@@ -526,7 +526,7 @@ int32 network_connect(bool v6,
|
|
|
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(t, '%s', %u...): cannot parse originating (from) IPV6 address (errno: %u / %s)\n", addr, port, errno, strerror(errno));
|
|
|
close(fd);
|
|
@@ -545,7 +545,7 @@ int32 network_connect(bool v6,
|
|
|
#ifdef ENABLE_IPV6
|
|
|
}
|
|
|
#endif
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// Set non block
|
|
@@ -556,26 +556,26 @@ int32 network_connect(bool v6,
|
|
|
}
|
|
|
|
|
|
|
|
|
- // Create ip addr block to connect to ..
|
|
|
+ // 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(t, '%s', %u...): cannot parse destination IPV6 address (errno: %u / %s)\n", 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);
|
|
|
+ ip4.sin_addr.s_addr = inet_addr(addr);
|
|
|
#ifdef ENABLE_IPV6
|
|
|
}
|
|
|
#endif
|
|
@@ -594,17 +594,17 @@ int32 network_connect(bool v6,
|
|
|
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..
|
|
|
+
|
|
|
+ // 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;
|
|
@@ -618,17 +618,17 @@ int32 network_connect(bool v6,
|
|
|
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.
|
|
|
+
|
|
|
+ // .. remove from evdp and close fd.
|
|
|
evdp_remove(fd, &s->evdp_data);
|
|
|
close(fd);
|
|
|
return -1;
|
|
@@ -637,7 +637,7 @@ int32 network_connect(bool v6,
|
|
|
// ! The Info Message :~D
|
|
|
ShowStatus("network_connect fd#%u (%s:%u) in progress.. \n", fd, addr, port);
|
|
|
|
|
|
-return fd;
|
|
|
+return fd;
|
|
|
}//end: network_connect()
|
|
|
|
|
|
|
|
@@ -648,20 +648,20 @@ static bool _onSend(int32 fd){
|
|
|
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.
|
|
|
-
|
|
|
+ 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){
|
|
@@ -669,16 +669,16 @@ static bool _onSend(int32 fd){
|
|
|
}else if(wLen == -1){
|
|
|
if(errno == EAGAIN || errno == EWOULDBLOCK)
|
|
|
return true; // dont disconnect / try again later.
|
|
|
-
|
|
|
- // all other errors. .
|
|
|
+
|
|
|
+ // all other errors. .
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Wrote data.. =>
|
|
|
szNeeded -= wLen;
|
|
|
if(szNeeded > 0){
|
|
|
- // still data left ..
|
|
|
- //
|
|
|
+ // still data left ..
|
|
|
+ //
|
|
|
s->write.dataPos += wLen; // fix offset.
|
|
|
return true;
|
|
|
}else{
|
|
@@ -686,29 +686,29 @@ static bool _onSend(int32 fd){
|
|
|
// could be returned to pool.
|
|
|
netbuffer_put(buf);
|
|
|
s->write.n_outstanding--; // When threadsafe -> Interlocked here.
|
|
|
- s->write.dataPos = 0;
|
|
|
+ s->write.dataPos = 0;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
buf = buf_next;
|
|
|
}
|
|
|
|
|
|
// okay,
|
|
|
// reaching this part means:
|
|
|
- // while interrupted by break -
|
|
|
+ // 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;
|
|
|
+
|
|
|
+ return true;
|
|
|
}//end: _onSend()
|
|
|
|
|
|
|
|
@@ -717,13 +717,13 @@ static bool _onRORecv(int32 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.
|
|
|
-
|
|
|
+ // 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;
|
|
@@ -734,64 +734,64 @@ static bool _onRORecv(int32 fd){
|
|
|
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 ..
|
|
|
+ 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
|
|
|
+
|
|
|
+ // 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 ..
|
|
|
- //
|
|
|
+ // next action also depends on current state ..
|
|
|
+ //
|
|
|
szNeeded -= rLen;
|
|
|
switch(s->read.state){
|
|
|
case NRS_WAITOP:
|
|
|
|
|
|
if(szNeeded > 0){
|
|
|
- // still data missing ..
|
|
|
+ // still data missing ..
|
|
|
s->read.head_left = szNeeded;
|
|
|
return true; // wait for completion.
|
|
|
}else{
|
|
|
- // complete ..
|
|
|
+ // 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]);
|
|
@@ -804,74 +804,74 @@ static bool _onRORecv(int32 fd){
|
|
|
s->read.head_left = 2;
|
|
|
return true; //
|
|
|
}
|
|
|
- else if(s->read.head[1] == 2){
|
|
|
+ else if(s->read.head[1] == 2){
|
|
|
// packet has no data (only opcode)
|
|
|
- register netbuf buf = netbuffer_get(2); // :D whoohoo its giant!
|
|
|
-
|
|
|
+ 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);
|
|
|
-
|
|
|
+
|
|
|
+ // 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;
|
|
|
-
|
|
|
+ s->read.state = NRS_WAITDATA;
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}//endif: szNeeded > 0 (opcode read completed?)
|
|
|
-
|
|
|
+
|
|
|
break;
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
case NRS_WAITLEN:
|
|
|
-
|
|
|
+
|
|
|
if(szNeeded > 0){
|
|
|
- // incomplete ..
|
|
|
+ // 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
|
|
|
+
|
|
|
+ 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.head_left = 2;
|
|
|
s->read.buf = NULL;
|
|
|
-
|
|
|
+
|
|
|
// call completion routine.
|
|
|
s->onPacketComplete(fd, s->read.head[0], 4, buf);
|
|
|
|
|
|
- return true;
|
|
|
+ return true;
|
|
|
}
|
|
|
else if(s->read.head[1] < 4){
|
|
|
// invalid header.
|
|
@@ -882,64 +882,64 @@ static bool _onRORecv(int32 fd){
|
|
|
// 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;
|
|
|
+ // 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];
|
|
|
-
|
|
|
+
|
|
|
#ifdef PARANOID_CHECKS
|
|
|
if(fd >= MAXCONN){
|
|
|
ShowError("network_send: tried to attach buffer to connection idientifer #%u which is out of bounds.\n", fd);
|
|
@@ -951,84 +951,84 @@ void network_send(int32 fd, netbuf buf){
|
|
|
|
|
|
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->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); //
|
|
|
+ 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)
|
|
|
+ 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;
|
|
|
+ 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;
|
|
|
+ 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()
|