Jump to content

phit666

Members
  • Posts

    11
  • Joined

  • Last visited

Posts posted by phit666

  1. On 10/18/2021 at 5:46 AM, Neffletics said:

    Great work, but nobody uses Windows for production. 

    Primarily because of the select socket but to sort it out I changed mine to IOCP, its now running in multi threaded taking advantage of multi core processors.

  2. Base to sa latest revisions, nag add lang ako ng GUI interface sa windows and using IOCP socket na, compile it using visual studio 2019, select nyo lang Release GUI sa configuration. Sa security nag add ako ng dynamic encryption (disabled sya by default), pwede nyo enable (defines_pre.hpp under Custom) and it will help against proxy exploits or mga bots, kasama sa thirdparty folder yung client DLL (encDLL.dll) na magssend ng encrypted packet, hook nyo yung DLL using nemo. Sa gui mode, nilagay ko lahat ng reload options sa menu ng map server.

    https://github.com/phit666/rathena/tree/Levent

     

  3. This will allow the pointshop dealer to sell a bounded item and specific refine level, good for starter as it can't be exploited/spammed. The example below will sell an item with bound type 4 and refine level 10.

     

    prontera,155,166,4    pointshop    Bounded Item Dealer    123,#votepoints:0:4,13103:600:10

     

    pointshopext.diff

  4. So I've replaced the standard SELECT library with Libevent (libevent.org) library for obvious reasons below...

    1. This will use EPOLL in linux which is a lot faster and efficient than SELECT mechanism, you will notice in socket.c, using SELECT mechanism the do_socket function is doing a lot of LOOOOOPS (sending/receiving/sending/parsing/sending to all active sockets)  whenever SELECT is triggered, note how many "for(i = 1; i < fd_max; i++)" are there and being invoked whenever the server is receiving a few bytes. Using libevent mechanism, I only need to process one socket, only the socket where its receiving the data.

    2. 1024 standard socket limit (FD_SETSIZE) of select in linux is enough for unpopulated server, but how about for those populated? EPOLL socket limit is way beyond 1024, its more than 100k sockets, it really depends on the kernel.

    Using select mechanism (note how many for loops are here)

    int do_sockets(int next)
    {
    	fd_set rfd;
    	struct timeval timeout;
    	int ret,i;
    
    	// PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof.
    	// Send remaining data and process client-side disconnects here.
    #ifdef SEND_SHORTLIST
    	send_shortlist_do_sends();
    #else
    	for (i = 1; i < fd_max; i++)
    	{
    		if(!session[i])
    			continue;
    
    		if(session[i]->wdata_size)
    			session[i]->func_send(i);
    	}
    #endif
    
    	// can timeout until the next tick
    	timeout.tv_sec  = next/1000;
    	timeout.tv_usec = next%1000*1000;
    
    	memcpy(&rfd, &readfds, sizeof(rfd));
    	ret = sSelect(fd_max, &rfd, NULL, NULL, &timeout);
    
    	if( ret == SOCKET_ERROR )
    	{
    		if( sErrno != S_EINTR )
    		{
    			ShowFatalError("do_sockets: select() failed, %s!\n", error_msg());
    			exit(EXIT_FAILURE);
    		}
    		return 0; // interrupted by a signal, just loop and try again
    	}
    
    	last_tick = time(NULL);
    
    #if defined(WIN32)
    	// on windows, enumerating all members of the fd_set is way faster if we access the internals
    	for( i = 0; i < (int)rfd.fd_count; ++i )
    	{
    		int fd = sock2fd(rfd.fd_array[i]);
    		if( session[fd] )
    			session[fd]->func_recv(fd);
    	}
    #else
    	// otherwise assume that the fd_set is a bit-array and enumerate it in a standard way
    	for( i = 1; ret && i < fd_max; ++i )
    	{
    		if(sFD_ISSET(i,&rfd) && session[i])
    		{
    			session[i]->func_recv(i);
    			--ret;
    		}
    	}
    #endif
    
    	// POSTSEND Send remaining data and handle eof sessions.
    #ifdef SEND_SHORTLIST
    	send_shortlist_do_sends();
    #else
    	for (i = 1; i < fd_max; i++)
    	{
    		if(!session[i])
    			continue;
    
    		if(session[i]->wdata_size)
    			session[i]->func_send(i);
    
    		if(session[i]->flag.eof) //func_send can't free a session, this is safe.
    		{	//Finally, even if there is no data to parse, connections signalled eof should be closed, so we call parse_func [Skotlex]
    			session[i]->func_parse(i); //This should close the session immediately.
    		}
    	}
    #endif
    
    	// parse input data on each socket
    	for(i = 1; i < fd_max; i++)
    	{
    		if(!session[i])
    			continue;
    
    		if (session[i]->rdata_tick && DIFF_TICK(last_tick, session[i]->rdata_tick) > stall_time) {
    			if( session[i]->flag.server ) {/* server is special */
    				if( session[i]->flag.ping != 2 )/* only update if necessary otherwise it'd resend the ping unnecessarily */
    					session[i]->flag.ping = 1;
    			} else {
    				ShowInfo("Session #%d timed out\n", i);
    				set_eof(i);
    			}
    		}
    
    		session[i]->func_parse(i);
    
    		if(!session[i])
    			continue;
    
    		// after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed)
    		if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) {
    			set_eof(i);
    			continue;
    		}
    		RFIFOFLUSH(i);
    	}
    
    #ifdef SHOW_SERVER_STATS
    	if (last_tick != socket_data_last_tick)
    	{
    		char buf[1024];
    		
    		sprintf(buf, "In: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | Out: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | RAM: %.03f MB", socket_data_i/1024., socket_data_ci/1024., socket_data_qi/1024., socket_data_o/1024., socket_data_co/1024., socket_data_qo/1024., malloc_usage()/1024.);
    #ifdef _WIN32
    		SetConsoleTitle(buf);
    #else
    		ShowMessage("\033[s\033[1;1H\033[2K%s\033[u", buf);
    #endif
    		socket_data_last_tick = last_tick;
    		socket_data_i = socket_data_ci = 0;
    		socket_data_o = socket_data_co = 0;
    	}
    #endif
    
    	return 0;
    }

    Now using libevent mechanism

    void conn_readcb(struct bufferevent *bev, void *ptr)
    {
    
        int len,i;
    	int fd = ptr;
    
    	if( !session_isValid(fd) )
        {
    		return;
        }
    
    	len = bufferevent_read(bev,(char *)session[fd]->rdata + session[fd]->rdata_size,(int)RFIFOSPACE(fd));
    
    	if(len == 0)
        {
        	set_eof(fd);
        }
    
    	session[fd]->rdata_size += len;
    	session[fd]->rdata_tick = last_tick;
    
    	if(session[fd]->kill_tick > 0)
        	return;
    
        session[fd]->func_parse(fd);   
    	session[fd]->func_send(fd);
        
        if(session[fd]->flag.eof)
    	{
    		session[fd]->func_parse(fd);
    	}
        
    	RFIFOFLUSH(fd);
    }

     

    Now for those owners who got a big number, preferrably more than 1024 players and using linux server, PM me if you would like to test my update.

     

×
×
  • Create New...