<commit_before>#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <GL/gl.h>
#include <stdlib.h>
#define PI 3.1415926535898

float w_width=700.0,w_height=700.0;
float x=0.0,y=0.0;
int s;
int r;
float xball=350.0,yball=350.0,a=1.0,b=1.0;

float speed[5]={0.05,0.08,0.1,0.14,0.18};
int level=0;

float xver,yver;
int target[700][700];
int font=0;
int flag=1;
int jz=0;
int score=0;

void init(void)
{
glClearColor(1.0,1.0,1.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(1,700,1,700,-1,1);
}

//::::::::::::::::TEXT FUNCTION:::::::::::::://
void drawBitmapText(const char *string,float x,float y,float z)
{
    const char *c;
    glRasterPos3f(x,y,z);

    for (c=string; *c != '\0'; c++)
    {
      if(font=0)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
      else if(font=1)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
      else if(font=2)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
      else if(font=3)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
    }
}

//::::::::::::::::Display Function::::::::::://
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);

GLint circle_points=100,i;
GLfloat angle;
glBegin(GL_POLYGON);
for(i=0;i<circle_points;i++) {
    angle=2*PI*i/circle_points;
    xver=xball+w_width*cos(angle)/35;
    yver=yball+w_height*sin(angle)/35;
    glVertex2f(xver,yver);
  }
glEnd();

//::::::::::::Separator:::::::::::://
glColor3f(0.0,0.0,0.0);
glRectf(50.0,70.0,641.0,73.0);
glRectf(50.0,37.0,641.0,40.0);

//::::::::::External GAME BOUNDARY::::::::::://
glColor3f(0.0,0.0,0.0);
glRectf(10.0,10.0,690.0,12.0);
glRectf(10.0,10.0,12.0,690.0);
glRectf(10.0,690.0,690.0,688.0);
glRectf(690.0,690.0,688.0,10.0);

//:::::::::::INTERNAL GAMING PLATFORM BOUNDARY:::::::::::::::://

glColor3f(0.0,0.0,0.0);
glRectf(50.0,594.0,641.0,591.0);
glRectf(50.0,594.0,47.0,37.0);
glRectf(641.0,594.0,644.0,37.0);

//::::::::::Target Blocks::::::::::://
if(flag==1)
{
  for(s=590;s>440;s-=50)
    {
      for(r=50;r<650;r+=50)
        {
          target[r][s]=1;
        }
    }
  flag=0;
}

glBegin(GL_QUADS);
{
  for(s=590;s>440;s-=50)
  {
    for(r=50;r<650;r+=50)
    {
      if(target[r][s]==1)
      {
        glColor3f(0.0,1.0,0.0);
        glVertex3f(r,s,0.0);
        glVertex3f(r+40.0,s,0.0);
        glVertex3f(r+40.0,s-40.0,0.0);
        glVertex3f(r,s-40.0,0.0);
      }
    }
  }
}
glEnd();

//::::::::::::Text:::::::::::://
glColor3f(0.0,0.0,0.0);
font=0;
drawBitmapText("Welcome To Tik-i-noids!!",300,650,0);

glColor3f(1.0,0.0,0.0);
if(jz==1)
{font=1;
drawBitmapText("!!!!GAME OVER!!!!",250,300,0);
}

//:::::::::::::Block:::::::::::::::://
glColor3f(1.0,0.0,1.0);
glBegin(GL_QUADS);
{
  glVertex3f(310.0+x,40.0,0.0);
  glVertex3f(390.0+x,40.0,0.0);
  glVertex3f(390.0+x,70.0,0.0);
  glVertex3f(310.0+x,70.0,0.0);
}
glEnd();
glFinish();
glutSwapBuffers();

}

//::::::::::::::Reshape Function:::::::::::::::::://
void reshape(int w, int h)
{
	w_height=h;
	w_width=w;
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0,(GLdouble)w,0.0,(GLdouble)h,0.0,1.0);
}

void againDisplay()
{
  xball=xball+(a*speed[level]);
  yball=yball+(b*speed[level]);

for(s=590;s>=490;s-=50)
   {
    for(r=50;r<650;r+=50)
     {
      if(target[r][s]==1)
      {
        if((yball<=s-32)&&(yball>=s-58)&&(xball>=r-2)&&(xball<=r+42)&&(b==1))
        {
          b=-b;
          target[r][s]=0;
          score++;
        }
      }
    }
  }

  if(((xball<=390.0+x)&&(xball>=310.0+x))&&((yball>=75.0)&&(yball<=90.0)))
  b=-b ;

  if(yball>590.0)
  b=-b;

  if((xball>=620.0)||(xball<=65.0))
  a=-a;

  if(yball<=10.0)
  jz=1;

  if(yball<=-200.0)
  glutIdleFunc(NULL);
  else
  glutPostRedisplay();

}

//::::::::::::::::::::keyboard function:::::::::::::::::://
void keyboard(unsigned char key, int xm, int ym)
{
  switch (key)
    {

      case 'a':x-=10;if(x<-360)x=-360;
      break;

      case 'd':x+=10; if(x>360)x=360;
      break;

      case 49:level=0;
      break;

      case 50:level=1;
      break;

      case 51:level=2;
      break;

      case 52:level=3;
      break;

      case 53:level=4;
      break;

      case 'p':glutIdleFunc(againDisplay);     //Start the game
      break;

      case 's':glutIdleFunc(NULL);            //Pause the game
      break;

      default:
      break;
    }
}

int main(int argc,char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
  glutInitWindowSize(w_width,w_height);
  glutInitWindowPosition(270,20);
  glutCreateWindow("Tik-i-noids by Jalaz");
  init();
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);
  glutMainLoop();
  return 0;
}
<commit_msg>score calculation<commit_after>#include <GL/freeglut.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <GL/gl.h>
#include <stdlib.h>
#define PI 3.1415926535898

float w_width=700.0,w_height=700.0;
float x=0.0,y=0.0;
int s;
int r;
float xball=350.0,yball=350.0,a=1.0,b=1.0;

float speed[5]={0.1,0.15,0.18,0.22,0.25};
int level=0;

float xver,yver;
int target[700][700];
int font=0;
int flag=1;
int score=0;
int play=1;

char sc[4];

void init(void)
{
glClearColor(1.0,1.0,1.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(1,700,1,700,-1,1);
}

//::::::::::::::::TEXT FUNCTION:::::::::::::://
void drawBitmapText(const char *string,float x,float y,float z)
{
    const char *c;
    glRasterPos3f(x,y,z);

    for (c=string; *c != '\0'; c++)
    {
      if(font==0)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
      else if(font==1)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
      else if(font==2)
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
      else if(font==3)
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *c);
      else if(font==4)
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *c);
      else if(font==5)
        glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *c);
      else if(font==6)
        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *c);

    }
}

//::::::::::::::::Display Function::::::::::://
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);

//:::::::::::Ball:::::::::::://
glColor3f(0.0,0.0,1.0);
GLint circle_points=100,i;
GLfloat angle;
glBegin(GL_POLYGON);
for(i=0;i<circle_points;i++)
  {
    angle=2*PI*i/circle_points;
    xver=xball+w_width*cos(angle)/35;
    yver=yball+w_height*sin(angle)/35;
    glVertex2f(xver,yver);
  }
glEnd();

//::::::::::::Separator:::::::::::://
glColor3f(0.0,0.0,0.0);
//glRectf(50.0,70.0,641.0,73.0);
glRectf(50.0,37.0,641.0,40.0);

//::::::::::External Boundary::::::::::://
glColor3f(0.0,0.0,0.0);
glRectf(10.0,10.0,690.0,12.0);
glRectf(10.0,10.0,12.0,690.0);
glRectf(10.0,690.0,690.0,688.0);
glRectf(690.0,690.0,688.0,10.0);

//:::::::::::Internal Gaming Platform Boundary:::::::::::::::://

glColor3f(0.0,0.0,0.0);
glRectf(50.0,594.0,641.0,591.0);
glRectf(50.0,594.0,47.0,37.0);
glRectf(641.0,594.0,644.0,37.0);

//::::::::::Target Blocks::::::::::://
if(flag==1)
{
  for(s=590;s>440;s-=50)
    {
      for(r=50;r<650;r+=50)
        {
          target[r][s]=1;
        }
    }
  flag=0;
}

glBegin(GL_QUADS);
{
  for(s=590;s>440;s-=50)
  {
    for(r=50;r<650;r+=50)
    {
      if(target[r][s]==1)
      {
        glColor3f(0.0,1.0,0.0);
        glVertex3f(r,s,0.0);
        glVertex3f(r+40.0,s,0.0);
        glVertex3f(r+40.0,s-40.0,0.0);
        glVertex3f(r,s-40.0,0.0);
      }
    }
  }
}
glEnd();

//::::::::::::Text:::::::::::://
glColor3f(0.0,0.0,0.0);
font=2;
drawBitmapText("Welcome To Tik-i-noids!!",220,650,0);
font=3;
drawBitmapText("Score:",500,650,0);
drawBitmapText(sc,550,650,0);
glColor3f(1.0,0.0,0.0);
  if(play==2)
    {
      font=1;
      drawBitmapText("!!!!GAME OVER!!!!",230,350,0);

      drawBitmapText("Your Score: ",230,300,0);
      drawBitmapText(sc,360,300,0);
      font=3;
      drawBitmapText("Press R to Restart the game",250,250,0);
    }

//:::::::::::::Block:::::::::::::::://
glColor3f(1.0,0.0,1.0);
glBegin(GL_QUADS);
{
  glVertex3f(310.0+x,40.0,0.0);
  glVertex3f(390.0+x,40.0,0.0);
  glVertex3f(390.0+x,70.0,0.0);
  glVertex3f(310.0+x,70.0,0.0);
}
glEnd();
glFinish();
glutSwapBuffers();

}

//::::::::::::::Reshape Function:::::::::::::::::://
void reshape(int w, int h)
{
	w_height=h;
	w_width=w;
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0,(GLdouble)w,0.0,(GLdouble)h,0.0,1.0);
}

void againDisplay()
{
  xball=xball+(a*speed[level]);
  yball=yball+(b*speed[level]);

  for(s=590;s>=490;s-=50)
   {
    for(r=50;r<650;r+=50)
     {
      if(target[r][s]==1)
      {
        if((yball<=s-32)&&(yball>=s-58)&&(xball>=r-2)&&(xball<=r+42)&&(b==1))
        {
          b=-b;
          target[r][s]=0;
          score+=10;
        }
      }
    }
  }

  if(((xball<=400.0+x)&&(xball>=300.0+x))&&((yball>=75.0)&&(yball<=90.0)))
  b=-b ;

  if(yball>590.0)
  b=-b;

  if((xball>=620.0)||(xball<=65.0))
  a=-a;

  int s1,s2,s3,s4;
  s1=score/1000;
  s2=(score%1000)/100;
  s3=(score%100)/10;
  s4=score%10;
  sc[0]=s1+48;
  sc[1]=s2+48;
  sc[2]=s3+48;
  sc[3]=s4+48;

  if(yball<=10.0)
  play=2;

  if(yball<=-20.0)
  glutIdleFunc(NULL);

  glutPostRedisplay();

}

