Switch to unified view

a/upmpd/ohmetacache.cxx b/upmpd/ohmetacache.cxx
...
...
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
16
 */
17
17
18
#include <unistd.h>
18
#include <unistd.h>
19
#include <fcntl.h>
19
#include <fcntl.h>
20
#include <string.h>
20
21
21
#include <iostream>
22
#include <iostream>
22
using namespace std;
23
using namespace std;
23
24
24
#include "ohmetacache.hxx"
25
#include "ohmetacache.hxx"
25
#include "conftree.hxx"
26
#include "libupnpp/workqueue.hxx"
26
#include "libupnpp/workqueue.hxx"
27
#include "libupnpp/log.hxx"
27
#include "libupnpp/log.hxx"
28
#include "base64.hxx"
29
28
30
class SaveCacheTask {
29
class SaveCacheTask {
31
public:
30
public:
32
    SaveCacheTask(const string& fn, const mcache_type& cache)
31
    SaveCacheTask(const string& fn, const mcache_type& cache)
33
        : m_fn(fn), m_cache(cache)
32
        : m_fn(fn), m_cache(cache)
...
...
36
    string m_fn;
35
    string m_fn;
37
    mcache_type m_cache;
36
    mcache_type m_cache;
38
};
37
};
39
static WorkQueue<SaveCacheTask*> saveQueue("SaveQueue");
38
static WorkQueue<SaveCacheTask*> saveQueue("SaveQueue");
40
39
41
// We use base64 to encode names and value, and need to replace the '='
40
// Encode uris and values so that they can be decoded (escape %, =, and eol)
42
static const char eqesc = '*';
41
static string encode(const string& in)
43
static void eqtoggle(string& nm)
44
{
42
{
45
    int i = nm.size() - 1;
43
    string out;
46
    while (i >= 0) {
44
    const char *cp = in.c_str();
47
        if (nm[i] == '=') {
45
    for (string::size_type i = 0; i < in.size(); i++) {
48
            nm[i] = eqesc;
46
  unsigned int c;
49
        } else if (nm[i] == eqesc) {
47
  const char *h = "0123456789ABCDEF";
50
            nm[i] = '=';
48
  c = cp[i];
51
        } else {
49
  if (c == '%' || c == '=' || c == '\n' || c == '\r') {
52
            break;
50
      out += '%';
51
      out += h[(c >> 4) & 0xf];
52
      out += h[c & 0xf];
53
  } else {
54
      out += char(c);
55
  }
56
    }
57
    return out;
58
}
59
60
static int h2d(int c)
61
{
62
    if ('0' <= c && c <= '9')
63
        return c - '0';
64
    else if ('A' <= c && c <= 'F')
65
        return 10 + c - 'A';
66
    else 
67
        return -1;
68
}
69
70
static string decode(const string &in)
71
{
72
    string out;
73
    const char *cp = in.c_str();
74
    if (in.size() <= 2)
75
        return in;
76
    string::size_type i = 0;
77
    for (; i < in.size() - 2; i++) {
78
  if (cp[i] == '%') {
79
            int d1 = h2d(cp[++i]);
80
            int d2 = h2d(cp[++i]);
81
            if (d1 != -1 && d2 != -1)
82
                out += (d1 << 4) + d2;
83
  } else {
84
            out += cp[i];
53
        }
85
        }
54
        i--;
55
    }
86
    }
87
    while (i < in.size()) {
88
        out += cp[i++];
89
    }
90
    return out;
56
}
91
}
57
92
58
bool dmcacheSave(const string& fn, const mcache_type& cache)
93
bool dmcacheSave(const string& fn, const mcache_type& cache)
59
{
94
{
60
    SaveCacheTask *tsk = new SaveCacheTask(fn, cache);
95
    SaveCacheTask *tsk = new SaveCacheTask(fn, cache);
...
...
79
            return (void*)1;
114
            return (void*)1;
80
        }
115
        }
81
        LOGDEB("dmcacheSave: got save task: " << tsk->m_cache.size() << 
116
        LOGDEB("dmcacheSave: got save task: " << tsk->m_cache.size() << 
82
               " entries to " << tsk->m_fn << endl);
117
               " entries to " << tsk->m_fn << endl);
83
118
84
        // Beware that calling the constructor with a std::string
119
          ofstream output(tsk->m_fn, ios::out | ios::trunc);
