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

#define BUFSIZE 122
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 129
#define ACK 0
#define NAK 1
#define WIN_SIZE 16

using namespace std;

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

int seqNum;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
unsigned char* window[16]; //packet window
int base; //used to determine position in window of arriving packets
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
int delayT;
int s;
unsigned char b[BUFSIZE];

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

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

  if(sendto(s, "GET Testfile", BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
    return false;
  }

  getFile();

  return 0;
}

bool init(int argc, char** argv) {
  base = 0; //initialize base
  s = 0;

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  char* delayTStr = argv[2];
  delayT = boost::lexical_cast<int>(delayTStr);

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

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

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

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = 0;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

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

    file = new char[length];

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

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

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

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

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

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

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

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

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

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

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

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

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

bool isvpack(unsigned char * p) {

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

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

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

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

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

  cout << "base: " << base << endl;
  cout << "sn: " << sn << endl;
  cout << "base + WIN_SIZE: " << base + WIN_SIZE << endl;

  if(!(sn >= base % 32 && sn <= (base + WIN_SIZE) % 33)) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

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

  ofstream file("Dumpfile");

  int rlen;
  int ack;

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

	for(int x = 0; x < PAKSIZE - 8; x++) {
      dataPull[x] = packet[x + 8];
    }
    dataPull[PAKSIZE - 8] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
	  char * sns = new char[3];
	  memcpy(sns, &packet[0], 3);
	  sns[2] = '\0';

      char * css = new char[6];
      memcpy(css, &packet[2], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << sns << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
	  int pid = boost::lexical_cast<int>(sns);
      if(isvpack(packet)) {
		if(pid == base) {
			base++; //increment base of window
			file << dataPull;
			file.flush();
		}
      } else cout << "%%% ERROR IN PACKET " << pid << "%%%" << endl;

      cout << "Sent response: ";
      cout << "ACK " << base << endl;

	  if(packet[6] == '1') usleep(delayT*1000);

	  string wbs = to_string((long long)base);
	  const char * ackval = wbs.c_str();

      if(sendto(s, ackval, 5, 0, (struct sockaddr *)&sa, salen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
		perror("sendto()");
        return 0;
      }
	  delete sns;
      delete css;
    }
  }
  file.close();
  return true;
}
<commit_msg>Fix the thingie<commit_after>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define BUFSIZE 122
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 129
#define ACK 0
#define NAK 1
#define WIN_SIZE 16

using namespace std;

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

int seqNum;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
unsigned char* window[16]; //packet window
int base; //used to determine position in window of arriving packets
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
int delayT;
int s;
unsigned char b[BUFSIZE];

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

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

  if(sendto(s, "GET Testfile", BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
    return false;
  }

  getFile();

  return 0;
}

bool init(int argc, char** argv) {
  base = 0; //initialize base
  s = 0;

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  char* delayTStr = argv[2];
  delayT = boost::lexical_cast<int>(delayTStr);

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

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

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

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = 0;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

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

    file = new char[length];

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

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

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

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

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

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

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

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

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

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

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

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

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

bool isvpack(unsigned char * p) {

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

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

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

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

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

  cout << "base: " << base << endl;
  cout << "sn: " << sn << endl;
  cout << "base + WIN_SIZE: " << base + WIN_SIZE << endl;

  if(!(sn >= base % 32 && sn <= ((base + WIN_SIZE) % 32) == 0 ? 32 : (base + WIN_SIZE) % 32)) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

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

  ofstream file("Dumpfile");

  int rlen;
  int ack;

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

	for(int x = 0; x < PAKSIZE - 8; x++) {
      dataPull[x] = packet[x + 8];
    }
    dataPull[PAKSIZE - 8] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
	  char * sns = new char[3];
	  memcpy(sns, &packet[0], 3);
	  sns[2] = '\0';

      char * css = new char[6];
      memcpy(css, &packet[2], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << sns << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
	  int pid = boost::lexical_cast<int>(sns);
      if(isvpack(packet)) {
		if(pid == base) {
			base++; //increment base of window
			file << dataPull;
			file.flush();
		}
      } else cout << "%%% ERROR IN PACKET " << pid << "%%%" << endl;

      cout << "Sent response: ";
      cout << "ACK " << base << endl;

	  if(packet[6] == '1') usleep(delayT*1000);

	  string wbs = to_string((long long)base);
	  const char * ackval = wbs.c_str();

      if(sendto(s, ackval, 5, 0, (struct sockaddr *)&sa, salen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
		perror("sendto()");
        return 0;
      }
	  delete sns;
      delete css;
    }
  }
  file.close();
  return true;
}
<|endoftext|>


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

#define BUFSIZE 121
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 128
#define ACK 0
#define NAK 1

using namespace std;

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

int seqNum;
int s;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
unsigned char* window[16]; //packet window
int windowBase; //used to determine position in window of arriving packets
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
int delayT;
unsigned char b[BUFSIZE];

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

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

  if(sendto(s, "GET Testfile", BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
    return false;
  }

  getFile();

  return 0;
}

bool init(int argc, char** argv) {
  windowBase = 0; //initialize windowBase
  s = 0;

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  char* delayTStr = argv[2];
  delayT = boost::lexical_cast<int>(delayTStr);

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

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

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

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = 0;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

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

    file = new char[length];

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

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

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

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

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

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

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

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

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

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

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

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

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

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

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

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

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

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

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

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

  // change to validate based on checksum and sequence number

  if(sn == seqNum) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

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

  ofstream file("Dumpfile");

  int rlen;
  int ack;

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

	/* Begin Window Loading */
	int tempSeqNum = boost::lexical_cast<int>(packet[0]);
	int properIndex = tempSeqNum - windowBase;

	window[properIndex] = packet;
	cout << "Packet loaded into window" << endl;
	char* tempTest = new char[6];
		memcpy(tempTest, &window[1], 0);
		tempTest[5] = '\0';

	cout << "The Checksum pulled from client window: " << tempTest[0] << endl;

	for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      if(isvpack(packet)) {
        ack = ACK;
		if(boost::lexical_cast<int>(packet[0]) == windowBase) windowBase++; //increment base of window //FIXME
        file << dataPull;
		file.flush();
      } else {
        ack = NAK;
      }
      cout << "Sent response: ";
      cout << ((ack == ACK) ? "ACK " : "NAK ") << windowBase << endl;

	  if(packet[6] == '1') usleep(delayT*1000);

	  string s = tostring(windowBase);
	  const char * ackval = s.c_str();

      if(sendto(s, *windowBase, PAKSIZE, 0, (struct sockaddr *)&sa, salen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}
<commit_msg>a fucking underscore.<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <stdlib.h>
#include "packet.h"

#define BUFSIZE 121
#define FILENAME "Testfile"
#define TEST_FILENAME "Testfile2"
#define PORT 10038
#define PAKSIZE 128
#define ACK 0
#define NAK 1

using namespace std;

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

int seqNum;
int s;
int probCorrupt;
int probLoss;
string hs;
short int port;
char * file;
unsigned char* window[16]; //packet window
int windowBase; //used to determine position in window of arriving packets
int length;
struct sockaddr_in a;
struct sockaddr_in sa;
socklen_t salen;
string fstr;
bool dropPck;
Packet p;
int delayT;
unsigned char b[BUFSIZE];

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

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

  if(sendto(s, "GET Testfile", BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
    cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
    return false;
  }

  getFile();

  return 0;
}

bool init(int argc, char** argv) {
  windowBase = 0; //initialize windowBase
  s = 0;

  hs = string("131.204.14.") + argv[1]; /* Needs to be updated? Might be a string like "tux175.engr.auburn.edu." */
  port = 10038; /* Can be any port within 10038-10041, inclusive. */

  char* delayTStr = argv[2];
  delayT = boost::lexical_cast<int>(delayTStr);

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

  if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY); //why does this always give us 0?
  a.sin_port = htons(0);

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

  memset((char *)&sa, 0, sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_port = htons(port);
  inet_pton(AF_INET, hs.c_str(), &(sa.sin_addr));

  cout << endl;

  cout << "Server address (inet mode): " << inet_ntoa(sa.sin_addr) << endl;
  cout << "Port: " << ntohs(sa.sin_port) << endl;

  cout << endl << endl;

  /*fstr = string(file);

  cout << "File: " << endl << fstr << endl << endl;*/

  seqNum = 0;
  dropPck = false;
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

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

    file = new char[length];

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

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

bool sendFile() {

  for(int x = 0; x <= length / BUFSIZE; x++) {
    p = createPacket(x);
    if(!sendPacket()) continue;

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

    memset(b, 0, BUFSIZE);
  }
  return true;
}

Packet createPacket(int index){
    cout << endl;
    cout << "=== TRANSMISSION START" << endl;
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);
    if(index * BUFSIZE + BUFSIZE > length) {
      mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (seqNum, mstr.c_str());
}

bool sendPacket(){
    int pc = probCorrupt; int pl = probLoss;
    if((dropPck = gremlin(&p, pc, pl)) == false){
      if(sendto(s, p.str(), BUFSIZE + 7, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
        cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
        return false;
      }
      return true;
    } else return false;
}
bool isAck() {
    recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&sa, &salen);

    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {

}
void handleNak(int& x) {

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

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

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

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

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

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}

bool gremlin(Packet * pack, int corruptProb, int lossProb){
  bool dropPacket = false;
  int r = rand() % 100;

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

  if(r <= (lossProb)){
    dropPacket = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  else seqNum = (seqNum) ? false : true;
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  cout << "Message: "  << pack->getDataBuffer() << endl;

  return dropPacket;
}

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

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

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

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

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

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

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

  // change to validate based on checksum and sequence number

  if(sn == seqNum) return false;
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

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

  ofstream file("Dumpfile");

  int rlen;
  int ack;

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

	/* Begin Window Loading */
	int tempSeqNum = boost::lexical_cast<int>(packet[0]);
	int properIndex = tempSeqNum - windowBase;

	window[properIndex] = packet;
	cout << "Packet loaded into window" << endl;
	char* tempTest = new char[6];
		memcpy(tempTest, &window[1], 0);
		tempTest[5] = '\0';

	cout << "The Checksum pulled from client window: " << tempTest[0] << endl;

	for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      if(isvpack(packet)) {
        ack = ACK;
		if(boost::lexical_cast<int>(packet[0]) == windowBase) windowBase++; //increment base of window //FIXME
        file << dataPull;
		file.flush();
      } else {
        ack = NAK;
      }
      cout << "Sent response: ";
      cout << ((ack == ACK) ? "ACK " : "NAK ") << windowBase << endl;

	  if(packet[6] == '1') usleep(delayT*1000);

	  string s = to_string(windowBase);
	  const char * ackval = s.c_str();

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


<commit_before>
#include "client.hpp"
#include "state.hpp"
#include "artifact.hpp"
#include <botan/base64.h>
#include <rtc> // RTC::now()

namespace mender {

  Client::Client(Auth_manager&& man, Device&& dev, net::TCP& tcp, const std::string& server, const uint16_t port)
    : am_{std::forward<Auth_manager>(man)},
      device_{std::forward<Device>(dev)},
      server_(server),
      cached_{0, port},
      httpclient_{std::make_unique<http::Client>(tcp)},
      state_(&state::Init::instance())
  {
    printf("<Client> Client created\n");
  }

  Client::Client(Auth_manager&& man, Device&& dev, net::TCP& tcp, net::tcp::Socket socket)
    : am_{std::forward<Auth_manager>(man)},
      device_{std::forward<Device>(dev)},
      server_{socket.address().to_string()},
      cached_(std::move(socket)),
      httpclient_{std::make_unique<http::Client>(tcp)},
      state_(&state::Init::instance())
  {
    printf("<Client> Client created\n");
  }

  void Client::boot()
  {
    if(liu::LiveUpdate::is_resumable(device_.update_loc()))
    {
      printf("<Client> Found resumable state, try restoring...\n");
      auto success = liu::LiveUpdate::resume(device_.update_loc(), {this, &Client::load_state});
      if(!success)
        printf("<Client> Failed.\n");
    }

    run_state();
  }

  void Client::run_state()
  {
    switch(state_->handle(*this, context_))
    {
      using namespace state;
      case State::Result::GO_NEXT:
        run_state();
        return;

      case State::Result::DELAYED_NEXT:
        run_state_delayed();
        return;

      case State::Result::AWAIT_EVENT:
        // todo: setup timeout
        return;
    }
  }

  void Client::make_auth_request()
  {
    auto auth = am_.make_auth_request();

    using namespace std::string_literals;
    using namespace http;

    std::string data{auth.data.begin(), auth.data.end()};

    //printf("Signature:\n%s\n", Botan::base64_encode(auth.signature).c_str());

    printf("<Client> Making Auth request\n");
    // Make post
    httpclient_->post(cached_,
      API_PREFIX + "/authentication/auth_requests",
      create_auth_headers(auth.signature),
      {data.begin(), data.end()},
      {this, &Client::response_handler});
  }

  http::Header_set Client::create_auth_headers(const byte_seq& signature) const
  {
    return {
      { http::header::Content_Type, "application/json" },
      { http::header::Accept, "application/json" },
      { "X-MEN-Signature", Botan::base64_encode(signature) }
    };
  }

  void Client::response_handler(http::Error err, http::Response_ptr res)
  {
    if(err) printf("<Client> Error: %s\n", err.to_string().c_str());
    if(!res)
    {
      printf("<Client> No reply.\n");
      //assert(false && "Exiting...");
    }
    else
    {
      if(is_valid_response(*res))
      {
        printf("<Client> Valid Response (payload %u bytes)\n", res->body().size());
      }
      else
      {
        printf("<Client> Invalid response:\n%s\n", res->to_string().c_str());
        //assert(false && "Exiting...");
      }
    }

    context_.response = std::move(res);
    run_state();
  }

  bool Client::is_valid_response(const http::Response& res) const
  {
    return is_json(res) or is_artifact(res);
  }

  bool Client::is_json(const http::Response& res) const
  {
    return res.header().value(http::header::Content_Type).find("application/json") != std::string::npos;
  }

  bool Client::is_artifact(const http::Response& res) const
  {
    return res.header().value(http::header::Content_Type).find("application/vnd.mender-artifact") != std::string::npos;
  }

  void Client::check_for_update()
  {
    printf("<Client> Checking for update\n");

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Content_Type, "application/json" },
      { header::Accept, "application/json" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    std::string path{API_PREFIX + "/deployments/device/deployments/next"};

    auto artifact_name = device_.inventory().value("artifact_name");
    if(! artifact_name.empty())
      path.append("?artifact_name=").append(std::move(artifact_name)).append("&");

    auto device_type = device_.inventory().value("device_type");
    if(! device_type.empty())
      path.append("?device_type=").append(std::move(device_type));

    httpclient_->get(cached_,
      std::move(path),
      headers, {this, &Client::response_handler});
  }

  void Client::fetch_update(http::Response_ptr res)
  {
    if(res == nullptr)
      res = std::move(context_.response);

    auto uri = parse_update_uri(*res);
    printf("<Client> Fetching update from: %s\n", uri.to_string().to_string().c_str());

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Accept, "application/json;application/vnd.mender-artifact" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    httpclient_->get({cached_.address(), uri.port()},
      uri.path().to_string() + "?" + uri.query().to_string(),
      headers, {this, &Client::response_handler});
  }

  http::URI Client::parse_update_uri(http::Response& res)
  {
    using namespace nlohmann;
    auto body = json::parse(res.body().to_string());

    std::string uri = body["artifact"]["source"]["uri"];

    return http::URI{uri};
  }

  void Client::update_inventory_attributes()
  {
    printf("<Client> Uploading attributes\n");

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Content_Type, "application/json" },
      { header::Accept, "application/json" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    auto data = device_.inventory().json_str();

    httpclient_->request(PATCH, cached_,
      "/api/devices/0.1/inventory/device/attributes",
      headers, data, {this, &Client::response_handler});

    context_.last_inventory_update = RTC::now();
  }

  void Client::install_update(http::Response_ptr res)
  {
    printf("<Client> Installing update ...\n");

    if(res == nullptr)
      res = std::move(context_.response);
    assert(res);

    auto data = res->body().to_string();

    // Process data:
    Artifact artifact{{data.begin(), data.end()}};

    // do stuff with artifact
    // checksum/verify
    // artifact.update() <- this is what liveupdate wants

    //artifact.verify();
    auto& e = artifact.get_update(0);  // returns element with index

    device_.inventory("artifact_name") = artifact.name();

    httpclient_.release();

    liu::LiveUpdate::begin(device_.update_loc(), {(const char*) e.content(), e.size()}, {this, &Client::store_state});
  }

  void Client::store_state(liu::Storage store, liu::buffer_len)
  {
    decltype(store)::uid id = 0;

    // SEQNO
    store.add_int(id++, am_.seqno());

    // ARTIFACT_NAME
    store.add_string(id++, device_.inventory("artifact_name"));

    printf("<Client> State stored.\n");
  }

  void Client::load_state(liu::Restore store)
  {
    // SEQNO
    am_.set_seqno(store.as_int()); store.go_next();

    // ARTIFACT_NAME
    device_.inventory("artifact_name") = store.as_string(); store.go_next();

    printf("<Client> State restored.\n");
  }

};
<commit_msg>Hang on error<commit_after>
#include "client.hpp"
#include "state.hpp"
#include "artifact.hpp"
#include <botan/base64.h>
#include <rtc> // RTC::now()

namespace mender {

  Client::Client(Auth_manager&& man, Device&& dev, net::TCP& tcp, const std::string& server, const uint16_t port)
    : am_{std::forward<Auth_manager>(man)},
      device_{std::forward<Device>(dev)},
      server_(server),
      cached_{0, port},
      httpclient_{std::make_unique<http::Client>(tcp)},
      state_(&state::Init::instance())
  {
    printf("<Client> Client created\n");
  }

  Client::Client(Auth_manager&& man, Device&& dev, net::TCP& tcp, net::tcp::Socket socket)
    : am_{std::forward<Auth_manager>(man)},
      device_{std::forward<Device>(dev)},
      server_{socket.address().to_string()},
      cached_(std::move(socket)),
      httpclient_{std::make_unique<http::Client>(tcp)},
      state_(&state::Init::instance())
  {
    printf("<Client> Client created\n");
  }

  void Client::boot()
  {
    if(liu::LiveUpdate::is_resumable(device_.update_loc()))
    {
      printf("<Client> Found resumable state, try restoring...\n");
      auto success = liu::LiveUpdate::resume(device_.update_loc(), {this, &Client::load_state});
      if(!success)
        printf("<Client> Failed.\n");
    }

    run_state();
  }

  void Client::run_state()
  {
    switch(state_->handle(*this, context_))
    {
      using namespace state;
      case State::Result::GO_NEXT:
        run_state();
        return;

      case State::Result::DELAYED_NEXT:
        run_state_delayed();
        return;

      case State::Result::AWAIT_EVENT:
        // todo: setup timeout
        return;
    }
  }

  void Client::make_auth_request()
  {
    auto auth = am_.make_auth_request();

    using namespace std::string_literals;
    using namespace http;

    std::string data{auth.data.begin(), auth.data.end()};

    //printf("Signature:\n%s\n", Botan::base64_encode(auth.signature).c_str());

    printf("<Client> Making Auth request\n");
    // Make post
    httpclient_->post(cached_,
      API_PREFIX + "/authentication/auth_requests",
      create_auth_headers(auth.signature),
      {data.begin(), data.end()},
      {this, &Client::response_handler});
  }

  http::Header_set Client::create_auth_headers(const byte_seq& signature) const
  {
    return {
      { http::header::Content_Type, "application/json" },
      { http::header::Accept, "application/json" },
      { "X-MEN-Signature", Botan::base64_encode(signature) }
    };
  }

  void Client::response_handler(http::Error err, http::Response_ptr res)
  {
    if(err) {
      printf("<Client> Error: %s\n", err.to_string().c_str());
      return;
    }
    if(!res)
    {
      printf("<Client> No reply.\n");
      //assert(false && "Exiting...");
    }
    else
    {
      if(is_valid_response(*res))
      {
        printf("<Client> Valid Response (payload %u bytes)\n", res->body().size());
      }
      else
      {
        printf("<Client> Invalid response:\n%s\n", res->to_string().c_str());
        //assert(false && "Exiting...");
      }
    }

    context_.response = std::move(res);
    run_state();
  }

  bool Client::is_valid_response(const http::Response& res) const
  {
    return is_json(res) or is_artifact(res);
  }

  bool Client::is_json(const http::Response& res) const
  {
    return res.header().value(http::header::Content_Type).find("application/json") != std::string::npos;
  }

  bool Client::is_artifact(const http::Response& res) const
  {
    return res.header().value(http::header::Content_Type).find("application/vnd.mender-artifact") != std::string::npos;
  }

  void Client::check_for_update()
  {
    printf("<Client> Checking for update\n");

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Content_Type, "application/json" },
      { header::Accept, "application/json" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    std::string path{API_PREFIX + "/deployments/device/deployments/next"};

    auto artifact_name = device_.inventory().value("artifact_name");
    if(! artifact_name.empty())
      path.append("?artifact_name=").append(std::move(artifact_name)).append("&");

    auto device_type = device_.inventory().value("device_type");
    if(! device_type.empty())
      path.append("?device_type=").append(std::move(device_type));

    httpclient_->get(cached_,
      std::move(path),
      headers, {this, &Client::response_handler});
  }

  void Client::fetch_update(http::Response_ptr res)
  {
    if(res == nullptr)
      res = std::move(context_.response);

    auto uri = parse_update_uri(*res);
    printf("<Client> Fetching update from: %s\n", uri.to_string().to_string().c_str());

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Accept, "application/json;application/vnd.mender-artifact" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    httpclient_->get({cached_.address(), uri.port()},
      uri.path().to_string() + "?" + uri.query().to_string(),
      headers, {this, &Client::response_handler});
  }

  http::URI Client::parse_update_uri(http::Response& res)
  {
    using namespace nlohmann;
    auto body = json::parse(res.body().to_string());

    std::string uri = body["artifact"]["source"]["uri"];

    return http::URI{uri};
  }

  void Client::update_inventory_attributes()
  {
    printf("<Client> Uploading attributes\n");

    using namespace http;

    const auto& token = am_.auth_token();
    // Setup headers
    const Header_set headers{
      { header::Content_Type, "application/json" },
      { header::Accept, "application/json" },
      { header::Authorization, "Bearer " + std::string{token.begin(), token.end()}}
    };

    auto data = device_.inventory().json_str();

    httpclient_->request(PATCH, cached_,
      "/api/devices/0.1/inventory/device/attributes",
      headers, data, {this, &Client::response_handler});

    context_.last_inventory_update = RTC::now();
  }

  void Client::install_update(http::Response_ptr res)
  {
    printf("<Client> Installing update ...\n");

    if(res == nullptr)
      res = std::move(context_.response);
    assert(res);

    auto data = res->body().to_string();

    // Process data:
    Artifact artifact{{data.begin(), data.end()}};

    // do stuff with artifact
    // checksum/verify
    // artifact.update() <- this is what liveupdate wants

    //artifact.verify();
    auto& e = artifact.get_update(0);  // returns element with index

    device_.inventory("artifact_name") = artifact.name();

    httpclient_.release();

    liu::LiveUpdate::begin(device_.update_loc(), {(const char*) e.content(), e.size()}, {this, &Client::store_state});
  }

  void Client::store_state(liu::Storage store, liu::buffer_len)
  {
    decltype(store)::uid id = 0;

    // SEQNO
    store.add_int(id++, am_.seqno());

    // ARTIFACT_NAME
    store.add_string(id++, device_.inventory("artifact_name"));

    printf("<Client> State stored.\n");
  }

  void Client::load_state(liu::Restore store)
  {
    // SEQNO
    am_.set_seqno(store.as_int()); store.go_next();

    // ARTIFACT_NAME
    device_.inventory("artifact_name") = store.as_string(); store.go_next();

    printf("<Client> State restored.\n");
  }

};
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    "../../Characters/CString/Utilities.h"
#include    "../../Characters/FloatConversion.h"
#include    "../../Characters/Format.h"
#include    "../../Characters/String2Int.h"
#include    "../BadFormatException.h"

#include    "ObjectReader.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::DataExchange;
using   namespace   Stroika::Foundation::DataExchange::StructuredStreamEvents;

using   Memory::Byte;

/*
 ********************************************************************************
 ************ StructuredStreamEvents::ObjectReader::Context *********************
 ********************************************************************************
 */
#if     qDefaultTracingOn
wstring ObjectReader::Context::TraceLeader_ () const
{
    wstring l;
    l.reserve (fStack_.size ());
    for (size_t i = 0; i < fStack_.size (); ++i) {
        l += L" ";
    }
    return l;
}
#endif

/*
 ********************************************************************************
 ******* StructuredStreamEvents::ObjectReader::IConsumerToContextTranslator******
 ********************************************************************************
 */
ObjectReader::IConsumerToContextTranslator::IConsumerToContextTranslator (Context& r)
    : fContext_ (r)
{
}

void    ObjectReader::IConsumerToContextTranslator::StartElement (const StructuredStreamEvents::Name& name)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling HandleChildStart ('%s',...)...", fContext_.TraceLeader_ ().c_str (), name.fLocalName.c_str ());
    }
#endif
    fContext_.GetTop ()->HandleChildStart (fContext_, name);
}
void    ObjectReader::IConsumerToContextTranslator::EndElement (const StructuredStreamEvents::Name& name)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling EndElement ('%s',...)...", fContext_.TraceLeader_ ().c_str (), name.fLocalName.c_str ());
    }
#endif
    fContext_.GetTop ()->HandleEndTag (fContext_);
}
void    ObjectReader::IConsumerToContextTranslator::TextInsideElement (const String& text)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling TextInsideElement ('%s',...)...", fContext_.TraceLeader_ ().c_str (), text.c_str () );
    }
#endif
    fContext_.GetTop ()->HandleTextInside (fContext_, text);
}

/*
 ********************************************************************************
 ***************** StructuredStreamEvents::ObjectReader *************************
 ********************************************************************************
 */
namespace   {
    struct DocumentReader_ : public ObjectReader::IContextReader {
        shared_ptr<IContextReader>      fDocEltBuilder;
        bool                            fAnyDocElt;
        String                          fDocEltURI;
        String                          fDocEltName;
        DocumentReader_ (const shared_ptr<IContextReader>& docEltBuilder)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (true)
            , fDocEltURI ()
            , fDocEltName ()
        {
        }
        DocumentReader_ (const shared_ptr<IContextReader>& docEltBuilder, const String& checkURI, const String& checkDocEltName)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (false)
            , fDocEltURI (checkURI)
            , fDocEltName (checkDocEltName)
        {
        }
        virtual void    HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name) override
        {
            if (not fAnyDocElt) {
                if (name.fLocalName != fDocEltName or name.fNamespaceURI.Value () != fDocEltURI) {
                    ThrowUnRecognizedStartElt (name);
                }
            }
            r.Push (fDocEltBuilder);
        }
        virtual void    HandleTextInside (ObjectReader::Context& r, const String& text)  override
        {
            // OK so long as text is whitespace - or comment. Probably should check/assert, but KISS..., and count on validation to
            // assure input is valid
            Assert (text.IsWhitespace ());
        }
        virtual void    HandleEndTag (ObjectReader::Context& r) override
        {
            r.Pop ();
        }
    };
}
void    ObjectReader::Run (const shared_ptr<IContextReader>& docEltBuilder, const Streams::InputStream<Byte>& in)
{
    RequireNotNull (docEltBuilder);
    Context ctx;
    Require (ctx.fStack_.size () == 0);

    ctx.Push (make_shared<DocumentReader_> (docEltBuilder));

    IConsumerToContextTranslator cb (ctx);
    XML::SAXParse (in, cb);

    ctx.Pop (); // the docuemnt reader we just added

    Ensure (ctx.fStack_.size () == 0);
}

