<commit_before>//
// Created by wastl on 19.11.15.
//
#include <cstdlib>
#include <thread>
#include <unordered_set>
#include <glog/logging.h>

#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/security/credentials.h>
#include <grpc++/support/sync_stream.h>

#include "sharding/sharding.h"
#include "model/rdf_model.h"
#include "model/rdf_operators.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::ClientReader;
using grpc::ClientReaderWriter;
using grpc::ClientWriter;
using grpc::Status;
using grpc::ServerContext;
using grpc::ServerReader;
using grpc::ServerWriter;
using marmotta::rdf::proto::Namespace;
using marmotta::rdf::proto::Resource;
using marmotta::rdf::proto::Statement;
using marmotta::service::proto::ContextRequest;
using marmotta::service::proto::SailService;
using marmotta::service::proto::UpdateRequest;
using marmotta::service::proto::UpdateResponse;
using google::protobuf::Int64Value;

namespace marmotta {
namespace sharding {

// A templated fanout function, forwarding the same request to all backends and collecting
// Int64Value responses by summing them up.
template<typename Request,
        Status (SailService::Stub::*ClientMethod)(ClientContext*, const Request&, Int64Value*)>
Status Fanout(const Request& request, ShardingService::ChannelList &backends, Int64Value *result) {
    auto start = std::chrono::steady_clock::now();
    std::vector<std::thread> threads;
    std::vector<Status> statuses(backends.size());

    int64_t r = 0;
    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, &backends, &statuses, &request, &r]() {
            ClientContext localctx;
            Int64Value response;
            auto stub = svc::SailService::NewStub(backends[i]);
            statuses[i] = ((*stub).*ClientMethod)(&localctx, request, &response);
            r += response.value();
        }));
    }

    // need to wait until all are completed now.
    for (auto& t : threads) {
        t.join();
    }

    result->set_value(r);

    for (auto s : statuses) {
        if (!s.ok())
            return s;
    }

    DLOG(INFO) << "Fanout operation done (time="
               << std::chrono::duration <double, std::milli> (
            std::chrono::steady_clock::now() - start).count()
               << "ms).";

    return Status::OK;
};

ShardingService::ShardingService(std::vector<std::string> backends) : backends(backends) {
    for (const std::string& server : backends) {
        LOG(INFO) << "Establishing channel to " << server;
        channels.push_back(grpc::CreateChannel(server, grpc::InsecureChannelCredentials()));
    }
}

grpc::Status ShardingService::AddNamespaces(
        ServerContext *context, ServerReader<Namespace> *reader, Int64Value *result) {

    std::vector<ClientContext> contexts(backends.size());
    std::vector<Int64Value> stats(backends.size());

    StubList stubs;
    WriterList <Namespace> writers;

    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(stubs.back()->AddNamespaces(&contexts[i], &stats[i]));
    }

    // Iterate over all namespaces and schedule a write task.
    Namespace ns;
    while (reader->Read(&ns)) {
        DLOG(INFO) << "Adding namespace " << ns.DebugString();
        for (auto& w : writers) {
            w->Write(ns);
        }
    }

    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    result->set_value(stats[0].value());

    return Status::OK;
}

Status ShardingService::GetNamespace(
        ServerContext *context, const Namespace *pattern, Namespace *result) {
    int bucket = rand() % backends.size();

    auto stub = makeStub(bucket);

    ClientContext ctx;
    return stub->GetNamespace(&ctx, *pattern, result);
}

Status ShardingService::GetNamespaces(ServerContext *context, const google::protobuf::Empty *ignored,
                                      ServerWriter<Namespace> *result) {
    int bucket = rand() % backends.size();

    auto stub = makeStub(bucket);

    ClientContext ctx;
    auto reader = stub->GetNamespaces(&ctx, *ignored);

    Namespace ns;
    while (reader->Read(&ns)) {
        result->Write(ns);
    }
    return reader->Finish();
}

grpc::Status ShardingService::AddStatements(grpc::ServerContext *context,
                                            grpc::ServerReader<Statement> *reader,
                                            Int64Value *result) {
    std::vector<ClientContext> contexts(backends.size());
    std::vector<Int64Value> responses(backends.size());

    StubList stubs;
    WriterList<Statement> writers;
    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(Writer<Statement>(
                stubs.back()->AddStatements(&contexts[i], &responses[i])));
    }

    std::hash<Statement> stmt_hash;

    Statement stmt;
    std::string buf;
    while (reader->Read(&stmt)) {
            size_t bucket = stmt_hash(stmt) % backends.size();

            DLOG(INFO) << "Shard " << bucket << ": Adding statement " << stmt.DebugString();
            writers[bucket]->Write(stmt);
    }
    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    for (auto& r : responses) {
        result->set_value(result->value() + r.value());
    }

    return Status::OK;
}

grpc::Status ShardingService::GetStatements(
        ServerContext *context, const Statement *pattern, ServerWriter<Statement> *result) {
    auto start = std::chrono::steady_clock::now();
    DLOG(INFO) << "Get statements matching pattern " << pattern->DebugString();

    std::vector<std::thread> threads;
    std::mutex mutex;

    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, this, &mutex, result, pattern]() {
            DLOG(INFO) << "Shard " << i << ": Getting statements.";
            ClientContext localctx;
            auto stub = makeStub(i);
            auto reader = stub->GetStatements(&localctx, *pattern);

            int64_t count = 0;
            Statement stmt;
            while (reader->Read(&stmt)) {
                std::lock_guard<std::mutex> guard(mutex);
                result->Write(stmt);
                count++;
            }
            DLOG(INFO) << "Shard " << i << ": Getting statements finished (" << count << " results)";
        }));
    }

    for (auto& t : threads) {
        t.join();
    }

    DLOG(INFO) << "Get statements done (time="
               << std::chrono::duration <double, std::milli> (
            std::chrono::steady_clock::now() - start).count()
               << "ms).";

    return Status::OK;
}

Status ShardingService::RemoveStatements(
        ServerContext *context, const Statement *pattern, Int64Value *result) {
    DLOG(INFO) << "Fanout: Remove statements matching pattern " << pattern->DebugString();

    return Fanout<Statement, &SailService::Stub::RemoveStatements>(*pattern, channels, result);
}

Status ShardingService::Update(
        ServerContext *context, ServerReader<UpdateRequest> *reader, UpdateResponse *result) {
    std::vector<ClientContext> contexts(backends.size());
    std::vector<UpdateResponse> responses(backends.size());

    StubList stubs;
    WriterList <UpdateRequest> writers;

    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(stubs.back()->Update(&contexts[i], &responses[i]));
    }

    std::hash<Statement> stmt_hash;
    std::hash<Namespace> ns_hash;

    UpdateRequest req;
    std::string buf;
    while (reader->Read(&req)) {
        if (req.has_stmt_added()) {
            size_t bucket = stmt_hash(req.stmt_added()) % backends.size();

            DLOG(INFO) << "Shard " << bucket << ": Add statement request " << req.DebugString();
            writers[bucket]->Write(req);
        } else {
            DLOG(INFO) << "Fanout update request " << req.DebugString();
            for (auto& w : writers) {
                w->Write(req);
            }
        }
    }
    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    for (auto& r : responses) {
        result->set_added_namespaces(result->added_namespaces() + r.added_namespaces());
        result->set_removed_namespaces(result->removed_namespaces() + r.removed_namespaces());
        result->set_added_statements(result->added_statements() + r.added_statements());
        result->set_removed_statements(result->removed_statements() + r.removed_statements());
    }

    return Status::OK;
}

Status ShardingService::Clear(
        ServerContext *context, const ContextRequest *contexts, Int64Value *result) {
    DLOG(INFO) << "Fanout: Clear contexts matching pattern " << contexts->DebugString();

    return Fanout<ContextRequest, &SailService::Stub::Clear>(*contexts, channels, result);
}

Status ShardingService::Size(
        ServerContext *context, const ContextRequest *contexts, Int64Value *result) {
    DLOG(INFO) << "Fanout: Computing size of contexts matching pattern " << contexts->DebugString();

    return Fanout<ContextRequest, &SailService::Stub::Size>(*contexts, channels, result);
}

std::unique_ptr<SailService::Stub> ShardingService::makeStub(int i) {
    return SailService::NewStub(channels[i]);
}

grpc::Status ShardingService::GetContexts(grpc::ServerContext *context, const google::protobuf::Empty *ignored,
                                          grpc::ServerWriter<rdf::proto::Resource> *result) {
    std::unordered_set<Resource> contexts;
    std::vector<std::thread> threads;
    std::mutex mutex;

    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, &mutex, &contexts, this](){
            ClientContext ctx;
            auto stub = makeStub(i);
            auto reader = stub->GetContexts(&ctx, google::protobuf::Empty());

            Resource r;
            while (reader->Read(&r)) {
                std::lock_guard<std::mutex> guard(mutex);
                contexts.insert(r);
            }
            reader->Finish();
        }));
    }

    for (auto c : contexts) {
        result->Write(c);
    }
    return Status::OK;
}
}
}<commit_msg>cleanups<commit_after>//
// Created by wastl on 19.11.15.
//
#include <cstdlib>
#include <thread>
#include <unordered_set>
#include <glog/logging.h>

#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/security/credentials.h>
#include <grpc++/support/sync_stream.h>

