Statistics
| Branch: | Tag: | Revision:

dvbd / unixclientsocket.cpp @ bfdb7446

History | View | Annotate | Download (4.06 KB)

1
/*
2
  Copyright 2003 John Knottenbelt
3
  
4
  This program is free software; you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation; either version 2 of the License, or
7
  (at your option) any later version.
8
 
9
  This program is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
 
14
  You should have received a copy of the GNU General Public License
15
  along with this program; if not, write to the Free Software
16
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17
*/
18

    
19
#include "unixclientsocket.h"
20
#include "inputbuffer.h"
21
#include "outputbuffer.h"
22
#include "utils.h"
23

    
24
#include <iostream>
25
#include <cstring>
26
#include <cstdlib>
27
#include <cerrno>
28
#include <unistd.h>
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
#include <sys/un.h>
32
#include <fcntl.h>
33

    
34
UnixClientSocket::UnixClientSocket(const std::string &path)
35
  : fd(-1), blocking(true), overflowed(false), input(NULL), output(NULL)
36
{
37
  connect(path);
38
}
39

    
40
UnixClientSocket::~UnixClientSocket()
41
{
42
  if (fd != -1) {
43
    close(fd);
44
    delete input;
45
    delete output;
46
  }
47
}
48

    
49
bool UnixClientSocket::connect(const std::string &path)
50
{
51
  fd = socket(PF_UNIX, SOCK_STREAM, 0);
52

    
53
  if (fd < 0) {
54
    std::cerr << "Fatal error: failed to create socket for connecting:\n"
55
              << strerror(errno) << std::endl;
56
    return false;
57
  }
58

    
59
  struct sockaddr_un addr;
60
  addr.sun_family = AF_UNIX;
61
  strcpy(addr.sun_path, path.c_str());
62

    
63
  if (::connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
64
    std::cerr << "Fatal error: failed to connect to socket " << path << "\n"
65
              << strerror(errno) << std::endl;
66
    close(fd);
67
    fd = -1;
68
    return false;
69
  }
70

    
71
  setNonBlocking(fd);
72

    
73
  input = new InputBuffer(fd, 8192, 32768);
74
  output = new OutputBuffer(fd, 8192, 32768);
75
  return true;
76
}
77

    
78
UnixClientSocket::operator bool() const
79
{
80
  return fd >= 0 && !overflowed;
81
}
82

    
83
void UnixClientSocket::setBlocking(bool mode)
84
{
85
  blocking = mode;
86
}
87

    
88
bool UnixClientSocket::isBlocking() const
89
{
90
  return blocking;
91
}
92

    
93
bool UnixClientSocket::write(const std::string &data)
94
{
95
  if (!output->write(data))
96
    return false;
97

    
98
  if (blocking)
99
    return output->flush();
100
  else
101
    return true;
102
}
103

    
104
bool UnixClientSocket::getMoreData()
105
{
106
  Select s;
107
  addSelectFDs(s);
108

    
109
  if (!blocking)
110
    s.addAlarm(0, 0);
111

    
112
  s.wait();
113

    
114
  if (!isReady(s))
115
    return false;
116

    
117
  if (!processReady(s))
118
    return false;
119

    
120
  return true;
121
}
122

    
123
int UnixClientSocket::read(char *data, int count)
124
{
125
  if (count > input->getMaxSize())
126
    return -1;
127

    
128
  if (!blocking) {
129
  tryAgain:
130
    if (count < input->getUsed()) 
131
      return input->read(data, count) ? count : -1;
132
    else if (input->getUsed() > 0) {
133
      count = input->getUsed();
134
      return input->read(data, count) ? count : -1;
135
    }
136
    else {
137
      if (getMoreData())
138
        goto tryAgain;
139
      else
140
        return -1;
141
    }
142
  }
143
  else {
144
    // Blocking read of N bytes
145
    while (input->getUsed() < count) {
146
      if (!getMoreData())
147
        return -1;
148
    };
149

    
150
    return input->read(data, count) ? count : - 1;
151
  }
152
}
153

    
154
void UnixClientSocket::addSelectFDs(Select &s) const
155
{
156
  // Write data out before accepting new data
157
  if (output->getUsed() > 0)
158
    output->addSelectFDs(s);
159
  else
160
    input->addSelectFDs(s);
161
}
162

    
163
bool UnixClientSocket::isReady(const Select &s) const
164
{
165
  return input->isReady(s) || output->isReady(s);
166
}
167

    
168
bool UnixClientSocket::processReady(const Select &s) 
169
{
170
  if (output->isReady(s)) {
171
    if (!output->process())
172
      return false;
173
  }
174
  else if (input->isReady(s)) {
175
    if (!input->process())
176
      return false;
177
  }
178
  return true;
179
}
180

    
181
bool UnixClientSocket::readLine(std::string &line)
182
{
183
  if (blocking) {
184
    while (true) {
185
      if (input->readLine(line))
186
        return true;
187

    
188
      if (input->getFree() == 0)
189
        return false;
190
      
191
      if (!getMoreData())
192
        return false;
193
    }
194
  }
195
  else 
196
    return input->readLine(line);
197
}
198

    
199
bool UnixClientSocket::writeCredentials()
200
{
201
  return output->writeCredentials();
202
}