diff options
| -rw-r--r-- | src/camera.cc | 60 | ||||
| -rw-r--r-- | src/camera.h | 1 | ||||
| -rw-r--r-- | src/decoder.cc | 17 | ||||
| -rw-r--r-- | src/encoder.cc | 93 | ||||
| -rw-r--r-- | src/encoder.h | 5 | ||||
| -rw-r--r-- | src/mainwindow.cc | 17 | ||||
| -rw-r--r-- | src/mainwindow.h | 1 | ||||
| -rw-r--r-- | src/miav_config.cc | 4 | ||||
| -rw-r--r-- | src/network.cc | 39 | ||||
| -rw-r--r-- | src/network.h | 4 | ||||
| -rw-r--r-- | src/player.cc | 35 | ||||
| -rw-r--r-- | src/player.h | 9 | ||||
| -rw-r--r-- | src/socket.cc | 54 | ||||
| -rw-r--r-- | src/socket.h | 7 | 
14 files changed, 226 insertions, 120 deletions
| diff --git a/src/camera.cc b/src/camera.cc index 0ba3da9..9e9fd82 100644 --- a/src/camera.cc +++ b/src/camera.cc @@ -34,13 +34,14 @@ Camera::Camera()  void Camera::connect(const char *ip, const int port)  {    errorstatus = new Error(); +  initialized = false;    pthread_mutex_init (&mutex, NULL);    //mutex = PTHREAD_MUTEX_INITIALIZER; -   +  /*    	AVFormatContext *ifmtctx;  	AVFormatContext *ofmtctx; - +  */    running = 1;  	int channel = 0; @@ -63,8 +64,10 @@ void Camera::connect(const char *ip, const int port)                          player_queue,                          &mutex,                          &running); -  //  ifmtctx = decoder->fc; -  if(!decoder->fc) return; +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (decoder)."); +    return; +  }  	encoder = new Encoder(errorstatus,                           ip, port, @@ -72,17 +75,38 @@ void Camera::connect(const char *ip, const int port)                          encode_queue,                          &mutex,                          &running); -  ofmtctx = encoder->fc; +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (encoder)."); +    return; +  }  	player = new Player(errorstatus,                        &running,                        &player_sem,                        player_queue,                        &mutex); +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (player)."); +    return; +  }    pthread_create (&decodetid, NULL, thread_run, decoder); +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (decoder thread)."); +    return; +  }    pthread_create (&encodetid, NULL, thread_run, encoder); +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (encoder thread)."); +    return; +  }    pthread_create (&playertid, NULL, thread_run, player); +  if(errorstatus->hasError()) { +    errorstatus->pushError("Camera initialization failed (player thread)."); +    return; +  } + +  initialized = true;  }  Camera::~Camera() @@ -110,36 +134,46 @@ Camera::~Camera()  void Camera::setCpr(char *newcpr)  { -  encoder->setCpr(newcpr); +  if(initialized) encoder->setCpr(newcpr); +  else errorstatus->pushError("Camera not initialized."); +  }  void Camera::start()  { -  encoder->start(); +  if(initialized) encoder->start(); +  else errorstatus->pushError("Camera not initialized.");  }  void Camera::stop()  { -  encoder->stop(); +  if(initialized) encoder->stop(); +  else errorstatus->pushError("Camera not initialized.");  }  void Camera::freeze()  {    // FIXME: Ensure they freeze the same frame, i.e. the player  -  //        shows the same frame that is actually fronzen on the server. -  player->stop(); -  encoder->freeze(); +  //        shows the same frame that is actually frozen on the server. +  if(initialized) { +    player->stop(); +    encoder->freeze(); +  } else { +    errorstatus->pushError("Camera not initialized."); +  }  }  void Camera::unfreeze()  { -  player->start(); +  if(initialized) player->start(); +  else errorstatus->pushError("Camera not initialized.");  }  void Camera::snapshot()  { -  encoder->shoot(); +  if(initialized) encoder->shoot(); +  else errorstatus->pushError("Camera not initialized.");  }  Error *Camera::errorObject() diff --git a/src/camera.h b/src/camera.h index 4f58d7e..25e1972 100644 --- a/src/camera.h +++ b/src/camera.h @@ -76,6 +76,7 @@ public:  private:    // Error object passed to all sub objects.    Error *errorstatus; +  bool initialized;  	pthread_t playertid;  	pthread_t decodetid; diff --git a/src/decoder.cc b/src/decoder.cc index dfddd87..bf9b75c 100644 --- a/src/decoder.cc +++ b/src/decoder.cc @@ -52,7 +52,8 @@ Decoder::Decoder(Error* err,    if(!(iformat = av_find_input_format("dv1394"))) {      errobj->pushError("Failed to get input format dv1394."); -    exit(1); +    fc = NULL;  +    return;    }    dvpars.device  = device;	/* "/dev/dv1394"; */ @@ -61,23 +62,27 @@ Decoder::Decoder(Error* err,    if(av_open_input_file(&ifc, "", iformat, 0, &dvpars) < 0) {      errobj->pushError("Device is in use."); -    fc = NULL; return; +    fc = NULL;  +    return;    }    if(av_find_stream_info(ifc) < 0) {      errobj->pushError("Could not find enough parameters."); -    fc = NULL; return; +    fc = NULL;  +    return;    }    dump_format(ifc, 1, "", 0);    if(!(dec_codec = avcodec_find_decoder(ifc->streams[0]->codec.codec_id))) {      errobj->pushError("Unsupported codec for input stream."); -    fc = NULL; return; +    fc = NULL; +    return;    }    if(avcodec_open(&ifc->streams[0]->codec, dec_codec) < 0) {      errobj->pushError("Error while opening codec for input stream."); -    fc = NULL; return; +    fc = NULL;  +    return;    }    fc = ifc; @@ -126,7 +131,7 @@ void Decoder::decode()        if(ret < 0) {          errobj->pushError("Error while decoding stream."); -        exit(1); +        return;        }        len -= ret; diff --git a/src/encoder.cc b/src/encoder.cc index ee60a8f..fc19921 100644 --- a/src/encoder.cc +++ b/src/encoder.cc @@ -34,13 +34,10 @@ Encoder::Encoder(Error* err,  {    errobj = err; -  sprintf(ip, gip); +  strcpy(ip, gip);    port = gport;    memset(cpr, 0, sizeof(cpr)); -  printf("[ip:   %s]\n", ip); -  printf("[port: %d]\n", port); -    sem = gsem;    queue = gqueue;    mutex = gmutex; @@ -67,95 +64,93 @@ Encoder::~Encoder()  } -void Encoder::setCpr(char *newcpr) -{ -  sprintf(cpr, newcpr); -} - -  void Encoder::encode()  {     DVFrame *f; +  printf("0\n");    while(*running) { +    printf("1\n");      sem_wait(sem); -    /* +    printf("2\n");      pthread_mutex_lock(mutex); -    while((f = queue->pop())) delete f; +    f = queue->pop();      pthread_mutex_unlock(mutex); - -    while(record) { -    sem_wait(sem); -    */ +     +    printf("3\n"); +    if((f && record) ||  +       (freeze_request != freeze_value) ||  +       (shoot_request != shoot_value)) { +      n_header h; -      pthread_mutex_lock(mutex); -      f = queue->pop(); -      pthread_mutex_unlock(mutex); +      h.header_type = DATA_HEADER; +      sprintf(h.header.h_data.cpr, cpr); +      h.header.h_data.freeze = (freeze_request != freeze_value); +      h.header.h_data.snapshot = (shoot_request != shoot_value); +      h.header.h_data.record = record; +         +      if(freeze_request != freeze_value) freeze_value = freeze_request; +      if(shoot_request != shoot_value) shoot_value = shoot_request; -      if((f && record) || (freeze_request != freeze_value) || (shoot_request != shoot_value)) { -        fprintf(stderr, "Rec!\n"); -        n_header h; - -        h.header_type = DATA_HEADER; -        sprintf(h.header.h_data.cpr, cpr); -        h.header.h_data.freeze = (freeze_request != freeze_value); -        h.header.h_data.snapshot = (shoot_request != shoot_value); -        h.header.h_data.record = record; - -        if(freeze_request != freeze_value) freeze_value = freeze_request; -        if(shoot_request != shoot_value) shoot_value = shoot_request; - -        n->sendPackage(&h, f->frame, sizeof(f->frame)); -      } - -      if(f) delete f; -      //} +      n->sendPackage(&h, f->frame, sizeof(f->frame)); +    } +     +    if(f) delete f;    }    pthread_exit(NULL);  } + +void Encoder::setCpr(char *newcpr) +{ +  strcpy(cpr, newcpr); +} + +  void Encoder::freeze()  {      if(!s) { -    s = new Socket(port); +    s = new Socket(port, errobj);      s->sconnect(ip); -    n = new Network(s); +    n = new Network(s, errobj);    } -  freeze_request = 1 - freeze_request; +  if(!errobj->hasError()) freeze_request = 1 - freeze_request;  } +  void Encoder::shoot()  {    if(!s) { -    s = new Socket(port); +    s = new Socket(port, errobj);      s->sconnect(ip); -    n = new Network(s); +    n = new Network(s, errobj);    } -  shoot_request = 1 - shoot_request; +  if(!errobj->hasError()) shoot_request = 1 - shoot_request;  } +  void Encoder::run() {    encode();  } +  void Encoder::start() { -  printf("GO!\n");    if(!s) { -    s = new Socket(port); +    s = new Socket(port, errobj);      s->sconnect(ip); -    n = new Network(s); +    n = new Network(s, errobj);    } -  record = 1; +  if(!errobj->hasError()) record = 1;  } +  void Encoder::stop() { -  printf("STOP!\n"); +  record = 0;    if(s) {      if(n) delete n;      delete s;      s = NULL;      n = NULL;    } -  record = 0;  } diff --git a/src/encoder.h b/src/encoder.h index 1b459b9..8a458c8 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -42,7 +42,10 @@  #define VIDEO_BUFFER_SIZE	(1024*1024) - +/** + * This class contains code for sending the video stream and the snapshots + * over the network, to the MIaV server. + */  class Encoder : public Thread {  public:    Encoder(Error* err, diff --git a/src/mainwindow.cc b/src/mainwindow.cc index dc5b5e2..212dfe7 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -92,7 +92,8 @@ MainWindow::MainWindow( QWidget* parent, const char* name )    cam_error = camera->errorObject();    while(cam_error->hasError()) { -    MessageBox(this, "", cam_error->popErrorString().c_str(), TYPE_OK, ICON_ERROR).exec(); +    MessageBox(this, "", cam_error->popErrorString().c_str(),  +               TYPE_OK, ICON_ERROR).exec();    }    recording = false; @@ -238,6 +239,14 @@ void MainWindow::cpr_clicked()    }  } +void MainWindow::checkErrors() +{ +  while(cam_error->hasError()) { +    MessageBox(this, "", cam_error->popErrorString().c_str(),  +               TYPE_OK, ICON_ERROR).exec(); +  } +} +  void MainWindow::rec_clicked()  {    recording = 1 - recording; @@ -245,10 +254,12 @@ void MainWindow::rec_clicked()      img_recedge->setBackgroundColor(red);      btn_rec->setPixmap(*pix_stop);      camera->start(); +    checkErrors();    } else {      img_recedge->setBackgroundColor(QColor(160,160,160));      btn_rec->setPixmap(*pix_record);      camera->stop(); +    checkErrors();    }  } @@ -257,6 +268,7 @@ void MainWindow::shoot_clicked()    QImage image;    camera->snapshot(); +  checkErrors();    image = img_live->getScreenshot();    image = image.smoothScale(img_history[0]->width(), img_history[0]->height()); @@ -270,6 +282,7 @@ void MainWindow::shoot_clicked()    if(frozen) {      camera->unfreeze(); +    checkErrors();      btn_freeze->setOn(false);      frozen = false;    } @@ -279,9 +292,11 @@ void MainWindow::freeze_clicked()  {    if(frozen) {      camera->unfreeze(); +    checkErrors();      frozen = false;    } else {      camera->freeze(); +    checkErrors();      frozen = true;    }  } diff --git a/src/mainwindow.h b/src/mainwindow.h index 88e924e..443ef83 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -60,6 +60,7 @@ public slots:    void freeze_clicked();  private: +  void checkErrors();    void createGui();    Camera *camera; diff --git a/src/miav_config.cc b/src/miav_config.cc index 05e0d06..1c2d0c6 100644 --- a/src/miav_config.cc +++ b/src/miav_config.cc @@ -75,20 +75,16 @@ _cfg *MiavConfig::addConfig(_cfg *parent, char* conf)    _cfg *cfg; -  printf("[%s]\n", conf); -    cfg = (_cfg*) malloc(sizeof(_cfg));    if(!parent) configs = cfg;    int namelen = strchr(conf, '=') - conf;    char* name = (char*)calloc(namelen + 1, 1);    strncpy(name, conf, namelen); -  printf("name [%s]#%d - ", name, namelen);    int vallen = conf + strlen(conf) - (strchr(conf, '=') + 1);    char* val = (char*)calloc(vallen + 1, 1);    strncpy(val, conf + strlen(conf) - vallen, vallen); -  printf("val [%s]#%d\n", val, vallen);    cfg->name = new string((const char*)name);    free(name); diff --git a/src/network.cc b/src/network.cc index 8e99855..3c7fd7e 100644 --- a/src/network.cc +++ b/src/network.cc @@ -31,8 +31,9 @@  #include <string.h>  #include <sys/socket.h>  -Network::Network(Socket *gs) +Network::Network(Socket *gs, Error* err)  { +  error = err;    s = gs;  } @@ -43,14 +44,18 @@ Network::~Network()  int Network::write(void *buf, int size)  {    if(!s->isConnected()) { -    fprintf(stderr, "Write attempted to a socket not connected!\n"); +    char errbuf[] = "Write attempted to a socket not connected!\0"; +    if(error) error->pushError(errbuf); +    else fprintf(stderr, errbuf);      return 0;    }    int n = send(s->ssocket, buf, size, MSG_WAITALL); -  if(n == -1) printf("An error occurred!\n"); - -  //  printf("Sent: %s\n", buf); +  if(n == -1) { +    char errbuf[] = "An error occurred!\0"; +    if(error) error->pushError(errbuf); +    else fprintf(stderr, errbuf); +  }    return n;  } @@ -58,14 +63,18 @@ int Network::write(void *buf, int size)  int Network::read(void *buf, int size)  {    if(!s->isConnected()) { -    fprintf(stderr, "Read attempted from a socket not connected!\n"); +    char errbuf[] = "Read attempted from a socket not connected!\0"; +    if(error) error->pushError(errbuf); +    else fprintf(stderr, errbuf);      return 0;    }    int n = recv(s->ssocket, buf, size, MSG_WAITALL); -  if(n == -1) printf("An error occurred!\n"); -   -  //  printf("Recieved: %s\n", buf); +  if(n == -1) { +    char errbuf[] = "An error occurred!\0"; +    if(error) error->pushError(errbuf); +    else fprintf(stderr, errbuf); +  }    return n;  } @@ -100,7 +109,9 @@ int Network::sendPackage(n_header *h, void* buf, int bufsz)    int n = sendmsg(s->ssocket, &msg, 0);    if(n < 0) { -    perror("sendmsg"); +    char errbuf[] = "A network error ocurred during sendPackage!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return -1;    } @@ -126,12 +137,16 @@ int Network::recvPackage(n_header *h, void* buf, int bufsz)    int n = recvmsg(s->ssocket, &msg, MSG_WAITALL);    if(n < 0) { -    perror("recvmsg"); +    char errbuf[] = "A network error ocurred during recvPackage!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return -1;    }    if(msg.msg_iovlen != 2) { -    fprintf(stderr, "Wrong package format!\n"); +    char errbuf[] = "Wrong package format!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return -1;    }    return n; diff --git a/src/network.h b/src/network.h index 72d5826..d1f68c0 100644 --- a/src/network.h +++ b/src/network.h @@ -29,10 +29,11 @@  #include "socket.h"  #include "package.h" +#include "error.h"  class Network {  public: -  Network(Socket *gs); +  Network(Socket *gs, Error* err = NULL);    ~Network();    // Raw communication @@ -44,6 +45,7 @@ public:    int recvPackage(n_header *h, void* buf, int bufsz);  private: +  Error *error;    Socket *s;  }; diff --git a/src/player.cc b/src/player.cc index 85a961a..db5b108 100644 --- a/src/player.cc +++ b/src/player.cc @@ -31,6 +31,9 @@ Player::Player(Error *err,                 Queue<FFFrame> *gqueue,                 pthread_mutex_t *gmutex)  { +  // No errors has ocurred... yet! +  noErrors = true; +    char errbuf[256];    errobj = err; @@ -42,28 +45,39 @@ Player::Player(Error *err,   	sem_init(&play_sem, 0, 1);    if(SDL_Init(SDL_INIT_VIDEO) < 0) { -    sprintf(errbuf, "Unable to init SDL: %s\n", SDL_GetError()); +    sprintf(errbuf, "Unable to init SDL: %s.", SDL_GetError());      errobj->pushError(errbuf); +    noErrors = false;      return;    } +    screen = SDL_SetVideoMode(DISPLAYWIDTH,                               DISPLAYHEIGHT,  -                            16,  -                            SDL_HWSURFACE|SDL_ANYFORMAT|SDL_HWACCEL); +                            0, // 0 bpp means 'use current display depth'  +                            SDL_HWSURFACE | SDL_ANYFORMAT | SDL_HWACCEL); +    if(!screen) { -    sprintf(errbuf, "Unable to set %dx%d video: %s\n",  +    sprintf(errbuf, "Unable to set %dx%d video: %s.",               DISPLAYWIDTH, DISPLAYHEIGHT, SDL_GetError());      errobj->pushError(errbuf); +    noErrors = false;      return;    } -  overlay = SDL_CreateYUVOverlay(DISPLAYWIDTH, DISPLAYHEIGHT, SDL_IYUV_OVERLAY, screen); +  overlay = SDL_CreateYUVOverlay(DISPLAYWIDTH, +                                 DISPLAYHEIGHT, +                                 SDL_IYUV_OVERLAY, screen); +  if(!overlay) { +    sprintf(errbuf, "Unable to create SDL overlay: %s.", SDL_GetError()); +    errobj->pushError(errbuf); +    noErrors = false; +    return; +  }  }  Player::~Player()  { -  if(overlay) -    SDL_FreeYUVOverlay(overlay); +  SDL_FreeYUVOverlay(overlay);    SDL_Quit();  } @@ -76,8 +90,9 @@ void Player::player()    int i;    struct timespec ts; -  //  rect.x = 20; -  //  rect.y = 182; +  if(!noErrors) return; // FIXME: Gracefully exit... +   +  // Setup the displayarea.    rect.x = 0;    rect.y = 0;    rect.w = DISPLAYWIDTH; @@ -94,7 +109,7 @@ void Player::player()      sem_wait(&play_sem);      sem_post(&play_sem); -    if(!SDL_WaitEvent(&event)) break; // FIXME: Gracefull exit...  +    if(!SDL_WaitEvent(&event)) break; // FIXME: Gracefully exit...       switch(event.type) {      case SDL_KEYDOWN: diff --git a/src/player.h b/src/player.h index 3e7efb6..2af4165 100644 --- a/src/player.h +++ b/src/player.h @@ -44,9 +44,13 @@  #include <qwidget.h> -#define DISPLAYWIDTH	720	/* FIXME: These numbers suck! */ +#define DISPLAYWIDTH	720	// FIXME: These numbers suck!  #define DISPLAYHEIGHT	576 +/** + * This class contains the SDL code, for displaying the movie frames + * in the widget, using hardware overlay. + */  class Player : public Thread {  public:    Player(Error* err, @@ -66,6 +70,9 @@ private:    void player(); +  // Used to verify if errors ha ocurred previously. +  bool noErrors; +    volatile int *running;    sem_t	*sem;    Queue<FFFrame> *queue; diff --git a/src/socket.cc b/src/socket.cc index 7cee58a..851a6ea 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -26,33 +26,36 @@  #include "socket.h" -Socket::Socket() +Socket::Socket(Error* _err)  { +  error = _err;    connected = false;    err = 0;  } -Socket::Socket(u_short port) +Socket::Socket(u_short port, Error* _err)  { +  error = _err;    connected = false;    err = 0; -  //  printf("Socket on port: %d\n", port); -    // create socket -  ssocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); // PF_INET: ipv4, PF_INET6: ipv6 -                                                      // tcp: IPPROTO_TCP -                                                      // upd: IPPROTO_UDP +  ssocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  +  // PF_INET: ipv4, PF_INET6: ipv6 +  // tcp: IPPROTO_TCP +  // upd: IPPROTO_UDP +    if (ssocket < 0) {      err = 1; -    perror("Socket: socket() failed"); +    char errbuf[] = "Socket: socket() failed!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);    } -  socketaddr.sin_family = AF_INET;       // Use "internet protocol" IP -  socketaddr.sin_port = htons(port);            // connect to that port -  socketaddr.sin_addr.s_addr = INADDR_ANY;// INADDR_ANY puts your IP address automatically  - -  //  fprintf(stderr, "Socket created\n"); +  socketaddr.sin_family = AF_INET; // Use "internet protocol" IP +  socketaddr.sin_port = htons(port);  // connect to that port +  socketaddr.sin_addr.s_addr = INADDR_ANY; +  // INADDR_ANY puts your IP address automatically   } @@ -69,7 +72,9 @@ Socket Socket::slisten()    Socket s = Socket();    if(err) { -    perror("Socket: No socket present"); +    char errbuf[] = "Socket: No socket present!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return s;    }    if(!connected) { @@ -81,10 +86,13 @@ Socket Socket::slisten()        return s;      } -    // start listen for connection - kernel will accept connection requests (max 5 in queue) +    // start listen for connection - kernel will accept connection  +    // requests (max 5 in queue)      err = listen(ssocket, 5);      if(err) { -      perror("Socket: listen() failed"); +      char errbuf[] = "Socket: listen() failed!\0"; +      if(error) error->pushError(errbuf); +      else perror(errbuf);        return s;      }    } @@ -92,14 +100,18 @@ Socket Socket::slisten()    // accept new connection and get its connection descriptor    int csalen = sizeof(s.socketaddr); -  s.ssocket = accept(ssocket, (struct sockaddr*)&s.socketaddr, (socklen_t*)&csalen); +  s.ssocket = accept(ssocket,  +                     (struct sockaddr*)&s.socketaddr,  +                     (socklen_t*)&csalen); +    if (s.ssocket < 0) {      err = 1; -    perror("Socket: accept() failed"); +    char errbuf[] = "Socket: accept() failed!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return s;    } -  fprintf(stderr, "Socket connected\n");    connected = true;    s.connected = true;    return s; @@ -119,7 +131,9 @@ int Socket::sconnect(char *ip)    err = connect(ssocket, (struct sockaddr*)&socketaddr, sizeof(socketaddr));    if (err) { -    perror("Socket: connect() failed"); +    char errbuf[] = "Socket: connect() failed!\0"; +    if(error) error->pushError(errbuf); +    else perror(errbuf);      return err;    }    //  fprintf(stderr, "Socket connected\n"); diff --git a/src/socket.h b/src/socket.h index d0d85af..70dc7fe 100644 --- a/src/socket.h +++ b/src/socket.h @@ -36,10 +36,12 @@  #include <sys/socket.h>  #include <arpa/inet.h> +#include "error.h" +  class Socket {  public: -  Socket(); -  Socket(u_short port); +  Socket(Error *_err = NULL); +  Socket(u_short port, Error *_err = NULL);    ~Socket();    Socket slisten();    int sconnect(char *ip); @@ -50,6 +52,7 @@ public:    bool connected;  private: +  Error *error;    int err;  }; | 