//::::::::::::Restart Function::::::::::::::://
void restart(void)
{
  play=1;
  flag=1;
  x=0.0,y=0.0;
  xball=350.0,yball=350.0,a=1.0,b=1.0;
  score=0;
  level=0;

  glutPostRedisplay();
}

//::::::::::::::::::::keyboard function:::::::::::::::::://
void keyboard(unsigned char key, int xm, int ym)
{
  switch (key)
    {

      case 'a':x-=15;if(x<-260)x=-260;
      break;

      case 'd':x+=15; if(x>251)x=251;
      break;

      case 49:level=0;
      break;

      case 50:level=1;
      break;

      case 51:level=2;
      break;

      case 52:level=3;
      break;

      case 53:level=4;
      break;

      case 's':glutIdleFunc(againDisplay);     //Start the game
      break;

      case 'p':glutIdleFunc(NULL);            //Pause the game
      break;

      case 'r':glutIdleFunc(restart);
      default:
      break;
    }
}

int main(int argc,char** argv)
{
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
  glutInitWindowSize(w_width,w_height);
  glutInitWindowPosition(270,20);
  glutCreateWindow("Tik-i-noids by Jalaz");
  init();
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);
  glutMainLoop();
  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/location_data.pb.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/util/tracking/box_tracker.h"
#include "mediapipe/graphs/instantmotiontracking/calculators/transformations.h"

namespace mediapipe {

constexpr char kSentinelTag[] = "SENTINEL";
constexpr char kAnchorsTag[] = "ANCHORS";
constexpr char kBoxesInputTag[] = "BOXES";
constexpr char kBoxesOutputTag[] = "START_POS";
constexpr char kCancelTag[] = "CANCEL_ID";
// TODO: Find optimal Height/Width (0.1-0.3)
constexpr float kBoxEdgeSize = 0.2f; // Used to establish tracking box dimensions
constexpr float kUsToMs = 1000.0f; // Used to convert from microseconds to millis

// This calculator manages the regions being tracked for each individual sticker
// and adjusts the regions being tracked if a change is detected in a sticker's
// initial anchor placement. Regions being tracked that have no associated sticker
// will be automatically removed upon the next iteration of the graph to optimize
// performance and remove all sticker artifacts
//
// Input:
//  SENTINEL - ID of sticker which has an anchor that must be reset (-1 when no
// anchor must be reset) [REQUIRED]
//  ANCHORS - Initial anchor data (tracks changes and where to re/position) [REQUIRED]
//  BOXES - Used in cycle, boxes being tracked meant to update positions [OPTIONAL
//  - provided by subgraph]
// Output:
//  START_POS - Positions of boxes being tracked (can be overwritten with ID) [REQUIRED]
//  CANCEL_ID - Single integer ID of tracking box to remove from tracker subgraph [OPTIONAL]
//  ANCHORS - Updated set of anchors with tracked and normalized X,Y,Z [REQUIRED]
//
// Example config:
// node {
//   calculator: "TrackedAnchorManagerCalculator"
//   input_stream: "SENTINEL:sticker_sentinel"
//   input_stream: "ANCHORS:initial_anchor_data"
//   input_stream: "BOXES:boxes"
//   input_stream_info: {
//     tag_index: 'BOXES'
//     back_edge: true
//   }
//   output_stream: "START_POS:start_pos"
//   output_stream: "CANCEL_ID:cancel_object_id"
//   output_stream: "ANCHORS:tracked_scaled_anchor_data"
// }

class TrackedAnchorManagerCalculator : public CalculatorBase {
private:
  // Previous graph iteration anchor data
  std::vector<Anchor> previous_anchor_data;

public:
  static ::mediapipe::Status GetContract(CalculatorContract* cc) {
    RET_CHECK(cc->Inputs().HasTag(kAnchorsTag)
      && cc->Inputs().HasTag(kSentinelTag));
    RET_CHECK(cc->Outputs().HasTag(kAnchorsTag)
      && cc->Outputs().HasTag(kBoxesOutputTag));

    cc->Inputs().Tag(kAnchorsTag).Set<std::vector<Anchor>>();
    cc->Inputs().Tag(kSentinelTag).Set<int>();

    if (cc->Inputs().HasTag(kBoxesInputTag)) {
      cc->Inputs().Tag(kBoxesInputTag).Set<TimedBoxProtoList>();
    }

    cc->Outputs().Tag(kAnchorsTag).Set<std::vector<Anchor>>();
    cc->Outputs().Tag(kBoxesOutputTag).Set<TimedBoxProtoList>();

    if (cc->Outputs().HasTag(kCancelTag)) {
      cc->Outputs().Tag(kCancelTag).Set<int>();
    }

    return ::mediapipe::OkStatus();
  }

  ::mediapipe::Status Open(CalculatorContext* cc) override {
    return ::mediapipe::OkStatus();
  }

  ::mediapipe::Status Process(CalculatorContext* cc) override;
};
REGISTER_CALCULATOR(TrackedAnchorManagerCalculator);

::mediapipe::Status TrackedAnchorManagerCalculator::Process(CalculatorContext* cc) {
  mediapipe::Timestamp timestamp = cc->InputTimestamp();
  const int sticker_sentinel = cc->Inputs().Tag(kSentinelTag).Get<int>();
  std::vector<Anchor> current_anchor_data = cc->Inputs().Tag(kAnchorsTag).Get<std::vector<Anchor>>();
  auto pos_boxes = absl::make_unique<TimedBoxProtoList>();
  std::vector<Anchor> tracked_scaled_anchor_data;

  // Delete any boxes being tracked without an associated anchor
  for (const TimedBoxProto& box : cc->Inputs().Tag(kBoxesInputTag)
       .Get<TimedBoxProtoList>().box()) {
    bool anchor_exists = false;
    for (Anchor anchor : current_anchor_data) {
      if (box.id() == anchor.sticker_id) {
        anchor_exists = true;
        break;
      }
    }
    if (!anchor_exists) {
      cc->Outputs().Tag(kCancelTag).AddPacket(MakePacket<int>(box.id()).At(timestamp++));
    }
  }

  // Perform tracking or updating for each anchor position
  for (Anchor anchor : current_anchor_data) {
    // Check if anchor position is being reset by user in this graph iteration
    if (sticker_sentinel == anchor.sticker_id) {
      // Delete associated tracking box
      // TODO: BoxTrackingSubgraph should accept vector to avoid breaking timestamp rules
      cc->Outputs().Tag(kCancelTag).AddPacket(MakePacket<int>(anchor.sticker_id).At(timestamp++));
      // Add a tracking box
      TimedBoxProto* box = pos_boxes->add_box();
      box->set_left(anchor.x - kBoxEdgeSize * 0.5f);
      box->set_right(anchor.x + kBoxEdgeSize * 0.5f);
      box->set_top(anchor.y - kBoxEdgeSize * 0.5f);
      box->set_bottom(anchor.y + kBoxEdgeSize * 0.5f);
      box->set_id(anchor.sticker_id);
      box->set_time_msec((timestamp++).Microseconds() / kUsToMs);
      // Default value for normalized z (scale factor)
      anchor.z = 1.0;
    }
    // Anchor position was not reset by user
    else {
      // Attempt to update anchor position from tracking subgraph (TimedBoxProto)
      bool updated_from_tracker = false;
      const TimedBoxProtoList box_list = cc->Inputs().Tag(kBoxesInputTag).Get<TimedBoxProtoList>();
      for (const auto& box : box_list.box())
      {
        if (box.id() == anchor.sticker_id) {
          // Get center x normalized coordinate [0.0-1.0]
          anchor.x = (box.left() + box.right()) * 0.5f;
          // Get center y normalized coordinate [0.0-1.0]
          anchor.y = (box.top() + box.bottom()) * 0.5f;
          // Get center z coordinate [z starts at normalized 1.0 and scales inversely with box-width]
          // TODO: Look into issues with uniform scaling on x-axis and y-axis
          anchor.z = kBoxEdgeSize / (box.right() - box.left());
          updated_from_tracker = true;
          break;
        }
      }
      // If anchor position was not updated from tracker, create new tracking box
      // at last recorded anchor coordinates. This will allow all current stickers
      // to be tracked at approximately last location even if re-acquisitioning
      // in the BoxTrackingSubgraph encounters errors
      if (!updated_from_tracker) {
        for (Anchor prev_anchor : previous_anchor_data) {
          if (anchor.sticker_id == prev_anchor.sticker_id) {
            anchor = prev_anchor;
            TimedBoxProto* box = pos_boxes->add_box();
            box->set_left(anchor.x - kBoxEdgeSize * 0.5f);
            box->set_right(anchor.x + kBoxEdgeSize * 0.5f);
            box->set_top(anchor.y - kBoxEdgeSize * 0.5f);
            box->set_bottom(anchor.y + kBoxEdgeSize * 0.5f);
            box->set_id(anchor.sticker_id);
            box->set_time_msec((timestamp++).Microseconds() / kUsToMs);
            // Default value for normalized z (scale factor)
            anchor.z = 1.0;
            break;
          }
        }
      }
    }
    tracked_scaled_anchor_data.emplace_back(anchor);
  }
  // Set anchor data for next iteration
  previous_anchor_data = tracked_scaled_anchor_data;

  cc->Outputs().Tag(kAnchorsTag).AddPacket(MakePacket<std::vector<Anchor>>(tracked_scaled_anchor_data).At(cc->InputTimestamp()));
  cc->Outputs().Tag(kBoxesOutputTag).Add(pos_boxes.release(), cc->InputTimestamp());

  return ::mediapipe::OkStatus();
}
}
<commit_msg>Update tracked_anchor_manager_calculator.cc<commit_after>// Copyright 2020 Google LLC
//
// Licensed 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mediapipe/framework/calculator_framework.h"
#include "mediapipe/framework/formats/detection.pb.h"
#include "mediapipe/framework/formats/location_data.pb.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/ret_check.h"
#include "mediapipe/util/tracking/box_tracker.h"
#include "mediapipe/graphs/instantmotiontracking/calculators/transformations.h"