void    ObjectReader::Run (const shared_ptr<IContextReader>& docEltBuilder, const String& docEltUri, const String& docEltLocalName, const Streams::InputStream<Byte>& in)
{
    RequireNotNull (docEltBuilder);
    Context ctx;
    Require (ctx.fStack_.size () == 0);

    ctx.Push (make_shared<DocumentReader_> (docEltBuilder, docEltUri, docEltLocalName));

    IConsumerToContextTranslator cb (ctx);
    XML::SAXParse (in, cb);

    ctx.Pop (); // the docuemnt reader we just added

    Ensure (ctx.fStack_.size () == 0);
}

/*
 ********************************************************************************
 ******************** StructuredStreamEvents::BuiltinReader<String> *************
 ********************************************************************************
 */
BuiltinReader<String>::BuiltinReader (String* intoVal)
    : value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = String ();
}

void    BuiltinReader<String>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<String>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    (*value_) += text;
}

void    BuiltinReader<String>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************** StructuredStreamEvents::BuiltinReader<int> *********************
 ********************************************************************************
 */
BuiltinReader<int>::BuiltinReader (int* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<int>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<int>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<int>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************** StructuredStreamEvents::BuiltinReader<unsigned int> ************
 ********************************************************************************
 */
BuiltinReader<unsigned int>::BuiltinReader (unsigned int* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<unsigned int>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<unsigned int>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<unsigned int>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************* StructuredStreamEvents::BuiltinReader<bool> ****************
 ********************************************************************************
 */
BuiltinReader<bool>::BuiltinReader (bool* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<bool>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<bool>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    String  tmp =   tmpVal_.Trim ().ToLowerCase ();
    (*value_) = (tmp == L"true");
}

void    BuiltinReader<bool>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *********** StructuredStreamEvents::BuiltinReader<float> ***********************
 ********************************************************************************
 */
BuiltinReader<float>::BuiltinReader (float* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<float>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<float>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = static_cast<float> (Characters::String2Float<float> (tmpVal_.As<wstring> ()));
}

void    BuiltinReader<float>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 **************** StructuredStreamEvents::BuiltinReader<double> *****************
 ********************************************************************************
 */
BuiltinReader<double>::BuiltinReader (double* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<double>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<double>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Float<double> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<double>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************* StructuredStreamEvents::BuiltinReader<Time::DateTime> ************
 ********************************************************************************
 */
BuiltinReader<Time::DateTime>::BuiltinReader (Time::DateTime* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = Time::DateTime ();
}

void    BuiltinReader<Time::DateTime>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<Time::DateTime>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    // not 100% right to ignore exceptions, but tricky to do more right (cuz not necesarily all text given us at once)
    IgnoreExceptionsForCall ((*value_) = Time::DateTime::Parse (tmpVal_.As<wstring> (), Time::DateTime::ParseFormat::eXML));
}

void    BuiltinReader<Time::DateTime>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ****************** StructuredStreamEvents::IgnoreNodeReader ********************
 ********************************************************************************
 */
IgnoreNodeReader::IgnoreNodeReader ()
    : fDepth_ (0)
{
}

void    IgnoreNodeReader::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    Require (fDepth_ >= 0);
    fDepth_++;
}

void    IgnoreNodeReader::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    // Ignore text
}

