Example #1
0
void NetClient::calc()
{
    ENetEvent event;

    if (me && server)
     while (enet_host_service(me, &event, 0) > 0) {

        char type = (event.type == ENET_EVENT_TYPE_RECEIVE)
                  ? (char) event.packet->data[0]
                  : LEMNET_NOTHING;

        if (event.type == ENET_EVENT_TYPE_CONNECT) {
            // Server shall check if protocols and versions match.
            send_welcome_data();
        }

        else if (event.type == ENET_EVENT_TYPE_DISCONNECT) {
            exit = true;
        }

        else if (type == LEMNET_DISCON_SILENT) {
            exit = true;
        }

        else if (type == LEMNET_WELCOME_DATA) {
            // The server sends out packets of this sort, but that only
            // happens to inform clients before 2009 Oct 25 of their very
            // old version. The server will probably stop that in some
            // months, and until then we simply ignore these.
        }

        else if (type == LEMNET_YOU_TOO_OLD
         ||      type == LEMNET_YOU_TOO_NEW) {
            const bool old = (type == LEMNET_YOU_TOO_OLD);
            if  (old) Console::push_back(Language::net_chat_we_too_old);
            else      Console::push_back(Language::net_chat_we_too_new);
            std::string msg = Language::net_chat_version_yours;
            msg += Help::version_to_string(gloB->version);
            msg += Language::net_chat_version_server;
            msg += Help::version_to_string(
                    get_uint32_from(event.packet->data + 2));
            msg += '.';
            Console::push_back(msg);
            if (old) Console::push_back(Language::net_chat_please_download);
            else     Console::push_back(Language::net_chat_server_update);
            // The server will throw us out.
        }

        else if (type == LEMNET_SOMEONE_OLD
         ||      type == LEMNET_SOMEONE_NEW) {
            int who_nr = event.packet->data[1];
            PlDatIt who = players.begin();
            while (who != players.end() && who->number != who_nr) ++who;

            if (type == LEMNET_SOMEONE_NEW) {
                Console::push_back(Language::net_chat_someone_new);
                Console::push_back(Language::net_chat_server_update);
            }
            // There exists someone with that number
            else if (who != players.end()) {
                std::string s = who->name + ' '
                              + Language::net_chat_named_guy_old;
                Console::push_back(s);
            }
            else Console::push_back(Language::net_chat_someone_old);
            // This is independent from new or old
            if (who != players.end()) {
                // reset player
                players.erase(who);
                set_nobody_ready();
                player_data_change = true;
            }
        }

        else if (type == LEMNET_RECHECK) {
            send_welcome_data();
        }

        else if (type == LEMNET_ASSIGN_NUMBER) {
            PlayerData pd(event.packet->data[2],
             gloB->user_name.c_str());
            pd.style = pd.number % (LixEn::STYLE_MAX-1) + 1;
            if (useR->network_last_style > 0
             && useR->network_last_style < LixEn::STYLE_MAX)
                pd.style = static_cast <char> (useR->network_last_style);
            // The lobby saves the style to useR->...

            players.clear();
            players.push_back(pd);
            ourself = players.begin();

            ENetPacket* p = pd.create_packet();
            enet_peer_send(server, LEMNET_CHANNEL_MAIN, p);
        }

        else if (type == LEMNET_ROOM_DATA) {
            rooms.clear();
            for (int room = 0; room < NETWORK_ROOMS_MAX; ++room)
             if (event.packet->data[2 + room] > 0) {
                RoomData rd;
                rd.number  = room;
                rd.members = event.packet->data[2 + room];
                rooms.insert(rd);
            }
            room_data_change = true;
        }

        else if (type == LEMNET_ROOM_CHANGE) {
            // Throw out all people other than us, because we'll soon receive
            // LEMNET_PLAYER_BEFORE packets for everyone in the new room.
            PlayerData temp_ourself = *ourself;
            players.clear();
            players.push_back(temp_ourself);
            ourself = players.begin();
            const char target_room = event.packet->data[2];
            if (ourself->room == -1)
             Console::push_back(Language::net_chat_we_connected);
            else if (target_room == 0)
             Console::push_back(Language::net_chat_we_in_lobby);
            else {
                std::ostringstream message;
                message << Language::net_chat_we_in_room
                        << (int) target_room
                        << Language::net_chat_we_in_room_2;
                Console::push_back(message.str());
            }
            ourself->room = target_room;
        }

        else if (type == LEMNET_PLAYER_DATA
         ||      type == LEMNET_PLAYER_BEFORE) {
            PlayerData pd;
            pd.read_from(event.packet);
            PlDatIt known = get_player(pd.number);

            // A new person has joined
            if (known == players.end()) {
                // Insert new data before the first higher data, so that
                // the players list is still sorted by operator <.
                PlDatIt insert_here = --players.end();
                while (insert_here != --players.begin()
                 && pd < *insert_here) --insert_here;
                players.insert(++insert_here, pd);
                set_nobody_ready();
                if (type == LEMNET_PLAYER_DATA) {
                    std::ostringstream message;
                    message << pd.name;
                    if (ourself->room == 0)
                        message << Language::net_chat_player_in_lobby;
                    else {
                        message << Language::net_chat_player_in_room;
                        message << (int) ourself->room;
                        message << Language::net_chat_player_in_room_2;
                    }
                    Console::push_back(message.str());
                    Sound::play_loud(Sound::JOIN);
                }
            }
            else {
                // Only the information about readiness doesn't set back
                // all ready states. Everything else does.
                // snr = set nobody ready
                bool dont_call_snr = *known == pd;
                known->ready  = !known->ready; // *known will be overwr. anyway
                dont_call_snr = dont_call_snr || *known == pd;
                *known = pd;
                if (!dont_call_snr) set_nobody_ready();
            }
            player_data_change = true;
        }

        else if (type == LEMNET_PLAYER_CLEAR
         ||      type == LEMNET_PLAYER_OUT_TO) {
            unsigned nr = event.packet->data[1];
            PlDatIt who = get_player(nr);
            if (who != players.end()) {
                std::ostringstream message;
                message << who->name;
                if (type == LEMNET_PLAYER_CLEAR) {
                    message << Language::net_chat_disconnection;
                }
                else {
                    int room = event.packet->data[2];
                    if (room == 0) {
                        message << Language::net_chat_player_out_lobby;
                    }
                    else {
                        message << Language::net_chat_player_out_room;
                        message << room;
                        message << Language::net_chat_player_out_room_2;
                    }
                }
                Console::push_back(message.str());
                players.erase(who);
                player_data_change = true;
                set_nobody_ready();
            }
        }

        else if (type == LEMNET_LEVEL_FILE) {
            set_nobody_ready();
            std::istringstream str((char*) event.packet->data + 2);
            level.load_from_stream(str);
            level_change = true;

            PlDatIt who = get_player(event.packet->data[1]);
            if (who != players.end()) {
                std::ostringstream msg;
                msg << who->name << ' ' << Language::net_chat_level_change
                    << ' ' << level.get_name();
                Console::push_back(msg.str());
            }
        }

        else if (type == LEMNET_CHAT_MESSAGE) {
            std::string message = (const char*) &event.packet->data[2];
            Console::push_back(message, true); // true = weiss
        }

        else if (type == LEMNET_GAME_START) {
            // Reset things to make it possible to play multiple games one
            // after another
            set_nobody_ready();
            replay_data.clear();
            permu = Permu(event.packet->data[2],(char*)event.packet->data + 3);

            // Jetzt aber... auf geht's!
            game_start = true;
            updates_change = 0;

            std::ostringstream start_message;
            start_message << Language::net_game_start;
            if (useR->key_chat > 0
             && useR->key_chat < KEY_MAX) {
                start_message << Language::net_game_how_to_chat_1;
                start_message << Help::scancode_to_string(useR->key_chat);
                start_message << Language::net_game_how_to_chat_2;
            }
            Console::push_back(start_message.str());
        }

        else if (type == LEMNET_GAME_END) {
            game_end = true;
            Console::push_back(Language::net_game_end);
        }

        else if (type == LEMNET_REPLAY_DATA) {
            // Only make available if we aren't the sender
            if (event.packet->data[1] != ourself->number) {
                ReplayData data;
                data.read_from(event.packet);
                replay_data.push_back(data);
            }
        }

        else if (type == LEMNET_UPDATES) {
            updates_change = get_uint32_from(&event.packet->data[2]);
        }

        if (event.type == ENET_EVENT_TYPE_RECEIVE)
         enet_packet_destroy(event.packet);
    }
}
Example #2
0
void *thread_operator(void *attr){
    int rc;
    int my_id = (int) attr;
    
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    void *socket = zmq_socket(server_pool.context, ZMQ_REP);
    zmq_connect(socket, ZMQ_INPROC_ADDR);
    pthread_cleanup_push((void (*)(void *)) zmq_close, socket);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        
        zmq_msg_t reply_msgs[DCS_SERVER_REPLY_COUNT];
        
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        for(int i = 0; i < DCS_SERVER_REPLY_COUNT; i++){
            zmq_msg_init_size(&reply_msgs[i], DCS_SERVER_REPLY_SIZE);
            memcpy(zmq_msg_data(&reply_msgs[i]), &server_replys[i], DCS_SERVER_REPLY_SIZE);
        }
        pthread_cleanup_push(thread_operator_msg_clean, reply_msgs);
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        
            if(!server_pool.no_barr){
                rc = pthread_barrier_wait(&server_pool.proxy_barr);
                if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD)
                    syslog(LOG_ERR, "Thread #%d cannot wait on barrier.", my_id);
            }
            
            while(1){
                int        reply_id = DCS_SERVER_REPLY_OK;
                zmq_msg_t  client_msg;
                char      *message;
                size_t     msg_size;
                unsigned char digest[MSG_DIGEST_SIZE];
                char      *domain;
                char      *md5sum;
                char      *sep;
                HASH_ELEMENT *comp;
                
                pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
                zmq_msg_init(&client_msg);
                pthread_cleanup_push((void (*)(void *)) zmq_msg_close, &client_msg);
                    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
                    
                    zmq_msg_recv(&client_msg, socket, 0);
                    message  = (char *) zmq_msg_data(&client_msg);
                    msg_size = zmq_msg_size(&client_msg);
                    DEBUGMSG(syslog(LOG_DEBUG, "msg_size = %d\n", msg_size));
                    if(msg_size >= MSG_DIGEST_SIZE + 1 + 1 + 2){
                        //~ проверка размера сообщения здесь!!!
                        //~ decrypt and verify message here!
                        //~ message = func(message)
                        memset(digest, '\0', MSG_DIGEST_SIZE);
                        rc = msg_digest(message + MSG_DIGEST_SIZE, MSG_SALT_PATH,
                                        msg_size - MSG_DIGEST_SIZE, digest);
                        if(rc){
                            DEBUGMSG(syslog(LOG_DEBUG, "msg_digest failed!!!"));
                        }
                        if(memcmp(message, digest, MSG_DIGEST_SIZE) == 0){
                            message += MSG_DIGEST_SIZE;
                            DEBUGMSG(syslog(LOG_DEBUG, "Thread #%d catch message: '%s'\n", my_id, message + 1));
                            
                            switch(*message){
                                case DCS_CLIENT_REQ_MD5:
                                    message++;
                                    sep = strchr(message, MSG_SEPARATOR);
                                    if(sep){
                                        *sep   = '\0';
                                        domain = message;
                                        md5sum = sep + 1;
                                        /* Проверки на длину md5-сум!!! */
                                        comp = Hash_find(&server_pool.hash, domain,
                                            (size_t) (unsigned int) sep - (unsigned int) message);
                                        if(comp){
                                            if(memcmp(md5sum, comp->val, HASH_ELEMENT_VAL_SIZE) != 0){
                                                /* Суммы различны, подать сюда полный список деталей! */
                                                reply_id = DCS_SERVER_REPLY_FULL;
                                                DEBUGMSG(syslog(LOG_DEBUG, "Суммы различны\n"));
                                            }
                                            else{
                                                //~ Суммы совпали, всё хорошо.
                                                reply_id = DCS_SERVER_REPLY_OK;
                                            }
                                        }
                                        else{ /* Компьютера в хэше нет. */
                                            reply_id = DCS_SERVER_REPLY_FULL;
                                            DEBUGMSG(syslog(LOG_DEBUG, "Компьютера в хэше нет\n"));
                                        }
                                    }
                                    break;
                                case DCS_CLIENT_REQ_FULL:
                                    message++;
                                    sep = strchr(message, MSG_SEPARATOR);
                                    if(sep){
                                        *sep   = '\0';
                                        domain = message;
                                        size_t domain_size;
                                        CL_Detail *details;
                                        size_t     details_count;
                                        unsigned char *hwdata = (unsigned char *) sep + 1;
                                        msg_size -= (MSG_DIGEST_SIZE + 2 + (
                                                (size_t) (unsigned int) sep - (unsigned int) message));
                                        
                                        domain_size = (size_t) ((unsigned int) sep - (unsigned int) message);
                                        /* Считаем md5 */
                                        MD5_CTX mdcontext;
                                        MD5Init(&mdcontext);
                                        MD5Update(&mdcontext, hwdata, msg_size);
                                        MD5Final(digest, &mdcontext);
                                        /* Ищем комп в хэше */
                                        comp = Hash_find(&server_pool.hash, domain, domain_size);
                                        if(!comp){ /* Компьютера в хэше нет - новый компьютер. */
                                            DEBUGMSG(syslog(LOG_DEBUG, "Новая машина!"));
                                            //~ details = (CL_Detail *) calloc(sizeof(CL_Detail), 40);
                                            details = (CL_Detail *) malloc(sizeof(CL_Detail) * 40);
                                            
                                            unsigned char *hwdata_p = hwdata;
                                            for(int i = 0; i < 40; i++){
                                                details[i].vendor_id = get_uint16_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].vendor_id);
                                                details[i].device_id = get_uint16_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].device_id);
                                                details[i].subsystem_id = get_uint32_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].subsystem_id);
                                                details[i].class_code = get_uint32_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].class_code);
                                                details[i].revision = get_uint8_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].revision);
                                                memcpy(&details[i].bus_addr, hwdata_p, sizeof(details[i].bus_addr));
                                                hwdata_p += sizeof(details[i].bus_addr);
                                                details[i].serial_length = get_uint32_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].serial_length);
                                                DEBUGMSG(syslog(LOG_DEBUG, "Detail: %.4x:%.4x:%.8x (rev %.2x) [class: %.6x] Bus: '%s', SL '%u'",
                                                                    details[i].vendor_id,
                                                                    details[i].device_id,
                                                                    details[i].subsystem_id,
                                                                    details[i].revision,
                                                                    details[i].class_code,
                                                                    details[i].bus_addr,
                                                                    details[i].serial_length
                                                ));
                                                memcpy(&details[i].serial, hwdata_p, details[i].serial_length);
                                                hwdata_p += details[i].serial_length;
                                                details[i].serial[details[i].serial_length] = '\0';
                                                details[i].params_length = get_uint32_from(hwdata_p);
                                                hwdata_p += sizeof(details[i].params_length);
                                                DEBUGMSG(syslog(LOG_DEBUG, "HERE4! params_length: %d", details[i].params_length));
                                                details[i].params = (char *) calloc(sizeof(char), details[i].params_length);
                                                memcpy(details[i].params, hwdata_p, details[i].params_length);
                                                hwdata_p += details[i].params_length;
                                                details[i].params[details[i].params_length] = '\0';
                                                
                                                DEBUGMSG(syslog(LOG_DEBUG, "Detail: %.4x:%.4x:%.8x (%.2x) [%.6x]: '%s', '%s'",
                                                                    details[i].vendor_id,
                                                                    details[i].device_id,
                                                                    details[i].subsystem_id,
                                                                    details[i].revision,
                                                                    details[i].class_code,
                                                                    details[i].serial,
                                                                    details[i].params
                                                ));
                                                if((unsigned int) (hwdata_p - hwdata) >= msg_size){
                                                    details_count = i + 1;
                                                    details = (CL_Detail *) realloc(details, sizeof(CL_Detail) * details_count);
                                                    break;
                                                }
                                            }
                                            /* Хэшируем результат */
                                            comp = Hash_insert(&server_pool.hash,
                                                               domain, domain_size,
                                                               (char *) digest, MSG_DIGEST_SIZE);
                                            if(!comp){
                                                DEBUGMSG(syslog(LOG_DEBUG, "Hash insert error: %d\n", errno));
                                                break;
                                            }
                                        }
                                        else{
                                            /* Есть в кэше, проверим md5 */
                                            if(memcmp(comp->val, digest, HASH_ELEMENT_VAL_SIZE) == 0){
                                                DEBUGMSG(syslog(LOG_DEBUG, "Суммы одинаковые, наверное ошибочный запрос\n"));
                                            }
                                            else{ /* Суммы различны (так и должно быть) - обновляем! */
                                                memcpy(comp->val, digest, HASH_ELEMENT_VAL_SIZE);
                                            }
                                        }
                                        sync_comp(comp, details, details_count);
                                    }
                                    break;
                                default:
                                    DEBUGMSG(syslog(LOG_DEBUG, "default = %02x\n", *message));
                                    break;
                            }
                        }
                        else{
                            DEBUGMSG(syslog(LOG_DEBUG, "memcmp failed!"));
                        }
                    }
                    
                pthread_cleanup_pop(1); /* zmq_msg_close() */
                DEBUGMSG(syslog(LOG_DEBUG, "Reply %d: '%.2x'\n", reply_id, *((unsigned int *) zmq_msg_data(&reply_msgs[reply_id]))));
                zmq_msg_send(&reply_msgs[reply_id], socket, 0);
            }
        pthread_cleanup_pop(0); /* thread_operator_msg_clean */
    pthread_cleanup_pop(0); /* zmq_close */
    pthread_exit(NULL);
}