namespace mediapipe {

constexpr char kSentinelTag[] = "SENTINEL";
constexpr char kAnchorsTag[] = "ANCHORS";
constexpr char kBoxesInputTag[] = "BOXES";
constexpr char kBoxesOutputTag[] = "START_POS";
constexpr char kCancelTag[] = "CANCEL_ID";
// TODO: Find optimal Height/Width (0.1-0.3)
constexpr float kBoxEdgeSize = 0.2f; // Used to establish tracking box dimensions
constexpr float kUsToMs = 1000.0f; // Used to convert from microseconds to millis

// This calculator manages the regions being tracked for each individual sticker
// and adjusts the regions being tracked if a change is detected in a sticker's
// initial anchor placement. Regions being tracked that have no associated sticker
// will be automatically removed upon the next iteration of the graph to optimize
// performance and remove all sticker artifacts
//
// Input:
//  SENTINEL - ID of sticker which has an anchor that must be reset (-1 when no
// anchor must be reset) [REQUIRED]
//  ANCHORS - Initial anchor data (tracks changes and where to re/position) [REQUIRED]
//  BOXES - Used in cycle, boxes being tracked meant to update positions [OPTIONAL
//  - provided by subgraph]
// Output:
//  START_POS - Positions of boxes being tracked (can be overwritten with ID) [REQUIRED]
//  CANCEL_ID - Single integer ID of tracking box to remove from tracker subgraph [OPTIONAL]
//  ANCHORS - Updated set of anchors with tracked and normalized X,Y,Z [REQUIRED]
//
// Example config:
// node {
//   calculator: "TrackedAnchorManagerCalculator"
//   input_stream: "SENTINEL:sticker_sentinel"
//   input_stream: "ANCHORS:initial_anchor_data"
//   input_stream: "BOXES:boxes"
//   input_stream_info: {
//     tag_index: 'BOXES'
//     back_edge: true
//   }
//   output_stream: "START_POS:start_pos"
//   output_stream: "CANCEL_ID:cancel_object_id"
//   output_stream: "ANCHORS:tracked_scaled_anchor_data"
// }

class TrackedAnchorManagerCalculator : public CalculatorBase {
private:
  // Previous graph iteration anchor data
  std::vector<Anchor> previous_anchor_data;

public:
  static ::mediapipe::Status GetContract(CalculatorContract* cc) {
    RET_CHECK(cc->Inputs().HasTag(kAnchorsTag)
      && cc->Inputs().HasTag(kSentinelTag));
    RET_CHECK(cc->Outputs().HasTag(kAnchorsTag)
      && cc->Outputs().HasTag(kBoxesOutputTag));

    cc->Inputs().Tag(kAnchorsTag).Set<std::vector<Anchor>>();
    cc->Inputs().Tag(kSentinelTag).Set<int>();

    if (cc->Inputs().HasTag(kBoxesInputTag)) {
      cc->Inputs().Tag(kBoxesInputTag).Set<TimedBoxProtoList>();
    }

    cc->Outputs().Tag(kAnchorsTag).Set<std::vector<Anchor>>();
    cc->Outputs().Tag(kBoxesOutputTag).Set<TimedBoxProtoList>();

    if (cc->Outputs().HasTag(kCancelTag)) {
      cc->Outputs().Tag(kCancelTag).Set<int>();
    }

    return ::mediapipe::OkStatus();
  }

  ::mediapipe::Status Open(CalculatorContext* cc) override {
    return ::mediapipe::OkStatus();
  }

  ::mediapipe::Status Process(CalculatorContext* cc) override;
};
REGISTER_CALCULATOR(TrackedAnchorManagerCalculator);

::mediapipe::Status TrackedAnchorManagerCalculator::Process(CalculatorContext* cc) {
  mediapipe::Timestamp timestamp = cc->InputTimestamp();
  const int sticker_sentinel = cc->Inputs().Tag(kSentinelTag).Get<int>();
  std::vector<Anchor> current_anchor_data = cc->Inputs().Tag(kAnchorsTag).Get<std::vector<Anchor>>();
  auto pos_boxes = absl::make_unique<TimedBoxProtoList>();
  std::vector<Anchor> tracked_scaled_anchor_data;

  // Delete any boxes being tracked without an associated anchor
  for (const TimedBoxProto& box : cc->Inputs().Tag(kBoxesInputTag)
       .Get<TimedBoxProtoList>().box()) {
    bool anchor_exists = false;
    for (Anchor anchor : current_anchor_data) {
      if (box.id() == anchor.sticker_id) {
        anchor_exists = true;
        break;
      }
    }
    if (!anchor_exists) {
      cc->Outputs().Tag(kCancelTag).AddPacket(MakePacket<int>(box.id()).At(timestamp++));
    }
  }

  // Perform tracking or updating for each anchor position
  for (Anchor anchor : current_anchor_data) {
    // Check if anchor position is being reset by user in this graph iteration
    if (sticker_sentinel == anchor.sticker_id) {
      // Delete associated tracking box
      // TODO: BoxTrackingSubgraph should accept vector to avoid breaking timestamp rules
      cc->Outputs().Tag(kCancelTag).AddPacket(MakePacket<int>(anchor.sticker_id).At(timestamp++));
      // Add a tracking box
      TimedBoxProto* box = pos_boxes->add_box();
      box->set_left(anchor.x - kBoxEdgeSize * 0.5f);
      box->set_right(anchor.x + kBoxEdgeSize * 0.5f);
      box->set_top(anchor.y - kBoxEdgeSize * 0.5f);
      box->set_bottom(anchor.y + kBoxEdgeSize * 0.5f);
      box->set_id(anchor.sticker_id);
      box->set_time_msec((timestamp++).Microseconds() / kUsToMs);
      // Default value for normalized z (scale factor)
      anchor.z = 1.0;
    }
    // Anchor position was not reset by user
    else {
      // Attempt to update anchor position from tracking subgraph (TimedBoxProto)
      bool updated_from_tracker = false;
      const TimedBoxProtoList box_list = cc->Inputs().Tag(kBoxesInputTag).Get<TimedBoxProtoList>();
      for (const auto& box : box_list.box())
      {
        if (box.id() == anchor.sticker_id) {
          // Get center x normalized coordinate [0.0-1.0]
          anchor.x = (box.left() + box.right()) * 0.5f;
          // Get center y normalized coordinate [0.0-1.0]
          anchor.y = (box.top() + box.bottom()) * 0.5f;
          // Get center z coordinate [z starts at normalized 1.0 and scales
          // inversely with box-width]
          // TODO: Look into issues with uniform scaling on x-axis and y-axis
          anchor.z = kBoxEdgeSize / (box.right() - box.left());
          updated_from_tracker = true;
          break;
        }
      }
      // If anchor position was not updated from tracker, create new tracking box
      // at last recorded anchor coordinates. This will allow all current stickers
      // to be tracked at approximately last location even if re-acquisitioning
      // in the BoxTrackingSubgraph encounters errors
      if (!updated_from_tracker) {
        for (Anchor prev_anchor : previous_anchor_data) {
          if (anchor.sticker_id == prev_anchor.sticker_id) {
            anchor = prev_anchor;
            TimedBoxProto* box = pos_boxes->add_box();
            box->set_left(anchor.x - kBoxEdgeSize * 0.5f);
            box->set_right(anchor.x + kBoxEdgeSize * 0.5f);
            box->set_top(anchor.y - kBoxEdgeSize * 0.5f);
            box->set_bottom(anchor.y + kBoxEdgeSize * 0.5f);
            box->set_id(anchor.sticker_id);
            box->set_time_msec((timestamp++).Microseconds() / kUsToMs);
            // Default value for normalized z (scale factor)
            anchor.z = 1.0;
            break;
          }
        }
      }
    }
    tracked_scaled_anchor_data.emplace_back(anchor);
  }
  // Set anchor data for next iteration
  previous_anchor_data = tracked_scaled_anchor_data;

  cc->Outputs().Tag(kAnchorsTag).AddPacket(MakePacket<std::vector<Anchor>>(tracked_scaled_anchor_data).At(cc->InputTimestamp()));
  cc->Outputs().Tag(kBoxesOutputTag).Add(pos_boxes.release(), cc->InputTimestamp());

  return ::mediapipe::OkStatus();
}
}
<|endoftext|>


<commit_before><commit_msg>Fix adaption to SAL_INFO<commit_after><|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Jin Ma, jin@multicorewareinc.com
//    Xiaopeng Fu, fuxiaopeng2222@163.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
using namespace perf;
using namespace std;
using namespace cv::ocl;
using namespace cv;
using std::tr1::tuple;
using std::tr1::get;
////////////////////////////////// K-NEAREST NEIGHBOR ////////////////////////////////////
static void genData(Mat& trainData, Size size, Mat& trainLabel = Mat().setTo(Scalar::all(0)), int nClasses = 0)
{
    trainData.create(size, CV_32FC1);
    randu(trainData, 1.0, 100.0);

    if(nClasses != 0)
    {
        trainLabel.create(size.height, 1, CV_8UC1);
        randu(trainLabel, 0, nClasses - 1);
        trainLabel.convertTo(trainLabel, CV_32FC1);
    }
}

typedef tuple<int> KNNParamType;
typedef TestBaseWithParam<KNNParamType> KNNFixture;

PERF_TEST_P(KNNFixture, KNN,
            testing::Values(1000, 2000, 4000))
{
    KNNParamType params = GetParam();
    const int rows = get<0>(params);
    int columns = 100;
    int k = rows/250;

    Mat trainData, trainLabels;
    Size size(columns, rows);
    genData(trainData, size, trainLabels, 3);

    Mat testData;
    genData(testData, size);
    Mat best_label;

    if(RUN_PLAIN_IMPL)
    {
        TEST_CYCLE()
        {
            CvKNearest knn_cpu;
            knn_cpu.train(trainData, trainLabels);
            knn_cpu.find_nearest(testData, k, &best_label);
        }
    }else if(RUN_OCL_IMPL)
    {
        cv::ocl::oclMat best_label_ocl;
        cv::ocl::oclMat testdata;
        testdata.upload(testData);

        OCL_TEST_CYCLE()
        {
            cv::ocl::KNearestNeighbour knn_ocl;
            knn_ocl.train(trainData, trainLabels);
            knn_ocl.find_nearest(testdata, k, best_label_ocl);
        }
        best_label_ocl.download(best_label);
    }else
        OCL_PERF_ELSE
    SANITY_CHECK(best_label);
}<commit_msg>ocl: added SVM perf test<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Jin Ma, jin@multicorewareinc.com
//    Xiaopeng Fu, fuxiaopeng2222@163.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors as is and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "perf_precomp.hpp"
using namespace perf;
using namespace std;
using namespace cv::ocl;
using namespace cv;
using std::tr1::tuple;
using std::tr1::get;
////////////////////////////////// K-NEAREST NEIGHBOR ////////////////////////////////////
static void genData(Mat& trainData, Size size, Mat& trainLabel = Mat().setTo(Scalar::all(0)), int nClasses = 0)
{
    trainData.create(size, CV_32FC1);
    randu(trainData, 1.0, 100.0);

    if(nClasses != 0)
    {
        trainLabel.create(size.height, 1, CV_8UC1);
        randu(trainLabel, 0, nClasses - 1);
        trainLabel.convertTo(trainLabel, CV_32FC1);
    }
}

typedef tuple<int> KNNParamType;
typedef TestBaseWithParam<KNNParamType> KNNFixture;

PERF_TEST_P(KNNFixture, KNN,
            testing::Values(1000, 2000, 4000))
{
    KNNParamType params = GetParam();
    const int rows = get<0>(params);
    int columns = 100;
    int k = rows/250;

    Mat trainData, trainLabels;
    Size size(columns, rows);
    genData(trainData, size, trainLabels, 3);

    Mat testData;
    genData(testData, size);
    Mat best_label;

    if(RUN_PLAIN_IMPL)
    {
        TEST_CYCLE()
        {
            CvKNearest knn_cpu;
            knn_cpu.train(trainData, trainLabels);
            knn_cpu.find_nearest(testData, k, &best_label);
        }
    }else if(RUN_OCL_IMPL)
    {
        cv::ocl::oclMat best_label_ocl;
        cv::ocl::oclMat testdata;
        testdata.upload(testData);

        OCL_TEST_CYCLE()
        {
            cv::ocl::KNearestNeighbour knn_ocl;
            knn_ocl.train(trainData, trainLabels);
            knn_ocl.find_nearest(testdata, k, best_label_ocl);
        }
        best_label_ocl.download(best_label);
    }else
        OCL_PERF_ELSE
    SANITY_CHECK(best_label);
}