85
        // would result in a memory-based object...
120
  if (!output.is_open()) {
86
        ConfSimple cs(tsk->m_fn.c_str());
87
        cs.clear();
88
        if (cs.getStatus() != ConfSimple::STATUS_RW) {
89
            LOGERR("dmcacheSave: could not open " << tsk->m_fn 
121
            LOGERR("dmcacheSave: could not open " << tsk->m_fn 
90
                   << " for writing" << endl);
122
                   << " for writing" << endl);
91
            delete tsk;
123
            delete tsk;
92
            continue;
124
            continue;
93
        }
125
        }
94
        cs.holdWrites(true);
126
95
        for (mcache_type::const_iterator it = tsk->m_cache.begin();
127
        for (mcache_type::const_iterator it = tsk->m_cache.begin();
96
             it != tsk->m_cache.end(); it++) {
128
             it != tsk->m_cache.end(); it++) {
97
            string name = base64_encode(it->first);
129
            output << encode(it->first) << '=' << encode(it->second) << '\n';
98
            eqtoggle(name);
130
      if (!output.good()) {
99
            string value = base64_encode(it->second);
131
                LOGERR("dmcacheSave: write error while saving to " << 
100
            //LOGDEB("dmcacheSave: " << name << " -> " << value << endl);
132
                       tsk->m_fn << endl);
101
            cs.set(name, value);
133
                break;
134
            }
102
        }
135
        }
103
    
136
        output.flush();
104
        if (!cs.holdWrites(false)) {
137
        if (!output.good()) {
105
            LOGERR("dmcacheSave: write error while saving to " << 
138
            LOGERR("dmcacheSave: flush error while saving to " << 
106
                   tsk->m_fn << endl);
139
                   tsk->m_fn << endl);
107
        }
140
        }
141
108
        delete tsk;
142
        delete tsk;
109
    }
143
    }
110
}
144
}
145
146
// Max size of metadata element ??
147
#define LL 10*1024
111
148
112
bool dmcacheRestore(const string& fn, mcache_type& cache)
149
bool dmcacheRestore(const string& fn, mcache_type& cache)
113
{
150
{
114
    // Restore is called once at startup, so seize the opportunity to start the
151
    // Restore is called once at startup, so seize the opportunity to start the
115
    // save thread
152
    // save thread
116
    if (!saveQueue.start(1, dmcacheSaveWorker, 0)) {
153
    if (!saveQueue.start(1, dmcacheSaveWorker, 0)) {
117
        LOGERR("dmcacheRestore: could not start save thread" << endl);
154
        LOGERR("dmcacheRestore: could not start save thread" << endl);
118
        return false;
155
        return false;
119
    }
156
    }
120
157
121
    // Beware that calling the constructor with a std::string
158
    ifstream input;
122
    // would result in a memory-based object...
159
    input.open(fn, ios::in);
123
    ConfSimple cs(fn.c_str(), 1);
160
    if (!input.is_open()) {
124
    if (!cs.ok()) {
125
        LOGINF("dmcacheRestore: could not read metadata from " << fn << endl);
161
        LOGERR("dmcacheRestore: could not open " << fn << endl);
126
        return false;
162
        return false;
127
    }
163
    }
128
164
129
    vector<string> names = cs.getNames("");
165
    char cline[LL];
130
    for (auto &name : names) {
166
    for (;;) {
131
        string value;
167
  input.getline(cline, LL-1, '\n');
132
        if (!cs.get(name, value)) {
168
        if (input.eof())
133
            // ??
169
            break;
170
        if (!input.good()) {
134
            LOGDEB("dmcacheRestore: no data for found name " << name << endl);
171
            LOGERR("dmcacheRestore: read error on " << fn << endl);
135
            continue;
172
            return false;
136
        }
173
        }
137
        eqtoggle(name);
174
        char *cp = strchr(cline, '=');
138
        name = base64_decode(name); 
175
        if (cp == 0) {
139
        value = base64_decode(value);
176
            LOGERR("dmcacheRestore: no = in line !" << endl);
140
        LOGDEB("dmcacheRestore: " << name << " -> " << 
177
            return false;
141
               value.substr(0, 20) << endl);
178
        }
142
        cache[name] = value;
179
        *cp = 0;
180
        cache[decode(cline)] = decode(cp+1);
143
    }
181
    }
144
    return true;
182
    return true;
145
}
183
}
146