#include "sharding/sharding.h"
#include "model/rdf_model.h"
#include "model/rdf_operators.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::ClientReader;
using grpc::ClientReaderWriter;
using grpc::ClientWriter;
using grpc::Status;
using grpc::ServerContext;
using grpc::ServerReader;
using grpc::ServerWriter;
using marmotta::rdf::proto::Namespace;
using marmotta::rdf::proto::Resource;
using marmotta::rdf::proto::Statement;
using marmotta::service::proto::ContextRequest;
using marmotta::service::proto::SailService;
using marmotta::service::proto::UpdateRequest;
using marmotta::service::proto::UpdateResponse;
using google::protobuf::Empty;
using google::protobuf::Int64Value;

namespace marmotta {
namespace sharding {

// A templated fanout function, forwarding the same request to all backends and collecting
// Int64Value responses by summing them up.
template<typename Request,
        Status (SailService::Stub::*ClientMethod)(ClientContext*, const Request&, Int64Value*)>
Status Fanout(const Request& request, ShardingService::ChannelList &backends, Int64Value *result) {
    auto start = std::chrono::steady_clock::now();
    std::vector<std::thread> threads;
    std::vector<Status> statuses(backends.size());

    int64_t r = 0;
    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, &backends, &statuses, &request, &r]() {
            ClientContext localctx;
            Int64Value response;
            auto stub = svc::SailService::NewStub(backends[i]);
            statuses[i] = ((*stub).*ClientMethod)(&localctx, request, &response);
            r += response.value();
        }));
    }

    // need to wait until all are completed now.
    for (auto& t : threads) {
        t.join();
    }

    result->set_value(r);

    for (auto s : statuses) {
        if (!s.ok())
            return s;
    }

    DLOG(INFO) << "Fanout operation done (time="
               << std::chrono::duration <double, std::milli> (
            std::chrono::steady_clock::now() - start).count()
               << "ms).";

    return Status::OK;
};

ShardingService::ShardingService(std::vector<std::string> backends) : backends(backends) {
    for (const std::string& server : backends) {
        LOG(INFO) << "Establishing channel to " << server;
        channels.push_back(grpc::CreateChannel(server, grpc::InsecureChannelCredentials()));
    }
}

grpc::Status ShardingService::AddNamespaces(
        ServerContext *context, ServerReader<Namespace> *reader, Int64Value *result) {

    std::vector<ClientContext> contexts(backends.size());
    std::vector<Int64Value> stats(backends.size());

    StubList stubs;
    WriterList <Namespace> writers;

    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(stubs.back()->AddNamespaces(&contexts[i], &stats[i]));
    }

    // Iterate over all namespaces and schedule a write task.
    Namespace ns;
    while (reader->Read(&ns)) {
        DLOG(INFO) << "Adding namespace " << ns.DebugString();
        for (auto& w : writers) {
            w->Write(ns);
        }
    }

    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    result->set_value(stats[0].value());

    return Status::OK;
}

Status ShardingService::GetNamespace(
        ServerContext *context, const Namespace *pattern, Namespace *result) {
    int bucket = rand() % backends.size();

    auto stub = makeStub(bucket);

    ClientContext ctx;
    return stub->GetNamespace(&ctx, *pattern, result);
}

Status ShardingService::GetNamespaces(
        ServerContext *context, const Empty *ignored, ServerWriter<Namespace> *result) {
    int bucket = rand() % backends.size();

    auto stub = makeStub(bucket);

    ClientContext ctx;
    auto reader = stub->GetNamespaces(&ctx, *ignored);

    Namespace ns;
    while (reader->Read(&ns)) {
        result->Write(ns);
    }
    return reader->Finish();
}

Status ShardingService::AddStatements(
        ServerContext *context, ServerReader<Statement> *reader, Int64Value *result) {
    std::vector<ClientContext> contexts(backends.size());
    std::vector<Int64Value> responses(backends.size());

    StubList stubs;
    WriterList<Statement> writers;
    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(Writer<Statement>(
                stubs.back()->AddStatements(&contexts[i], &responses[i])));
    }

    std::hash<Statement> stmt_hash;

    Statement stmt;
    while (reader->Read(&stmt)) {
            size_t bucket = stmt_hash(stmt) % backends.size();

            DLOG(INFO) << "Shard " << bucket << ": Adding statement " << stmt.DebugString();
            writers[bucket]->Write(stmt);
    }
    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    for (auto& r : responses) {
        result->set_value(result->value() + r.value());
    }

    return Status::OK;
}

Status ShardingService::GetStatements(
        ServerContext *context, const Statement *pattern, ServerWriter<Statement> *result) {
    auto start = std::chrono::steady_clock::now();
    DLOG(INFO) << "Get statements matching pattern " << pattern->DebugString();

    std::vector<std::thread> threads;
    std::mutex mutex;

    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, this, &mutex, result, pattern]() {
            DLOG(INFO) << "Shard " << i << ": Getting statements.";
            ClientContext localctx;
            auto stub = makeStub(i);
            auto reader = stub->GetStatements(&localctx, *pattern);

            int64_t count = 0;
            Statement stmt;
            while (reader->Read(&stmt)) {
                std::lock_guard<std::mutex> guard(mutex);
                result->Write(stmt);
                count++;
            }
            DLOG(INFO) << "Shard " << i << ": Getting statements finished (" << count << " results)";
        }));
    }

    for (auto& t : threads) {
        t.join();
    }

    DLOG(INFO) << "Get statements done (time="
               << std::chrono::duration <double, std::milli> (
            std::chrono::steady_clock::now() - start).count()
               << "ms).";

    return Status::OK;
}

Status ShardingService::RemoveStatements(
        ServerContext *context, const Statement *pattern, Int64Value *result) {
    DLOG(INFO) << "Fanout: Remove statements matching pattern " << pattern->DebugString();

    return Fanout<Statement, &SailService::Stub::RemoveStatements>(*pattern, channels, result);
}

Status ShardingService::Update(
        ServerContext *context, ServerReader<UpdateRequest> *reader, UpdateResponse *result) {
    std::vector<ClientContext> contexts(backends.size());
    std::vector<UpdateResponse> responses(backends.size());

    StubList stubs;
    WriterList <UpdateRequest> writers;

    for (int i=0; i<backends.size(); i++) {
        stubs.push_back(makeStub(i));
        writers.push_back(stubs.back()->Update(&contexts[i], &responses[i]));
    }

    std::hash<Statement> stmt_hash;
    std::hash<Namespace> ns_hash;

    UpdateRequest req;
    std::string buf;
    while (reader->Read(&req)) {
        if (req.has_stmt_added()) {
            size_t bucket = stmt_hash(req.stmt_added()) % backends.size();

            DLOG(INFO) << "Shard " << bucket << ": Add statement request " << req.DebugString();
            writers[bucket]->Write(req);
        } else {
            DLOG(INFO) << "Fanout update request " << req.DebugString();
            for (auto& w : writers) {
                w->Write(req);
            }
        }
    }
    for (auto& w : writers) {
        w->WritesDone();
        w->Finish();
    }

    for (auto& r : responses) {
        result->set_added_namespaces(result->added_namespaces() + r.added_namespaces());
        result->set_removed_namespaces(result->removed_namespaces() + r.removed_namespaces());
        result->set_added_statements(result->added_statements() + r.added_statements());
        result->set_removed_statements(result->removed_statements() + r.removed_statements());
    }

    return Status::OK;
}

Status ShardingService::Clear(
        ServerContext *context, const ContextRequest *contexts, Int64Value *result) {
    DLOG(INFO) << "Fanout: Clear contexts matching pattern " << contexts->DebugString();

    return Fanout<ContextRequest, &SailService::Stub::Clear>(*contexts, channels, result);
}

Status ShardingService::Size(
        ServerContext *context, const ContextRequest *contexts, Int64Value *result) {
    DLOG(INFO) << "Fanout: Computing size of contexts matching pattern " << contexts->DebugString();

    return Fanout<ContextRequest, &SailService::Stub::Size>(*contexts, channels, result);
}

std::unique_ptr<SailService::Stub> ShardingService::makeStub(int i) {
    return SailService::NewStub(channels[i]);
}

Status ShardingService::GetContexts(
        ServerContext *context, const Empty *ignored, ServerWriter<Resource> *result) {
    std::unordered_set<Resource> contexts;
    std::vector<std::thread> threads;
    std::mutex mutex;

    for (int i=0; i<backends.size(); i++) {
        threads.push_back(std::thread([i, &mutex, &contexts, this](){
            ClientContext ctx;
            auto stub = makeStub(i);
            auto reader = stub->GetContexts(&ctx, Empty());

            Resource r;
            while (reader->Read(&r)) {
                std::lock_guard<std::mutex> guard(mutex);
                contexts.insert(r);
            }
            reader->Finish();
        }));
    }

    for (auto c : contexts) {
        result->Write(c);
    }
    return Status::OK;
}
}
}<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "cntfrm.hxx"
#include "doc.hxx"
#include "flyfrm.hxx"
#include "frmtool.hxx"
#include "frmfmt.hxx"
#include "hints.hxx"
#include <fmtornt.hxx>
#include <fmtfsize.hxx>
#include "txtfrm.hxx"       //fuer IsLocked()
#include "flyfrms.hxx"
// OD 2004-01-19 #110582#
#include <dflyobj.hxx>

