1 #include <rtthread.h> 2 #include <sys/socket.h> 3 4 #ifdef SAL_USING_POSIX 5 #include <sys/select.h> // only dfs_net 6 #include <dfs_posix.h> 7 #else 8 #define read lwip_read 9 #define write lwip_write 10 #endif /* SAL_USING_POSIX */ 11 12 #include "netdb.h" 13 14 #define MAX_SERV 32 /* Maximum number of chargen services. Don't need too many */ 15 #define CHARGEN_THREAD_NAME "chargen" 16 #if RT_THREAD_PRIORITY_MAX == 32 17 #define CHARGEN_PRIORITY 20 /* Really low priority */ 18 #else 19 #define CHARGEN_PRIORITY 200 /* Really low priority */ 20 #endif 21 #define CHARGEN_THREAD_STACKSIZE 1024 22 struct charcb 23 { 24 struct charcb *next; 25 int socket; 26 struct sockaddr_in cliaddr; 27 socklen_t clilen; 28 char nextchar; 29 }; 30 31 static struct charcb *charcb_list = 0; 32 static int do_read(struct charcb *p_charcb); 33 static void close_chargen(struct charcb *p_charcb); 34 extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 35 36 /************************************************************** 37 * void chargen_thread(void *arg) 38 * 39 * chargen task. This server will wait for connections on well 40 * known TCP port number: 19. For every connection, the server will 41 * write as much data as possible to the tcp port. 42 **************************************************************/ 43 static void chargen_thread(void *arg) 44 { 45 int listenfd; 46 struct sockaddr_in chargen_saddr; 47 fd_set readset; 48 fd_set writeset; 49 int i, maxfdp1; 50 struct charcb *p_charcb; 51 52 /* First acquire our socket for listening for connections */ 53 listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 54 LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0); 55 memset(&chargen_saddr, 0, sizeof(chargen_saddr)); 56 chargen_saddr.sin_family = AF_INET; 57 chargen_saddr.sin_addr.s_addr = htonl(INADDR_ANY); 58 chargen_saddr.sin_port = htons(19); // Chargen server port 59 60 if (bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1) 61 LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0); 62 63 /* Put socket into listening mode */ 64 if (listen(listenfd, MAX_SERV) == -1) 65 LWIP_ASSERT("chargen_thread(): Listen failed.", 0); 66 67 68 /* Wait forever for network input: This could be connections or data */ 69 for (;;) 70 { 71 maxfdp1 = listenfd + 1; 72 73 /* Determine what sockets need to be in readset */ 74 FD_ZERO(&readset); 75 FD_ZERO(&writeset); 76 FD_SET(listenfd, &readset); 77 for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) 78 { 79 if (maxfdp1 < p_charcb->socket + 1) 80 maxfdp1 = p_charcb->socket + 1; 81 FD_SET(p_charcb->socket, &readset); 82 FD_SET(p_charcb->socket, &writeset); 83 } 84 85 /* Wait for data or a new connection */ 86 i = select(maxfdp1, &readset, &writeset, 0, 0); 87 88 if (i == 0) continue; 89 90 /* At least one descriptor is ready */ 91 if (FD_ISSET(listenfd, &readset)) 92 { 93 /* We have a new connection request!!! */ 94 /* Lets create a new control block */ 95 p_charcb = (struct charcb *)rt_calloc(1, sizeof(struct charcb)); 96 if (p_charcb) 97 { 98 p_charcb->socket = accept(listenfd, 99 (struct sockaddr *) &p_charcb->cliaddr, 100 &p_charcb->clilen); 101 if (p_charcb->socket < 0) 102 rt_free(p_charcb); 103 else 104 { 105 /* Keep this tecb in our list */ 106 p_charcb->next = charcb_list; 107 charcb_list = p_charcb; 108 p_charcb->nextchar = 0x21; 109 } 110 } 111 else 112 { 113 /* No memory to accept connection. Just accept and then close */ 114 int sock; 115 struct sockaddr cliaddr; 116 socklen_t clilen; 117 118 sock = accept(listenfd, &cliaddr, &clilen); 119 if (sock >= 0) 120 closesocket(sock); 121 } 122 } 123 124 /* Go through list of connected clients and process data */ 125 for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) 126 { 127 if (FD_ISSET(p_charcb->socket, &readset)) 128 { 129 /* This socket is ready for reading. This could be because someone typed 130 * some characters or it could be because the socket is now closed. Try reading 131 * some data to see. */ 132 if (do_read(p_charcb) < 0) 133 break; 134 } 135 136 if (FD_ISSET(p_charcb->socket, &writeset)) 137 { 138 char line[80]; 139 char setchar = p_charcb->nextchar; 140 141 for (i = 0; i < 59; i++) 142 { 143 line[i] = setchar; 144 if (++setchar == 0x7f) 145 setchar = 0x21; 146 } 147 148 line[i] = 0; 149 strcat(line, "\n\r"); 150 if (write(p_charcb->socket, line, strlen(line)) < 0) 151 { 152 close_chargen(p_charcb); 153 break; 154 } 155 156 if (++p_charcb->nextchar == 0x7f) 157 p_charcb->nextchar = 0x21; 158 } 159 } 160 } 161 } 162 163 /************************************************************** 164 * void close_chargen(struct charcb *p_charcb) 165 * 166 * Close the socket and remove this charcb from the list. 167 **************************************************************/ 168 static void close_chargen(struct charcb *p_charcb) 169 { 170 struct charcb *p_search_charcb; 171 172 /* Either an error or tcp connection closed on other 173 * end. Close here */ 174 closesocket(p_charcb->socket); 175 176 /* Free charcb */ 177 if (charcb_list == p_charcb) 178 charcb_list = p_charcb->next; 179 else 180 for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next) 181 { 182 if (p_search_charcb->next == p_charcb) 183 { 184 p_search_charcb->next = p_charcb->next; 185 break; 186 } 187 } 188 189 rt_free(p_charcb); 190 } 191 192 /************************************************************** 193 * void do_read(struct charcb *p_charcb) 194 * 195 * Socket definitely is ready for reading. Read a buffer from the socket and 196 * discard the data. If no data is read, then the socket is closed and the 197 * charcb is removed from the list and freed. 198 **************************************************************/ 199 static int do_read(struct charcb *p_charcb) 200 { 201 char buffer[80]; 202 int readcount; 203 204 /* Read some data */ 205 readcount = read(p_charcb->socket, &buffer, 80); 206 if (readcount <= 0) 207 { 208 close_chargen(p_charcb); 209 return -1; 210 } 211 return 0; 212 } 213 214 void chargen_init(void) 215 { 216 rt_thread_t chargen; 217 218 chargen = rt_thread_create(CHARGEN_THREAD_NAME, 219 chargen_thread, RT_NULL, 220 CHARGEN_THREAD_STACKSIZE, 221 CHARGEN_PRIORITY, 5); 222 if (chargen != RT_NULL) rt_thread_startup(chargen); 223 } 224 #ifdef RT_USING_FINSH 225 #include <finsh.h> 226 void chargen() 227 { 228 chargen_init(); 229 } 230 FINSH_FUNCTION_EXPORT(chargen, start chargen server); 231 #endif 232