CPPMyth
Library to interoperate with MythTV server
mythprototransfer.cpp
1 /*
2  * Copyright (C) 2014 Jean-Luc Barriere
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, or (at your option)
7  * 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; see the file COPYING. If not, write to
16  * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17  * MA 02110-1301 USA
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21 
22 #include "mythprototransfer.h"
23 #include "../private/debug.h"
24 #include "../private/socket.h"
25 #include "../private/os/threads/mutex.h"
26 #include "../private/builtin.h"
27 
28 #include <limits>
29 #include <cstdio>
30 
31 using namespace Myth;
32 
37 
38 ProtoTransfer::ProtoTransfer(const std::string& server, unsigned port, const std::string& pathname, const std::string& sgname)
39 : ProtoBase(server, port)
40 , m_fileSize(0)
41 , m_filePosition(0)
42 , m_fileRequest(0)
43 , m_fileId(0)
44 , m_pathName(pathname)
45 , m_storageGroupName(sgname)
46 {
47 }
48 
49 bool ProtoTransfer::Open()
50 {
51  bool ok = false;
52 
53  if (IsOpen())
54  return true;
55  if (!OpenConnection(PROTO_TRANSFER_RCVBUF))
56  return false;
57 
58  if (m_protoVersion >= 75)
59  ok = Announce75();
60 
61  if (!ok)
62  {
63  m_hang = true; // set hang to close without notice
64  Close();
65  return false;
66  }
67  return true;
68 }
69 
70 void ProtoTransfer::Close()
71 {
72  OS::CLockGuard lock(*m_mutex);
73  ProtoBase::Close();
74  // Clean hanging and disable retry
75  m_tainted = m_hang = false;
76  // Reset transfer
77  m_filePosition = m_fileRequest = 0;
78  m_fileId = 0;
79 }
80 
81 void ProtoTransfer::Lock()
82 {
83  m_mutex->Lock();
84 }
85 
86 void ProtoTransfer::Unlock()
87 {
88  m_mutex->Unlock();
89 }
90 
91 bool ProtoTransfer::TryLock()
92 {
93  return m_mutex->TryLock();
94 }
95 
97 {
98  OS::CLockGuard lock(*m_mutex);
99  int64_t unread = m_fileRequest - m_filePosition;
100  if (unread > 0)
101  {
102  char buf[PROTO_BUFFER_SIZE];
103  size_t n = (size_t)unread;
104  while (n > 0)
105  {
106  size_t s = (n > PROTO_BUFFER_SIZE ? PROTO_BUFFER_SIZE : n);
107  if(m_socket->ReceiveData(buf, s) != s)
108  break;
109  n -= s;
110  }
111  DBG(DBG_DEBUG, "%s: unreaded bytes (%u)\n", __FUNCTION__, (unsigned)n);
112  // Reset position regardless bytes read
113  m_filePosition = m_fileRequest;
114  }
115 }
116 
117 bool ProtoTransfer::Announce75()
118 {
119  OS::CLockGuard lock(*m_mutex);
120  m_filePosition = m_fileSize = m_fileRequest = 0;
121  std::string cmd("ANN FileTransfer ");
122  cmd.append(m_socket->GetMyHostName());
123  cmd.append(" 0 0 1000" PROTO_STR_SEPARATOR);
124  cmd.append(m_pathName).append(PROTO_STR_SEPARATOR);
125  cmd.append(m_storageGroupName);
126  if (!SendCommand(cmd.c_str()))
127  return false;
128 
129  std::string field;
130  if (!ReadField(field) || !IsMessageOK(field))
131  goto out;
132  if (!ReadField(field) || 0 != string_to_uint32(field.c_str(), &m_fileId))
133  goto out;
134  if (!ReadField(field) || 0 != string_to_int64(field.c_str(), &m_fileSize))
135  goto out;
136  return true;
137 
138 out:
139  FlushMessage();
140  return false;
141 }
142 
143 uint32_t ProtoTransfer::GetFileId() const
144 {
145  return m_fileId;
146 }
147 
148 std::string ProtoTransfer::GetPathName() const
149 {
150  return m_pathName;
151 }
152 
153 std::string ProtoTransfer::GetStorageGroupName() const
154 {
155  return m_storageGroupName;
156 }
157 
158 int64_t ProtoTransfer::GetSize() const
159 {
160  OS::CLockGuard lock(*m_mutex);
161  return m_fileSize;
162 }
163 
164 int64_t ProtoTransfer::GetPosition() const
165 {
166  OS::CLockGuard lock(*m_mutex);
167  return m_filePosition;
168 }
169 
170 int64_t ProtoTransfer::GetRequested() const
171 {
172  OS::CLockGuard lock(*m_mutex);
173  return m_fileRequest;
174 }
175 
176 int64_t ProtoTransfer::GetRemaining() const
177 {
178  OS::CLockGuard lock(*m_mutex);
179  return (m_fileSize - m_filePosition);
180 }
181 
182 void ProtoTransfer::SetSize(int64_t size)
183 {
184  OS::CLockGuard lock(*m_mutex);
185  m_fileSize = size;
186 }
187 
188 void ProtoTransfer::SetPosition(int64_t position)
189 {
190  OS::CLockGuard lock(*m_mutex);
191  m_filePosition = position;
192 }
193 
194 void ProtoTransfer::SetRequested(int64_t requested)
195 {
196  OS::CLockGuard lock(*m_mutex);
197  m_fileRequest = requested;
198 }
void Flush()
Flushing unread data previously requested.
bool m_hang
Connection hang: while true allow retry.
Definition: mythprotobase.h:76
bool ReadField(std::string &field)
This is the main namespace that encloses all public classes.
Definition: mythcontrol.h:29
bool m_tainted
Connection has hung since last reset.
Definition: mythprotobase.h:77