typedef TestBaseWithParam<tuple<int> > SVMFixture;

// code is based on: samples\cpp\tutorial_code\ml\non_linear_svms\non_linear_svms.cpp
PERF_TEST_P(SVMFixture, DISABLED_SVM,
            testing::Values(50, 100))
{

    const int NTRAINING_SAMPLES = get<0>(GetParam()); // Number of training samples per class

    #define FRAC_LINEAR_SEP     0.9f // Fraction of samples which compose the linear separable part

    const int WIDTH = 512, HEIGHT = 512;

    Mat trainData(2*NTRAINING_SAMPLES, 2, CV_32FC1);
    Mat labels   (2*NTRAINING_SAMPLES, 1, CV_32FC1);

    RNG rng(100); // Random value generation class

    // Set up the linearly separable part of the training data
    int nLinearSamples = (int) (FRAC_LINEAR_SEP * NTRAINING_SAMPLES);

    // Generate random points for the class 1
    Mat trainClass = trainData.rowRange(0, nLinearSamples);
    // The x coordinate of the points is in [0, 0.4)
    Mat c = trainClass.colRange(0, 1);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(0.4 * WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    // Generate random points for the class 2
    trainClass = trainData.rowRange(2*NTRAINING_SAMPLES-nLinearSamples, 2*NTRAINING_SAMPLES);
    // The x coordinate of the points is in [0.6, 1]
    c = trainClass.colRange(0 , 1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.6*WIDTH), Scalar(WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //------------------ Set up the non-linearly separable part of the training data ---------------

    // Generate random points for the classes 1 and 2
    trainClass = trainData.rowRange(  nLinearSamples, 2*NTRAINING_SAMPLES-nLinearSamples);
    // The x coordinate of the points is in [0.4, 0.6)
    c = trainClass.colRange(0,1);
    rng.fill(c, RNG::UNIFORM, Scalar(0.4*WIDTH), Scalar(0.6*WIDTH));
    // The y coordinate of the points is in [0, 1)
    c = trainClass.colRange(1,2);
    rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(HEIGHT));

    //------------------------- Set up the labels for the classes ---------------------------------
    labels.rowRange(                0,   NTRAINING_SAMPLES).setTo(1);  // Class 1
    labels.rowRange(NTRAINING_SAMPLES, 2*NTRAINING_SAMPLES).setTo(2);  // Class 2

    //------------------------ Set up the support vector machines parameters --------------------
    CvSVMParams params;
    params.svm_type    = SVM::C_SVC;
    params.C           = 0.1;
    params.kernel_type = SVM::LINEAR;
    params.term_crit   = TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6);

    Mat dst = Mat::zeros(HEIGHT, WIDTH, CV_8UC1);

    Mat samples(WIDTH*HEIGHT, 2, CV_32FC1);
    int k = 0;
    for (int i = 0; i < HEIGHT; ++i)
    {
        for (int j = 0; j < WIDTH; ++j)
        {
            samples.at<float>(k, 0) = (float)i;
            samples.at<float>(k, 0) = (float)j;
            k++;
        }
    }
    Mat results(WIDTH*HEIGHT, 1, CV_32FC1);

    CvMat samples_ = samples;
    CvMat results_ = results;

    if(RUN_PLAIN_IMPL)
    {
        CvSVM svm;
        svm.train(trainData, labels, Mat(), Mat(), params);
        TEST_CYCLE()
        {
            svm.predict(&samples_, &results_);
        }
    }
    else if(RUN_OCL_IMPL)
    {
        CvSVM_OCL svm;
        svm.train(trainData, labels, Mat(), Mat(), params);
        OCL_TEST_CYCLE()
        {
            svm.predict(&samples_, &results_);
        }
    }
    else
        OCL_PERF_ELSE

    SANITY_CHECK_NOTHING();
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Jin Ma,        jin@multicorewareinc.com
//    Xiaopeng Fu,   fuxiaopeng2222@163.com
//    Erping Pang,   pang_er_ping@163.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other oclMaterials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "test_precomp.hpp"

#ifdef HAVE_OPENCL

using namespace cv;
using namespace cv::ocl;
using namespace cvtest;
using namespace testing;

///////K-NEAREST NEIGHBOR//////////////////////////

static void genTrainData(cv::RNG& rng, Mat& trainData, int trainDataRow, int trainDataCol,
                         Mat& trainLabel = Mat().setTo(Scalar::all(0)), int nClasses = 0)
{
    cv::Size size(trainDataCol, trainDataRow);
    trainData = randomMat(rng, size, CV_32FC1, 1.0, 1000.0, false);
    if(nClasses != 0)
    {
        cv::Size size1(trainDataRow, 1);
        trainLabel = randomMat(rng, size1, CV_8UC1, 0, nClasses - 1, false);
        trainLabel.convertTo(trainLabel, CV_32FC1);
    }
}

PARAM_TEST_CASE(KNN, int, Size, int, bool)
{
    int k;
    int trainDataCol;
    int testDataRow;
    int nClass;
    bool regression;
    virtual void SetUp()
    {
        k = GET_PARAM(0);
        nClass = GET_PARAM(2);
        trainDataCol = GET_PARAM(1).width;
        testDataRow = GET_PARAM(1).height;
        regression = GET_PARAM(3);
    }
};

OCL_TEST_P(KNN, Accuracy)
{
    Mat trainData, trainLabels;
    const int trainDataRow = 500;
    genTrainData(rng, trainData, trainDataRow, trainDataCol, trainLabels, nClass);

    Mat testData, testLabels;
    genTrainData(rng, testData, testDataRow, trainDataCol);

    KNearestNeighbour knn_ocl;
    CvKNearest knn_cpu;
    Mat best_label_cpu;
    oclMat best_label_ocl;

    /*ocl k-Nearest_Neighbor start*/
    oclMat trainData_ocl;
    trainData_ocl.upload(trainData);
    Mat simpleIdx;
    knn_ocl.train(trainData, trainLabels, simpleIdx, regression);

    oclMat testdata;
    testdata.upload(testData);
    knn_ocl.find_nearest(testdata, k, best_label_ocl);
    /*ocl k-Nearest_Neighbor end*/

    /*cpu k-Nearest_Neighbor start*/
    knn_cpu.train(trainData, trainLabels, simpleIdx, regression);
    knn_cpu.find_nearest(testData, k, &best_label_cpu);
    /*cpu k-Nearest_Neighbor end*/
    if(regression)
    {
        EXPECT_MAT_SIMILAR(Mat(best_label_ocl), best_label_cpu, 1e-5);
    }
    else
    {
        EXPECT_MAT_NEAR(Mat(best_label_ocl), best_label_cpu, 0.0);
    }
}

INSTANTIATE_TEST_CASE_P(OCL_ML, KNN, Combine(Values(6, 5), Values(Size(200, 400), Size(300, 600)),
    Values(4, 3), Values(false, true)));

#ifndef HAVE_CLAMDBLAS // TODO does not work non-blas version of SVM

////////////////////////////////SVM/////////////////////////////////////////////////

PARAM_TEST_CASE(SVM_OCL, int, int, int)
{
    cv::Size size;
    int kernel_type;
    int svm_type;
    Mat src, labels, samples, labels_predict;
    int K;

    virtual void SetUp()
    {

        kernel_type = GET_PARAM(0);
        svm_type = GET_PARAM(1);
        K = GET_PARAM(2);
        cv::Size size = cv::Size(MWIDTH, MHEIGHT);
        src.create(size, CV_32FC1);
        labels.create(1, size.height, CV_32SC1);
        int row_idx = 0;
        const int max_number = size.height / K - 1;
        CV_Assert(K <= size.height);
        for(int i = 0; i < K; i++ )
        {
            Mat center_row_header = src.row(row_idx);
            center_row_header.setTo(0);
            int nchannel = center_row_header.channels();
            for(int j = 0; j < nchannel; j++)
            {
                center_row_header.at<float>(0, i * nchannel + j) = 500.0;
            }
            labels.at<int>(0, row_idx) = i;
            for(int j = 0; (j < max_number) ||
                    (i == K - 1 && j < max_number + size.height % K); j ++)
            {
                Mat cur_row_header = src.row(row_idx + 1 + j);
                center_row_header.copyTo(cur_row_header);
                Mat tmpmat = randomMat(cur_row_header.size(), cur_row_header.type(), 1, 100, false);
                cur_row_header += tmpmat;
                labels.at<int>(0, row_idx + 1 + j) = i;
            }
            row_idx += 1 + max_number;
        }
        labels.convertTo(labels, CV_32FC1);
        cv::Size test_size = cv::Size(MWIDTH, 100);
        samples.create(test_size, CV_32FC1);
        labels_predict.create(1, test_size.height, CV_32SC1);
        const int max_number_test = test_size.height / K - 1;
        row_idx = 0;
        for(int i = 0; i < K; i++ )
        {
            Mat center_row_header = samples.row(row_idx);
            center_row_header.setTo(0);
            int nchannel = center_row_header.channels();
            for(int j = 0; j < nchannel; j++)
            {
                center_row_header.at<float>(0, i * nchannel + j) = 500.0;
            }
            labels_predict.at<int>(0, row_idx) = i;
            for(int j = 0; (j < max_number_test) ||
                    (i == K - 1 && j < max_number_test + test_size.height % K); j ++)
            {
                Mat cur_row_header = samples.row(row_idx + 1 + j);
                center_row_header.copyTo(cur_row_header);
                Mat tmpmat = randomMat(cur_row_header.size(), cur_row_header.type(), 1, 100, false);
                cur_row_header += tmpmat;
                labels_predict.at<int>(0, row_idx + 1 + j) = i;
            }
            row_idx += 1 + max_number_test;
        }
        labels_predict.convertTo(labels_predict, CV_32FC1);
    }
};

OCL_TEST_P(SVM_OCL, Accuracy)
{
    CvSVMParams params;
    params.degree = 0.4;
    params.gamma = 1;
    params.coef0 = 1;
    params.C = 1;
    params.nu = 0.5;
    params.p = 1;
    params.svm_type = svm_type;
    params.kernel_type = kernel_type;

    params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, 0.001);

    CvSVM SVM;
    SVM.train(src, labels, Mat(), Mat(), params);

    cv::ocl::CvSVM_OCL SVM_OCL;
    SVM_OCL.train(src, labels, Mat(), Mat(), params);

    int c = SVM.get_support_vector_count();
    int c1 = SVM_OCL.get_support_vector_count();

    Mat sv(c, MHEIGHT, CV_32FC1);
    Mat sv_ocl(c1, MHEIGHT, CV_32FC1);
    for(int i = 0; i < c; i++)
    {
        const float* v = SVM.get_support_vector(i);

        for(int j = 0; j < MHEIGHT; j++)
        {
            sv.at<float>(i, j) = v[j];
        }
    }
    for(int i = 0; i < c1; i++)
    {
        const float* v_ocl = SVM_OCL.get_support_vector(i);

        for(int j = 0; j < MHEIGHT; j++)
        {
            sv_ocl.at<float>(i, j) = v_ocl[j];
        }
    }
    cv::BFMatcher matcher(cv::NORM_L2);
    std::vector<cv::DMatch> matches;
    matcher.match(sv, sv_ocl, matches);
    int count = 0;

    for(std::vector<cv::DMatch>::iterator itr = matches.begin(); itr != matches.end(); itr++)
    {
        if((*itr).distance < 0.1)
        {
            count ++;
        }
    }
    if(c != 0)
    {
        float matchedRatio = (float)count / c;
        EXPECT_GT(matchedRatio, 0.95);
    }
    if(c != 0)
    {
        CvMat *result = cvCreateMat(1, samples.rows, CV_32FC1);
        CvMat test_samples = samples;

        CvMat *result_ocl = cvCreateMat(1, samples.rows, CV_32FC1);

        SVM.predict(&test_samples, result);

        SVM_OCL.predict(&test_samples, result_ocl);

        int true_resp = 0, true_resp_ocl = 0;
        for (int i = 0; i < samples.rows; i++)
        {
            if (result->data.fl[i] == labels_predict.at<float>(0, i))
            {
                true_resp++;
            }
        }
        float matchedRatio = (float)true_resp / samples.rows;

        for (int i = 0; i < samples.rows; i++)
        {
            if (result_ocl->data.fl[i] == labels_predict.at<float>(0, i))
            {
                true_resp_ocl++;
            }
        }
        float matchedRatio_ocl = (float)true_resp_ocl / samples.rows;

        if(matchedRatio != 0 && true_resp_ocl < true_resp)
        {
            EXPECT_NEAR(matchedRatio_ocl, matchedRatio, 0.03);
        }
    }
}