void    IgnoreNodeReader::HandleEndTag (ObjectReader::Context& r)
{
    Require (fDepth_ >= 0);
    --fDepth_;
    if (fDepth_ < 0) {
        r.Pop ();
    }
}

/*
 ********************************************************************************
 ****************** StructuredStreamEvents::ThrowUnRecognizedStartElt ***********
 ********************************************************************************
 */
void    StructuredStreamEvents::ThrowUnRecognizedStartElt (const StructuredStreamEvents::Name& name)
{
    Execution::DoThrow (BadFormatException (Characters::CString::Format (L"Unrecognized start tag '%s'", name.fLocalName.c_str ())));
}

<commit_msg>Comments<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#include    "../../Characters/CString/Utilities.h"
#include    "../../Characters/FloatConversion.h"
#include    "../../Characters/Format.h"
#include    "../../Characters/String2Int.h"
#include    "../BadFormatException.h"

#include    "ObjectReader.h"

using   namespace   Stroika;
using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::DataExchange;
using   namespace   Stroika::Foundation::DataExchange::StructuredStreamEvents;

using   Memory::Byte;

/*
 ********************************************************************************
 ************ StructuredStreamEvents::ObjectReader::Context *********************
 ********************************************************************************
 */
#if     qDefaultTracingOn
wstring ObjectReader::Context::TraceLeader_ () const
{
    wstring l;
    l.reserve (fStack_.size ());
    for (size_t i = 0; i < fStack_.size (); ++i) {
        l += L" ";
    }
    return l;
}
#endif

