WKJay 5 лет назад
Родитель
Сommit
8aaba741f4
9 измененных файлов с 258 добавлено и 138 удалено
  1. 136 17
      netserver.c
  2. 2 0
      netserver.h
  3. 0 38
      ns_if_socket.c
  4. 0 20
      ns_if_socket.h
  5. 0 34
      ns_platform.c
  6. 0 6
      ns_platform.h
  7. 103 15
      ns_session.c
  8. 13 6
      ns_session.h
  9. 4 2
      ns_types.h

+ 136 - 17
netserver.c

@@ -9,12 +9,26 @@
     Author:     wangjunjie
     Modify:
 *************************************************/
+#include <rtthread.h>
+
 #include "netserver.h"
 #include "ns_session.h"
-#include "ns_platform.h"
+#include <sys/time.h>
+
+#ifdef SAL_USING_POSIX
+#include <sys/select.h>
+#else
+#include <lwip/select.h>
+#endif
 
-#define NS_IF_LISTEN_BACKLOG 5
+#define NS_IF_LISTEN_BACKLOG 6
+#define NS_SELECT_TIMEOUT    2000
 
+#define NS_THREAD_STACK_SIZE 8192
+#define NS_THREAD_PRIORITY   10
+#define NS_THREAD_TICK       5
+
+#define NS_IS_RESET(s) (s & NS_RESET_FLAG)
 /**
  * Name:    netserver_create
  * Brief:   create netserber manager
@@ -37,6 +51,7 @@ netserver_mgr_t *netserver_create(uint32_t max_conns, uint32_t flag) {
         NS_LOG("TLS SUPPORT NOT AVAILABLE");
 #endif
     }
+    mgr->max_conns = max_conns;
     return mgr;
 }
 
@@ -53,6 +68,29 @@ static void netserver_close_all(netserver_mgr_t *mgr) {
     }
 }
 
+static void check_session_timeout(netserver_mgr_t *mgr) {
+    ns_session_t *conn = NULL;
+    if (mgr->session_timeout == 0) {
+        return;
+    }
+    for (conn = mgr->conns; conn; conn = conn->next) {
+        if ((rt_tick_get() - conn->tick_timeout) < (RT_TICK_MAX / 2)) {
+            NS_LOG("connecion %d timout,close it.", conn->socket);
+            ns_session_close(mgr, conn);
+        }
+    }
+}
+
+static void netserver_accept_and_close(netserver_mgr_t *mgr) {
+    int sock;
+    struct sockaddr cliaddr;
+    socklen_t clilen;
+    clilen = sizeof(struct sockaddr_in);
+    sock = accept(mgr->listener->socket, &cliaddr, &clilen);
+    if (sock >= 0) {
+        closesocket(sock);
+    }
+}
 /**
  * Name:    netserver_bind
  * Brief:   bind port to netserver
@@ -66,44 +104,125 @@ int netserver_bind(netserver_mgr_t *mgr, uint16_t port) {
     return 0;
 }
 
-void netserver(netserver_mgr_t *mgr) {
-    if (mgr->listener) {
-        NS_LOG("already have a listener");
-        goto exit;
-    }
+void netserver_set_session_timeout(netserver_mgr_t *mgr, uint32_t ms) {
+    mgr->session_timeout = ms;
+}
+
+static void netserver_handle(void *param) {
+    netserver_mgr_t *mgr = (netserver_mgr_t *)param;
+    struct sockaddr_in servaddr;
+    fd_set readset, exceptfds, tempreadfds, tempexptfds;
+    int maxfd = 0, sockfd = -1;
+    struct timeval timeout;
 
-    mgr->listener = ns_session_create(NS_SESSION_F_LISTENING);
+    mgr->listener = ns_session_create(mgr, NS_SESSION_F_LISTENING);
     if (mgr->listener == NULL) {
         NS_LOG("cannot create netserver session");
         goto exit;
     }
 
-    mgr->listener->socket = ns_if_socket();
+    mgr->listener->socket = socket(AF_INET, SOCK_STREAM, 0);
     if (mgr->listener->socket < 0) {
         NS_LOG("create socket failed");
         goto exit;
     }
 
-    if (ns_if_bind(mgr->listener->socket, mgr->listen_port) < 0) {
+    NS_MEMSET(&servaddr, 0, sizeof(servaddr));
+    servaddr.sin_family = AF_INET;
+    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    servaddr.sin_port = htons(mgr->listen_port);
+    if (bind(mgr->listener->socket, (struct sockaddr *)&servaddr,
+             sizeof(servaddr)) < 0) {
         NS_LOG("bind socket failed");
-        ns_if_socket_close(mgr->listener->socket);
+        closesocket(mgr->listener->socket);
         goto exit;
     }
 
-    if (ns_if_listen(mgr->listener->socket, NS_IF_LISTEN_BACKLOG) < 0) {
+    if (listen(mgr->listener->socket, NS_IF_LISTEN_BACKLOG) < 0) {
         NS_LOG("listen socket failed");
-        ns_if_socket_close(mgr->listener->socket);
+        closesocket(mgr->listener->socket);
         goto exit;
     }
 
+    timeout.tv_sec = NS_SELECT_TIMEOUT / 1000;
+    timeout.tv_usec = (NS_SELECT_TIMEOUT % 1000) * 1000;
     /* waiting for new connection or data come in */
