- #include <string.h>
- #ifdef __WIN32__
- #include <winsock.h>
- #include <wininet.h>
- #define SHUT_RDWR SD_BOTH
- #else
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #endif
- #include "debug.h"
- #include "server.h"
- #include "conn.h"
- #include "xmlparser.h"
- static void load_config(struct ftpserver* srv)
- {
- struct XML_DATA* xml = xml_load("./config.xml");
- strcpy(srv->server_root, xml_readstr(xml, "server_root"));
- strcpy(srv->server_ip, xml_readstr(xml, "server_ip"));
- srv->server_port = xml_readnum(xml, "server_port");
- srv->max_ips = xml_readnum(xml, "max_ips");
- srv->max_conns = xml_readnum(xml, "max_conns");
- srv->max_conns_per_ip = xml_readnum(xml, "max_conns_per_ip");
- srv->conn_timeout = xml_readnum(xml, "conn_timeout");
- srv->reserved_ips = xml_readnum(xml, "reserved_ips");
- int terminal_log = xml_readnum(xml, "terminal_log");
- int file_log = xml_readnum(xml, "file_log");
- debug_set_dir( xml_readstr(xml, "file_log:directory") );
- if( terminal_log )
- debug_term_on();
- else
- debug_term_off();
- if( file_log )
- debug_file_on();
- else
- debug_file_off();
- xml_free(xml);
- }
- int server_create(struct ftpserver* srv)
- {
- /* Initialization
- * Why not check pointer?
- * Reference header files assert.h
- */
- /* initialization srv */
- memset(srv, 0, sizeof(struct ftpserver));
- /* set server name */
- strcpy(srv->server_name, "xxftpd");
- /* load config XML jump */
- load_config(srv);
- if(!srv->server_ip[0]){
- /* get host ip */
- char hostname[128];
- gethostname(hostname, 127);
- DBG("hostname: %s", hostname);
- struct hostent * pHostent;
- pHostent = gethostbyname(hostname);
- struct in_addr iaddr;
- memcpy(&srv->server_ipnum, pHostent->h_addr_list[0], 4);
- iaddr.s_addr = srv->server_ipnum;
- strcpy(srv->server_ip, inet_ntoa(iaddr));
- }
- return 0;
- }
- static int loop_ips_search_by_ip(const void* p, const void* q)
- {
- if(((struct ftpip*)p)->ipnum == (unsigned int)q)
- return 1;
- return 0;
- }
- static void * server_listen(void* data)
- {
- struct sockaddr_in addr;
- unsigned int ipnum;
- unsigned len;
- struct ftpserver* srv = (struct ftpserver*)data;
- while(!srv->server_end){
- len = sizeof(addr);
- int fd = accept(srv->server_fd, (struct sockaddr *)&addr, &len);
- if(fd < 0){
- DBG("accept failed. fd=%d", fd);
- continue;
- }
- ipnum = ntohl(addr.sin_addr.s_addr);
- struct ftpip* ip = (struct ftpip* )loop_search(&srv->loop_ips, (void*)ipnum, loop_ips_search_by_ip);
- if(ip == NULL){
- if(srv->cur_ips >= srv->max_ips){
- shutdown(fd, SHUT_RDWR);
- closesocket(fd);
- }else{
- ip = (struct ftpip*)malloc(sizeof(struct ftpip));
- ip->ipnum = ipnum;
- ip->cur_conns = 0;
- struct in_addr iaddr;
- iaddr.s_addr = htonl( ipnum );
- strcpy(ip->ipstr, inet_ntoa(iaddr));
- ip->server = srv;
- loop_push_to_head(&srv->loop_ips, ip);
- srv->cur_ips ++;
- }
- }
- if(ip != NULL){
- if(ip->cur_conns >= srv->max_conns_per_ip || srv->cur_conns>=srv->max_conns){
- shutdown(fd, SHUT_RDWR);
- closesocket(fd);
- }else{
- struct ftpconn* conn = (struct ftpconn*)malloc(sizeof(struct ftpconn));
- memset(conn, 0, sizeof(struct ftpconn));
- conn->conn_fd = fd;
- conn->time_create =
- conn->time_alive = time(NULL);
- conn->ip = ip;
- conn->server = srv;
- conn->opts_utf8 = 1;
- loop_push_to_head(&srv->loop_conns, conn);
- ip->cur_conns ++;
- srv->cur_conns ++;
- DBG("new connection %d from %s, ips:%d conns:%d", fd, ip->ipstr, srv->cur_ips, srv->cur_conns);
- int ret = pthread_create(&conn->thread_conn, &srv->thread_attr, conn_start, (void*)conn);
- }
- }
- }
- return NULL;
- }
- static int loop_conns_iterator(const void*p, const void*q)
- {
- struct ftpconn* conn = (struct ftpconn*)p;
- if((time_t)q - conn->time_alive >= conn->server->conn_timeout){
- DBG("timeout connection of user: %s",
- q, conn->time_alive, conn->username);
- conn->conn_end = 1;
- if(conn->dataconn_fd){
- shutdown(conn->dataconn_fd, SHUT_RDWR);
- closesocket(conn->dataconn_fd);
- conn->dataconn_fd = 0;
- }
- if(conn->conn_fd){
- shutdown(conn->conn_fd, SHUT_RDWR);
- closesocket(conn->conn_fd);
- conn->conn_fd = 0;
- }
- }
- return conn->conn_end;
- }
- static int loop_ips_iterator(const void*p, const void*q)
- {
- struct ftpip* ip = (struct ftpip*)p;
- if(ip->cur_conns == 0)
- return 1;
- return 0;
- }
- static void * server_guard(void* data)
- {
- struct ftpserver* srv = (struct ftpserver*)data;
- while(!srv->server_end){
- time_t t = time(NULL);
- struct ftpconn* conn;
- while( conn = loop_search(&srv->loop_conns, (void*)t, loop_conns_iterator) ){
- pthread_join(conn->thread_conn, NULL);
- if(conn->dataconn_fd){
- closesocket(conn->dataconn_fd);
- conn->dataconn_fd = 0;
- }
- if(conn->conn_fd){
- closesocket(conn->conn_fd);
- conn->conn_fd = 0;
- }
- loop_remove(&srv->loop_conns, conn);
- conn->ip->cur_conns --;
- srv->cur_conns --;
- free(conn);
- }
- struct ftpip* ip;
- while( ip = loop_search(&srv->loop_ips, (void*)0, loop_ips_iterator) ){
- loop_remove(&srv->loop_ips, ip);
- srv->cur_ips --;
- free(ip);
- }
- SLEEP(1);
- }
- return NULL;
- }
- int server_start(struct ftpserver* srv)
- {
- int ret;
- pthread_attr_init(&srv->thread_attr);
- pthread_attr_setstacksize(&srv->thread_attr, 128*1024);
- srv->server_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
- /* Socket Reuse */
- ret = 1;
- setsockopt(srv->server_fd, SOL_SOCKET, SO_REUSEADDR, (void*)&ret, sizeof(ret));
- /* Bind Socket */
- struct sockaddr_in addr;
- memset(&addr,0, sizeof(addr));
- addr.sin_family = AF_INET;
- if( !srv->server_ip[0] )
- addr.sin_addr.s_addr = INADDR_ANY;
- else
- addr.sin_addr.s_addr = inet_addr( srv->server_ip );
- addr.sin_port = htons( srv->server_port );
- if ( bind( srv->server_fd, (struct sockaddr*)&addr, sizeof( addr ) ) <0 ){
- DBG("Bind Socket Error.");
- return 1;
- }
- //try to listen
- if( listen( srv->server_fd, srv->max_conns ) <0 ){
- DBG("Listen Socket Error.");
- return 1;
- }
- srv->time_start = time(NULL);
- DBG("listening on %s:%d", srv->server_ip, srv->server_port );
- loop_create(&srv->loop_ips, srv->max_ips, NULL);
- loop_create(&srv->loop_conns, srv->max_conns, NULL);
- /* create threads */
- ret = pthread_create( &srv->thread_guard, &srv->thread_attr, (void*)server_guard, (void*)srv );
- ret = pthread_create( &srv->thread_listen, &srv->thread_attr, (void*)server_listen, (void*)srv );
- return ret;
- }
- int server_stop(struct ftpserver* srv)
- {
- srv->server_end = 1;
- shutdown(srv->server_fd, 0);
- closesocket(srv->server_fd);
- pthread_join(srv->thread_listen, NULL);
- pthread_join(srv->thread_guard, NULL);
- pthread_attr_destroy(&srv->thread_attr);
- }