CCTelnetSever是用于建立Telnet侦听,并处理Socket相关事件的模块。简单说,就是一个Socket Server的实现,并不难。代码是基于WinSocket实现的。
#include <stdio.h>
#include <time.h>
#include <winsock2.h>
#include "CCDataType.h"
#include "CCCmd.h"
#include "CCOutput.h"
#include "CCTelnetServer.h"
int cc_TelnetServer_AddClient(SOCKET s, const struct sockaddr_in * addr)
{
int index = 0;
if(cc_Global.telnet.count + 1 > cc_Global.telnet.max)
{
cc_TelnetServer_ClientWriteText(s, "Sorry, the number of connection has exceeded the limit.\n");
closesocket(s);
}
else
{
struct _cc_telnet_clientdata * tmp = cc_Global.telnet.client;
struct _cc_telnet_clientdata * client = (struct _cc_telnet_clientdata*)malloc(sizeof(struct _cc_telnet_clientdata));
client->sock = s;
strncpy(client->ip, inet_ntoa(addr->sin_addr), sizeof(client->ip));
client->port = addr->sin_port;
client->updated = time(NULL);
client->recv = 0;
client->next = NULL;
if(tmp == NULL)
{
client->index = 0;
cc_Global.telnet.client = client;
}
else
{
index = tmp->index;
while(tmp->next != NULL)
{
if(index < tmp->index)
index = tmp->index;
tmp = tmp->next;
}
client->index = index + 1;
tmp->next = client;
}
++ cc_Global.telnet.count;
CC_LOG_OUTPUT("INFO", "Client %d connected.\n", client->index);
cc_TelnetServer_ClientWritePrompt(s);
}
return 0;
}
int cc_TelnetServer_RemoveClient(struct _cc_telnet_clientdata* client)
{
struct _cc_telnet_clientdata* tmp = cc_Global.telnet.client;
if(tmp->next == NULL)
{
cc_Global.telnet.client = NULL;
}
else if(tmp == client)
{
cc_Global.telnet.client = tmp->next;
}
else
{
while(tmp->next != client)
{
tmp = tmp->next;
}
tmp->next = client->next;
}
closesocket(client->sock);
-- cc_Global.telnet.count;
free(client);
return 0;
}
void cc_TelnetServer_RemoveAllClients()
{
struct _cc_telnet_clientdata* client = cc_Global.telnet.client, *tmp = NULL;
while(client != NULL)
{
tmp = client;
client = client->next;
closesocket(tmp->sock);
free(tmp);
-- cc_Global.telnet.count;
}
}
int cc_TelnetServer_SetFd(fd_set* fd)
{
int ret = cc_Global.telnet.sock;
struct _cc_telnet_clientdata* client = cc_Global.telnet.client;
FD_ZERO(fd);
FD_SET(cc_Global.telnet.sock, fd);
while(client != NULL)
{
FD_SET(client->sock, fd);
if(client->sock > ret)
ret = client->sock;
client = client->next;
}
return ret;
}
int cc_TelnetServer_CheckFd(fd_set* fd)
{
SOCKET cs = INVALID_SOCKET;
struct sockaddr_in addr;
int len = sizeof(struct sockaddr_in);
struct _cc_telnet_clientdata* client = cc_Global.telnet.client;
if(FD_ISSET(cc_Global.telnet.sock, fd) != 0)
{
cs = accept(cc_Global.telnet.sock, &addr, &len);
if(cs != 0)
{
cc_TelnetServer_AddClient(cs, &addr);
}
}
while(client != NULL)
{
if(FD_ISSET(client->sock, fd) != 0)
{
cc_TelnetServer_OnClientRead(client);
break;
}
client = client->next;
}
return 0;
}
//int cc_TelnetServer_Socket2File(SOCKET s, FILE** file)
//{
// *file = fdopen(s, "w");
// if((*file) == NULL)
// return -1;
/**///// setlinebuf((*file));//
// return 0;
//}
/**//* ------------------------------- */
int cc_TelnetServer_ClientWrite(SOCKET s, const char* buf, int size)
{
char output[CC_SIZE_CMD];
int len = 0, i = 0;
while(i < size)
{
if(buf[i] == '\n')
{
if(i > 0)
{
if(buf[i - 1] != '\r')
{
output[len ++] = '\r';
}
}
else
{
output[len ++] = '\r';
}
}
output[len ++ ] = buf[i];
++ i;
}
send(s, output, len, 0);
return 0;
}
int cc_TelnetServer_ClientWriteText(SOCKET s, const char* text)
{
return cc_TelnetServer_ClientWrite(s, text, strlen(text));
}
int cc_TelnetServer_ClientWritePrompt(SOCKET s)
{
return cc_TelnetServer_ClientWriteText(s, cc_Global.telnet.prompt);
}
int cc_TelnetServer_ClientBufferProc(struct _cc_telnet_clientdata* client, const char* input, int size)
{
struct _cc_cmddata* cmd = NULL;
int argc = -1;
char argv[CC_SIZE_CMD/2][CC_SIZE_CMD];
int pos = -1;
memset(argv, 0, sizeof(argv));
if(client->recv + size > CC_SIZE_CMD)
{
client->recv = 0;
cc_TelnetServer_ClientWriteText(client->sock, "command is too long.\r\n");
cc_TelnetServer_ClientWritePrompt(client->sock);
return 0;
}
memcpy(client->buf + client->recv, input, size);
pos = client->recv;
client->recv += size;
while(pos < client->recv)
{
if(client->buf[pos] == 0x08)//bs
{
if(pos > 0)
{
memcpy(client->buf + pos - 1, client->buf + pos + 2, (client->recv - pos - 1));
client->recv -= 2;
}
else if(pos == 0)
{
memcpy(client->buf, client->buf + 1, (client->recv - 1));
client->recv -= 1;
}
else
{
return -1;
}
break;
}
//else if(client->buf[pos] == 0x1b)//esc
//{
// client->recv = 0;
// cc_TelnetServer_ClientWriteText(client->sock, "\r\n");
// cc_TelnetServer_ClientWritePrompt(client->sock);
//}
else if(client->buf[pos] == '\r' || client->buf[pos] == '\n')
{
if(client->recv > 2)
{
if(cc_CmdParser_Parser(client, &cmd, &argc, argv) == 0)
{
if((cmd->callback)(client, argc, argv) != 0)
return -1;
}
}
client->recv = 0;
cc_TelnetServer_ClientWritePrompt(client->sock);
}
++ pos;
}
return 0;
//
//
//if (input[0] == ' ' ||
// input[0] == ',' ||
// input[0] == '!' ||
// input[0] == '.' ||
// input[0] == '/' ||
// input[0] == '<' ||
// input[0] == '>' ||
// input[0] == '?' ||
// input[0] == '_' ||
// (input[0] >= '0' && input[0] <= '9') ||
// (input[0] >= 'A' && input[0] <= 'Z') ||
// (input[0] >= 'a' && input[0] <= 'z'))
// {
// memcpy(client->buf + client->recv, input, size);
// client->recv += size;
// cc_TelnetServer_ClientWrite(client->sock, input, size);
// }
// else if(input[0] == 0x08)//bs
// {
// if(client->recv > 0)
// {
// -- client->recv;
// cc_TelnetServer_ClientWrite(client->sock, input, size);
// }
// }
// else if(input[0] == 0x1b && input[1] == 0)
// {
// client->recv = 0;
// cc_TelnetServer_ClientWrite(client->sock, "\r\n", 2);
// }
// else if(input[0] == '\r')
// {
// if(client->recv > 0)
// {
// cc_TelnetServer_ClientWrite(client->sock, "\r\n", 2);
// //if(cc_CmdParser_Parser(client->buf, client->recv, &cmd, &argc, &argv) == 0)
// //{
// // return cmd->callback(client, argc, argv);
// //}
// //else
// //{
// // return -1;
// //}
// cc_TelnetServer_ClientWrite(client->sock, "\r\n", 2);
// client->recv = 0;
// cc_TelnetServer_ClientWrite(client->sock, ">", 1);
// }
// }
// return 0;
}
int cc_TelnetServer_OnClientRead(struct _cc_telnet_clientdata* client)
{
int rc = -1;
char input[64];
rc = recv(client->sock, input, sizeof(input), 0);
if(rc > 0)
{
if(cc_TelnetServer_ClientBufferProc(client, input, rc) != 0)
{
CC_LOG_OUTPUT("INFO", "Client %d request to disconnect.\n", client->index);
cc_TelnetServer_RemoveClient(client);
}
}
else if(rc == 0)
{
CC_LOG_OUTPUT("INFO", "Client %d disconnect.\n", client->index);
cc_TelnetServer_RemoveClient(client);
}
else
{
CC_LOG_OUTPUT("ERROR", "Client %d read failed.\n", client->index);
cc_TelnetServer_RemoveClient(client);
}
return 0;
}
/**//* -------------------------- */
int cc_TelnetServer_Init()
{
int flag = 1;
struct sockaddr_in addr;
WSADATA wsa;
int ret = WSAStartup(MAKEWORD(2, 2), &wsa);
if(ret != NO_ERROR)
{
CC_LOG_OUTPUT("ERROR", "WSAStartup() failed.\n");
return -1;
}
cc_Global.telnet.sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(cc_Global.telnet.sock == INVALID_SOCKET)
{
CC_LOG_OUTPUT("ERROR", "socket() failed.\n");
return -1;
}
if(ioctlsocket(cc_Global.telnet.sock, FIONBIO, &flag) != 0)
{
CC_LOG_OUTPUT("ERROR", "socket() failed.\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(cc_Global.telnet.ip);
addr.sin_port = htons(cc_Global.telnet.port);
if(bind(cc_Global.telnet.sock, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
{
CC_LOG_OUTPUT("ERROR", "bind() failed.\n");
return -1;
}
if(listen(cc_Global.telnet.sock, SOMAXCONN) != 0)
{
CC_LOG_OUTPUT("ERROR", "listen() failed.\n");
return -1;
}
return 0;
}
int cc_TelnetServer_Final()
{
cc_TelnetServer_RemoveAllClients();
if(cc_Global.telnet.sock != INVALID_SOCKET)
closesocket(cc_Global.telnet.sock);
WSACleanup();
return 0;
}
int cc_TelnetServer_Run()
{
struct timeval val;
fd_set rd;
int maxfd = -1;
int ret = 1;
val.tv_sec = 0;
val.tv_usec = 10;
cc_Global.telnet.run = 1;
while(cc_Global.telnet.run)
{
maxfd = cc_TelnetServer_SetFd(&rd);
ret = select(maxfd + 1, &rd, NULL, NULL, &val);
if(ret > 0)
{
cc_TelnetServer_CheckFd(&rd);
}
else if(ret < 0)
{
CC_LOG_OUTPUT("ERROR", "select() failed.\n");
break;
}
}
cc_Global.telnet.run = 0;
return 0;
}
int cc_TelnetServer_Create()
{
if(cc_TelnetServer_Init() == 0)
{
cc_TelnetServer_Run();
}
else
{
CC_LOG_OUTPUT("ERROR", "Create failed.\n");
}
cc_TelnetServer_Final();
return 0;
}