-    for(;;)
-    {
-        
+    for (;;) {
+        FD_ZERO(&readset);
+        FD_ZERO(&exceptfds);
+        FD_SET(mgr->listener->socket, &readset);
+        FD_SET(mgr->listener->socket, &exceptfds);
+
+        maxfd = ns_all_connections_set_fds(mgr, &readset, &exceptfds);
+        if (maxfd < mgr->listener->socket + 1)
+            maxfd = mgr->listener->socket + 1;
+
+        // prevent select from changing
+        tempreadfds = readset;
+        tempexptfds = exceptfds;
+
+        sockfd = select(maxfd, &tempreadfds, NULL, &tempexptfds, &timeout);
+        if (NS_IS_RESET(mgr->flag)) {
+            NS_LOG("net server reseting...");
+            goto exit;
+        }
+        check_session_timeout(mgr);
+        if (sockfd == 0) {
+            // NS_LOG("net server select timeout");
+            continue;
+        }
+
+        /* if the listen fd is ready*/
+        if (FD_ISSET(mgr->listener->socket, &tempreadfds)) {
+            socklen_t clilen;
+            NS_LOG("new connection comes in");
+            clilen = sizeof(struct sockaddr_in);
+
+            ns_session_t *new_conn = ns_session_create(mgr, NULL);
+            if (new_conn) {
+                new_conn->socket =
+                    accept(mgr->listener->socket,
+                           (struct sockaddr *)&new_conn->cliaddr, &clilen);
+                if (new_conn->socket < 0) {
+                    NS_LOG("new connection accept failed");
+                    ns_session_close(mgr, new_conn);
+                } else {
+                    FD_SET(new_conn->socket, &readset);
+                    FD_SET(new_conn->socket, &exceptfds);
+                }
+            } else {
+                /* cannot create new connection,just accept and close it */
+                NS_LOG("accept connection and close");
+                netserver_accept_and_close(mgr);
+            }
+        }
+
+        /* handle sessions */
+        ns_session_handle(mgr, &tempreadfds, &tempexptfds);
     }
 
 exit:
     netserver_close_all(mgr);
 }
 
-int netserver_start(netserver_mgr_t *mgr) { ns_thread_start(netserver, mgr); }
+void netserver(void *param) {
+    while (1) {
+        netserver_handle(param);
+        rt_thread_mdelay(1000);
+    }
+}
+
+int netserver_start(netserver_mgr_t *mgr) {
+    rt_thread_t tid =
+        rt_thread_create("netserver", netserver, mgr, NS_THREAD_STACK_SIZE,
+                         NS_THREAD_PRIORITY, NS_THREAD_TICK);
+    if (tid) {
+        if (rt_thread_startup(tid) == RT_EOK) {
+            return 0;
+        } else {
+            return -1;
+        }
+    } else {
+        return -1;
+    }
+}