// TODO FIXIT: CvSVM::EPS_SVR case is crashed inside CPU implementation
// Anonymous enums are not supported well so cast them to 'int'

INSTANTIATE_TEST_CASE_P(OCL_ML, SVM_OCL, testing::Combine(
                            Values((int)CvSVM::LINEAR, (int)CvSVM::POLY, (int)CvSVM::RBF, (int)CvSVM::SIGMOID),
                            Values((int)CvSVM::C_SVC, (int)CvSVM::NU_SVC, (int)CvSVM::ONE_CLASS, (int)CvSVM::NU_SVR),
                            Values(2, 3, 4)
                        ));

#endif // HAVE_CLAMDBLAS

#endif // HAVE_OPENCL
<commit_msg>misprint in disabling ocl::svm<commit_after>///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
//    Jin Ma,        jin@multicorewareinc.com
//    Xiaopeng Fu,   fuxiaopeng2222@163.com
//    Erping Pang,   pang_er_ping@163.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other oclMaterials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "test_precomp.hpp"

#ifdef HAVE_OPENCL

using namespace cv;
using namespace cv::ocl;
using namespace cvtest;
using namespace testing;

///////K-NEAREST NEIGHBOR//////////////////////////

static void genTrainData(cv::RNG& rng, Mat& trainData, int trainDataRow, int trainDataCol,
                         Mat& trainLabel = Mat().setTo(Scalar::all(0)), int nClasses = 0)
{
    cv::Size size(trainDataCol, trainDataRow);
    trainData = randomMat(rng, size, CV_32FC1, 1.0, 1000.0, false);
    if(nClasses != 0)
    {
        cv::Size size1(trainDataRow, 1);
        trainLabel = randomMat(rng, size1, CV_8UC1, 0, nClasses - 1, false);
        trainLabel.convertTo(trainLabel, CV_32FC1);
    }
}

PARAM_TEST_CASE(KNN, int, Size, int, bool)
{
    int k;
    int trainDataCol;
    int testDataRow;
    int nClass;
    bool regression;
    virtual void SetUp()
    {
        k = GET_PARAM(0);
        nClass = GET_PARAM(2);
        trainDataCol = GET_PARAM(1).width;
        testDataRow = GET_PARAM(1).height;
        regression = GET_PARAM(3);
    }
};

OCL_TEST_P(KNN, Accuracy)
{
    Mat trainData, trainLabels;
    const int trainDataRow = 500;
    genTrainData(rng, trainData, trainDataRow, trainDataCol, trainLabels, nClass);

    Mat testData, testLabels;
    genTrainData(rng, testData, testDataRow, trainDataCol);

    KNearestNeighbour knn_ocl;
    CvKNearest knn_cpu;
    Mat best_label_cpu;
    oclMat best_label_ocl;

    /*ocl k-Nearest_Neighbor start*/
    oclMat trainData_ocl;
    trainData_ocl.upload(trainData);
    Mat simpleIdx;
    knn_ocl.train(trainData, trainLabels, simpleIdx, regression);

    oclMat testdata;
    testdata.upload(testData);
    knn_ocl.find_nearest(testdata, k, best_label_ocl);
    /*ocl k-Nearest_Neighbor end*/

    /*cpu k-Nearest_Neighbor start*/
    knn_cpu.train(trainData, trainLabels, simpleIdx, regression);
    knn_cpu.find_nearest(testData, k, &best_label_cpu);
    /*cpu k-Nearest_Neighbor end*/
    if(regression)
    {
        EXPECT_MAT_SIMILAR(Mat(best_label_ocl), best_label_cpu, 1e-5);
    }
    else
    {
        EXPECT_MAT_NEAR(Mat(best_label_ocl), best_label_cpu, 0.0);
    }
}

INSTANTIATE_TEST_CASE_P(OCL_ML, KNN, Combine(Values(6, 5), Values(Size(200, 400), Size(300, 600)),
    Values(4, 3), Values(false, true)));

#ifdef HAVE_CLAMDBLAS // TODO does not work non-blas version of SVM

////////////////////////////////SVM/////////////////////////////////////////////////

PARAM_TEST_CASE(SVM_OCL, int, int, int)
{
    cv::Size size;
    int kernel_type;
    int svm_type;
    Mat src, labels, samples, labels_predict;
    int K;

    virtual void SetUp()
    {

        kernel_type = GET_PARAM(0);
        svm_type = GET_PARAM(1);
        K = GET_PARAM(2);
        cv::Size size = cv::Size(MWIDTH, MHEIGHT);
        src.create(size, CV_32FC1);
        labels.create(1, size.height, CV_32SC1);
        int row_idx = 0;
        const int max_number = size.height / K - 1;
        CV_Assert(K <= size.height);
        for(int i = 0; i < K; i++ )
        {
            Mat center_row_header = src.row(row_idx);
            center_row_header.setTo(0);
            int nchannel = center_row_header.channels();
            for(int j = 0; j < nchannel; j++)
            {
                center_row_header.at<float>(0, i * nchannel + j) = 500.0;
            }
            labels.at<int>(0, row_idx) = i;
            for(int j = 0; (j < max_number) ||
                    (i == K - 1 && j < max_number + size.height % K); j ++)
            {
                Mat cur_row_header = src.row(row_idx + 1 + j);
                center_row_header.copyTo(cur_row_header);
                Mat tmpmat = randomMat(cur_row_header.size(), cur_row_header.type(), 1, 100, false);
                cur_row_header += tmpmat;
                labels.at<int>(0, row_idx + 1 + j) = i;
            }
            row_idx += 1 + max_number;
        }
        labels.convertTo(labels, CV_32FC1);
        cv::Size test_size = cv::Size(MWIDTH, 100);
        samples.create(test_size, CV_32FC1);
        labels_predict.create(1, test_size.height, CV_32SC1);
        const int max_number_test = test_size.height / K - 1;
        row_idx = 0;
        for(int i = 0; i < K; i++ )
        {
            Mat center_row_header = samples.row(row_idx);
            center_row_header.setTo(0);
            int nchannel = center_row_header.channels();
            for(int j = 0; j < nchannel; j++)
            {
                center_row_header.at<float>(0, i * nchannel + j) = 500.0;
            }
            labels_predict.at<int>(0, row_idx) = i;
            for(int j = 0; (j < max_number_test) ||
                    (i == K - 1 && j < max_number_test + test_size.height % K); j ++)
            {
                Mat cur_row_header = samples.row(row_idx + 1 + j);
                center_row_header.copyTo(cur_row_header);
                Mat tmpmat = randomMat(cur_row_header.size(), cur_row_header.type(), 1, 100, false);
                cur_row_header += tmpmat;
                labels_predict.at<int>(0, row_idx + 1 + j) = i;
            }
            row_idx += 1 + max_number_test;
        }
        labels_predict.convertTo(labels_predict, CV_32FC1);
    }
};

OCL_TEST_P(SVM_OCL, Accuracy)
{
    CvSVMParams params;
    params.degree = 0.4;
    params.gamma = 1;
    params.coef0 = 1;
    params.C = 1;
    params.nu = 0.5;
    params.p = 1;
    params.svm_type = svm_type;
    params.kernel_type = kernel_type;

    params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, 0.001);

    CvSVM SVM;
    SVM.train(src, labels, Mat(), Mat(), params);

    cv::ocl::CvSVM_OCL SVM_OCL;
    SVM_OCL.train(src, labels, Mat(), Mat(), params);

    int c = SVM.get_support_vector_count();
    int c1 = SVM_OCL.get_support_vector_count();

    Mat sv(c, MHEIGHT, CV_32FC1);
    Mat sv_ocl(c1, MHEIGHT, CV_32FC1);
    for(int i = 0; i < c; i++)
    {
        const float* v = SVM.get_support_vector(i);

        for(int j = 0; j < MHEIGHT; j++)
        {
            sv.at<float>(i, j) = v[j];
        }
    }
    for(int i = 0; i < c1; i++)
    {
        const float* v_ocl = SVM_OCL.get_support_vector(i);

        for(int j = 0; j < MHEIGHT; j++)
        {
            sv_ocl.at<float>(i, j) = v_ocl[j];
        }
    }
    cv::BFMatcher matcher(cv::NORM_L2);
    std::vector<cv::DMatch> matches;
    matcher.match(sv, sv_ocl, matches);
    int count = 0;

    for(std::vector<cv::DMatch>::iterator itr = matches.begin(); itr != matches.end(); itr++)
    {
        if((*itr).distance < 0.1)
        {
            count ++;
        }
    }
    if(c != 0)
    {
        float matchedRatio = (float)count / c;
        EXPECT_GT(matchedRatio, 0.95);
    }
    if(c != 0)
    {
        CvMat *result = cvCreateMat(1, samples.rows, CV_32FC1);
        CvMat test_samples = samples;

        CvMat *result_ocl = cvCreateMat(1, samples.rows, CV_32FC1);

        SVM.predict(&test_samples, result);

        SVM_OCL.predict(&test_samples, result_ocl);

        int true_resp = 0, true_resp_ocl = 0;
        for (int i = 0; i < samples.rows; i++)
        {
            if (result->data.fl[i] == labels_predict.at<float>(0, i))
            {
                true_resp++;
            }
        }
        float matchedRatio = (float)true_resp / samples.rows;

        for (int i = 0; i < samples.rows; i++)
        {
            if (result_ocl->data.fl[i] == labels_predict.at<float>(0, i))
            {
                true_resp_ocl++;
            }
        }
        float matchedRatio_ocl = (float)true_resp_ocl / samples.rows;

        if(matchedRatio != 0 && true_resp_ocl < true_resp)
        {
            EXPECT_NEAR(matchedRatio_ocl, matchedRatio, 0.03);
        }
    }
}

// TODO FIXIT: CvSVM::EPS_SVR case is crashed inside CPU implementation
// Anonymous enums are not supported well so cast them to 'int'