//from FlyCnt.cxx
void DeepCalc( const SwFrm *pFrm );

/*************************************************************************
|*
|*  SwFlyInCntFrm::SwFlyInCntFrm(), ~SwFlyInCntFrm()
|*
|*************************************************************************/
SwFlyInCntFrm::SwFlyInCntFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) :
    SwFlyFrm( pFmt, pSib, pAnch )
{
    bInCnt = bInvalidLayout = bInvalidCntnt = sal_True;
    SwTwips nRel = pFmt->GetVertOrient().GetPos();
    // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject>
    Point aRelPos;
    if( pAnch && pAnch->IsVertical() )
        aRelPos.setX(pAnch->IsReverse() ? nRel : -nRel);
    else
        aRelPos.setY(nRel);
    SetCurrRelPos( aRelPos );
}

SwFlyInCntFrm::~SwFlyInCntFrm()
{
    //good bye
    if ( !GetFmt()->GetDoc()->IsInDtor() && GetAnchorFrm() )
    {
        SwRect aTmp( GetObjRectWithSpaces() );
        SwFlyInCntFrm::NotifyBackground( FindPageFrm(), aTmp, PREP_FLY_LEAVE );
    }
}

// #i28701#
TYPEINIT1(SwFlyInCntFrm,SwFlyFrm);
/*************************************************************************
|*
|*  SwFlyInCntFrm::SetRefPoint(),
|*
|*************************************************************************/
void SwFlyInCntFrm::SetRefPoint( const Point& rPoint,
                                 const Point& rRelAttr,
                                 const Point& rRelPos )
{
    // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject>
    OSL_ENSURE( rPoint != aRef || rRelAttr != GetCurrRelPos(), "SetRefPoint: no change" );
    SwFlyNotify *pNotify = NULL;
    // No notify at a locked fly frame, if a fly frame is locked, there's
    // already a SwFlyNotify object on the stack (MakeAll).
    if( !IsLocked() )
        pNotify = new SwFlyNotify( this );
    aRef = rPoint;
    SetCurrRelPos( rRelAttr );
    SWRECTFN( GetAnchorFrm() )
    (Frm().*fnRect->fnSetPos)( rPoint + rRelPos );
    // #i68520#
    InvalidateObjRectWithSpaces();
    if( pNotify )
    {
        InvalidatePage();
        mbValidPos = sal_False;
        bInvalid  = sal_True;
        Calc();
        delete pNotify;
    }
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::Modify()
|*
|*************************************************************************/
void SwFlyInCntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
{
    bool bCallPrepare = false;
    sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    if( RES_ATTRSET_CHG == nWhich )
    {
        if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->
            GetItemState( RES_SURROUND, sal_False ) ||
            SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->
            GetItemState( RES_FRMMACRO, sal_False ) )
        {
            SwAttrSetChg aOld( *(SwAttrSetChg*)pOld );
            SwAttrSetChg aNew( *(SwAttrSetChg*)pNew );

            aOld.ClearItem( RES_SURROUND );
            aNew.ClearItem( RES_SURROUND );
            aOld.ClearItem( RES_FRMMACRO );
            aNew.ClearItem( RES_FRMMACRO );
            if( aNew.Count() )
            {
                SwFlyFrm::Modify( &aOld, &aNew );
                bCallPrepare = true;
            }
        }
        else if( ((SwAttrSetChg*)pNew)->GetChgSet()->Count())
        {
            SwFlyFrm::Modify( pOld, pNew );
            bCallPrepare = true;
        }
    }
    else if( nWhich != RES_SURROUND && RES_FRMMACRO != nWhich )
    {
        SwFlyFrm::Modify( pOld, pNew );
        bCallPrepare = true;
    }

    if ( bCallPrepare && GetAnchorFrm() )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, GetFmt() );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::Format()
