This file is indexed.

/usr/share/z-push/backend/ipcmemcached/ipcmemcachedprovider.php is in z-push-ipc-memcached 2.3.8-2ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<?php
/***********************************************
* File      :   ipcmemcachedprovider.php
* Project   :   Z-Push
* Descr     :   IPC provider using Memcached PHP extension
*               and memcached servers defined in
*               $zpush_ipc_memcached_servers
*
* Created   :   22.11.2015 by Ralf Becker <rb@stylite.de>
*
* Copyright 2007 - 2016 Zarafa Deutschland GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* Consult LICENSE file for details
************************************************/
//include own config file
require_once("backend/ipcmemcached/config.php");

class IpcMemcachedProvider implements IIpcProvider {
    protected $type;
    private $typeMutex;
    private $maxWaitCycles;
    private $logWaitCycles;
    private $isDownUntil;
    private $wasDown;
    private $reconnectCount;

    /**
     * Instance of memcached class
     *
     * @var memcached
     */
    protected $memcached;


    /**
     * Constructor
     *
     * @param int $type
     * @param int $allocate
     * @param string $class
     */
    public function __construct($type, $allocate, $class) {
        $this->type = $type;
        $this->typeMutex = $type . "MX";
        $this->maxWaitCycles = round(MEMCACHED_MUTEX_TIMEOUT * 1000 / MEMCACHED_BLOCK_WAIT)+1;
        $this->logWaitCycles = round($this->maxWaitCycles/5);

        // not used, but required by function signature
        unset($allocate, $class);

        if (!class_exists('Memcached')) {
            throw new FatalMisconfigurationException("IpcMemcachedProvider failure: can not find class Memcached. Please make sure the php memcached extension is installed.");
        }

        $this->reconnectCount = 0;
        $this->init();

        // check if memcached was down recently
        $this->isDownUntil = $this->getIsDownUntil();
        $this->wasDown = ! $this->IsActive();
    }

    /**
     * Initializes the Memcached object & connection.
     *
     * @access private
     * @return void
     */
    private function init() {
        $this->memcached = new Memcached(md5(MEMCACHED_SERVERS) . $this->reconnectCount++);
        $this->memcached->setOptions(array(
            // setting a short timeout, to better kope with failed nodes
            Memcached::OPT_CONNECT_TIMEOUT => MEMCACHED_TIMEOUT,
            Memcached::OPT_SEND_TIMEOUT => MEMCACHED_TIMEOUT * 1000,
            Memcached::OPT_RECV_TIMEOUT => MEMCACHED_TIMEOUT * 1000,

            // use igbinary, if available
            Memcached::OPT_SERIALIZER => Memcached::HAVE_IGBINARY ? Memcached::SERIALIZER_IGBINARY : (Memcached::HAVE_JSON ? Memcached::SERIALIZER_JSON : Memcached::SERIALIZER_PHP),
            // use more efficient binary protocol (also required for consistent hashing)
            Memcached::OPT_BINARY_PROTOCOL => true,
            // enable Libketama compatible consistent hashing
            Memcached::OPT_LIBKETAMA_COMPATIBLE => true,
            // automatic failover and disabling of failed nodes
            Memcached::OPT_SERVER_FAILURE_LIMIT => 2,
            Memcached::OPT_AUTO_EJECT_HOSTS => true,
            // setting a prefix for all keys
            Memcached::OPT_PREFIX_KEY => MEMCACHED_PREFIX,
        ));

        // with persistent connections, only add servers, if they not already added!
        if (!count($this->memcached->getServerList())) {
            foreach(explode(',', MEMCACHED_SERVERS) as $host_port) {
                list($host,$port) = explode(':', trim($host_port));
                $this->memcached->addServer($host, $port);
            }
        }
    }

    /**
     * Reinitializes the IPC data. If the provider has no way of performing
     * this action, it should return 'false'.
     *
     * @access public
     * @return boolean
     */
    public function ReInitIPC() {
        // this is not supported in memcache
        return false;
    }

    /**
     * Cleans up the IPC data block.
     *
     * @access public
     * @return boolean
     */
    public function Clean() {
        return false;
    }

    /**
     * Indicates if the IPC is active.
     *
     * @access public
     * @return boolean
     */
    public function IsActive() {
        $down = $this->isDownUntil > time();
        // reconnect if we were down but should retry now
        if (!$down && $this->wasDown) {
            ZLog::Write(LOGLEVEL_DEBUG, "IpcMemcachedProvider->IsActive(): memcache was down, trying to reconnect");
            $this->init();
            $this->wasDown = false;
        }
        return !$down;
    }