INSTANTIATE_TEST_CASE_P(OCL_ML, SVM_OCL, testing::Combine(
                            Values((int)CvSVM::LINEAR, (int)CvSVM::POLY, (int)CvSVM::RBF, (int)CvSVM::SIGMOID),
                            Values((int)CvSVM::C_SVC, (int)CvSVM::NU_SVC, (int)CvSVM::ONE_CLASS, (int)CvSVM::NU_SVR),
                            Values(2, 3, 4)
                        ));

#endif // HAVE_CLAMDBLAS

#endif // HAVE_OPENCL
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "transport.h"
#include "transport_thread.h"
#include "iocomponent.h"
#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/vespalib/util/size_literals.h>
#include <vespa/vespalib/util/rendezvous.h>
#include <vespa/vespalib/util/backtrace.h>
#include <xxhash.h>

#include <vespa/log/log.h>
LOG_SETUP(".fnet.transport");

namespace {

struct HashState {
    using clock = std::chrono::high_resolution_clock;

    const void       *self;
    clock::time_point now;
    uint64_t          key_hash;
    HashState(const void *key, size_t key_len)
        : self(this),
          now(clock::now()),
          key_hash(XXH64(key, key_len, 0)) {}
};

VESPA_THREAD_STACK_TAG(fnet_work_pool);

struct DefaultTimeTools : fnet::TimeTools {
    vespalib::duration event_timeout() const override {
        return FNET_Scheduler::tick_ms;
    }
    vespalib::steady_time current_time() const override {
        return vespalib::steady_clock::now();
    }
};

struct DebugTimeTools : fnet::TimeTools {
    vespalib::duration my_event_timeout;
    std::function<vespalib::steady_time()> my_current_time;
    DebugTimeTools(vespalib::duration d, std::function<vespalib::steady_time()> f) noexcept
      : my_event_timeout(d), my_current_time(std::move(f)) {}
    vespalib::duration event_timeout() const override {
        return my_event_timeout;
    }
    vespalib::steady_time current_time() const override {
        return my_current_time();
    }
};

struct CaptureMeet : vespalib::Rendezvous<int,bool> {
    using SP = std::shared_ptr<CaptureMeet>;
    vespalib::SyncableThreadExecutor &work_pool;
    vespalib::AsyncResolver &async_resolver;
    std::function<bool()> capture_hook;
    CaptureMeet(size_t N,
                vespalib::SyncableThreadExecutor &work_pool_in,
                vespalib::AsyncResolver &resolver_in,
                std::function<bool()> capture_hook_in)
      : vespalib::Rendezvous<int,bool>(N),
        work_pool(work_pool_in),
        async_resolver(resolver_in),
        capture_hook(std::move(capture_hook_in)) {}
    void mingle() override {
        work_pool.sync();
        async_resolver.wait_for_pending_resolves();
        bool result = capture_hook();
        for (size_t i = 0; i < size(); ++i) {
            out(i) = result;
        }
    }
};

struct CaptureTask : FNET_Task {
    CaptureMeet::SP meet;
    CaptureTask(FNET_Scheduler *scheduler, CaptureMeet::SP meet_in)
      : FNET_Task(scheduler), meet(std::move(meet_in)) {}
    void PerformTask() override {
        int dummy_value = 0; // rendezvous must have input value
        if (meet->rendezvous(dummy_value)) {
            ScheduleNow();
        } else {
            delete this;
        }
    };
};

} // namespace <unnamed>

namespace fnet {

TimeTools::SP
TimeTools::make_debug(vespalib::duration event_timeout,
                      std::function<vespalib::steady_time()> current_time)
{
    return std::make_shared<DebugTimeTools>(event_timeout, std::move(current_time));
}

TransportConfig::TransportConfig(int num_threads)
    : _config(),
      _resolver(),
      _crypto(),
      _time_tools(),
      _num_threads(num_threads)
{}

TransportConfig::~TransportConfig() = default;

vespalib::AsyncResolver::SP
TransportConfig::resolver() const {
    return _resolver ? _resolver : vespalib::AsyncResolver::get_shared();
}

vespalib::CryptoEngine::SP
TransportConfig::crypto() const {
    return _crypto ? _crypto : vespalib::CryptoEngine::get_default();
}

fnet::TimeTools::SP
TransportConfig::time_tools() const {
    return _time_tools ? _time_tools : std::make_shared<DefaultTimeTools>();
}

} // fnet

void
FNET_Transport::wait_for_pending_resolves() {
    _async_resolver->wait_for_pending_resolves();
}

FNET_Transport::FNET_Transport(const fnet::TransportConfig &cfg)
    : _async_resolver(cfg.resolver()),
      _crypto_engine(cfg.crypto()),
      _time_tools(cfg.time_tools()),
      _work_pool(std::make_unique<vespalib::ThreadStackExecutor>(1, 128_Ki, fnet_work_pool, 1024)),
      _threads(),
      _config(cfg.config())
{
    // TODO Temporary logging to track down overspend
    LOG(debug, "FNET_Transport threads=%d from :%s", cfg.num_threads(), vespalib::getStackTrace(0).c_str());
    assert(cfg.num_threads() >= 1);
    for (size_t i = 0; i < cfg.num_threads(); ++i) {
        _threads.emplace_back(std::make_unique<FNET_TransportThread>(*this));
    }
}

FNET_Transport::~FNET_Transport() = default;

void
FNET_Transport::post_or_perform(vespalib::Executor::Task::UP task)
{
    if (auto rejected = _work_pool->execute(std::move(task))) {
        rejected->run();
    }
}

void
FNET_Transport::resolve_async(const vespalib::string &spec,
                              vespalib::AsyncResolver::ResultHandler::WP result_handler)
{
    _async_resolver->resolve_async(spec, std::move(result_handler));
}

vespalib::CryptoSocket::UP
FNET_Transport::create_client_crypto_socket(vespalib::SocketHandle socket, const vespalib::SocketSpec &spec)
{
    return _crypto_engine->create_client_crypto_socket(std::move(socket), spec);
}

vespalib::CryptoSocket::UP
FNET_Transport::create_server_crypto_socket(vespalib::SocketHandle socket)
{
    return _crypto_engine->create_server_crypto_socket(std::move(socket));
}

FNET_TransportThread *
FNET_Transport::select_thread(const void *key, size_t key_len) const
{
    HashState hash_state(key, key_len);
    size_t hash_value = XXH64(&hash_state, sizeof(hash_state), 0);
    size_t thread_id = (hash_value % _threads.size());
    return _threads[thread_id].get();
}

FNET_Connector *
FNET_Transport::Listen(const char *spec, FNET_IPacketStreamer *streamer,
                       FNET_IServerAdapter *serverAdapter)
{
    return select_thread(spec, strlen(spec))->Listen(spec, streamer, serverAdapter);
}

FNET_Connection *
FNET_Transport::Connect(const char *spec, FNET_IPacketStreamer *streamer,
                        FNET_IServerAdapter *serverAdapter,
                        FNET_Context connContext)
{
    return select_thread(spec, strlen(spec))->Connect(spec, streamer, serverAdapter, connContext);
}

uint32_t
FNET_Transport::GetNumIOComponents()
{
    uint32_t result = 0;
    for (const auto &thread: _threads) {
        result += thread->GetNumIOComponents();
    }
    return result;
}

void
FNET_Transport::sync()
{
    for (const auto &thread: _threads) {
        thread->sync();
    }
}

void
FNET_Transport::detach(FNET_IServerAdapter *server_adapter)
{
    for (const auto &thread: _threads) {
        thread->init_detach(server_adapter);
    }
    wait_for_pending_resolves();
    for (const auto &thread: _threads) {
        thread->fini_detach(server_adapter);
    }
    sync();
}

FNET_Scheduler *
FNET_Transport::GetScheduler()
{
    return select_thread(nullptr, 0)->GetScheduler();
}

bool
FNET_Transport::execute(FNET_IExecutable *exe)
{
    return select_thread(nullptr, 0)->execute(exe);
}

void
FNET_Transport::ShutDown(bool waitFinished)
{
    for (const auto &thread: _threads) {
        thread->ShutDown(waitFinished);
    }
    if (waitFinished) {
        wait_for_pending_resolves();
        _work_pool->shutdown().sync();
    }
}

void
FNET_Transport::WaitFinished()
{
    for (const auto &thread: _threads) {
        thread->WaitFinished();
    }
    wait_for_pending_resolves();
    _work_pool->shutdown().sync();
}

bool
FNET_Transport::Start(FastOS_ThreadPool *pool)
{
    bool result = true;
    for (const auto &thread: _threads) {
        result &= thread->Start(pool);
    }
    return result;
}

void
FNET_Transport::attach_capture_hook(std::function<bool()> capture_hook)
{
    auto meet = std::make_shared<CaptureMeet>(_threads.size(), *_work_pool, *_async_resolver, std::move(capture_hook));
    for (auto &thread: _threads) {
        // tasks will be deleted when the capture_hook returns false
        auto *task = new CaptureTask(thread->GetScheduler(), meet);
        task->ScheduleNow();
    }
}

void
FNET_Transport::Add(FNET_IOComponent *comp, bool needRef) {
    comp->Owner()->Add(comp, needRef);
}

void
FNET_Transport::Close(FNET_IOComponent *comp, bool needRef) {
    comp->Owner()->Close(comp, needRef);
}

void
FNET_Transport::Main() {
    assert(_threads.size() == 1);
    _threads[0]->Main();
}
<commit_msg>extra sync needed<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "transport.h"
#include "transport_thread.h"
#include "iocomponent.h"
#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/vespalib/util/size_literals.h>
#include <vespa/vespalib/util/rendezvous.h>
#include <vespa/vespalib/util/backtrace.h>
#include <xxhash.h>

#include <vespa/log/log.h>
LOG_SETUP(".fnet.transport");

namespace {

struct HashState {
    using clock = std::chrono::high_resolution_clock;

    const void       *self;
    clock::time_point now;
    uint64_t          key_hash;
    HashState(const void *key, size_t key_len)
        : self(this),
          now(clock::now()),
          key_hash(XXH64(key, key_len, 0)) {}
};

VESPA_THREAD_STACK_TAG(fnet_work_pool);

struct DefaultTimeTools : fnet::TimeTools {
    vespalib::duration event_timeout() const override {
        return FNET_Scheduler::tick_ms;
    }
    vespalib::steady_time current_time() const override {
        return vespalib::steady_clock::now();
    }
};

struct DebugTimeTools : fnet::TimeTools {
    vespalib::duration my_event_timeout;
    std::function<vespalib::steady_time()> my_current_time;
    DebugTimeTools(vespalib::duration d, std::function<vespalib::steady_time()> f) noexcept
      : my_event_timeout(d), my_current_time(std::move(f)) {}
    vespalib::duration event_timeout() const override {
        return my_event_timeout;
    }
    vespalib::steady_time current_time() const override {
        return my_current_time();
    }
};

struct CaptureMeet : vespalib::Rendezvous<int,bool> {
    using SP = std::shared_ptr<CaptureMeet>;
    vespalib::SyncableThreadExecutor &work_pool;
    vespalib::AsyncResolver &async_resolver;
    std::function<bool()> capture_hook;
    CaptureMeet(size_t N,
                vespalib::SyncableThreadExecutor &work_pool_in,
                vespalib::AsyncResolver &resolver_in,
                std::function<bool()> capture_hook_in)
      : vespalib::Rendezvous<int,bool>(N),
        work_pool(work_pool_in),
        async_resolver(resolver_in),
        capture_hook(std::move(capture_hook_in)) {}
    void mingle() override {
        work_pool.sync();
        async_resolver.wait_for_pending_resolves();
        bool result = capture_hook();
        for (size_t i = 0; i < size(); ++i) {
            out(i) = result;
        }
    }
};

struct CaptureTask : FNET_Task {
    CaptureMeet::SP meet;
    CaptureTask(FNET_Scheduler *scheduler, CaptureMeet::SP meet_in)
      : FNET_Task(scheduler), meet(std::move(meet_in)) {}
    void PerformTask() override {
        int dummy_value = 0; // rendezvous must have input value
        if (meet->rendezvous(dummy_value)) {
            ScheduleNow();
        } else {
            delete this;
        }
    };
};

} // namespace <unnamed>