+ 2 - 0
netserver.h

@@ -15,6 +15,7 @@ typedef struct _netserver_mgr {
     struct _ns_session *conns;     // session list
     uint16_t listen_port;          // server listen port
     uint32_t max_conns;            // max connections
+    uint32_t session_timeout;      // session timeout
     uint32_t flag;                 // status flag
 } netserver_mgr_t;
 
@@ -24,5 +25,6 @@ typedef struct _netserver_mgr {
 netserver_mgr_t *netserver_create(uint32_t max_conns, uint32_t flag);
 int netserver_bind(netserver_mgr_t *mgr, uint16_t port);
 int netserver_start(netserver_mgr_t *mgr);
+void netserver_set_session_timeout(netserver_mgr_t *mgr, uint32_t ms);
 
 #endif /* __NETSERVER_H */

+ 0 - 38
ns_if_socket.c

@@ -1,38 +0,0 @@
-/*************************************************
- Copyright (c) 2020
- All rights reserved.
- File name:     ns_if_socket.c
- Description:   
- History:
- 1. Version:    
-    Date:       2020-11-26
-    Author:     wangjunjie
-    Modify:     
-*************************************************/
-#include "ns_if_socket.h"
-
-int ns_if_socket(void) {
-    int sock = 0, reuse = 1;
-    sock = socket(AF_INET, SOCK_STREAM, 0);
-
-    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
-    return sock;
-}
-
-int ns_if_bind(socket_t socket, uint16_t port) {
-    struct sockaddr_in servaddr;
-    NS_MEMSET(&servaddr, 0, sizeof(servaddr));
-    servaddr.sin_family = AF_INET;
-    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
-    servaddr.sin_port = htons(port);
-
-    return bind(socket, &servaddr, sizeof(servaddr));
-}
-
-int ns_if_listen(socket_t socket, int backlog) {
-    return listen(socket, backlog);
-}
-
-int ns_if_socket_close(socket_t socket) {
-    return closesocket(socket);
-}

+ 0 - 20
ns_if_socket.h

@@ -1,20 +0,0 @@
-#ifndef __NS_SOCKET_H
-#define __NS_SOCKET_H
-
-#include <sys/socket.h>
-#include "ns_types.h"
-
-typedef struct sockaddr_in ns_sockaddr_in;
-typedef int socket_t;
-
-#define ns_fd_set   fd_set
-#define NS_FD_ZERO  FD_ZERO
-#define NS_FD_SET   FD_SET
-#define NS_FD_ISSET FD_ISSET
-
-int ns_if_socket(void);
-int ns_if_bind(socket_t socket, uint16_t port);
-int ns_if_listen(socket_t socket, int backlog);
-int ns_if_socket_close(socket_t socket);
-
-#endif /* __NS_SOCKET_H */

+ 0 - 34
ns_platform.c

@@ -1,34 +0,0 @@
-/*************************************************
- Copyright (c) 2020
- All rights reserved.
- File name:     ns_platform.c
- Description:   
- History:
- 1. Version:    
-    Date:       2020-11-26
-    Author:     wangjunjie
-    Modify:     
-*************************************************/
-#include "netserver.h"
-
-#include <rtthread.h>
-#define NS_THREAD_STACK_SIZE 8192
-#define NS_THREAD_PRIORITY   10
-#define NS_THREAD_TICK       5
-
-int ns_thread_start(void *(*entry)(void *), void *param) {
-    rt_thread_t tid = rt_thread_create("netserver", entry, param,
-                                       NS_THREAD_STACK_SIZE,
-                                       NS_THREAD_PRIORITY,
-                                       NS_THREAD_TICK);
-    if (tid) {
-        if (rt_thread_startup(tid) == RT_EOK) {
-            return 0;
-        } else {
-            return -1;
-        }
-        return 0;
-    } else {
-        return -1;
-    }
-}

+ 0 - 6
ns_platform.h

@@ -1,6 +0,0 @@
-#ifndef __NS_PLATFORM_H
-#define __NS_PLATFORM_H
-
-int ns_thread_start(void *(*entry)(void *), void *param);
-
-#endif /* __NS_PLATFORM_H */

+ 103 - 15
ns_session.c

@@ -11,11 +11,40 @@
 *************************************************/
 #include "netserver.h"
 #include "ns_session.h"
-#include "ns_if_socket.h"
-
 
 #define IS_LISTEN_SESSION(s) (s->flag & NS_SESSION_F_LISTENING)
 
+static ns_session_t *find_last_connection(netserver_mgr_t *mgr, int *cnt) {
+    ns_session_t *conn = mgr->conns;
+    if (mgr->conns == NULL) {
+        /* There's no connection */
+        return NULL;
+    }
+    (*cnt)++;
+    while (conn->next) {
+        conn = conn->next;
+        (*cnt)++;
+    }
+    return conn;
+}
+
+static void _session_handle(netserver_mgr_t *mgr, ns_session_t *conn) {
+    int ret = 0;
+    uint8_t buf[256];
+    NS_MEMSET(buf, 0, 256);
+
+    conn->tick_timeout =
+        rt_tick_get() + rt_tick_from_millisecond(mgr->session_timeout);
+
+    ret = recv(conn->socket, buf, 256, 0);
+    if (ret > 0) {
+        send(conn->socket, buf, ret, 0);
+    } else {
+        NS_LOG("socket %d read err,close it", conn->socket);
+        ns_session_close(mgr, conn);
+    }
+}
+
 /**
  * Name:    ns_session_create
  * Brief:   create netserber session
@@ -24,31 +53,50 @@
  *         NS_USE_TLS : use tls connection
  * Output:  netserver manager handler , NULL if create failed
  */
-ns_session_t *ns_session_create(uint32_t flag) {
+ns_session_t *ns_session_create(netserver_mgr_t *mgr, uint32_t flag) {
     ns_session_t *session = NS_CALLOC(1, sizeof(ns_session_t));
     if (session == NULL) {
         NS_LOG("no memory for ns session");
         return NULL;
     }
+
+    if (flag & NS_SESSION_F_LISTENING) {
+        if (mgr->listener) {
+            NS_LOG("already have a listener");
+            NS_FREE(session);
+            return NULL;
+        } else {
+            mgr->listener = session;
+        }
+    } else {
+        int conn_cnt = 0;
+        ns_session_t *last_conn = find_last_connection(mgr, &conn_cnt);
+        if (last_conn) {
+            if (conn_cnt >= mgr->max_conns) {
+                NS_LOG("no more connections");
+                NS_FREE(session);
+                return NULL;
+            } else {
+                last_conn->next = session;
+            }
+        } else {
+            mgr->conns = session;
+        }
+    }
+
     session->flag = flag;
+    session->socket = -1;
+    session->tick_timeout =
+        rt_tick_get() + rt_tick_from_millisecond(mgr->session_timeout);
     return session;
 }
 
 int ns_session_close(netserver_mgr_t *mgr, ns_session_t *session) {
     ns_session_t *iter;
 
+    if (session->socket >= 0) closesocket(session->socket);
+
     if (IS_LISTEN_SESSION(session)) {
-        /* listen session free */
-        if (mgr->listener != session) {
-            NS_LOG("listener error");
-            return -1;
-        }
-        // TODO maybe you need to process close failure
-        ns_if_socket_close(session->socket);
-#if NS_SUPPORT_TLS
-        ns_tls_free(session->tls_backend);
-        session->tls_backend = NULL;
-#endif
         NS_FREE(session);
         mgr->listener = NULL;
     } else {
@@ -65,6 +113,10 @@ int ns_session_close(netserver_mgr_t *mgr, ns_session_t *session) {
         }
         NS_FREE(session);
     }
+#if NS_SUPPORT_TLS
+    ns_tls_free(session->tls_backend);
+    session->tls_backend = NULL;
+#endif
     return 0;
 }
 
@@ -80,9 +132,45 @@ int ns_sesion_close_all_connections(netserver_mgr_t *mgr) {
     for (cur_conn = mgr->conns; cur_conn; cur_conn = next_conn) {
         /* obtain next connection in case it be closed */
         next_conn = cur_conn->next;
-        if (ns_session_close(mgr,cur_conn) < 0) {
+        if (ns_session_close(mgr, cur_conn) < 0) {
             NS_LOG("close session failed");
             return -1;
         }
     }
+    return 0;
+}
+
+/**
+ * Name:    ns_all_connections_set_fds
+ * Brief:   set all connections fds
+ * Input:   None
+ * Output:  maximal fd number
+ */
+int ns_all_connections_set_fds(netserver_mgr_t *mgr, fd_set *readset,
+                               fd_set *exceptfds) {
+    int maxfdp1 = 0;
+    ns_session_t *session;
+
+    for (session = mgr->conns; session; session = session->next) {
+        if (maxfdp1 < session->socket + 1) maxfdp1 = session->socket + 1;
+        FD_SET(session->socket, readset);
+        FD_SET(session->socket, exceptfds);
+    }
+    return maxfdp1;
+}
+
+void ns_session_handle(netserver_mgr_t *mgr, fd_set *readset,
+                       fd_set *excptset) {
+    ns_session_t *cur_conn, *next_conn;
+
+    for (cur_conn = mgr->conns; cur_conn; cur_conn = next_conn) {
+        // obtain next session in case current session be closed
+        next_conn = cur_conn->next;
+        if (FD_ISSET(cur_conn->socket, excptset)) {
+            NS_LOG("socket %d error,now close", cur_conn->socket);
+            ns_session_close(mgr, cur_conn);
+        } else if (FD_ISSET(cur_conn->socket, readset)) {
+            _session_handle(mgr, cur_conn);
+        }
+    }
 }

+ 13 - 6
ns_session.h

@@ -1,16 +1,22 @@
 #ifndef __NS_SESSION_H
 #define __NS_SESSION_H
 
+#include <rtthread.h>
 #include "netserver.h"
 #include "ns_types.h"
-#include "ns_if_socket.h"
+
+#ifdef RT_USING_SAL
+#include <sys/socket.h>
+#else
+#include <lwip/sockets.h>
+#endif
 
 /* Flags set by net server*/
 #define NS_SESSION_F_LISTENING (1 << 0)
 
 typedef struct _ns_session {
-    socket_t socket;
-    ns_sockaddr_in cliaddr;
+    int socket;
+    struct sockaddr_in cliaddr;
     uint32_t tick_timeout;
     uint32_t flag;
     struct _ns_session *next;
@@ -22,9 +28,10 @@ typedef struct _ns_session {
 #endif
 } ns_session_t;
 
-
-ns_session_t *ns_session_create(uint32_t flag);
+ns_session_t *ns_session_create(netserver_mgr_t *mgr, uint32_t flag);
 int ns_session_close(netserver_mgr_t *mgr, ns_session_t *session);
 int ns_sesion_close_all_connections(netserver_mgr_t *mgr);
-
+int ns_all_connections_set_fds(netserver_mgr_t *mgr, fd_set *readset,
+                               fd_set *exceptfds);
+void ns_session_handle(netserver_mgr_t *mgr, fd_set *readset, fd_set *excptset);
 #endif /* __NS_SESSION_H */

+ 4 - 2
ns_types.h

@@ -19,8 +19,10 @@
 #define NS_CALLOC(c, s)        calloc(c, s)
 
 #include <stdio.h>
-#define NS_LOG(...)      \
-    printf(__VA_ARGS__); \
+#define NS_LOG(...)          \
+    printf("[netserver]: "); \
+    printf(__VA_ARGS__);     \
     printf("\r\n");
+    
 
 #endif /* __NS_TYPES_H */