/*
 ********************************************************************************
 ******* StructuredStreamEvents::ObjectReader::IConsumerToContextTranslator******
 ********************************************************************************
 */
ObjectReader::IConsumerToContextTranslator::IConsumerToContextTranslator (Context& r)
    : fContext_ (r)
{
}

void    ObjectReader::IConsumerToContextTranslator::StartElement (const StructuredStreamEvents::Name& name)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling HandleChildStart ('%s',...)...", fContext_.TraceLeader_ ().c_str (), name.fLocalName.c_str ());
    }
#endif
    fContext_.GetTop ()->HandleChildStart (fContext_, name);
}
void    ObjectReader::IConsumerToContextTranslator::EndElement (const StructuredStreamEvents::Name& name)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling EndElement ('%s',...)...", fContext_.TraceLeader_ ().c_str (), name.fLocalName.c_str ());
    }
#endif
    fContext_.GetTop ()->HandleEndTag (fContext_);
}
void    ObjectReader::IConsumerToContextTranslator::TextInsideElement (const String& text)
{
    AssertNotNull (fContext_.GetTop ());
#if     qDefaultTracingOn
    if (fContext_.fTraceThisReader) {
        DbgTrace (L"%sCalling TextInsideElement ('%s',...)...", fContext_.TraceLeader_ ().c_str (), text.c_str () );
    }
#endif
    fContext_.GetTop ()->HandleTextInside (fContext_, text);
}