namespace fnet {

TimeTools::SP
TimeTools::make_debug(vespalib::duration event_timeout,
                      std::function<vespalib::steady_time()> current_time)
{
    return std::make_shared<DebugTimeTools>(event_timeout, std::move(current_time));
}

TransportConfig::TransportConfig(int num_threads)
    : _config(),
      _resolver(),
      _crypto(),
      _time_tools(),
      _num_threads(num_threads)
{}

TransportConfig::~TransportConfig() = default;

vespalib::AsyncResolver::SP
TransportConfig::resolver() const {
    return _resolver ? _resolver : vespalib::AsyncResolver::get_shared();
}

vespalib::CryptoEngine::SP
TransportConfig::crypto() const {
    return _crypto ? _crypto : vespalib::CryptoEngine::get_default();
}

fnet::TimeTools::SP
TransportConfig::time_tools() const {
    return _time_tools ? _time_tools : std::make_shared<DefaultTimeTools>();
}

} // fnet

void
FNET_Transport::wait_for_pending_resolves() {
    _async_resolver->wait_for_pending_resolves();
}

FNET_Transport::FNET_Transport(const fnet::TransportConfig &cfg)
    : _async_resolver(cfg.resolver()),
      _crypto_engine(cfg.crypto()),
      _time_tools(cfg.time_tools()),
      _work_pool(std::make_unique<vespalib::ThreadStackExecutor>(1, 128_Ki, fnet_work_pool, 1024)),
      _threads(),
      _config(cfg.config())
{
    // TODO Temporary logging to track down overspend
    LOG(debug, "FNET_Transport threads=%d from :%s", cfg.num_threads(), vespalib::getStackTrace(0).c_str());
    assert(cfg.num_threads() >= 1);
    for (size_t i = 0; i < cfg.num_threads(); ++i) {
        _threads.emplace_back(std::make_unique<FNET_TransportThread>(*this));
    }
}

FNET_Transport::~FNET_Transport() = default;

void
FNET_Transport::post_or_perform(vespalib::Executor::Task::UP task)
{
    if (auto rejected = _work_pool->execute(std::move(task))) {
        rejected->run();
    }
}

void
FNET_Transport::resolve_async(const vespalib::string &spec,
                              vespalib::AsyncResolver::ResultHandler::WP result_handler)
{
    _async_resolver->resolve_async(spec, std::move(result_handler));
}

vespalib::CryptoSocket::UP
FNET_Transport::create_client_crypto_socket(vespalib::SocketHandle socket, const vespalib::SocketSpec &spec)
{
    return _crypto_engine->create_client_crypto_socket(std::move(socket), spec);
}

vespalib::CryptoSocket::UP
FNET_Transport::create_server_crypto_socket(vespalib::SocketHandle socket)
{
    return _crypto_engine->create_server_crypto_socket(std::move(socket));
}

FNET_TransportThread *
FNET_Transport::select_thread(const void *key, size_t key_len) const
{
    HashState hash_state(key, key_len);
    size_t hash_value = XXH64(&hash_state, sizeof(hash_state), 0);
    size_t thread_id = (hash_value % _threads.size());
    return _threads[thread_id].get();
}

FNET_Connector *
FNET_Transport::Listen(const char *spec, FNET_IPacketStreamer *streamer,
                       FNET_IServerAdapter *serverAdapter)
{
    return select_thread(spec, strlen(spec))->Listen(spec, streamer, serverAdapter);
}

FNET_Connection *
FNET_Transport::Connect(const char *spec, FNET_IPacketStreamer *streamer,
                        FNET_IServerAdapter *serverAdapter,
                        FNET_Context connContext)
{
    return select_thread(spec, strlen(spec))->Connect(spec, streamer, serverAdapter, connContext);
}

uint32_t
FNET_Transport::GetNumIOComponents()
{
    uint32_t result = 0;
    for (const auto &thread: _threads) {
        result += thread->GetNumIOComponents();
    }
    return result;
}

void
FNET_Transport::sync()
{
    for (const auto &thread: _threads) {
        thread->sync();
    }
}

void
FNET_Transport::detach(FNET_IServerAdapter *server_adapter)
{
    for (const auto &thread: _threads) {
        thread->init_detach(server_adapter);
    }
    wait_for_pending_resolves();
    sync();
    for (const auto &thread: _threads) {
        thread->fini_detach(server_adapter);
    }
    sync();
}

FNET_Scheduler *
FNET_Transport::GetScheduler()
{
    return select_thread(nullptr, 0)->GetScheduler();
}

bool
FNET_Transport::execute(FNET_IExecutable *exe)
{
    return select_thread(nullptr, 0)->execute(exe);
}

void
FNET_Transport::ShutDown(bool waitFinished)
{
    for (const auto &thread: _threads) {
        thread->ShutDown(waitFinished);
    }
    if (waitFinished) {
        wait_for_pending_resolves();
        _work_pool->shutdown().sync();
    }
}

void
FNET_Transport::WaitFinished()
{
    for (const auto &thread: _threads) {
        thread->WaitFinished();
    }
    wait_for_pending_resolves();
    _work_pool->shutdown().sync();
}

bool
FNET_Transport::Start(FastOS_ThreadPool *pool)
{
    bool result = true;
    for (const auto &thread: _threads) {
        result &= thread->Start(pool);
    }
    return result;
}

void
FNET_Transport::attach_capture_hook(std::function<bool()> capture_hook)
{
    auto meet = std::make_shared<CaptureMeet>(_threads.size(), *_work_pool, *_async_resolver, std::move(capture_hook));
    for (auto &thread: _threads) {
        // tasks will be deleted when the capture_hook returns false
        auto *task = new CaptureTask(thread->GetScheduler(), meet);
        task->ScheduleNow();
    }
}

void
FNET_Transport::Add(FNET_IOComponent *comp, bool needRef) {
    comp->Owner()->Add(comp, needRef);
}

void
FNET_Transport::Close(FNET_IOComponent *comp, bool needRef) {
    comp->Owner()->Close(comp, needRef);
}

void
FNET_Transport::Main() {
    assert(_threads.size() == 1);
    _threads[0]->Main();
}
<|endoftext|>


<commit_before>/***************************************************************
*
* Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
* University of Wisconsin-Madison, WI.
*
* Licensed 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************/

#include "condor_common.h"
#include "condor_uid.h"
#include "internet.h"
#include "network_adapter.linux.h"

#if HAVE_NET_IF_H
#  include <net/if.h>
#endif
#if HAVE_LINUX_SOCKIOS_H
#  include <linux/sockios.h>
#endif
#if HAVE_LINUX_TYPES_H
#  include <linux/types.h>
#endif
#if HAVE_OS_TYPES_H
#  include <os_types.h>
#endif
#if HAVE_LINUX_ETHTOOL_H
#  include <linux/ethtool.h>
#endif

// For now, the only wake-on-lan type we use is UDP magic
#if defined(HAVE_LINUX_ETHTOOL_H)
# define WAKE_MASK	( 0 | (WAKE_MAGIC) )
#endif

// Possible values for the above (OR them together) :
//	WAKE_PHY
//	WAKE_UCAST
//	WAKE_MCAST
//	WAKE_BCAST
//	WAKE_ARP
//	WAKE_MAGIC
//	WAKE_MAGICSECURE

/***************************************************************
* LinuxNetworkAdapter class
***************************************************************/

/// Constructor
LinuxNetworkAdapter::LinuxNetworkAdapter ( const char */*ip_string*/,
										   unsigned int ip_addr ) throw ()
		: UnixNetworkAdapter( ip_addr )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

LinuxNetworkAdapter::LinuxNetworkAdapter ( const char *name ) throw()
		: UnixNetworkAdapter( name )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

/// Destructor
LinuxNetworkAdapter::~LinuxNetworkAdapter ( void ) throw()
{
}

bool
LinuxNetworkAdapter::findAdapter( unsigned int ip_addr )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifconf	ifc;
	int				sock;
	int				num_req = 3;	// Should be enough for a machine
									// with lo, eth0, eth1

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	struct sockaddr_in	in_addr;
	ifc.ifc_buf = NULL;
	while( !found ) {
		int size	= num_req * sizeof(struct ifreq);
		ifc.ifc_buf	= (char *) calloc( num_req, sizeof(struct ifreq) );
		ifc.ifc_len	= size;

		int status = ioctl( sock, SIOCGIFCONF, &ifc );
		if ( status < 0 ) {
			derror( "ioctl(SIOCGIFCONF)" );
			break;
		}

		// Did we find it in the ifc?
		int				 num = ifc.ifc_len / sizeof(struct ifreq);
		struct ifreq	*ifr = ifc.ifc_req;
		for ( int i = 0;  i < num;  i++, ifr++ ) {
			struct sockaddr_in *in = (struct sockaddr_in*)&(ifr->ifr_addr);
			MemCopy( &in_addr, in, sizeof(struct sockaddr_in) );

			if ( in->sin_addr.s_addr == ip_addr ) {
				setIpAddr( *ifr );
				setName( *ifr );
				found = true;
				break;
			}
		}

		// If the length returned by ioctl() is the same as the size
		// we started with, it probably overflowed.... try again
		if ( (!found) && (ifc.ifc_len == size) ) {
			num_req += 2;
			free( ifc.ifc_buf );
			ifc.ifc_buf = NULL;
		}
		else {
			break;
		}
	}

	// Make sure we free up the buffer memory
	if ( ifc.ifc_buf ) {
		free( ifc.ifc_buf );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s that matches %s\n",
				 interfaceName( ),
				 sin_to_string( &in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG,
				 "No interface for address %s\n",
				 sin_to_string( &in_addr )
				 );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::findAdapter( const char *name )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	getName( ifr, name );
	int status = ioctl( sock, SIOCGIFADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFADDR)" );
	}
	else {
		found = true;
		setIpAddr( ifr );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s with ip %s\n",
				 name,
				 inet_ntoa( m_in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG, "No interface for name %s\n", name );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::getAdapterInfo( void )
{
	bool			ok = true;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;
	int				status;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Get the hardware address
	getName( ifr );
	status = ioctl( sock, SIOCGIFHWADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFHWADDR)" );
	}
	else {
		setHwAddr( ifr );
	}

	// Get the net mask
	getName( ifr );
	ifr.ifr_addr.sa_family = AF_INET;
	status = ioctl( sock, SIOCGIFNETMASK, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFNETMASK)" );
	}
	else {
		setNetMask( ifr );
	}

	// And, we're done