|*
|*  Here the content gets formatted initially.
|*
|*************************************************************************/
void SwFlyInCntFrm::Format( const SwBorderAttrs *pAttrs )
{
    if ( !Frm().Height() )
    {
        Lock(); //don't format the anchor on the crook.
        SwCntntFrm *pCntnt = ContainsCntnt();
        while ( pCntnt )
        {   pCntnt->Calc();
            pCntnt = pCntnt->GetNextCntntFrm();
        }
        Unlock();
    }
    SwFlyFrm::Format( pAttrs );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::MakeFlyPos()
|*
|*  Description         In contrast to other Frms we only calculate the RelPos
|*      here. The absolute position is only calculated using SetAbsPos.
|*************************************************************************/
// OD 2004-03-23 #i26791#
//void SwFlyInCntFrm::MakeFlyPos()
void SwFlyInCntFrm::MakeObjPos()
{
    if ( !mbValidPos )
    {
        mbValidPos = sal_True;
        SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt();
        const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
        //Update the current values in the format if needed, during this we of
        //course must not send any Modify.
        const bool bVert = GetAnchorFrm()->IsVertical();
        const bool bRev = GetAnchorFrm()->IsReverse();
        SwTwips nOld = rVert.GetPos();
        SwTwips nAct = bVert ? -GetCurrRelPos().X() : GetCurrRelPos().Y();
        if( bRev )
            nAct = -nAct;
        if( nAct != nOld )
        {
            SwFmtVertOrient aVert( rVert );
            aVert.SetPos( nAct );
            pFmt->LockModify();
            pFmt->SetFmtAttr( aVert );
            pFmt->UnlockModify();
        }
    }
}

// #115759#
void SwFlyInCntFrm::_ActionOnInvalidation( const InvalidationType _nInvalid )
{
    if ( INVALID_POS == _nInvalid || INVALID_ALL == _nInvalid )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, &GetFrmFmt() );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::NotifyBackground()
|*
|*************************************************************************/
void SwFlyInCntFrm::NotifyBackground( SwPageFrm *, const SwRect& rRect,
                                       PrepareHint eHint)
{
    if ( eHint == PREP_FLY_ATTR_CHG )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG );
    else
        AnchorFrm()->Prepare( eHint, (void*)&rRect );
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::GetRelPos()
|*
|*************************************************************************/
const Point SwFlyInCntFrm::GetRelPos() const
{
    Calc();
    return GetCurrRelPos();
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::RegistFlys()
|*
|*************************************************************************/
void SwFlyInCntFrm::RegistFlys()
{
    // vgl. SwRowFrm::RegistFlys()
    SwPageFrm *pPage = FindPageFrm();
    OSL_ENSURE( pPage, "Register Flys without pages?" );
    ::RegistFlys( pPage, this );
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::MakeAll()
|*
|*************************************************************************/
void SwFlyInCntFrm::MakeAll()
{
    // OD 2004-01-19 #110582#
    if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
    {
        return;
    }

    if ( !GetAnchorFrm() || IsLocked() || IsColLocked() || !FindPageFrm() )
        return;

    Lock(); // The curtain falls

        //does the notification in the DTor
    const SwFlyNotify aNotify( this );
    SwBorderAttrAccess aAccess( SwFrm::GetCache(), this );
    const SwBorderAttrs &rAttrs = *aAccess.Get();

    if ( IsClipped() )
        mbValidSize = bHeightClipped = bWidthClipped = sal_False;

    while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
    {
        //Only stop, if the flag is set!!
        if ( !mbValidSize )
        {
            mbValidPrtArea = sal_False;
        }

        if ( !mbValidPrtArea )
            MakePrtArea( rAttrs );

        if ( !mbValidSize )
            Format( &rAttrs );

        if ( !mbValidPos )
        {
            // OD 2004-03-23 #i26791#
            //MakeFlyPos();
            MakeObjPos();
        }

        //
        // re-activate clipping of as-character anchored Writer fly frames
        // depending on compatibility option <ClipAsCharacterAnchoredWriterFlyFrames>
        if ( mbValidPos && mbValidSize &&
             GetFmt()->getIDocumentSettingAccess()->get( IDocumentSettingAccess::CLIP_AS_CHARACTER_ANCHORED_WRITER_FLY_FRAME ) )
        {
            SwFrm* pFrm = AnchorFrm();
            if ( Frm().Left() == (pFrm->Frm().Left()+pFrm->Prt().Left()) &&
                 Frm().Width() > pFrm->Prt().Width() )
            {
                Frm().Width( pFrm->Prt().Width() );
                mbValidPrtArea = sal_False;
                bWidthClipped = sal_True;
            }
        }
    }
    Unlock();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>sw: unused includes in flyincnt<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "doc.hxx"
#include "frmtool.hxx"
#include "hints.hxx"
#include <fmtornt.hxx>
#include "txtfrm.hxx"       //fuer IsLocked()
#include "flyfrms.hxx"
// OD 2004-01-19 #110582#
#include <dflyobj.hxx>

//from FlyCnt.cxx
void DeepCalc( const SwFrm *pFrm );

/*************************************************************************
|*
|*  SwFlyInCntFrm::SwFlyInCntFrm(), ~SwFlyInCntFrm()
|*
|*************************************************************************/
SwFlyInCntFrm::SwFlyInCntFrm( SwFlyFrmFmt *pFmt, SwFrm* pSib, SwFrm *pAnch ) :
    SwFlyFrm( pFmt, pSib, pAnch )
{
    bInCnt = bInvalidLayout = bInvalidCntnt = sal_True;
    SwTwips nRel = pFmt->GetVertOrient().GetPos();
    // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject>
    Point aRelPos;
    if( pAnch && pAnch->IsVertical() )
        aRelPos.setX(pAnch->IsReverse() ? nRel : -nRel);
    else
        aRelPos.setY(nRel);
    SetCurrRelPos( aRelPos );
}

SwFlyInCntFrm::~SwFlyInCntFrm()
{
    //good bye
    if ( !GetFmt()->GetDoc()->IsInDtor() && GetAnchorFrm() )
    {
        SwRect aTmp( GetObjRectWithSpaces() );
        SwFlyInCntFrm::NotifyBackground( FindPageFrm(), aTmp, PREP_FLY_LEAVE );
    }
}

// #i28701#
TYPEINIT1(SwFlyInCntFrm,SwFlyFrm);
/*************************************************************************
|*
|*  SwFlyInCntFrm::SetRefPoint(),
|*
|*************************************************************************/
void SwFlyInCntFrm::SetRefPoint( const Point& rPoint,
                                 const Point& rRelAttr,
                                 const Point& rRelPos )
{
    // OD 2004-05-27 #i26791# - member <aRelPos> moved to <SwAnchoredObject>
    OSL_ENSURE( rPoint != aRef || rRelAttr != GetCurrRelPos(), "SetRefPoint: no change" );
    SwFlyNotify *pNotify = NULL;
    // No notify at a locked fly frame, if a fly frame is locked, there's
    // already a SwFlyNotify object on the stack (MakeAll).
    if( !IsLocked() )
        pNotify = new SwFlyNotify( this );
    aRef = rPoint;
    SetCurrRelPos( rRelAttr );
    SWRECTFN( GetAnchorFrm() )
    (Frm().*fnRect->fnSetPos)( rPoint + rRelPos );
    // #i68520#
    InvalidateObjRectWithSpaces();
    if( pNotify )
    {
        InvalidatePage();
        mbValidPos = sal_False;
        bInvalid  = sal_True;
        Calc();
        delete pNotify;
    }
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::Modify()
|*
|*************************************************************************/
void SwFlyInCntFrm::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
{
    bool bCallPrepare = false;
    sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
    if( RES_ATTRSET_CHG == nWhich )
    {
        if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->
            GetItemState( RES_SURROUND, sal_False ) ||
            SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->
            GetItemState( RES_FRMMACRO, sal_False ) )
        {
            SwAttrSetChg aOld( *(SwAttrSetChg*)pOld );
            SwAttrSetChg aNew( *(SwAttrSetChg*)pNew );

            aOld.ClearItem( RES_SURROUND );
            aNew.ClearItem( RES_SURROUND );
            aOld.ClearItem( RES_FRMMACRO );
            aNew.ClearItem( RES_FRMMACRO );
            if( aNew.Count() )
            {
                SwFlyFrm::Modify( &aOld, &aNew );
                bCallPrepare = true;
            }
        }
        else if( ((SwAttrSetChg*)pNew)->GetChgSet()->Count())
        {
            SwFlyFrm::Modify( pOld, pNew );
            bCallPrepare = true;
        }
    }
    else if( nWhich != RES_SURROUND && RES_FRMMACRO != nWhich )
    {
        SwFlyFrm::Modify( pOld, pNew );
        bCallPrepare = true;
    }

    if ( bCallPrepare && GetAnchorFrm() )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, GetFmt() );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::Format()
|*
|*  Here the content gets formatted initially.
|*
|*************************************************************************/
void SwFlyInCntFrm::Format( const SwBorderAttrs *pAttrs )
{
    if ( !Frm().Height() )
    {
        Lock(); //don't format the anchor on the crook.
        SwCntntFrm *pCntnt = ContainsCntnt();
        while ( pCntnt )
        {   pCntnt->Calc();
            pCntnt = pCntnt->GetNextCntntFrm();
        }
        Unlock();
    }
    SwFlyFrm::Format( pAttrs );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::MakeFlyPos()
|*
|*  Description         In contrast to other Frms we only calculate the RelPos
|*      here. The absolute position is only calculated using SetAbsPos.
|*************************************************************************/
// OD 2004-03-23 #i26791#
//void SwFlyInCntFrm::MakeFlyPos()
void SwFlyInCntFrm::MakeObjPos()
{
    if ( !mbValidPos )
    {
        mbValidPos = sal_True;
        SwFlyFrmFmt *pFmt = (SwFlyFrmFmt*)GetFmt();
        const SwFmtVertOrient &rVert = pFmt->GetVertOrient();
        //Update the current values in the format if needed, during this we of
        //course must not send any Modify.
        const bool bVert = GetAnchorFrm()->IsVertical();
        const bool bRev = GetAnchorFrm()->IsReverse();
        SwTwips nOld = rVert.GetPos();
        SwTwips nAct = bVert ? -GetCurrRelPos().X() : GetCurrRelPos().Y();
        if( bRev )
            nAct = -nAct;
        if( nAct != nOld )
        {
            SwFmtVertOrient aVert( rVert );
            aVert.SetPos( nAct );
            pFmt->LockModify();
            pFmt->SetFmtAttr( aVert );
            pFmt->UnlockModify();
        }
    }
}

// #115759#
void SwFlyInCntFrm::_ActionOnInvalidation( const InvalidationType _nInvalid )
{
    if ( INVALID_POS == _nInvalid || INVALID_ALL == _nInvalid )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG, &GetFrmFmt() );
}
/*************************************************************************
|*
|*  SwFlyInCntFrm::NotifyBackground()
|*
|*************************************************************************/
void SwFlyInCntFrm::NotifyBackground( SwPageFrm *, const SwRect& rRect,
                                       PrepareHint eHint)
{
    if ( eHint == PREP_FLY_ATTR_CHG )
        AnchorFrm()->Prepare( PREP_FLY_ATTR_CHG );
    else
        AnchorFrm()->Prepare( eHint, (void*)&rRect );
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::GetRelPos()
|*
|*************************************************************************/
const Point SwFlyInCntFrm::GetRelPos() const
{
    Calc();
    return GetCurrRelPos();
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::RegistFlys()
|*
|*************************************************************************/
void SwFlyInCntFrm::RegistFlys()
{
    // vgl. SwRowFrm::RegistFlys()
    SwPageFrm *pPage = FindPageFrm();
    OSL_ENSURE( pPage, "Register Flys without pages?" );
    ::RegistFlys( pPage, this );
}

/*************************************************************************
|*
|*  SwFlyInCntFrm::MakeAll()
|*
|*************************************************************************/
void SwFlyInCntFrm::MakeAll()
{
    // OD 2004-01-19 #110582#
    if ( !GetFmt()->GetDoc()->IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
    {
        return;
    }

    if ( !GetAnchorFrm() || IsLocked() || IsColLocked() || !FindPageFrm() )
        return;

    Lock(); // The curtain falls

        //does the notification in the DTor
    const SwFlyNotify aNotify( this );
    SwBorderAttrAccess aAccess( SwFrm::GetCache(), this );
    const SwBorderAttrs &rAttrs = *aAccess.Get();

    if ( IsClipped() )
        mbValidSize = bHeightClipped = bWidthClipped = sal_False;

    while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
    {
        //Only stop, if the flag is set!!
        if ( !mbValidSize )
        {
            mbValidPrtArea = sal_False;
        }

        if ( !mbValidPrtArea )
            MakePrtArea( rAttrs );

        if ( !mbValidSize )
            Format( &rAttrs );

        if ( !mbValidPos )
        {
            // OD 2004-03-23 #i26791#
            //MakeFlyPos();
            MakeObjPos();
        }

        //
        // re-activate clipping of as-character anchored Writer fly frames
        // depending on compatibility option <ClipAsCharacterAnchoredWriterFlyFrames>
        if ( mbValidPos && mbValidSize &&
             GetFmt()->getIDocumentSettingAccess()->get( IDocumentSettingAccess::CLIP_AS_CHARACTER_ANCHORED_WRITER_FLY_FRAME ) )
        {
            SwFrm* pFrm = AnchorFrm();
            if ( Frm().Left() == (pFrm->Frm().Left()+pFrm->Prt().Left()) &&
                 Frm().Width() > pFrm->Prt().Width() )
            {
                Frm().Width( pFrm->Prt().Width() );
                mbValidPrtArea = sal_False;
                bWidthClipped = sal_True;
            }
        }
    }
    Unlock();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>//===-- ipcopt.c ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// IPC Optimization Central Runtime Management
//
//===----------------------------------------------------------------------===//

#include "debug.h"
#include "ipcd.h"
#include "ipcopt.h"
#include "ipcreg_internal.h"
#include "real.h"
#include "shm.h"

#include <assert.h>
#include <stdio.h>
#include <unistd.h>

// TODO: This table is presently not used thread-safe at all!
libipc_state state;
libipc_state::libipc_state() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    FDMap[i] = fd_info();
    EndpointInfo[i] = ipc_info();
  }
}

void scan_for_cloexec() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    fd_info &f = getFDInfo(i);
    if ((valid_ep(f.EP) || f.epoll.valid) && f.close_on_exec) {
      // This fd is actually already closed!

      // Unregister it, closing localfd as needed...
      unregister_inet_socket(i);
    }
  }
}

void dump_registered_fds() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    fd_info &f = getFDInfo(i);
    if (valid_ep(f.EP)) {
      ipc_info &info = getInfo(f.EP);
      ipclog("Inherited known fd: %d -> (endpoint: %d, localfd: %d)\n", i, f.EP,
             info.localfd);
    }
  }
}

void __ipcopt_init() {
  state = libipc_state();
  shm_state_restore();
  scan_for_cloexec();
  dump_registered_fds();
}

void __attribute__((destructor)) ipcopt_fini() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i)
    if (is_registered_socket(i)) {
      endpoint ep = getEP(i);
      ipc_info &info = getInfo(ep);
      if (is_optimized_socket_safe(i)) {
        ipclog("Optimized endpoint: ep=%d, fd=%d, localfd=%d, S: %zu R: %zu\n",
               ep, i, info.localfd, info.bytes_sent, info.bytes_recv);
      } else
        ipclog("Normal endpoint: ep=%d, fd=%d, S: %zu R: %zu\n",
               ep, i, info.bytes_sent, info.bytes_recv);

    }

  // And ensure they're unregistered!
  for (unsigned i = 0; i < TABLE_SIZE; ++i)
    if (is_registered_socket(i))
      unregister_inet_socket(i);
}