/*
 ********************************************************************************
 ***************** StructuredStreamEvents::ObjectReader *************************
 ********************************************************************************
 */
namespace   {
	// @todo see https://stroika.atlassian.net/browse/STK-284
    struct DocumentReader_ : public ObjectReader::IContextReader {
        shared_ptr<IContextReader>      fDocEltBuilder;
        bool                            fAnyDocElt;
        String                          fDocEltURI;
        String                          fDocEltName;
        DocumentReader_ (const shared_ptr<IContextReader>& docEltBuilder)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (true)
            , fDocEltURI ()
            , fDocEltName ()
        {
        }
        DocumentReader_ (const shared_ptr<IContextReader>& docEltBuilder, const String& checkURI, const String& checkDocEltName)
            : fDocEltBuilder (docEltBuilder)
            , fAnyDocElt (false)
            , fDocEltURI (checkURI)
            , fDocEltName (checkDocEltName)
        {
        }
        virtual void    HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name) override
        {
            if (not fAnyDocElt) {
                if (name.fLocalName != fDocEltName or name.fNamespaceURI.Value () != fDocEltURI) {
                    ThrowUnRecognizedStartElt (name);
                }
            }
            r.Push (fDocEltBuilder);
        }
        virtual void    HandleTextInside (ObjectReader::Context& r, const String& text)  override
        {
            // OK so long as text is whitespace - or comment. Probably should check/assert, but KISS..., and count on validation to
            // assure input is valid
            Assert (text.IsWhitespace ());
        }
        virtual void    HandleEndTag (ObjectReader::Context& r) override
        {
            r.Pop ();
        }
    };
}
void    ObjectReader::Run (const shared_ptr<IContextReader>& docEltBuilder, const Streams::InputStream<Byte>& in)
{
	// @todo see https://stroika.atlassian.net/browse/STK-284
    RequireNotNull (docEltBuilder);
    Context ctx;
    Require (ctx.fStack_.size () == 0);

    ctx.Push (make_shared<DocumentReader_> (docEltBuilder));

    IConsumerToContextTranslator cb (ctx);
    XML::SAXParse (in, cb);

    ctx.Pop (); // the docuemnt reader we just added

    Ensure (ctx.fStack_.size () == 0);
}

void    ObjectReader::Run (const shared_ptr<IContextReader>& docEltBuilder, const String& docEltUri, const String& docEltLocalName, const Streams::InputStream<Byte>& in)
{
	// @todo see https://stroika.atlassian.net/browse/STK-284
    RequireNotNull (docEltBuilder);
    Context ctx;
    Require (ctx.fStack_.size () == 0);

    ctx.Push (make_shared<DocumentReader_> (docEltBuilder, docEltUri, docEltLocalName));

    IConsumerToContextTranslator cb (ctx);
    XML::SAXParse (in, cb);

    ctx.Pop (); // the docuemnt reader we just added

    Ensure (ctx.fStack_.size () == 0);
}

/*
 ********************************************************************************
 ******************** StructuredStreamEvents::BuiltinReader<String> *************
 ********************************************************************************
 */
BuiltinReader<String>::BuiltinReader (String* intoVal)
    : value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = String ();
}

void    BuiltinReader<String>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<String>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    (*value_) += text;
}

void    BuiltinReader<String>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************** StructuredStreamEvents::BuiltinReader<int> *********************
 ********************************************************************************
 */
BuiltinReader<int>::BuiltinReader (int* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<int>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<int>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<int>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *************** StructuredStreamEvents::BuiltinReader<unsigned int> ************
 ********************************************************************************
 */
BuiltinReader<unsigned int>::BuiltinReader (unsigned int* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<unsigned int>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<unsigned int>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Int<int> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<unsigned int>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ******************* StructuredStreamEvents::BuiltinReader<bool> ****************
 ********************************************************************************
 */
BuiltinReader<bool>::BuiltinReader (bool* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<bool>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<bool>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    String  tmp =   tmpVal_.Trim ().ToLowerCase ();
    (*value_) = (tmp == L"true");
}

void    BuiltinReader<bool>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 *********** StructuredStreamEvents::BuiltinReader<float> ***********************
 ********************************************************************************
 */
BuiltinReader<float>::BuiltinReader (float* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<float>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<float>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = static_cast<float> (Characters::String2Float<float> (tmpVal_.As<wstring> ()));
}

void    BuiltinReader<float>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 **************** StructuredStreamEvents::BuiltinReader<double> *****************
 ********************************************************************************
 */
BuiltinReader<double>::BuiltinReader (double* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
}

void    BuiltinReader<double>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<double>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    (*value_) = Characters::String2Float<double> (tmpVal_.As<wstring> ());
}

void    BuiltinReader<double>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ************* StructuredStreamEvents::BuiltinReader<Time::DateTime> ************
 ********************************************************************************
 */
BuiltinReader<Time::DateTime>::BuiltinReader (Time::DateTime* intoVal)
    : tmpVal_ ()
    , value_ (intoVal)
{
    RequireNotNull (intoVal);
    *intoVal = Time::DateTime ();
}

void    BuiltinReader<Time::DateTime>::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    ThrowUnRecognizedStartElt (name);
}

void    BuiltinReader<Time::DateTime>::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    tmpVal_ += text;
    // not 100% right to ignore exceptions, but tricky to do more right (cuz not necesarily all text given us at once)
    IgnoreExceptionsForCall ((*value_) = Time::DateTime::Parse (tmpVal_.As<wstring> (), Time::DateTime::ParseFormat::eXML));
}