    /**
     * Blocks the class mutex.
     * Method blocks until mutex is available!
     * ATTENTION: make sure that you *always* release a blocked mutex!
     *
     * We try to add mutex to our cache, until we succeed.
     * It will fail as long other client has stored it or the
     * MEMCACHED_MUTEX_TIMEOUT is reached.
     *
     * @access public
     * @return boolean
     */
    public function BlockMutex() {
        if (!$this->IsActive()) {
            return false;
        }

        $n = 0;
        while(!$this->memcached->add($this->typeMutex, true, MEMCACHED_MUTEX_TIMEOUT)) {
            if (++$n % $this->logWaitCycles == 0) {
                ZLog::Write(LOGLEVEL_DEBUG, sprintf("IpcMemcachedProvider->BlockMutex() waiting to aquire mutex for type: %s ", $this->typeMutex));
            }
            // wait before retrying
            usleep(MEMCACHED_BLOCK_WAIT * 1000);
            if ($n > $this->maxWaitCycles) {
                ZLog::Write(LOGLEVEL_ERROR, sprintf("IpcMemcachedProvider->BlockMutex() could not aquire mutex for type: %s. Check memcache service!", $this->typeMutex));
                $this->markAsDown();
                return false;
            }
        }
        if ($n*MEMCACHED_BLOCK_WAIT > 50) {
            ZLog::Write(LOGLEVEL_WARN, sprintf("IpcMemcachedProvider->BlockMutex() mutex aquired after waiting for %sms for type: %s", ($n*MEMCACHED_BLOCK_WAIT), $this->typeMutex));
        }
        return true;
    }

    /**
     * Releases the class mutex.
     * After the release other processes are able to block the mutex themselves.
     *
     * @access public
     * @return boolean
     */
    public function ReleaseMutex() {
        return $this->memcached->delete($this->typeMutex);
    }

    /**
     * Indicates if the requested variable is available in IPC data.
     *
     * @param int   $id     int indicating the variable
     *
     * @access public
     * @return boolean
     */
    public function HasData($id = 2) {
        $this->memcached->get($this->type.':'.$id);
        return $this->memcached->getResultCode() === Memcached::RES_SUCCESS;
    }

    /**
     * Returns the requested variable from IPC data.
     *
     * @param int   $id     int indicating the variable
     *
     * @access public
     * @return mixed
     */
    public function GetData($id = 2) {
        return $this->memcached->get($this->type.':'.$id);
    }

    /**
     * Writes the transmitted variable to IPC data.
     * Subclasses may never use an id < 2!
     *
     * @param mixed $data   data which should be saved into IPC data
     * @param int   $id     int indicating the variable (bigger than 2!)
     *
     * @access public
     * @return boolean
     */
    public function SetData($data, $id = 2) {
        return $this->memcached->set($this->type.':'.$id, $data);
    }

    /**
     * Gets the epoch time until the memcache server should not be retried.
     * If there is no data available, 0 is returned.
     *
     * @access private
     * @return long
     */
    private function getIsDownUntil() {
        if (file_exists(MEMCACHED_DOWN_LOCK_FILE)) {
            $timestamp = file_get_contents(MEMCACHED_DOWN_LOCK_FILE);
            // is the lock file expired?
            if ($timestamp > time()) {
                ZLog::Write(LOGLEVEL_WARN, sprintf("IpcMemcachedProvider(): Memcache service is marked as down until %s.", strftime("%d.%m.%Y %H:%M:%S", $timestamp)));
                return $timestamp;
            }
            else {
                @unlink(MEMCACHED_DOWN_LOCK_FILE);
            }
        }
        return 0;
    }

    /**
     * Indicates that memcache is not available and that it should not be retried.
     *
     * @access private
     * @return boolean
     */
    private function markAsDown() {
        ZLog::Write(LOGLEVEL_WARN, sprintf("IpcMemcachedProvider(): Marking memcache service as down for %d seconds.", MEMCACHED_DOWN_LOCK_EXPIRATION));
        $downUntil = time() + MEMCACHED_DOWN_LOCK_EXPIRATION;
        $this->isDownUntil = $downUntil;
        $this->wasDown = true;
        return !!file_put_contents(MEMCACHED_DOWN_LOCK_FILE, $downUntil);
    }
}