void invalidate(endpoint ep) {
  ipc_info &i = getInfo(ep);
  assert(i.state != STATE_INVALID);
  assert(i.ref_count == 0);
  i.reset();
}

void register_inet_socket(int fd) {
  if (!ipcd_enabled())
    return;
  // Freshly created socket
  ipclog("Registering socket fd=%d\n", fd);
  endpoint &ep = getEP(fd);
  // We better not think we already have an endpoint ID for this fd
  assert(ep == EP_INVALID);
  ep = ipcd_register_socket(fd);

  ipc_info &i = getInfo(ep);
  assert(i.ref_count == 0);
  assert(i.state == STATE_INVALID);
  i.reset();

  i.ref_count++;
  i.state = STATE_UNOPT;
}

void unregister_inet_socket(int fd) {
  if (!ipcd_enabled())
    return;
  if (!inbounds_fd(fd)) {
    return;
  }

  // Closing epoll fd makes it no longer valid epoll fd.
  fd_info &f = getFDInfo(fd);
  f.epoll.valid = false;

  endpoint ep = getEP(fd);
  // Allow attempt to unregister fd's we don't
  // have endpoints for, this happens all the time :)
  if (ep == EP_INVALID) {
    return;
  }
  ipc_info &i = getInfo(ep);
  assert(i.state != STATE_INVALID);
  ipclog("Unregistering socket fd=%d, S: %zu R: %zu\n", fd,
         i.bytes_sent, i.bytes_recv);

  assert(i.ref_count > 0);
  // FD no longer refers to this endpoint!
  f.EP = EP_INVALID;
  f.close_on_exec = false;
  if (--i.ref_count == 0) {
    // Last reference to this endpoint,
    // tell ipcd we're done with it.
    bool success = ipcd_unregister_socket(ep);
    if (!success) {
      ipclog("ipcd_unregister_socket(%d) failed!\n", ep);
    }

    // Close local fd if exists
    if (i.localfd) {
      assert(i.state == STATE_OPTIMIZED);
      __real_close(i.localfd);

      ipclog("Closing opt. endpt : ep=%d, fd=%d, localfd=%d, S: %zu R: %zu\n",
             ep, fd, i.localfd, i.bytes_sent, i.bytes_recv);

      bool &isLocal = is_local(i.localfd);
      // Consistency check
      assert(isLocal);
      assert(getEP(i.localfd) == EP_INVALID);
      // No longer special 'local' fd
      isLocal = false;
    }

    invalidate(ep);
    return;
  } else {
    ipclog("Retaining endpoint info for ep=%d, despite unreegistering fd=%d!\n",
           ep, fd);
  }
}

char is_registered_socket(int fd) {
  return inbounds_fd(fd) && (getEP(fd) != EP_INVALID);
}

char is_optimized_socket_safe(int fd) {
  if (!inbounds_fd(fd) || is_local(fd))
    return false;

  endpoint ep = getEP(fd);
  if (ep == EP_INVALID)
    return false;

  return getInfo(ep).state == STATE_OPTIMIZED;
}

int getlocalfd(int fd) {
  assert(is_registered_socket(fd));
  int local = ipcd_getlocalfd(getEP(fd));

  bool &isLocal = is_local(local);
  assert(!isLocal);
  assert(getEP(local) == EP_INVALID);
  isLocal = true;

  return local;
}

char is_protected_fd(int fd) {
  // Logging fd is protected
  if (FILE *logfp = getlogfp())
    if (int logfd = fileno(logfp))
      if (logfd == fd)
        return true;

  if (!ipcd_enabled())
    return false;

  // Check for ipcd protected sockets:
  if (ipcd_is_protected(fd))
    return true;

  if (!inbounds_fd(fd)) {
    return false;
  }

  // So are all local fd's:
  if (is_local(fd))
    return true;

  // Everything else is unprotected
  return false;
}

void register_inherited_fds() {
  // We just forked, bump ref count
  // on the fd's we inherited.
  for (unsigned fd = 0; fd < TABLE_SIZE; ++fd) {
    if (is_registered_socket(fd)) {
      endpoint ep = getEP(fd);
      assert(ep != EP_INVALID);
      bool ret = ipcd_reregister_socket(ep, fd);
      if (!ret) {
        ipclog("Failed to reregister endpoint '%d' for inherited fd '%d'\n",
               ep, fd);
      }
    }
  }
}

void dup_inet_socket(int fd1, int fd2) {
  assert(!is_protected_fd(fd2));

  // Ensure fd2 is closed if we didn't already think so.
  unregister_inet_socket(fd2);

  if (!is_registered_socket(fd1)) {
    return;
  }

  ipclog("Dup: %d -> %d\n", fd1, fd2);

  // Get info for the source descriptor
  endpoint ep = getEP(fd1);
  assert(valid_ep(ep));

  ipc_info &i = getInfo(ep);
  assert(i.ref_count > 0);
  assert(i.state != STATE_INVALID);
  // Bump reference count
  i.ref_count++;

  // Point fd2 at this ep:
  assert(getEP(fd2) == EP_INVALID);
  getEP(fd2) = ep;
}

void set_nonblocking(int fd, bool non_blocking) {
  if (!ipcd_enabled())
    return;
  endpoint ep = getEP(fd);
  assert(valid_ep(ep));

  getInfo(ep).non_blocking = non_blocking;
}

void set_cloexec(int fd, bool cloexec) {
  if (!ipcd_enabled())
    return;
  getFDInfo(fd).close_on_exec = cloexec;
}
<commit_msg>libipc: In destructor, only inform ipcd, avoid breaking other threads.<commit_after>//===-- ipcopt.c ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// IPC Optimization Central Runtime Management
//
//===----------------------------------------------------------------------===//

#include "debug.h"
#include "ipcd.h"
#include "ipcopt.h"
#include "ipcreg_internal.h"
#include "real.h"
#include "shm.h"

#include <assert.h>
#include <stdio.h>
#include <unistd.h>

// TODO: This table is presently not used thread-safe at all!
libipc_state state;
libipc_state::libipc_state() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    FDMap[i] = fd_info();
    EndpointInfo[i] = ipc_info();
  }
}

void scan_for_cloexec() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    fd_info &f = getFDInfo(i);
    if ((valid_ep(f.EP) || f.epoll.valid) && f.close_on_exec) {
      // This fd is actually already closed!

      // Unregister it, closing localfd as needed...
      unregister_inet_socket(i);
    }
  }
}

void dump_registered_fds() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i) {
    fd_info &f = getFDInfo(i);
    if (valid_ep(f.EP)) {
      ipc_info &info = getInfo(f.EP);
      ipclog("Inherited known fd: %d -> (endpoint: %d, localfd: %d)\n", i, f.EP,
             info.localfd);
    }
  }
}

void __ipcopt_init() {
  state = libipc_state();
  shm_state_restore();
  scan_for_cloexec();
  dump_registered_fds();
}

void __attribute__((destructor)) ipcopt_fini() {
  for (unsigned i = 0; i < TABLE_SIZE; ++i)
    if (is_registered_socket(i)) {
      endpoint ep = getEP(i);
      ipc_info &info = getInfo(ep);
      if (is_optimized_socket_safe(i)) {
        ipclog("Optimized endpoint: ep=%d, fd=%d, localfd=%d, S: %zu R: %zu\n",
               ep, i, info.localfd, info.bytes_sent, info.bytes_recv);
      } else
        ipclog("Normal endpoint: ep=%d, fd=%d, S: %zu R: %zu\n",
               ep, i, info.bytes_sent, info.bytes_recv);

    }

  // And ensure they're unregistered!
  for (unsigned i = 0; i < TABLE_SIZE; ++i)
    if (is_registered_socket(i)) {
      // Don't use unregister_inet_socket--
      // we don't want to change state that may
      // break concurrently executing threads,
      // only to let IPCD know we're done with it.

      endpoint ep = getEP(i);
      if (--getInfo(ep).ref_count == 0) {
        bool success = ipcd_unregister_socket(ep);
        if (!success) {
          ipclog("Failure unregistering socket in destructor!\n");
        }
      }
    }
}

void invalidate(endpoint ep) {
  ipc_info &i = getInfo(ep);
  assert(i.state != STATE_INVALID);
  assert(i.ref_count == 0);
  i.reset();
}