void    BuiltinReader<Time::DateTime>::HandleEndTag (ObjectReader::Context& r)
{
    r.Pop ();
}

/*
 ********************************************************************************
 ****************** StructuredStreamEvents::IgnoreNodeReader ********************
 ********************************************************************************
 */
IgnoreNodeReader::IgnoreNodeReader ()
    : fDepth_ (0)
{
}

void    IgnoreNodeReader::HandleChildStart (ObjectReader::Context& r, const StructuredStreamEvents::Name& name)
{
    Require (fDepth_ >= 0);
    fDepth_++;
}

void    IgnoreNodeReader::HandleTextInside (ObjectReader::Context& r, const String& text)
{
    // Ignore text
}

void    IgnoreNodeReader::HandleEndTag (ObjectReader::Context& r)
{
    Require (fDepth_ >= 0);
    --fDepth_;
    if (fDepth_ < 0) {
        r.Pop ();
    }
}

/*
 ********************************************************************************
 ****************** StructuredStreamEvents::ThrowUnRecognizedStartElt ***********
 ********************************************************************************
 */
void    StructuredStreamEvents::ThrowUnRecognizedStartElt (const StructuredStreamEvents::Name& name)
{
    Execution::DoThrow (BadFormatException (Characters::CString::Format (L"Unrecognized start tag '%s'", name.fLocalName.c_str ())));
}

<|endoftext|>


<commit_before>#include "iotsaSimple.h"

void IotsaSimpleMod::setup() {
  // Handled in client application, in normal setup() function
}

void IotsaSimpleMod::serverSetup() {
#ifdef WITH_HTTP_OR_HTTPS
  server->on(url, hfun);
#endif
}

void IotsaSimpleMod::loop() {
  // Handled in client application, in normal loop() function
}

String IotsaSimpleMod::info() {
  if (ifun) {
  	return ifun();
  }
  return "";
}
<commit_msg>Oops, IotsaSimpleMod didn't work because of typo.<commit_after>#include "iotsaSimple.h"

void IotsaSimpleMod::setup() {
  // Handled in client application, in normal setup() function
}

void IotsaSimpleMod::serverSetup() {
#ifdef IOTSA_WITH_HTTP_OR_HTTPS
  server->on(url, hfun);
#endif
}

void IotsaSimpleMod::loop() {
  // Handled in client application, in normal loop() function
}

String IotsaSimpleMod::info() {
  if (ifun) {
  	return ifun();
  }
  return "";
}
<|endoftext|>


<commit_before>// Copyright 2008-present Contributors to the OpenImageIO project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md

#include "py_oiio.h"

#include <OpenImageIO/sysutil.h>

namespace PyOpenImageIO {

const char*
python_array_code(TypeDesc format)
{
    switch (format.basetype) {
    case TypeDesc::UINT8: return "uint8";
    case TypeDesc::INT8: return "int8";
    case TypeDesc::UINT16: return "uint16";
    case TypeDesc::INT16: return "int16";
    case TypeDesc::UINT32: return "uint32";
    case TypeDesc::INT32: return "int32";
    case TypeDesc::FLOAT: return "float";
    case TypeDesc::DOUBLE: return "double";
    case TypeDesc::HALF: return "half";
    default:
        // For any other type, including UNKNOWN, pack it into an
        // unsigned byte array.
        return "B";
    }
}

TypeDesc
typedesc_from_python_array_code(string_view code)
{
    TypeDesc t(code);
    if (!t.is_unknown())
        return t;

    if (code == "b" || code == "c")
        return TypeDesc::INT8;
    if (code == "B")
        return TypeDesc::UINT8;
    if (code == "h")
        return TypeDesc::INT16;
    if (code == "H")
        return TypeDesc::UINT16;
    if (code == "i")
        return TypeDesc::INT;
    if (code == "I")
        return TypeDesc::UINT;
    if (code == "l")
        return TypeDesc::INT64;
    if (code == "L")
        return TypeDesc::UINT64;
    if (code == "f")
        return TypeDesc::FLOAT;
    if (code == "d")
        return TypeDesc::DOUBLE;
    if (code == "float16" || code == "e")
        return TypeDesc::HALF;
    return TypeDesc::UNKNOWN;
}

oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf)
{
    if (pybuf.format.size())
        format = typedesc_from_python_array_code(pybuf.format);
    if (format != TypeUnknown) {
        data    = pybuf.ptr;
        xstride = format.size();
        size    = 1;
        for (int i = pybuf.ndim - 1; i >= 0; --i) {
            if (pybuf.strides[i] != ssize_t(size * xstride)) {
                // Just can't handle non-contiguous strides
                format = TypeUnknown;
                size   = 0;
                break;
            }
            size *= pybuf.shape[i];
        }
    }
}

oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
                           int height, int depth, int pixeldims)
{
    if (pybuf.format.size())
        format = typedesc_from_python_array_code(pybuf.format);
    if (size_t(pybuf.itemsize) != format.size()
        || pybuf.size
               != int64_t(width) * int64_t(height) * int64_t(depth * nchans)) {
        format = TypeUnknown;  // Something went wrong
        error  = Strutil::sprintf(
            "buffer is wrong size (expected %dx%dx%dx%d, got total %d)", depth,
            height, width, nchans, pybuf.size);
        return;
    }
    size = pybuf.size;
    if (pixeldims == 3) {
        // Reading a 3D volumetric cube
        if (pybuf.ndim == 4 && pybuf.shape[0] == depth
            && pybuf.shape[1] == height && pybuf.shape[2] == width
            && pybuf.shape[3] == nchans) {
            // passed from python as [z][y][x][c]
            xstride = pybuf.strides[2];
            ystride = pybuf.strides[1];
            zstride = pybuf.strides[0];
        } else if (pybuf.ndim == 3 && pybuf.shape[0] == depth
                   && pybuf.shape[1] == height
                   && pybuf.shape[2] == width * nchans) {
            // passed from python as [z][y][xpixel] -- chans mushed together
            xstride = pybuf.strides[2];
            ystride = pybuf.strides[1];
            zstride = pybuf.strides[0];
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = "Bad dimensions of pixel data";
        }
    } else if (pixeldims == 2) {
        // Reading an 2D image rectangle
        if (pybuf.ndim == 3 && pybuf.shape[0] == height
            && pybuf.shape[1] == width && pybuf.shape[2] == nchans) {
            // passed from python as [y][x][c]
            xstride = pybuf.strides[1];
            ystride = pybuf.strides[0];
        } else if (pybuf.ndim == 2) {
            // Somebody collapsed a dimsision. Is it [pixel][c] with x&y
            // combined, or is it [y][xpixel] with channels mushed together?
            if (pybuf.shape[0] == width * height && pybuf.shape[1] == nchans)
                xstride = pybuf.strides[0];
            else if (pybuf.shape[0] == height
                     && pybuf.shape[1] == width * nchans) {
                ystride = pybuf.strides[0];
                xstride = pybuf.strides[0] * nchans;
            } else {
                format = TypeUnknown;  // error
                error  = Strutil::sprintf(
                    "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                    pixeldims, pybuf.ndim);
            }
        } else if (pybuf.ndim == 1
                   && pybuf.shape[0] == height * width * nchans) {
            // all pixels & channels smushed together
            // just rely on autostride
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = Strutil::sprintf(
                "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                pixeldims, pybuf.ndim);
        }
    } else if (pixeldims == 1) {
        // Reading a 1D scanline span
        if (pybuf.ndim == 2 && pybuf.shape[0] == width
            && pybuf.shape[1] == nchans) {
            // passed from python as [x][c]
            xstride = pybuf.strides[0];
        } else if (pybuf.ndim == 1 && pybuf.shape[0] == width * nchans) {
            // all pixels & channels smushed together
            xstride = pybuf.strides[0] * nchans;
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = Strutil::sprintf(
                "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                pixeldims, pybuf.ndim);
        }
    } else {
        error = Strutil::sprintf(
            "Can't figure out array shape (pixeldims=%d, pydim=%d)", pixeldims,
            pybuf.ndim);
    }

    if (nchans > 1 && size_t(pybuf.strides.back()) != format.size()) {
        format = TypeUnknown;  // can't handle noncontig channels
        error  = "Can't handle numpy array with noncontiguous channels";
    }
    if (format != TypeUnknown)
        data = pybuf.ptr;
}

bool
oiio_attribute_typed(const std::string& name, TypeDesc type,
                     const py::object& obj)
{
    if (type.basetype == TypeDesc::INT) {
        std::vector<int> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate)
            return OIIO::attribute(name, type, &vals[0]);
        return false;
    }
    if (type.basetype == TypeDesc::FLOAT) {
        std::vector<float> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate)
            return OIIO::attribute(name, type, &vals[0]);
        return false;
    }
    if (type.basetype == TypeDesc::STRING) {
        std::vector<std::string> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate) {
            std::vector<ustring> u;
            for (auto& val : vals)
                u.emplace_back(val);
            return OIIO::attribute(name, type, &u[0]);
        }
        return false;
    }
    return false;
}

