├── .gitmodules ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.yml ├── docker-entrypoint.sh └── patches └── randr_compat.patch /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MTProxy"] 2 | path = MTProxy 3 | url = git@github.com:TelegramMessenger/MTProxy.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.6 2 | 3 | # Uncomment if local sources 4 | # COPY ./MTProxy /mtproxy/sources 5 | 6 | COPY ./patches /mtproxy/patches 7 | 8 | RUN apk add --no-cache --virtual .build-deps \ 9 | git make gcc musl-dev linux-headers openssl-dev \ 10 | && git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources \ 11 | && cd /mtproxy/sources \ 12 | && patch -p0 -i /mtproxy/patches/randr_compat.patch \ 13 | && make -j$(getconf _NPROCESSORS_ONLN) 14 | # Let's skip all cleaning stuff for faster build 15 | # && cp /mtproxy/sources/objs/bin/mtproto-proxy /mtproxy/ \ 16 | # && rm -rf /mtproxy/{sources,patches} \ 17 | # && apk add --virtual .rundeps libcrypto1.0 \ 18 | # && apk del .build-deps 19 | 20 | FROM alpine:3.6 21 | LABEL maintainer="Alex Doe " \ 22 | description="Telegram Messenger MTProto zero-configuration proxy server." 23 | 24 | RUN apk add --no-cache curl \ 25 | && ln -s /usr/lib/libcrypto.so.41 /usr/lib/libcrypto.so.1.0.0 26 | # alpine:3.7 will need symlink to libcrypto.so.42 27 | 28 | WORKDIR /mtproxy 29 | 30 | COPY --from=0 /mtproxy/sources/objs/bin/mtproto-proxy . 31 | COPY docker-entrypoint.sh / 32 | 33 | VOLUME /data 34 | EXPOSE 2398 443 35 | 36 | ENTRYPOINT ["/docker-entrypoint.sh"] 37 | CMD [ \ 38 | "--port", "2398", \ 39 | "--http-ports", "443", \ 40 | "--slaves", "2", \ 41 | "--max-special-connections", "60000", \ 42 | "--allow-skip-dh" \ 43 | ] 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alex Doe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telegram MTProto Proxy (Alpine) 2 | 3 | The Telegram Messenger MTProto proxy is a zero-configuration container that automatically sets up a proxy server that speaks Telegram's native MTProto. 4 | 5 | ## Quick reference 6 | To start the proxy all you need to do is 7 | `docker run -d -p443:443 --name=mtproxy --restart=always -v ./config:/data alexdoesh/mtproxy:latest` 8 | 9 | The container's log output (`docker logs mtproxy`) will contain the links to paste into the Telegram app: 10 | 11 | ``` 12 | [+] Using the explicitly passed secret: '00baadf00d15abad1deaa515baadcafe'. 13 | [+] Saving it to /data/secret. 14 | [*] Final configuration: 15 | [*] Secret 1: 00baadf00d15abad1deaa515baadcafe 16 | [*] tg:// link for secret 1 auto configuration: : tg://proxy?server=3.14.15.92&port=443&secret=00baadf00d15abad1deaa515baadcafe 17 | [*] t.me link for secret 1: tg://proxy?server=3.14.15.92&port=443&secret=00baadf00d15abad1deaa515baadcafe 18 | [*] Tag: no tag 19 | [*] External IP: 3.14.15.92 20 | [*] Make sure to fix the links in case you run the proxy on a different port. 21 | ``` 22 | The secret will persist across container upgrades in a volume. It is a mandatory configuration parameter: if not provided, it will be generated automatically at container start. You may forward any other port to the container's 443: be sure to fix the automatic configuration links if you do so. 23 | 24 | Please note that the proxy gets the Telegram core IP addresses at the start of the container. We try to keep the changes to a minimum, but you should restart the container about once a day, just in case. 25 | 26 | ## Registering your proxy 27 | Once your MTProxy server is up and running go to [@MTProxybot](https://t.me/mtproxybot) and register your proxy with Telegram to gain access to usage statistics and monetization. 28 | 29 | ## Custom configuration 30 | If you need to specify a custom secret (say, if you are deploying multiple proxies with DNS load-balancing), you may pass the SECRET environment variable as 16 bytes in lower-case hexidecimals.: 31 | `docker run -d -p443:443 -v ./config:/data -e SECRET=00baadf00d15abad1deaa51sbaadcafe alexdoesh/mtproxy:latest` 32 | 33 | The proxy may be configured to accept up to 16 different secrets. You may specify them explicitly as comma-separated hex strings in the SECRET environment variable, or you may let the container generate the secrets automatically using the SECRET_COUNT variable to limit the number of generated secrets. 34 | 35 | `docker run -d -p443:443 -v ./config:/data -e SECRET=935ddceb2f6bbbb78363b224099f75c8,2084c7e58d8213296a3206da70356c81 telegrammessenger/proxy:latest` 36 | `docker run -d -p443:443 -v ./config:/data -e SECRET_COUNT=4 alexdoesh/mtproxy:latest` 37 | 38 | A custom advertisement tag may be provided using the TAG environment variable: 39 | `docker run -d -p443:443 -v ./config:/data -e TAG=3f40462915a3e6026a4d790127b95ded alexdoesh/mtproxy:latest`. 40 | Please note that the tag is not persistent: you'll have to provide it as an environment variable every time you run an MTProto proxy container. 41 | 42 | A single worker process is expected to handle tens of thousands of clients on a modern CPU. For best performance we artificially limit the proxy to 60000 connections per core and run two workers by default. If you have many clients, be sure to adjust the WORKERS variable: 43 | `docker run -d -p443:443 -v ./config:/data -e WORKERS=16 alexdoesh/mtproxy:latest` 44 | 45 | ## Monitoring 46 | The MTProto proxy server exports internal statistics as tab-separated values over the http://localhost:2398/stats endpoint. Please note that this endpoint is available only from localhost: depending on your configuration, you may need to collect the statistics with `docker exec mtproto-proxy curl http://localhost:2398/stats`. 47 | 48 | * `ready_targets`: number of Telegram core servers the proxy will try to connect to. 49 | * `active_targets`: number of Telegram core servers the proxy is actually connected to. Should be equal to ready_targets. 50 | * `total_special_connections`: number of inbound client connections 51 | * `total_max_special_connections`: the upper limit on inbound connections. Is equal to 60000 multiplied by worker count. 52 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | mtproxy: 6 | image: alexdoesh/mtproxy 7 | container_name: mtproxy 8 | restart: always 9 | # command: --add --your --commands 10 | # environment: 11 | # - OVERRIDE=SOME 12 | # - VARIABLES=HERE 13 | volumes: 14 | - ./config:/data 15 | ports: 16 | - "2398:2398" 17 | - "443:443" 18 | networks: 19 | - tg_stack 20 | 21 | networks: 22 | tg_stack: 23 | 24 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ ! -z "$DEBUG" ]; then set -x; fi 3 | mkdir /data 2>/dev/null >/dev/null 4 | RANDOM=$(printf "%d" "0x$(head -c4 /dev/urandom | od -t x1 -An | tr -d ' ')") 5 | 6 | if [ -z "$WORKERS" ]; then 7 | WORKERS=2 8 | fi 9 | 10 | echo "####" 11 | echo "#### Telegram Proxy" 12 | echo "####" 13 | echo 14 | SECRET_CMD="" 15 | if [ ! -z "$SECRET" ]; then 16 | echo "[+] Using the explicitly passed secret: '$SECRET'." 17 | elif [ -f /data/secret ]; then 18 | SECRET="$(cat /data/secret)" 19 | echo "[+] Using the secret in /data/secret: '$SECRET'." 20 | else 21 | if [[ ! -z "$SECRET_COUNT" ]]; then 22 | if [[ "$SECRET_COUNT" -le 1 || "$SECRET_COUNT" -ge 16 ]]; then 23 | echo "[F] Can generate between 1 and 16 secrets." 24 | exit 5 25 | fi 26 | else 27 | SECRET_COUNT="1" 28 | fi 29 | 30 | echo "[+] No secret passed. Will generate $SECRET_COUNT random ones." 31 | SECRET="$(dd if=/dev/urandom bs=16 count=1 2>&1 | od -tx1 | head -n1 | tail -c +9 | tr -d ' ')" 32 | for pass in $(seq 2 $SECRET_COUNT); do 33 | SECRET="$SECRET,$(dd if=/dev/urandom bs=16 count=1 2>&1 | od -tx1 | head -n1 | tail -c +9 | tr -d ' ')" 34 | done 35 | fi 36 | 37 | if echo "$SECRET" | grep -qE '^[0-9a-fA-F]{32}(,[0-9a-fA-F]{32}){0,15}$'; then 38 | SECRET="$(echo "$SECRET" | tr '[:upper:]' '[:lower:]')" 39 | SECRET_CMD="-S $(echo "$SECRET" | sed 's/,/ -S /g')" 40 | echo -- "$SECRET_CMD" > /data/secret_cmd 41 | echo "$SECRET" > /data/secret 42 | else 43 | echo '[F] Bad secret format: should be 32 hex chars (for 16 bytes) for every secret; secrets should be comma-separated.' 44 | exit 1 45 | fi 46 | 47 | if [ ! -z "$TAG" ]; then 48 | echo "[+] Using the explicitly passed tag: '$TAG'." 49 | fi 50 | 51 | TAG_CMD="" 52 | if [[ ! -z "$TAG" ]]; then 53 | if echo "$TAG" | grep -qE '^[0-9a-fA-F]{32}$'; then 54 | TAG="$(echo "$TAG" | tr '[:upper:]' '[:lower:]')" 55 | TAG_CMD="-P $TAG" 56 | else 57 | echo '[!] Bad tag format: should be 32 hex chars (for 16 bytes).' 58 | echo '[!] Continuing.' 59 | fi 60 | fi 61 | 62 | REMOTE_CONFIG=/data/proxy-multi.conf 63 | curl -s https://core.telegram.org/getProxyConfig -o ${REMOTE_CONFIG} || { 64 | echo '[F] Cannot download proxy configuration from Telegram servers.' 65 | exit 2 66 | } 67 | 68 | REMOTE_SECRET=/data/proxy-secret 69 | curl -s https://core.telegram.org/getProxySecret -o ${REMOTE_SECRET} || { 70 | echo '[F] Cannot download proxy secret from Telegram servers.' 71 | exit 5 72 | } 73 | 74 | if [ ! -z "$EXTERNAL_IP" ]; then 75 | echo "[+] Using the explicitly passed external IP: ${EXTERNAL_IP}." 76 | else 77 | EXTERNAL_IP="$(curl -s -4 "https://digitalresistance.dog/myIp")" 78 | if [[ -z "$EXTERNAL_IP" ]]; then 79 | echo "[F] Cannot determine external IP address." 80 | exit 3 81 | else 82 | echo "[+] Using the detected external IP: ${EXTERNAL_IP}." 83 | fi 84 | fi 85 | 86 | if [ ! -z "$INTERNAL_IP" ]; then 87 | echo "[+] Using the explicitly passed internal IP: ${INTERNAL_IP}." 88 | else 89 | INTERNAL_IP="$(ip -4 route get 8.8.8.8 | grep '^8\.8\.8\.8\s' | grep -Eo 'src\s+\d+\.\d+\.\d+\.\d+' | awk '{print $2}')" 90 | if [[ -z "$INTERNAL_IP" ]]; then 91 | echo "[F] Cannot determine internal IP address." 92 | exit 4 93 | else 94 | echo "[+] Using the detected internal IP: ${INTERNAL_IP}." 95 | fi 96 | fi 97 | 98 | echo "[*] Final configuration:" 99 | I=1 100 | echo "$SECRET" | tr ',' '\n' | while read S; do 101 | echo "[*] Secret $I: $S" 102 | echo "[*] tg:// link for secret $I auto configuration: tg://proxy?server=${EXTERNAL_IP}&port=443&secret=${S}" 103 | echo "[*] t.me link for secret $I: https://t.me/proxy?server=${EXTERNAL_IP}&port=443&secret=${S}" 104 | I=$(($I+1)) 105 | done 106 | 107 | [ ! -z "$TAG" ] && echo "[*] Tag: $TAG" || echo "[*] Tag: no tag" 108 | echo "[*] External IP: ${EXTERNAL_IP}" 109 | echo "[*] Make sure to fix the links in case you run the proxy on a different port." 110 | echo 111 | echo '[+] Starting proxy...' 112 | sleep 1 113 | 114 | # exec /mtproxy/mtproto-proxy -p 2398 -H 443 -M "$WORKERS" -C 60000 --aes-pwd /etc/telegram/hello-explorers-how-are-you-doing -u root $CONFIG --allow-skip-dh --nat-info "$INTERNAL_IP:$IP" $SECRET_CMD $TAG_CMD 115 | exec /mtproxy/mtproto-proxy "$@" --aes-pwd ${REMOTE_SECRET} --user root ${REMOTE_CONFIG} --nat-info "$INTERNAL_IP:$EXTERNAL_IP" ${SECRET_CMD} ${TAG_CMD} 116 | -------------------------------------------------------------------------------- /patches/randr_compat.patch: -------------------------------------------------------------------------------- 1 | Index: jobs/jobs.h 2 | IDEA additional info: 3 | Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP 4 | <+>UTF-8 5 | =================================================================== 6 | --- jobs/jobs.h (revision cdd348294d86e74442bb29bd6767e48321259bec) 7 | +++ jobs/jobs.h (date 1527996954000) 8 | @@ -28,6 +28,8 @@ 9 | #include "net/net-msg.h" 10 | #include "net/net-timers.h" 11 | 12 | +#include "common/randr_compat.h" 13 | + 14 | #define __joblocked 15 | #define __jobref 16 | 17 | Index: common/server-functions.c 18 | IDEA additional info: 19 | Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP 20 | <+>UTF-8 21 | =================================================================== 22 | --- common/server-functions.c (revision cdd348294d86e74442bb29bd6767e48321259bec) 23 | +++ common/server-functions.c (date 1527998325000) 24 | @@ -35,7 +35,9 @@ 25 | #include 26 | #include 27 | #include 28 | +#ifdef __GLIBC__ 29 | #include 30 | +#endif 31 | #include 32 | #include 33 | #include 34 | @@ -168,6 +170,7 @@ 35 | } 36 | 37 | void print_backtrace (void) { 38 | +#ifdef __GLIBC__ 39 | void *buffer[64]; 40 | int nptrs = backtrace (buffer, 64); 41 | kwrite (2, "\n------- Stack Backtrace -------\n", 33); 42 | @@ -178,6 +181,7 @@ 43 | kwrite (2, s, strlen (s)); 44 | kwrite (2, "\n", 1); 45 | } 46 | +#endif 47 | } 48 | 49 | pthread_t debug_main_pthread_id; 50 | Index: common/randr_compat.h 51 | IDEA additional info: 52 | Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP 53 | <+>UTF-8 54 | =================================================================== 55 | --- common/randr_compat.h (date 1527998264000) 56 | +++ common/randr_compat.h (date 1527998264000) 57 | @@ -0,0 +1,72 @@ 58 | +/* 59 | + The GNU C Library is free software. See the file COPYING.LIB for copying 60 | + conditions, and LICENSES for notices about a few contributions that require 61 | + these additional notices to be distributed. License copyright years may be 62 | + listed using range notation, e.g., 2000-2011, indicating that every year in 63 | + the range, inclusive, is a copyrightable year that would otherwise be listed 64 | + individually. 65 | +*/ 66 | + 67 | +#pragma once 68 | + 69 | +#include 70 | +#include 71 | + 72 | +struct drand48_data { 73 | + unsigned short int __x[3]; /* Current state. */ 74 | + unsigned short int __old_x[3]; /* Old state. */ 75 | + unsigned short int __c; /* Additive const. in congruential formula. */ 76 | + unsigned short int __init; /* Flag for initializing. */ 77 | + unsigned long long int __a; /* Factor in congruential formula. */ 78 | +}; 79 | + 80 | +union ieee754_double 81 | +{ 82 | + double d; 83 | + 84 | + /* This is the IEEE 754 double-precision format. */ 85 | + struct 86 | + { 87 | +#if __BYTE_ORDER == __BIG_ENDIAN 88 | + unsigned int negative:1; 89 | + unsigned int exponent:11; 90 | + /* Together these comprise the mantissa. */ 91 | + unsigned int mantissa0:20; 92 | + unsigned int mantissa1:32; 93 | +#endif /* Big endian. */ 94 | +#if __BYTE_ORDER == __LITTLE_ENDIAN 95 | + /* Together these comprise the mantissa. */ 96 | + unsigned int mantissa1:32; 97 | + unsigned int mantissa0:20; 98 | + unsigned int exponent:11; 99 | + unsigned int negative:1; 100 | +#endif /* Little endian. */ 101 | + } ieee; 102 | + 103 | + /* This format makes it easier to see if a NaN is a signalling NaN. */ 104 | + struct 105 | + { 106 | +#if __BYTE_ORDER == __BIG_ENDIAN 107 | + unsigned int negative:1; 108 | + unsigned int exponent:11; 109 | + unsigned int quiet_nan:1; 110 | + /* Together these comprise the mantissa. */ 111 | + unsigned int mantissa0:19; 112 | + unsigned int mantissa1:32; 113 | +#else 114 | + /* Together these comprise the mantissa. */ 115 | + unsigned int mantissa1:32; 116 | + unsigned int mantissa0:19; 117 | + unsigned int quiet_nan:1; 118 | + unsigned int exponent:11; 119 | + unsigned int negative:1; 120 | +#endif 121 | + } ieee_nan; 122 | +}; 123 | + 124 | +#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */ 125 | + 126 | +int drand48_r (struct drand48_data *buffer, double *result); 127 | +int lrand48_r (struct drand48_data *buffer, long int *result); 128 | +int mrand48_r (struct drand48_data *buffer, long int *result); 129 | +int srand48_r (long int seedval, struct drand48_data *buffer); 130 | \ No newline at end of file 131 | Index: Makefile 132 | IDEA additional info: 133 | Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP 134 | <+>UTF-8 135 | =================================================================== 136 | --- Makefile (revision cdd348294d86e74442bb29bd6767e48321259bec) 137 | +++ Makefile (date 1527998107000) 138 | @@ -40,6 +40,7 @@ 139 | DEPENDENCE_NORM := $(subst ${OBJ}/,${DEP}/,$(patsubst %.o,%.d,${OBJECTS})) 140 | 141 | LIB_OBJS_NORMAL := \ 142 | + ${OBJ}/common/randr_compat.o \ 143 | ${OBJ}/common/crc32c.o \ 144 | ${OBJ}/common/pid.o \ 145 | ${OBJ}/common/sha1.o \ 146 | Index: common/randr_compat.c 147 | IDEA additional info: 148 | Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP 149 | <+>UTF-8 150 | =================================================================== 151 | --- common/randr_compat.c (date 1527998213000) 152 | +++ common/randr_compat.c (date 1527998213000) 153 | @@ -0,0 +1,120 @@ 154 | +/* 155 | + The GNU C Library is free software. See the file COPYING.LIB for copying 156 | + conditions, and LICENSES for notices about a few contributions that require 157 | + these additional notices to be distributed. License copyright years may be 158 | + listed using range notation, e.g., 2000-2011, indicating that every year in 159 | + the range, inclusive, is a copyrightable year that would otherwise be listed 160 | + individually. 161 | +*/ 162 | + 163 | +#include 164 | +#include "common/randr_compat.h" 165 | + 166 | +int __drand48_iterate (unsigned short int xsubi[3], struct drand48_data *buffer) { 167 | + uint64_t X; 168 | + uint64_t result; 169 | + 170 | + /* Initialize buffer, if not yet done. */ 171 | + if (!buffer->__init == 0) 172 | + { 173 | + buffer->__a = 0x5deece66dull; 174 | + buffer->__c = 0xb; 175 | + buffer->__init = 1; 176 | + } 177 | + 178 | + /* Do the real work. We choose a data type which contains at least 179 | + 48 bits. Because we compute the modulus it does not care how 180 | + many bits really are computed. */ 181 | + 182 | + X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0]; 183 | + 184 | + result = X * buffer->__a + buffer->__c; 185 | + 186 | + xsubi[0] = result & 0xffff; 187 | + xsubi[1] = (result >> 16) & 0xffff; 188 | + xsubi[2] = (result >> 32) & 0xffff; 189 | + 190 | + return 0; 191 | +} 192 | + 193 | +int __erand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, double *result) { 194 | + union ieee754_double temp; 195 | + 196 | + /* Compute next state. */ 197 | + if (__drand48_iterate (xsubi, buffer) < 0) 198 | + return -1; 199 | + 200 | + /* Construct a positive double with the 48 random bits distributed over 201 | + its fractional part so the resulting FP number is [0.0,1.0). */ 202 | + 203 | + temp.ieee.negative = 0; 204 | + temp.ieee.exponent = IEEE754_DOUBLE_BIAS; 205 | + temp.ieee.mantissa0 = (xsubi[2] << 4) | (xsubi[1] >> 12); 206 | + temp.ieee.mantissa1 = ((xsubi[1] & 0xfff) << 20) | (xsubi[0] << 4); 207 | + 208 | + /* Please note the lower 4 bits of mantissa1 are always 0. */ 209 | + *result = temp.d - 1.0; 210 | + 211 | + return 0; 212 | +} 213 | + 214 | +int __nrand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, long int *result) { 215 | + /* Compute next state. */ 216 | + if (__drand48_iterate (xsubi, buffer) < 0) 217 | + return -1; 218 | + 219 | + /* Store the result. */ 220 | + if (sizeof (unsigned short int) == 2) 221 | + *result = xsubi[2] << 15 | xsubi[1] >> 1; 222 | + else 223 | + *result = xsubi[2] >> 1; 224 | + 225 | + return 0; 226 | +} 227 | + 228 | +int __jrand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, long int *result) { 229 | + /* Compute next state. */ 230 | + if (__drand48_iterate (xsubi, buffer) < 0) 231 | + return -1; 232 | + 233 | + /* Store the result. */ 234 | + *result = (int32_t) ((xsubi[2] << 16) | xsubi[1]); 235 | + 236 | + return 0; 237 | +} 238 | + 239 | +int drand48_r (struct drand48_data *buffer, double *result) { 240 | + return __erand48_r (buffer->__x, buffer, result); 241 | +} 242 | + 243 | +int lrand48_r (struct drand48_data *buffer, long int *result) { 244 | + /* Be generous for the arguments, detect some errors. */ 245 | + if (buffer == NULL) 246 | + return -1; 247 | + 248 | + return __nrand48_r (buffer->__x, buffer, result); 249 | +} 250 | + 251 | +int mrand48_r (struct drand48_data *buffer, long int *result) { 252 | + /* Be generous for the arguments, detect some errors. */ 253 | + if (buffer == NULL) 254 | + return -1; 255 | + 256 | + return __jrand48_r (buffer->__x, buffer, result); 257 | +} 258 | + 259 | +int srand48_r (long int seedval, struct drand48_data *buffer) { 260 | + /* The standards say we only have 32 bits. */ 261 | + if (sizeof (long int) > 4) 262 | + seedval &= 0xffffffffl; 263 | + 264 | + buffer->__x[2] = seedval >> 16; 265 | + buffer->__x[1] = seedval & 0xffffl; 266 | + buffer->__x[0] = 0x330e; 267 | + 268 | + buffer->__a = 0x5deece66dull; 269 | + buffer->__c = 0xb; 270 | + buffer->__init = 1; 271 | + 272 | + return 0; 273 | +} 274 | \ No newline at end of file 275 | --------------------------------------------------------------------------------