void register_inet_socket(int fd) {
  if (!ipcd_enabled())
    return;
  // Freshly created socket
  ipclog("Registering socket fd=%d\n", fd);
  endpoint &ep = getEP(fd);
  // We better not think we already have an endpoint ID for this fd
  assert(ep == EP_INVALID);
  ep = ipcd_register_socket(fd);

  ipc_info &i = getInfo(ep);
  assert(i.ref_count == 0);
  assert(i.state == STATE_INVALID);
  i.reset();

  i.ref_count++;
  i.state = STATE_UNOPT;
}

void unregister_inet_socket(int fd) {
  if (!ipcd_enabled())
    return;
  if (!inbounds_fd(fd)) {
    return;
  }

  // Closing epoll fd makes it no longer valid epoll fd.
  fd_info &f = getFDInfo(fd);
  f.epoll.valid = false;

  endpoint ep = getEP(fd);
  // Allow attempt to unregister fd's we don't
  // have endpoints for, this happens all the time :)
  if (ep == EP_INVALID) {
    return;
  }
  ipc_info &i = getInfo(ep);
  assert(i.state != STATE_INVALID);
  ipclog("Unregistering socket fd=%d, S: %zu R: %zu\n", fd,
         i.bytes_sent, i.bytes_recv);

  assert(i.ref_count > 0);
  // FD no longer refers to this endpoint!
  f.EP = EP_INVALID;
  f.close_on_exec = false;
  if (--i.ref_count == 0) {
    // Last reference to this endpoint,
    // tell ipcd we're done with it.
    bool success = ipcd_unregister_socket(ep);
    if (!success) {
      ipclog("ipcd_unregister_socket(%d) failed!\n", ep);
    }

    // Close local fd if exists
    if (i.localfd) {
      assert(i.state == STATE_OPTIMIZED);
      __real_close(i.localfd);

      ipclog("Closing opt. endpt : ep=%d, fd=%d, localfd=%d, S: %zu R: %zu\n",
             ep, fd, i.localfd, i.bytes_sent, i.bytes_recv);

      bool &isLocal = is_local(i.localfd);
      // Consistency check
      assert(isLocal);
      assert(getEP(i.localfd) == EP_INVALID);
      // No longer special 'local' fd
      isLocal = false;
    }

    invalidate(ep);
    return;
  } else {
    ipclog("Retaining endpoint info for ep=%d, despite unreegistering fd=%d!\n",
           ep, fd);
  }
}

char is_registered_socket(int fd) {
  return inbounds_fd(fd) && (getEP(fd) != EP_INVALID);
}

char is_optimized_socket_safe(int fd) {
  if (!inbounds_fd(fd) || is_local(fd))
    return false;

  endpoint ep = getEP(fd);
  if (ep == EP_INVALID)
    return false;

  return getInfo(ep).state == STATE_OPTIMIZED;
}

int getlocalfd(int fd) {
  assert(is_registered_socket(fd));
  int local = ipcd_getlocalfd(getEP(fd));

  bool &isLocal = is_local(local);
  assert(!isLocal);
  assert(getEP(local) == EP_INVALID);
  isLocal = true;

  return local;
}

char is_protected_fd(int fd) {
  // Logging fd is protected
  if (FILE *logfp = getlogfp())
    if (int logfd = fileno(logfp))
      if (logfd == fd)
        return true;

  if (!ipcd_enabled())
    return false;

  // Check for ipcd protected sockets:
  if (ipcd_is_protected(fd))
    return true;

  if (!inbounds_fd(fd)) {
    return false;
  }

  // So are all local fd's:
  if (is_local(fd))
    return true;

  // Everything else is unprotected
  return false;
}

void register_inherited_fds() {
  // We just forked, bump ref count
  // on the fd's we inherited.
  for (unsigned fd = 0; fd < TABLE_SIZE; ++fd) {
    if (is_registered_socket(fd)) {
      endpoint ep = getEP(fd);
      assert(ep != EP_INVALID);
      bool ret = ipcd_reregister_socket(ep, fd);
      if (!ret) {
        ipclog("Failed to reregister endpoint '%d' for inherited fd '%d'\n",
               ep, fd);
      }
    }
  }
}

void dup_inet_socket(int fd1, int fd2) {
  assert(!is_protected_fd(fd2));

  // Ensure fd2 is closed if we didn't already think so.
  unregister_inet_socket(fd2);

  if (!is_registered_socket(fd1)) {
    return;
  }

  ipclog("Dup: %d -> %d\n", fd1, fd2);

  // Get info for the source descriptor
  endpoint ep = getEP(fd1);
  assert(valid_ep(ep));

  ipc_info &i = getInfo(ep);
  assert(i.ref_count > 0);
  assert(i.state != STATE_INVALID);
  // Bump reference count
  i.ref_count++;

  // Point fd2 at this ep:
  assert(getEP(fd2) == EP_INVALID);
  getEP(fd2) = ep;
}

void set_nonblocking(int fd, bool non_blocking) {
  if (!ipcd_enabled())
    return;
  endpoint ep = getEP(fd);
  assert(valid_ep(ep));

  getInfo(ep).non_blocking = non_blocking;
}

void set_cloexec(int fd, bool cloexec) {
  if (!ipcd_enabled())
    return;
  getFDInfo(fd).close_on_exec = cloexec;
}
<|endoftext|>


<commit_before>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 512
#define ACK 0
#define NAK 1
#define BUFSIZE 505
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		/*if(strlen(window[i-base].getDataBuffer()) < BUFSIZE - 1) {
			for(++i; i < base + WIN_SIZE; i++){
				window[i-base].loadDataBuffer("\0");
			}
			break;
		}*/
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		if(p.str()[0] == '\0') break;
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}

	if(sendto(s, "\0", BUFSIZE, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Final package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
	}
	return true;
}

Packet createPacket(int index){
    cout << endl;

    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);

	if(mstr.length() < BUFSIZE) {
		cout << "Null terminated mstr." << endl;
		mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 8, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<commit_msg>Correct correction<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 512
#define ACK 0
#define NAK 1
#define BUFSIZE 505
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		if(strlen(window[i-base].getDataBuffer()) < BUFSIZE - 1) {
			for(++i; i < base + WIN_SIZE; i++){
				window[i-base].loadDataBuffer("\0");
			}
			break;
		}
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		if(p.str()[0] == '\0') break;
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}

	if(sendto(s, "\0", BUFSIZE, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Final package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
	}
	return true;
}