# endif
	return ok;
}

bool
LinuxNetworkAdapter::detectWOL ( void )
{
	bool					ok = false;
#if (HAVE_DECL_SIOCETHTOOL) && (HAVE_STRUCT_IFREQ) && (HAVE_LINUX_ETHTOOL_H)
	int						err;
	struct ethtool_wolinfo	wolinfo;
	struct ifreq			ifr;

	// Open control socket.
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		dprintf( D_ALWAYS, "Cannot get control socket for WOL detection\n" );
		return false;
	}

	// Fill in the WOL request and the ioctl request
	wolinfo.cmd = ETHTOOL_GWOL;
	getName( ifr );
	ifr.ifr_data = (caddr_t)(& wolinfo);

	priv_state saved_priv = set_priv( PRIV_ROOT );
	err = ioctl(sock, SIOCETHTOOL, &ifr);
	set_priv( saved_priv );

	if ( err < 0 ) {
		derror( "ioctl(SIOCETHTOOL/GWOL)" );
		m_wol_support_mask = 0;
		m_wol_enable_mask = 0;
	}
	else {
		m_wol_support_mask = wolinfo.supported;
		m_wol_enable_mask = wolinfo.wolopts;
		ok = true;
	}

	// For now, all we support is the "magic" packet
	setWolBits( NetworkAdapterBase::WOL_HW_SUPPORT, m_wol_support_mask );
	setWolBits( NetworkAdapterBase::WOL_HW_ENABLED, m_wol_enable_mask );
	dprintf( D_FULLDEBUG, "%s supports Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeSupported() ? "yes" : "no", m_wol_support_mask );
	dprintf( D_FULLDEBUG, "%s enabled Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeEnabled() ? "yes" : "no", m_wol_enable_mask );

	close( sock );
#  endif
	return ok;
}

struct WolTable
{
	unsigned						bit_mask;
	NetworkAdapterBase::WOL_BITS	wol_bits;
};
static WolTable wol_table [] =
{
# if (HAVE_LINUX_ETHTOOL_H)
	{ WAKE_PHY,			NetworkAdapterBase::WOL_PHYSICAL },
	{ WAKE_UCAST,		NetworkAdapterBase::WOL_UCAST },
	{ WAKE_MCAST,		NetworkAdapterBase::WOL_MCAST },
	{ WAKE_BCAST,		NetworkAdapterBase::WOL_BCAST },
	{ WAKE_ARP,			NetworkAdapterBase::WOL_ARP },
	{ WAKE_MAGIC,		NetworkAdapterBase::WOL_MAGIC },
	{ WAKE_MAGICSECURE,	NetworkAdapterBase::WOL_MAGICSECURE },
# endif
	{ 0,				NetworkAdapterBase::WOL_NONE }
};

void
LinuxNetworkAdapter::setWolBits ( WOL_TYPE type, unsigned bits )
{
	if ( type == WOL_HW_SUPPORT ) {
		wolResetSupportBits( );
	}
	else {
		wolResetEnableBits( );
	}
	for( unsigned bit = 0;  wol_table[bit].bit_mask;  bit++ ) {
		if ( wol_table[bit].bit_mask & bits ) {
			wolSetBit( type, wol_table[bit].wol_bits );
		}
	}
}
<commit_msg>Added a simple message along with the error generated when the ioctl for detecting Wake-On-LAN fails -- that the error can be ignored unless you're using hibernation. (#231)<commit_after>/***************************************************************
*
* Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
* University of Wisconsin-Madison, WI.
*
* Licensed 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************/

#include "condor_common.h"
#include "condor_uid.h"
#include "internet.h"
#include "network_adapter.linux.h"

#if HAVE_NET_IF_H
#  include <net/if.h>
#endif
#if HAVE_LINUX_SOCKIOS_H
#  include <linux/sockios.h>
#endif
#if HAVE_LINUX_TYPES_H
#  include <linux/types.h>
#endif
#if HAVE_OS_TYPES_H
#  include <os_types.h>
#endif
#if HAVE_LINUX_ETHTOOL_H
#  include <linux/ethtool.h>
#endif

// For now, the only wake-on-lan type we use is UDP magic
#if defined(HAVE_LINUX_ETHTOOL_H)
# define WAKE_MASK	( 0 | (WAKE_MAGIC) )
#endif

// Possible values for the above (OR them together) :
//	WAKE_PHY
//	WAKE_UCAST
//	WAKE_MCAST
//	WAKE_BCAST
//	WAKE_ARP
//	WAKE_MAGIC
//	WAKE_MAGICSECURE

/***************************************************************
* LinuxNetworkAdapter class
***************************************************************/

/// Constructor
LinuxNetworkAdapter::LinuxNetworkAdapter ( const char */*ip_string*/,
										   unsigned int ip_addr ) throw ()
		: UnixNetworkAdapter( ip_addr )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

LinuxNetworkAdapter::LinuxNetworkAdapter ( const char *name ) throw()
		: UnixNetworkAdapter( name )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

/// Destructor
LinuxNetworkAdapter::~LinuxNetworkAdapter ( void ) throw()
{
}

bool
LinuxNetworkAdapter::findAdapter( unsigned int ip_addr )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifconf	ifc;
	int				sock;
	int				num_req = 3;	// Should be enough for a machine
									// with lo, eth0, eth1

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	struct sockaddr_in	in_addr;
	ifc.ifc_buf = NULL;
	while( !found ) {
		int size	= num_req * sizeof(struct ifreq);
		ifc.ifc_buf	= (char *) calloc( num_req, sizeof(struct ifreq) );
		ifc.ifc_len	= size;

		int status = ioctl( sock, SIOCGIFCONF, &ifc );
		if ( status < 0 ) {
			derror( "ioctl(SIOCGIFCONF)" );
			break;
		}

		// Did we find it in the ifc?
		int				 num = ifc.ifc_len / sizeof(struct ifreq);
		struct ifreq	*ifr = ifc.ifc_req;
		for ( int i = 0;  i < num;  i++, ifr++ ) {
			struct sockaddr_in *in = (struct sockaddr_in*)&(ifr->ifr_addr);
			MemCopy( &in_addr, in, sizeof(struct sockaddr_in) );

			if ( in->sin_addr.s_addr == ip_addr ) {
				setIpAddr( *ifr );
				setName( *ifr );
				found = true;
				break;
			}
		}

		// If the length returned by ioctl() is the same as the size
		// we started with, it probably overflowed.... try again
		if ( (!found) && (ifc.ifc_len == size) ) {
			num_req += 2;
			free( ifc.ifc_buf );
			ifc.ifc_buf = NULL;
		}
		else {
			break;
		}
	}

	// Make sure we free up the buffer memory
	if ( ifc.ifc_buf ) {
		free( ifc.ifc_buf );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s that matches %s\n",
				 interfaceName( ),
				 sin_to_string( &in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG,
				 "No interface for address %s\n",
				 sin_to_string( &in_addr )
				 );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::findAdapter( const char *name )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	getName( ifr, name );
	int status = ioctl( sock, SIOCGIFADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFADDR)" );
	}
	else {
		found = true;
		setIpAddr( ifr );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s with ip %s\n",
				 name,
				 inet_ntoa( m_in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG, "No interface for name %s\n", name );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::getAdapterInfo( void )
{
	bool			ok = true;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;
	int				status;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Get the hardware address
	getName( ifr );
	status = ioctl( sock, SIOCGIFHWADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFHWADDR)" );
	}
	else {
		setHwAddr( ifr );
	}

	// Get the net mask
	getName( ifr );
	ifr.ifr_addr.sa_family = AF_INET;
	status = ioctl( sock, SIOCGIFNETMASK, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFNETMASK)" );
	}
	else {
		setNetMask( ifr );
	}

	// And, we're done
# endif
	return ok;
}

bool
LinuxNetworkAdapter::detectWOL ( void )
{
	bool					ok = false;
#if (HAVE_DECL_SIOCETHTOOL) && (HAVE_STRUCT_IFREQ) && (HAVE_LINUX_ETHTOOL_H)
	int						err;
	struct ethtool_wolinfo	wolinfo;
	struct ifreq			ifr;

	// Open control socket.
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		dprintf( D_ALWAYS, "Cannot get control socket for WOL detection\n" );
		return false;
	}

	// Fill in the WOL request and the ioctl request
	wolinfo.cmd = ETHTOOL_GWOL;
	getName( ifr );
	ifr.ifr_data = (caddr_t)(& wolinfo);

	priv_state saved_priv = set_priv( PRIV_ROOT );
	err = ioctl(sock, SIOCETHTOOL, &ifr);
	set_priv( saved_priv );

	if ( err < 0 ) {
		derror( "ioctl(SIOCETHTOOL/GWOL)" );
		dprintf( D_ALWAYS,
				 "You can safely ignore the above error if you're not"
				 " using hibernation\n" );
		m_wol_support_mask = 0;
		m_wol_enable_mask = 0;
	}
	else {
		m_wol_support_mask = wolinfo.supported;
		m_wol_enable_mask = wolinfo.wolopts;
		ok = true;
	}

	// For now, all we support is the "magic" packet
	setWolBits( NetworkAdapterBase::WOL_HW_SUPPORT, m_wol_support_mask );
	setWolBits( NetworkAdapterBase::WOL_HW_ENABLED, m_wol_enable_mask );
	dprintf( D_FULLDEBUG, "%s supports Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeSupported() ? "yes" : "no", m_wol_support_mask );
	dprintf( D_FULLDEBUG, "%s enabled Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeEnabled() ? "yes" : "no", m_wol_enable_mask );

	close( sock );
#  endif
	return ok;
}

struct WolTable
{
	unsigned						bit_mask;
	NetworkAdapterBase::WOL_BITS	wol_bits;
};
static WolTable wol_table [] =
{
# if (HAVE_LINUX_ETHTOOL_H)
	{ WAKE_PHY,			NetworkAdapterBase::WOL_PHYSICAL },
	{ WAKE_UCAST,		NetworkAdapterBase::WOL_UCAST },
	{ WAKE_MCAST,		NetworkAdapterBase::WOL_MCAST },
	{ WAKE_BCAST,		NetworkAdapterBase::WOL_BCAST },
	{ WAKE_ARP,			NetworkAdapterBase::WOL_ARP },
	{ WAKE_MAGIC,		NetworkAdapterBase::WOL_MAGIC },
	{ WAKE_MAGICSECURE,	NetworkAdapterBase::WOL_MAGICSECURE },
# endif
	{ 0,				NetworkAdapterBase::WOL_NONE }
};

void
LinuxNetworkAdapter::setWolBits ( WOL_TYPE type, unsigned bits )
{
	if ( type == WOL_HW_SUPPORT ) {
		wolResetSupportBits( );
	}
	else {
		wolResetEnableBits( );
	}
	for( unsigned bit = 0;  wol_table[bit].bit_mask;  bit++ ) {
		if ( wol_table[bit].bit_mask & bits ) {
			wolSetBit( type, wol_table[bit].wol_bits );
		}
	}
}
<|endoftext|>