/* To compile: gcc sircd.c rtlib.c rtgrading.c csapp.c -lpthread -osircd */
#include "rtlib.h"
#include "rtgrading.h"
#include "csapp.h"
#include "sircd.h"
#include <stdlib.h>
/* Macros */
#define MAX_MSG_TOKENS 10
#define MAX_MSG_LEN 512
#define MAX_LINE 256
#define SERVER_PORT 28902
#define MAX_IN_CHANNEL 32
#define MAX_CHANNELS 512
#define MAX_CHANNAME 16
/* Global variables */
u_long curr_nodeID;
rt_config_file_t curr_node_config_file; /* The config_file for this node */
rt_config_entry_t *curr_node_config_entry; /* The config_entry for this node */
client_t *client_list[FD_SETSIZE];/* The global client list */
channel_t *channel_list[FD_SETSIZE];/* The global channel list */
u_long client_count;/* The global client count of the server */
u_long channel_count;/* The global channel count of the server */
/* Function prototypes */
void init_node( int argc, char *argv[] );
void init_pool(int listenfd, pool *p);
void add_client(int connfd, pool *p);
void read_from_clients(pool *p);
int msg_of_the_day(client_t *client);/* The method to send the message of the day */
int client_exist(char *nick);/* The method to check if the client with the nick have been exist */
int is_command(char *buf);/* The method to check if the message is a command */
int execute_command(int connfd, char *buf, pool *p);/* The method of the command entries */
int execute_nick(int connfd, char *nick);/* The method to execute nick command */
/* The method to execute user command */
int execute_user(int connfd, char *username, char *hostname, char *servname, char *realname);
int execute_quit(int connfd, char *msg, pool *p);/* The method to execute quit command */
int create_channel(int connfd, char *channel_name);/* The method to execute channel command */
int execute_join(int connfd, char *channel_name);/* The method to execute join command */
int execute_part(int connfd, char *names);/* The method to execute part command */
int execute_who(int connfd, char *channel_name);/* The method to execute who command */
int execute_list(int connfd);/* The method to execute list command */
int execute_privmsg(int connfd, char *target, char *msg);/* The method to execute privmsg command */
int leave_channel(int connfd, char *channel_name);/* The method to leave the channel */
client_t *get_client(int connfd);/* The method to get client with connfd */
channel_t *get_channel(char *channel_name);/* The method to get channel with channel_name */
void broadcast_channel(int connfd, channel_t *channel, char *msg);/* The method to broadcast clients with msg */
void msg_client(int connfd, client_t *target_client, char *msg);/* The method to send msg to specific client */
int channel_has_client(int clientfd, channel_t *channel);/* The method to check if the channel has the client */
size_t get_msg( char *buf, char *msg );
int tokenize( char const *in_buf, char tokens[MAX_MSG_TOKENS][MAX_MSG_LEN+1] );
/* Main */
int main( int argc, char *argv[] )
{
struct sockaddr_in client_addr;
int listenfd, connfd, client_length = sizeof(struct sockaddr_in);
static pool pool;
init_node( argc, argv );
printf( "I am node %d and I listen on port %d for new users\n", (int)curr_nodeID, curr_node_config_entry->irc_port );
client_count = 0;
channel_count = 0;
// Open listenfd with the particular port
listenfd = Open_listenfd(SERVER_PORT);
// Init a pool to listen clients' requests
init_pool(listenfd, &pool);
while(1){
// Call the select function
pool.ready_set = pool.read_set;
pool.nready = Select(pool.maxfd+1, &pool.ready_set, NULL, NULL, NULL);
if(FD_ISSET(listenfd, &pool.ready_set)){
// Wait for client
connfd = Accept(listenfd, (SA *)&client_addr, &client_length);
add_client(connfd, &pool);
}
// Read client
read_from_clients(&pool);
}
return 0;
}
/*
* This method is to init the elements of the pool p
*/
void init_pool(int listenfd, pool *p){
// initially, there are no connected descriptors
int i;
p->maxi = -1;
for(i = 0; i < FD_SETSIZE; i++){
p->client[i].clientfd = -1;
}
// initially, listenfd is only member of select read set
p->maxfd = listenfd;
FD_ZERO(&p->read_set);
FD_SET(listenfd, &p->read_set);
}
/*
* This method is to add a clientfd to the clientfd array of the pool p
*/
void add_client(int connfd, pool *p){
int i;
p->nready--;
// find available slot
for(i = 0; i < FD_SETSIZE; i++){
if(p->client[i].clientfd < 0){
p->client[i].clientfd = connfd;
Rio_readinitb(&p->clientrio[i], connfd);
// add descriptor to read set
FD_SET(connfd, &p->read_set);
// update max descriptor num
if(connfd > p->maxfd){
p->maxfd = connfd;
}
// update pool high water mark
if(i > p->maxi){
p->maxi = i;
}
break;
}
}
/* Initialize a new client for the client list */
client_t *client = Malloc(sizeof(client_t));
*(client->nickname) = "*";
*(client->username) = "*";
client->clientfd = connfd;
client->channel_id = -1;
client->nick_is_set = 0;
client->user_is_set = 0;
client_list[connfd] = client;
client_count++;
// couldn't find an empty slot
if(i == FD_SETSIZE){
perror("add_client error: too many clients");
}
}
/*
* This method is to check clients, then read from them and write to them
*/
void read_from_clients(pool *p){
int i, connfd, n;
char buf[MAX_LINE];
rio_t rio;
int r;
for(i = 0; (i <= p->maxi) && (p->nready > 0); i++){
connfd = p->client[i].clientfd;
rio = p->clientrio[i];
// if the descriptor is ready, echo a text line from it
if((connfd > 0) && (FD_ISSET(connfd, &p->ready_set))){
p->nready--;
if((n = Rio_readlineb(&rio, buf, MAX_LINE)) != 0){
byte_cnt += n;
char msg[MAX_MSG_LEN];
get_msg(buf, msg);
/* Check whether the msg is a command */
if(!is_command(msg)){
/* if not, return error */
char buf1[1024];
sprintf(buf1, "421: %s Unkown command\n", msg);
Write(connfd, buf1, strlen(buf1));
}
else{
/* if it is a command, execute it */
if((r = execute_command(connfd, msg, p)) == 0){
sprintf(msg, "%s command failed\n", msg);
Write(connfd, msg, n);
}
}
}
// EOF detected, remove descriptor
else{
Close(connfd);
FD_CLR(connfd, &p->read_set);
p->client[i].clientfd = -1;
Free(client_list[connfd]);
client_count--;
}
}
}
}
/* The method to get client with connfd */
client_t *get_client(int connfd){
return client_list[connfd];
}
/* The method to check whether the buf is a command, if not, return 0 */
int is_command(char *buf){
char tokens[MAX_MSG_TOKENS][MAX_MSG_LEN+1];
if(tokenize(buf, tokens) == 0){
perror("read_from_clients error: tokenize error");
}
char *temp = tokens[0];
if(strncasecmp(temp, "nick", sizeof("nick")) == 0){
return 1;
}
else if(strncasecmp(temp, "user", sizeof("user")) == 0){
return 1;
}
else if(strncasecmp(temp, "quit", sizeof("quit")) == 0){
return 1;
}
else if(strncasecmp(temp, "join", sizeof("join")) == 0){
return 1;
}
else if(strncasecmp(temp, "part", sizeof("part")) == 0){
return 1;
}
else if(strncasecmp(temp, "list", sizeof("list")) == 0){
return 1;
}
else if(strncasecmp(temp, "privmsg", sizeof("privmsg")) == 0){
return 1;
}
else if(strncasecmp(temp, "who", sizeof("who")) == 0){
return 1;
}
return 0;
}
/* The entry of all the commands. dispatch the command to different executing methods. */
int execute_command(int connfd, char *buf, pool *p){
char tokens[MAX_MSG_TOKENS][MAX_MSG_LEN+1];
if(tokenize(buf, tokens) == 0){
perror("read_from_clients error: tokenize error");
}
char *temp = tokens[0];/* Get the command */
/* NICK */
if(strncasecmp(temp, "nick", sizeof("nick")) == 0){
if(tokens[1]){
return execute_nick(connfd, tokens[1]);
}
else {
char buf[128];
sprintf(buf,"The number of parameters for NICK command must be more than 2.");
W
IRC.zip_IRC server_IRCserver_irc_sircd.c_简单IRC实现
版权申诉
14 浏览量
2022-09-23
10:59:30
上传
评论
收藏 55KB ZIP 举报
weixin_42653672
- 粉丝: 93
- 资源: 1万+
最新资源
- 测试aaaaaaabbbbb
- VID20240521070643.mp4
- Android系统原理与开发学习要点详解-培训课件.zip
- 部署yolov8的tensorrt模型支持检测分割姿态估计的C++源码+部署步骤.zip
- 以简单、易用、高性能为目标、开源的时序数据库,支持Linux及Windows, Time Series Database.zip
- python-leetcode面试题解之第198题打家劫舍-题解.zip
- python-leetcode面试题解之第191题位1的个数-题解.zip
- python-leetcode面试题解之第186题反转字符串中的单词II-题解.zip
- 一个基于python的web后端高性能开发框架,下载可用
- python-leetcode面试题解之第179题最大数-题解.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