Packet createPacket(int index){
    cout << endl;

    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);

	if(mstr.length() < BUFSIZE) {
		cout << "Null terminated mstr." << endl;
		mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 8, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<|endoftext|>


<commit_before>/***********************************************************************************
**
** Target.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "stdafx.h"
//----------------------------------------------------------------------------------
CTarget g_Target;
//----------------------------------------------------------------------------------
CTarget::CTarget()
{
	//Чистимся
	memset(m_Data, 0, sizeof(m_Data));
	memset(m_LastData, 0, sizeof(m_LastData));
}
//----------------------------------------------------------------------------------
void CTarget::Reset()
{
	WISPFUN_DEBUG("c209_f1");
	//Чистимся
	memset(m_Data, 0, sizeof(m_Data));
	memset(m_LastData, 0, sizeof(m_LastData));

	if (m_Multi != NULL)
	{
		delete m_Multi;
		m_Multi = NULL;
	}

	m_Type = 0;
	m_CursorType = 0;
	m_CursorID = 0;
	m_Targeting = false;
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::SetLastTargetObject(const uint &serial)
{
	m_Type = 0;
	pack32(m_LastData + 7, serial);
}
//----------------------------------------------------------------------------------
void CTarget::SetData(WISP_DATASTREAM::CDataReader &reader)
{
	WISPFUN_DEBUG("c209_f2");
	//Копируем буффер
	memcpy(&m_Data[0], reader.Start, reader.Size);

	//И устанавливаем соответствующие значения
	m_Type = reader.ReadUInt8();
	m_CursorID = reader.ReadUInt32BE();
	m_CursorType = reader.ReadUInt8();
	m_Targeting = (m_CursorType < 3);
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::SetMultiData(WISP_DATASTREAM::CDataReader &reader)
{
	WISPFUN_DEBUG("c209_f3");
	//Устанавливаем соответствующие значения
	m_Type = 1;
	m_CursorType = 0;
	m_Targeting = true;
	m_CursorID = reader.ReadUInt32BE(1);

	//Копируем буффер
	memset(&m_Data[0], 0, 19);
	m_Data[0] = 0x6C;
	m_Data[1] = 1; //Таргет на ландшафт
	memcpy(m_Data + 2, reader.Start + 2, 4); //Копируем ID курсора (ID дида)

	reader.ResetPtr();
	m_MultiGraphic = reader.ReadUInt16BE(18) + 1;
}
//----------------------------------------------------------------------------------
void CTarget::SendTargetObject(const uint &serial)
{
	WISPFUN_DEBUG("c209_f4");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Пишем серийник объекта, на который ткнули прицелом, остальное - затираем
	pack32(m_Data + 7, serial);
	m_Data[1] = 0;

	CGameObject *obj = (g_World != NULL ? g_World->FindWorldObject(serial) : NULL);

	if (obj != NULL)
	{
		pack16(m_Data + 11, obj->X);
		pack16(m_Data + 13, obj->Y);
		m_Data[15] = 0xFF;
		m_Data[16] = obj->Z;
		pack16(m_Data + 17, obj->Graphic);
	}
	else
	{
		pack32(m_Data + 11, 0);
		pack32(m_Data + 15, 0);
	}

	if (serial != g_PlayerSerial)
	{
		g_LastTargetObject = serial;

		//Скопируем для LastTarget
		memcpy(m_LastData, m_Data, sizeof(m_Data));

		if (serial < 0x40000000)
			CPacketStatusRequest(serial).Send();
	}

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendTargetTile(const ushort &tileID, const short &x, const short &y, char z)
{
	WISPFUN_DEBUG("c209_f5");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	m_Data[1] = 1;

	//Пишем координаты и индекс тайла, на который ткнули, остальное трем
	pack32(m_Data + 7, 0);
	pack16(m_Data + 11, x);
	pack16(m_Data + 13, y);

	//m_Data[15] = 0xFF;
	//m_Data[16] = z;
	pack16(m_Data + 15, (short)z);
	pack16(m_Data + 17, tileID);

	//Скопируем для LastTarget
	memcpy(m_LastData, m_Data, sizeof(m_Data));

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendCancelTarget()
{
	WISPFUN_DEBUG("c209_f6");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Уходят только нули
	pack32(m_Data + 7, 0);
	pack32(m_Data + 11, 0xFFFFFFFF);
	pack32(m_Data + 15, 0);

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTargetObject(const uint &serial)
{
	WISPFUN_DEBUG("c209_f4");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Пишем серийник объекта, на который ткнули прицелом, остальное - затираем
	pack32(m_Data + 7, serial);
	m_Data[1] = 0;

	CGameObject *obj = (g_World != NULL ? g_World->FindWorldObject(serial) : NULL);

	if (obj != NULL)
	{
		pack16(m_Data + 11, obj->X);
		pack16(m_Data + 13, obj->Y);
		m_Data[15] = 0xFF;
		m_Data[16] = obj->Z;
		pack16(m_Data + 17, obj->Graphic);
	}
	else
	{
		pack32(m_Data + 11, 0);
		pack32(m_Data + 15, 0);
	}

	if (serial != g_PlayerSerial)
	{
		g_LastTargetObject = serial;

		//Скопируем для LastTarget
		memcpy(m_LastData, m_Data, sizeof(m_Data));

		if (serial < 0x40000000)
		{
			CPacketStatusRequest packet(serial);
			SendMessage(g_OrionWindow.Handle, UOMSG_SEND, (WPARAM)packet.Data().data(), packet.Data().size());
		}
	}

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTargetTile(const ushort &tileID, const short &x, const short &y, char z)
{
	WISPFUN_DEBUG("c209_f5");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	m_Data[1] = 1;

	//Пишем координаты и индекс тайла, на который ткнули, остальное трем
	pack32(m_Data + 7, 0);
	pack16(m_Data + 11, x);
	pack16(m_Data + 13, y);

	//m_Data[15] = 0xFF;
	//m_Data[16] = z;
	pack16(m_Data + 15, (short)z);
	pack16(m_Data + 17, tileID);

	//Скопируем для LastTarget
	memcpy(m_LastData, m_Data, sizeof(m_Data));

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendCancelTarget()
{
	WISPFUN_DEBUG("c209_f6");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Уходят только нули
	pack32(m_Data + 7, 0);
	pack32(m_Data + 11, 0xFFFFFFFF);
	pack32(m_Data + 15, 0);

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendLastTarget()
{
	WISPFUN_DEBUG("c209_f7");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Восстановим пакет последнего актуального таргета
	memcpy(m_Data, m_LastData, sizeof(m_Data));
	m_Data[0] = 0x6C;
	m_Data[1] = m_Type;
	m_Data[6] = m_CursorType;
	pack32(m_Data + 2, m_CursorID);

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendTarget()
{
	WISPFUN_DEBUG("c209_f8");
	g_Orion.Send(m_Data, sizeof(m_Data));

	//Чистим данные
	memset(m_Data, 0, sizeof(m_Data));
	m_Targeting = false;
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTarget()
{
	WISPFUN_DEBUG("c209_f8");
	SendMessage(g_OrionWindow.Handle, UOMSG_SEND, (WPARAM)m_Data, sizeof(m_Data));

	//Чистим данные
	memset(m_Data, 0, sizeof(m_Data));
	m_Targeting = false;
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::UnloadMulti()
{
	WISPFUN_DEBUG("c209_f9");
	if (m_Multi != NULL)
	{
		delete m_Multi;
		m_Multi = NULL;
	}
}
//----------------------------------------------------------------------------------
void CTarget::LoadMulti(const int &x, const int &y, const char &z)
{
	WISPFUN_DEBUG("c209_f10");
	UnloadMulti();

	CIndexMulti &index = g_Orion.m_MultiDataIndex[m_MultiGraphic - 1];

	if (index.Address != NULL)
	{
		int count = (int)index.Count;

		int itemOffset = sizeof(MULTI_BLOCK);

		if (g_PacketManager.ClientVersion >= CV_7090)
			itemOffset = sizeof(MULTI_BLOCK_NEW);

		IFOR(j, 0, count)
		{
			PMULTI_BLOCK pmb = (PMULTI_BLOCK)(index.Address + (j * itemOffset));

			CMultiObject *mo = new CMultiObject(pmb->ID, x + pmb->X, y + pmb->Y, z + (char)pmb->Z, 2);
			g_MapManager->AddRender(mo);
			AddMultiObject(mo);
		}
	}
}
//----------------------------------------------------------------------------------
void CTarget::AddMultiObject(CMultiObject *obj)
{
	WISPFUN_DEBUG("c209_f11");
	if (m_Multi == NULL)
	{
		m_Multi = new CMulti(obj->X, obj->Y);
		m_Multi->m_Next = NULL;
		m_Multi->m_Prev = NULL;
		m_Multi->m_Items = obj;
		obj->m_Next = NULL;
		obj->m_Prev = NULL;
	}
	else
	{
		CMulti *multi = GetMultiAtXY(obj->X, obj->Y);

		if (multi != NULL)
		{
			QFOR(multiobj, multi->m_Items, CMultiObject*)
			{
				if (obj->Z < multiobj->Z)
				{
					if (multiobj->m_Prev == NULL)
						multi->Insert(multiobj->m_Prev, obj);
					else
						multi->Insert(multiobj, obj);

					return;
				}

				if (multiobj->m_Next == NULL)
				{
					multiobj->m_Next = obj;
					obj->m_Prev = multiobj;
					obj->m_Next = NULL;

					return;
				}
			}

			//Если пришли сюда - что-то пошло не так
		}
		else
		{
			CMulti *newmulti = new CMulti(obj->X, obj->Y);
			newmulti->m_Next = NULL;
			newmulti->m_Items = obj;
			obj->m_Next = NULL;
			obj->m_Prev = NULL;

			multi = m_Multi;

			while (multi != NULL)
			{
				if (multi->m_Next == NULL)
				{
					multi->m_Next = newmulti;
					newmulti->m_Prev = multi;
					break;
				}

				multi = (CMulti*)multi->m_Next;
			}
		}
	}
}
//----------------------------------------------------------------------------------
CMulti *CTarget::GetMultiAtXY(const short &x, const short &y)
{
	WISPFUN_DEBUG("c209_f12");
	CMulti *multi = m_Multi;

	while (multi != NULL)
	{
		if (multi->X == x && multi->Y == y)
			break;

		multi = (CMulti*)multi->m_Next;
	}

	return multi;
}
//----------------------------------------------------------------------------------
<commit_msg>Cancel double clicks after targeting.<commit_after>/***********************************************************************************
**
** Target.cpp
**
** Copyright (C) August 2016 Hotride
**
************************************************************************************
*/
//----------------------------------------------------------------------------------
#include "stdafx.h"
//----------------------------------------------------------------------------------
CTarget g_Target;
//----------------------------------------------------------------------------------
CTarget::CTarget()
{
	//Чистимся
	memset(m_Data, 0, sizeof(m_Data));
	memset(m_LastData, 0, sizeof(m_LastData));
}
//----------------------------------------------------------------------------------
void CTarget::Reset()
{
	WISPFUN_DEBUG("c209_f1");
	//Чистимся
	memset(m_Data, 0, sizeof(m_Data));
	memset(m_LastData, 0, sizeof(m_LastData));

	if (m_Multi != NULL)
	{
		delete m_Multi;
		m_Multi = NULL;
	}

	m_Type = 0;
	m_CursorType = 0;
	m_CursorID = 0;
	m_Targeting = false;
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::SetLastTargetObject(const uint &serial)
{
	m_Type = 0;
	pack32(m_LastData + 7, serial);
}
//----------------------------------------------------------------------------------
void CTarget::SetData(WISP_DATASTREAM::CDataReader &reader)
{
	WISPFUN_DEBUG("c209_f2");
	//Копируем буффер
	memcpy(&m_Data[0], reader.Start, reader.Size);

	//И устанавливаем соответствующие значения
	m_Type = reader.ReadUInt8();
	m_CursorID = reader.ReadUInt32BE();
	m_CursorType = reader.ReadUInt8();
	m_Targeting = (m_CursorType < 3);
	m_MultiGraphic = 0;
}
//----------------------------------------------------------------------------------
void CTarget::SetMultiData(WISP_DATASTREAM::CDataReader &reader)
{
	WISPFUN_DEBUG("c209_f3");
	//Устанавливаем соответствующие значения
	m_Type = 1;
	m_CursorType = 0;
	m_Targeting = true;
	m_CursorID = reader.ReadUInt32BE(1);

	//Копируем буффер
	memset(&m_Data[0], 0, 19);
	m_Data[0] = 0x6C;
	m_Data[1] = 1; //Таргет на ландшафт
	memcpy(m_Data + 2, reader.Start + 2, 4); //Копируем ID курсора (ID дида)

	reader.ResetPtr();
	m_MultiGraphic = reader.ReadUInt16BE(18) + 1;
}
//----------------------------------------------------------------------------------
void CTarget::SendTargetObject(const uint &serial)
{
	WISPFUN_DEBUG("c209_f4");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Пишем серийник объекта, на который ткнули прицелом, остальное - затираем
	pack32(m_Data + 7, serial);
	m_Data[1] = 0;

	CGameObject *obj = (g_World != NULL ? g_World->FindWorldObject(serial) : NULL);

	if (obj != NULL)
	{
		pack16(m_Data + 11, obj->X);
		pack16(m_Data + 13, obj->Y);
		m_Data[15] = 0xFF;
		m_Data[16] = obj->Z;
		pack16(m_Data + 17, obj->Graphic);
	}
	else
	{
		pack32(m_Data + 11, 0);
		pack32(m_Data + 15, 0);
	}

	if (serial != g_PlayerSerial)
	{
		g_LastTargetObject = serial;

		//Скопируем для LastTarget
		memcpy(m_LastData, m_Data, sizeof(m_Data));

		if (serial < 0x40000000)
			CPacketStatusRequest(serial).Send();
	}

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendTargetTile(const ushort &tileID, const short &x, const short &y, char z)
{
	WISPFUN_DEBUG("c209_f5");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	m_Data[1] = 1;

	//Пишем координаты и индекс тайла, на который ткнули, остальное трем
	pack32(m_Data + 7, 0);
	pack16(m_Data + 11, x);
	pack16(m_Data + 13, y);

	//m_Data[15] = 0xFF;
	//m_Data[16] = z;
	pack16(m_Data + 15, (short)z);
	pack16(m_Data + 17, tileID);

	//Скопируем для LastTarget
	memcpy(m_LastData, m_Data, sizeof(m_Data));

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendCancelTarget()
{
	WISPFUN_DEBUG("c209_f6");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Уходят только нули
	pack32(m_Data + 7, 0);
	pack32(m_Data + 11, 0xFFFFFFFF);
	pack32(m_Data + 15, 0);

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTargetObject(const uint &serial)
{
	WISPFUN_DEBUG("c209_f4");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Пишем серийник объекта, на который ткнули прицелом, остальное - затираем
	pack32(m_Data + 7, serial);
	m_Data[1] = 0;

	CGameObject *obj = (g_World != NULL ? g_World->FindWorldObject(serial) : NULL);

	if (obj != NULL)
	{
		pack16(m_Data + 11, obj->X);
		pack16(m_Data + 13, obj->Y);
		m_Data[15] = 0xFF;
		m_Data[16] = obj->Z;
		pack16(m_Data + 17, obj->Graphic);
	}
	else
	{
		pack32(m_Data + 11, 0);
		pack32(m_Data + 15, 0);
	}

	if (serial != g_PlayerSerial)
	{
		g_LastTargetObject = serial;

		//Скопируем для LastTarget
		memcpy(m_LastData, m_Data, sizeof(m_Data));

		if (serial < 0x40000000)
		{
			CPacketStatusRequest packet(serial);
			SendMessage(g_OrionWindow.Handle, UOMSG_SEND, (WPARAM)packet.Data().data(), packet.Data().size());
		}
	}

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTargetTile(const ushort &tileID, const short &x, const short &y, char z)
{
	WISPFUN_DEBUG("c209_f5");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	m_Data[1] = 1;

	//Пишем координаты и индекс тайла, на который ткнули, остальное трем
	pack32(m_Data + 7, 0);
	pack16(m_Data + 11, x);
	pack16(m_Data + 13, y);

	//m_Data[15] = 0xFF;
	//m_Data[16] = z;
	pack16(m_Data + 15, (short)z);
	pack16(m_Data + 17, tileID);

	//Скопируем для LastTarget
	memcpy(m_LastData, m_Data, sizeof(m_Data));

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendCancelTarget()
{
	WISPFUN_DEBUG("c209_f6");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Уходят только нули
	pack32(m_Data + 7, 0);
	pack32(m_Data + 11, 0xFFFFFFFF);
	pack32(m_Data + 15, 0);

	Plugin_SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendLastTarget()
{
	WISPFUN_DEBUG("c209_f7");
	if (!m_Targeting)
		return; //Если в клиенте нет таргета - выход

	//Восстановим пакет последнего актуального таргета
	memcpy(m_Data, m_LastData, sizeof(m_Data));
	m_Data[0] = 0x6C;
	m_Data[1] = m_Type;
	m_Data[6] = m_CursorType;
	pack32(m_Data + 2, m_CursorID);

	SendTarget();
}
//----------------------------------------------------------------------------------
void CTarget::SendTarget()
{
	WISPFUN_DEBUG("c209_f8");
	g_Orion.Send(m_Data, sizeof(m_Data));

	//Чистим данные
	memset(m_Data, 0, sizeof(m_Data));
	m_Targeting = false;
	m_MultiGraphic = 0;

	g_MouseManager.CancelDoubleClick = true;
}
//----------------------------------------------------------------------------------
void CTarget::Plugin_SendTarget()
{
	WISPFUN_DEBUG("c209_f8");
	SendMessage(g_OrionWindow.Handle, UOMSG_SEND, (WPARAM)m_Data, sizeof(m_Data));

	//Чистим данные
	memset(m_Data, 0, sizeof(m_Data));
	m_Targeting = false;
	m_MultiGraphic = 0;

	g_MouseManager.CancelDoubleClick = true;
}
//----------------------------------------------------------------------------------
void CTarget::UnloadMulti()
{
	WISPFUN_DEBUG("c209_f9");
	if (m_Multi != NULL)
	{
		delete m_Multi;
		m_Multi = NULL;
	}
}
//----------------------------------------------------------------------------------
void CTarget::LoadMulti(const int &x, const int &y, const char &z)
{
	WISPFUN_DEBUG("c209_f10");
	UnloadMulti();

	CIndexMulti &index = g_Orion.m_MultiDataIndex[m_MultiGraphic - 1];

	if (index.Address != NULL)
	{
		int count = (int)index.Count;

		int itemOffset = sizeof(MULTI_BLOCK);

		if (g_PacketManager.ClientVersion >= CV_7090)
			itemOffset = sizeof(MULTI_BLOCK_NEW);

		IFOR(j, 0, count)
		{
			PMULTI_BLOCK pmb = (PMULTI_BLOCK)(index.Address + (j * itemOffset));

			CMultiObject *mo = new CMultiObject(pmb->ID, x + pmb->X, y + pmb->Y, z + (char)pmb->Z, 2);
			g_MapManager->AddRender(mo);
			AddMultiObject(mo);
		}
	}
}
//----------------------------------------------------------------------------------
void CTarget::AddMultiObject(CMultiObject *obj)
{
	WISPFUN_DEBUG("c209_f11");
	if (m_Multi == NULL)
	{
		m_Multi = new CMulti(obj->X, obj->Y);
		m_Multi->m_Next = NULL;
		m_Multi->m_Prev = NULL;
		m_Multi->m_Items = obj;
		obj->m_Next = NULL;
		obj->m_Prev = NULL;
	}
	else
	{
		CMulti *multi = GetMultiAtXY(obj->X, obj->Y);

		if (multi != NULL)
		{
			QFOR(multiobj, multi->m_Items, CMultiObject*)
			{
				if (obj->Z < multiobj->Z)
				{
					if (multiobj->m_Prev == NULL)
						multi->Insert(multiobj->m_Prev, obj);
					else
						multi->Insert(multiobj, obj);

					return;
				}

				if (multiobj->m_Next == NULL)
				{
					multiobj->m_Next = obj;
					obj->m_Prev = multiobj;
					obj->m_Next = NULL;

					return;
				}
			}

			//Если пришли сюда - что-то пошло не так
		}
		else
		{
			CMulti *newmulti = new CMulti(obj->X, obj->Y);
			newmulti->m_Next = NULL;
			newmulti->m_Items = obj;
			obj->m_Next = NULL;
			obj->m_Prev = NULL;

			multi = m_Multi;

			while (multi != NULL)
			{
				if (multi->m_Next == NULL)
				{
					multi->m_Next = newmulti;
					newmulti->m_Prev = multi;
					break;
				}

				multi = (CMulti*)multi->m_Next;
			}
		}
	}
}
//----------------------------------------------------------------------------------
CMulti *CTarget::GetMultiAtXY(const short &x, const short &y)
{
	WISPFUN_DEBUG("c209_f12");
	CMulti *multi = m_Multi;

	while (multi != NULL)
	{
		if (multi->X == x && multi->Y == y)
			break;

		multi = (CMulti*)multi->m_Next;
	}

	return multi;
}
//----------------------------------------------------------------------------------
<|endoftext|>