static py::object
oiio_getattribute_typed(const std::string& name, TypeDesc type = TypeUnknown)
{
    if (type == TypeDesc::UNKNOWN)
        return py::none();
    char* data = OIIO_ALLOCA(char, type.size());
    if (!OIIO::getattribute(name, type, data))
        return py::none();
    if (type.basetype == TypeDesc::INT)
        return C_to_val_or_tuple((const int*)data, type);
    if (type.basetype == TypeDesc::FLOAT)
        return C_to_val_or_tuple((const float*)data, type);
    if (type.basetype == TypeDesc::STRING)
        return C_to_val_or_tuple((const char**)data, type);
    return py::none();
}

// This OIIO_DECLARE_PYMODULE mojo is necessary if we want to pass in the
// MODULE name as a #define. Google for Argument-Prescan for additional
// info on why this is necessary

#define OIIO_DECLARE_PYMODULE(x) PYBIND11_MODULE(x, m)

OIIO_DECLARE_PYMODULE(PYMODULE_NAME)
{
    using namespace pybind11::literals;

    if (Sysutil::getenv("OPENIMAGEIO_DEBUG_PYTHON") != "")
        Sysutil::setup_crash_stacktrace("stdout");

    // Basic helper classes
    declare_typedesc(m);
    declare_paramvalue(m);
    declare_imagespec(m);
    declare_roi(m);
    declare_deepdata(m);
    declare_colorconfig(m);

    // Main OIIO I/O classes
    declare_imageinput(m);
    declare_imageoutput(m);
    declare_imagebuf(m);
    declare_imagecache(m);

    // TextureSys classes
    declare_wrap(m);
    declare_mipmpode(m);
    declare_interpmode(m);
    declare_textureopt(m);
    declare_texturesystem(m);

    declare_imagebufalgo(m);

    // Global (OpenImageIO scope) functions and symbols
    m.def("geterror", &OIIO::geterror, "clear"_a = true);
    m.def("attribute", [](const std::string& name, float val) {
        OIIO::attribute(name, val);
    });
    m.def("attribute",
          [](const std::string& name, int val) { OIIO::attribute(name, val); });
    m.def("attribute", [](const std::string& name, const std::string& val) {
        OIIO::attribute(name, val);
    });
    m.def("attribute",
          [](const std::string& name, TypeDesc type, const py::object& obj) {
              oiio_attribute_typed(name, type, obj);
          });

    m.def(
        "get_int_attribute",
        [](const std::string& name, int def) {
            return OIIO::get_int_attribute(name, def);
        },
        py::arg("name"), py::arg("defaultval") = 0);
    m.def(
        "get_float_attribute",
        [](const std::string& name, float def) {
            return OIIO::get_float_attribute(name, def);
        },
        py::arg("name"), py::arg("defaultval") = 0.0f);
    m.def(
        "get_string_attribute",
        [](const std::string& name, const std::string& def) {
            return PY_STR(std::string(OIIO::get_string_attribute(name, def)));
        },
        py::arg("name"), py::arg("defaultval") = "");
    m.def("getattribute", &oiio_getattribute_typed);
    m.def(
        "is_imageio_format_name",
        [](const std::string& name) {
            return OIIO::is_imageio_format_name(name);
        },
        py::arg("name"));
    m.attr("AutoStride")          = AutoStride;
    m.attr("openimageio_version") = OIIO_VERSION;
    m.attr("VERSION")             = OIIO_VERSION;
    m.attr("VERSION_STRING")      = PY_STR(OIIO_VERSION_STRING);
    m.attr("VERSION_MAJOR")       = OIIO_VERSION_MAJOR;
    m.attr("VERSION_MINOR")       = OIIO_VERSION_MINOR;
    m.attr("VERSION_PATCH")       = OIIO_VERSION_PATCH;
    m.attr("INTRO_STRING")        = PY_STR(OIIO_INTRO_STRING);
    m.attr("__version__")         = PY_STR(OIIO_VERSION_STRING);
}

}  // namespace PyOpenImageIO
<commit_msg>Fix identifier not found error on MSVC (#3168)<commit_after>// Copyright 2008-present Contributors to the OpenImageIO project.
// SPDX-License-Identifier: BSD-3-Clause
// https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md

#include "py_oiio.h"

#include <OpenImageIO/sysutil.h>

namespace PyOpenImageIO {

const char*
python_array_code(TypeDesc format)
{
    switch (format.basetype) {
    case TypeDesc::UINT8: return "uint8";
    case TypeDesc::INT8: return "int8";
    case TypeDesc::UINT16: return "uint16";
    case TypeDesc::INT16: return "int16";
    case TypeDesc::UINT32: return "uint32";
    case TypeDesc::INT32: return "int32";
    case TypeDesc::FLOAT: return "float";
    case TypeDesc::DOUBLE: return "double";
    case TypeDesc::HALF: return "half";
    default:
        // For any other type, including UNKNOWN, pack it into an
        // unsigned byte array.
        return "B";
    }
}

TypeDesc
typedesc_from_python_array_code(string_view code)
{
    TypeDesc t(code);
    if (!t.is_unknown())
        return t;

    if (code == "b" || code == "c")
        return TypeDesc::INT8;
    if (code == "B")
        return TypeDesc::UINT8;
    if (code == "h")
        return TypeDesc::INT16;
    if (code == "H")
        return TypeDesc::UINT16;
    if (code == "i")
        return TypeDesc::INT;
    if (code == "I")
        return TypeDesc::UINT;
    if (code == "l")
        return TypeDesc::INT64;
    if (code == "L")
        return TypeDesc::UINT64;
    if (code == "f")
        return TypeDesc::FLOAT;
    if (code == "d")
        return TypeDesc::DOUBLE;
    if (code == "float16" || code == "e")
        return TypeDesc::HALF;
    return TypeDesc::UNKNOWN;
}

oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf)
{
    if (pybuf.format.size())
        format = typedesc_from_python_array_code(pybuf.format);
    if (format != TypeUnknown) {
        data    = pybuf.ptr;
        xstride = format.size();
        size    = 1;
        for (int i = pybuf.ndim - 1; i >= 0; --i) {
            if (pybuf.strides[i] != py::ssize_t(size * xstride)) {
                // Just can't handle non-contiguous strides
                format = TypeUnknown;
                size   = 0;
                break;
            }
            size *= pybuf.shape[i];
        }
    }
}

oiio_bufinfo::oiio_bufinfo(const py::buffer_info& pybuf, int nchans, int width,
                           int height, int depth, int pixeldims)
{
    if (pybuf.format.size())
        format = typedesc_from_python_array_code(pybuf.format);
    if (size_t(pybuf.itemsize) != format.size()
        || pybuf.size
               != int64_t(width) * int64_t(height) * int64_t(depth * nchans)) {
        format = TypeUnknown;  // Something went wrong
        error  = Strutil::sprintf(
            "buffer is wrong size (expected %dx%dx%dx%d, got total %d)", depth,
            height, width, nchans, pybuf.size);
        return;
    }
    size = pybuf.size;
    if (pixeldims == 3) {
        // Reading a 3D volumetric cube
        if (pybuf.ndim == 4 && pybuf.shape[0] == depth
            && pybuf.shape[1] == height && pybuf.shape[2] == width
            && pybuf.shape[3] == nchans) {
            // passed from python as [z][y][x][c]
            xstride = pybuf.strides[2];
            ystride = pybuf.strides[1];
            zstride = pybuf.strides[0];
        } else if (pybuf.ndim == 3 && pybuf.shape[0] == depth
                   && pybuf.shape[1] == height
                   && pybuf.shape[2] == width * nchans) {
            // passed from python as [z][y][xpixel] -- chans mushed together
            xstride = pybuf.strides[2];
            ystride = pybuf.strides[1];
            zstride = pybuf.strides[0];
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = "Bad dimensions of pixel data";
        }
    } else if (pixeldims == 2) {
        // Reading an 2D image rectangle
        if (pybuf.ndim == 3 && pybuf.shape[0] == height
            && pybuf.shape[1] == width && pybuf.shape[2] == nchans) {
            // passed from python as [y][x][c]
            xstride = pybuf.strides[1];
            ystride = pybuf.strides[0];
        } else if (pybuf.ndim == 2) {
            // Somebody collapsed a dimsision. Is it [pixel][c] with x&y
            // combined, or is it [y][xpixel] with channels mushed together?
            if (pybuf.shape[0] == width * height && pybuf.shape[1] == nchans)
                xstride = pybuf.strides[0];
            else if (pybuf.shape[0] == height
                     && pybuf.shape[1] == width * nchans) {
                ystride = pybuf.strides[0];
                xstride = pybuf.strides[0] * nchans;
            } else {
                format = TypeUnknown;  // error
                error  = Strutil::sprintf(
                    "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                    pixeldims, pybuf.ndim);
            }
        } else if (pybuf.ndim == 1
                   && pybuf.shape[0] == height * width * nchans) {
            // all pixels & channels smushed together
            // just rely on autostride
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = Strutil::sprintf(
                "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                pixeldims, pybuf.ndim);
        }
    } else if (pixeldims == 1) {
        // Reading a 1D scanline span
        if (pybuf.ndim == 2 && pybuf.shape[0] == width
            && pybuf.shape[1] == nchans) {
            // passed from python as [x][c]
            xstride = pybuf.strides[0];
        } else if (pybuf.ndim == 1 && pybuf.shape[0] == width * nchans) {
            // all pixels & channels smushed together
            xstride = pybuf.strides[0] * nchans;
        } else {
            format = TypeUnknown;  // No idea what's going on -- error
            error  = Strutil::sprintf(
                "Can't figure out array shape (pixeldims=%d, pydim=%d)",
                pixeldims, pybuf.ndim);
        }
    } else {
        error = Strutil::sprintf(
            "Can't figure out array shape (pixeldims=%d, pydim=%d)", pixeldims,
            pybuf.ndim);
    }

    if (nchans > 1 && size_t(pybuf.strides.back()) != format.size()) {
        format = TypeUnknown;  // can't handle noncontig channels
        error  = "Can't handle numpy array with noncontiguous channels";
    }
    if (format != TypeUnknown)
        data = pybuf.ptr;
}

bool
oiio_attribute_typed(const std::string& name, TypeDesc type,
                     const py::object& obj)
{
    if (type.basetype == TypeDesc::INT) {
        std::vector<int> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate)
            return OIIO::attribute(name, type, &vals[0]);
        return false;
    }
    if (type.basetype == TypeDesc::FLOAT) {
        std::vector<float> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate)
            return OIIO::attribute(name, type, &vals[0]);
        return false;
    }
    if (type.basetype == TypeDesc::STRING) {
        std::vector<std::string> vals;
        py_to_stdvector(vals, obj);
        if (vals.size() == type.numelements() * type.aggregate) {
            std::vector<ustring> u;
            for (auto& val : vals)
                u.emplace_back(val);
            return OIIO::attribute(name, type, &u[0]);
        }
        return false;
    }
    return false;
}

static py::object
oiio_getattribute_typed(const std::string& name, TypeDesc type = TypeUnknown)
{
    if (type == TypeDesc::UNKNOWN)
        return py::none();
    char* data = OIIO_ALLOCA(char, type.size());
    if (!OIIO::getattribute(name, type, data))
        return py::none();
    if (type.basetype == TypeDesc::INT)
        return C_to_val_or_tuple((const int*)data, type);
    if (type.basetype == TypeDesc::FLOAT)
        return C_to_val_or_tuple((const float*)data, type);
    if (type.basetype == TypeDesc::STRING)
        return C_to_val_or_tuple((const char**)data, type);
    return py::none();
}

// This OIIO_DECLARE_PYMODULE mojo is necessary if we want to pass in the
// MODULE name as a #define. Google for Argument-Prescan for additional
// info on why this is necessary

#define OIIO_DECLARE_PYMODULE(x) PYBIND11_MODULE(x, m)

OIIO_DECLARE_PYMODULE(PYMODULE_NAME)
{
    using namespace pybind11::literals;

    if (Sysutil::getenv("OPENIMAGEIO_DEBUG_PYTHON") != "")
        Sysutil::setup_crash_stacktrace("stdout");

    // Basic helper classes
    declare_typedesc(m);
    declare_paramvalue(m);
    declare_imagespec(m);
    declare_roi(m);
    declare_deepdata(m);
    declare_colorconfig(m);

    // Main OIIO I/O classes
    declare_imageinput(m);
    declare_imageoutput(m);
    declare_imagebuf(m);
    declare_imagecache(m);

    // TextureSys classes
    declare_wrap(m);
    declare_mipmpode(m);
    declare_interpmode(m);
    declare_textureopt(m);
    declare_texturesystem(m);

    declare_imagebufalgo(m);

    // Global (OpenImageIO scope) functions and symbols
    m.def("geterror", &OIIO::geterror, "clear"_a = true);
    m.def("attribute", [](const std::string& name, float val) {
        OIIO::attribute(name, val);
    });
    m.def("attribute",
          [](const std::string& name, int val) { OIIO::attribute(name, val); });
    m.def("attribute", [](const std::string& name, const std::string& val) {
        OIIO::attribute(name, val);
    });
    m.def("attribute",
          [](const std::string& name, TypeDesc type, const py::object& obj) {
              oiio_attribute_typed(name, type, obj);
          });

    m.def(
        "get_int_attribute",
        [](const std::string& name, int def) {
            return OIIO::get_int_attribute(name, def);
        },
        py::arg("name"), py::arg("defaultval") = 0);
    m.def(
        "get_float_attribute",
        [](const std::string& name, float def) {
            return OIIO::get_float_attribute(name, def);
        },
        py::arg("name"), py::arg("defaultval") = 0.0f);
    m.def(
        "get_string_attribute",
        [](const std::string& name, const std::string& def) {
            return PY_STR(std::string(OIIO::get_string_attribute(name, def)));
        },
        py::arg("name"), py::arg("defaultval") = "");
    m.def("getattribute", &oiio_getattribute_typed);
    m.def(
        "is_imageio_format_name",
        [](const std::string& name) {
            return OIIO::is_imageio_format_name(name);
        },
        py::arg("name"));
    m.attr("AutoStride")          = AutoStride;
    m.attr("openimageio_version") = OIIO_VERSION;
    m.attr("VERSION")             = OIIO_VERSION;
    m.attr("VERSION_STRING")      = PY_STR(OIIO_VERSION_STRING);
    m.attr("VERSION_MAJOR")       = OIIO_VERSION_MAJOR;
    m.attr("VERSION_MINOR")       = OIIO_VERSION_MINOR;
    m.attr("VERSION_PATCH")       = OIIO_VERSION_PATCH;
    m.attr("INTRO_STRING")        = PY_STR(OIIO_INTRO_STRING);
    m.attr("__version__")         = PY_STR(OIIO_VERSION_STRING);
}

}  // namespace PyOpenImageIO
<|endoftext|>