mirror of https://github.com/PurpleI2P/i2pd.git
Jeff Becker
7 years ago
58 changed files with 2114 additions and 903 deletions
@ -1,54 +0,0 @@
@@ -1,54 +0,0 @@
|
||||
FROM alpine:latest |
||||
|
||||
MAINTAINER Mikal Villa <mikal@sigterm.no> |
||||
|
||||
ENV GIT_BRANCH="master" |
||||
ENV I2PD_PREFIX="/opt/i2pd-${GIT_BRANCH}" |
||||
ENV PATH=${I2PD_PREFIX}/bin:$PATH |
||||
|
||||
ENV GOSU_VERSION=1.7 |
||||
ENV GOSU_SHASUM="34049cfc713e8b74b90d6de49690fa601dc040021980812b2f1f691534be8a50 /usr/local/bin/gosu" |
||||
|
||||
RUN mkdir /user && adduser -S -h /user i2pd && chown -R i2pd:nobody /user |
||||
|
||||
|
||||
# |
||||
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the |
||||
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer. |
||||
# |
||||
|
||||
# 1. install deps, clone and build. |
||||
# 2. strip binaries. |
||||
# 3. Purge all dependencies and other unrelated packages, including build directory. |
||||
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \ |
||||
&& mkdir -p /tmp/build \ |
||||
&& cd /tmp/build && git clone -b ${GIT_BRANCH} https://github.com/PurpleI2P/i2pd.git \ |
||||
&& cd i2pd \ |
||||
&& make -j4 \ |
||||
&& mkdir -p ${I2PD_PREFIX}/bin \ |
||||
&& mv i2pd ${I2PD_PREFIX}/bin/ \ |
||||
&& cd ${I2PD_PREFIX}/bin \ |
||||
&& strip i2pd \ |
||||
&& rm -fr /tmp/build && apk --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \ |
||||
boost-python3 python3 gdbm boost-unit_test_framework boost-python linux-headers boost-prg_exec_monitor \ |
||||
boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \ |
||||
libtool g++ gcc pkgconfig |
||||
|
||||
# 2. Adding required libraries to run i2pd to ensure it will run. |
||||
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl musl-utils libstdc++ |
||||
|
||||
# Gosu is a replacement for su/sudo in docker and not a backdoor :) See https://github.com/tianon/gosu |
||||
RUN wget -O /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64 \ |
||||
&& echo "${GOSU_SHASUM}" | sha256sum -c && chmod +x /usr/local/bin/gosu |
||||
|
||||
COPY entrypoint.sh /entrypoint.sh |
||||
|
||||
RUN chmod a+x /entrypoint.sh |
||||
RUN echo "export PATH=${PATH}" >> /etc/profile |
||||
|
||||
VOLUME [ "/var/lib/i2pd" ] |
||||
|
||||
EXPOSE 7070 4444 4447 7656 2827 7654 7650 |
||||
|
||||
ENTRYPOINT [ "/entrypoint.sh" ] |
||||
|
@ -1,26 +1,56 @@
@@ -1,26 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="org.purplei2p.i2pd" |
||||
android:versionCode="1" |
||||
android:versionName="2.18.0" |
||||
android:installLocation="auto"> |
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/> |
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
||||
<uses-permission android:name="android.permission.INTERNET"/> |
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> |
||||
<application android:label="@string/app_name" android:allowBackup="true" android:icon="@drawable/icon"> |
||||
<receiver android:name=".NetworkStateChangeReceiver"> |
||||
<intent-filter> |
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> |
||||
</intent-filter> |
||||
</receiver> |
||||
<activity android:name=".I2PD" |
||||
android:label="@string/app_name"> |
||||
package="org.purplei2p.i2pd" |
||||
android:installLocation="auto" |
||||
android:versionCode="1" |
||||
android:versionName="2.18.0"> |
||||
|
||||
<uses-sdk |
||||
android:minSdkVersion="14" |
||||
android:targetSdkVersion="25" /> |
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
||||
<uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html --> |
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> |
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- normal perm --> |
||||
<application |
||||
android:allowBackup="true" |
||||
android:icon="@drawable/icon" |
||||
android:label="@string/app_name" |
||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar" |
||||
> |
||||
<receiver android:name=".NetworkStateChangeReceiver"> |
||||
<intent-filter> |
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> |
||||
</intent-filter> |
||||
</receiver> |
||||
|
||||
<activity |
||||
android:name=".I2PDPermsAskerActivity" |
||||
android:label="@string/app_name"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
<service android:enabled="true" android:name=".ForegroundService"/> |
||||
<activity |
||||
android:name=".I2PDActivity" |
||||
android:label="@string/app_name" /> |
||||
|
||||
<service |
||||
android:name=".ForegroundService" |
||||
android:enabled="true" /> |
||||
|
||||
<activity |
||||
android:name=".I2PDPermsExplanationActivity" |
||||
android:label="@string/title_activity_i2_pdperms_asker_prompt" |
||||
android:parentActivityName=".I2PDPermsAskerActivity"> |
||||
<meta-data |
||||
android:name="android.support.PARENT_ACTIVITY" |
||||
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" /> |
||||
</activity> |
||||
</application> |
||||
</manifest> |
||||
|
||||
</manifest> |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
<LinearLayout android:id="@+id/main_layout" |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical" |
||||
android:paddingBottom="@dimen/vertical_page_margin" |
||||
android:paddingLeft="@dimen/horizontal_page_margin" |
||||
android:paddingRight="@dimen/horizontal_page_margin" |
||||
android:paddingTop="@dimen/vertical_page_margin" |
||||
tools:context=".I2PDPermsAskerActivity"> |
||||
|
||||
<TextView |
||||
android:id="@+id/textview_retry" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginBottom="@dimen/horizontal_page_margin" |
||||
android:visibility="gone" |
||||
/> |
||||
|
||||
<Button |
||||
android:id="@+id/button_request_write_ext_storage_perms" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="Retry requesting the SD card write permissions" |
||||
android:visibility="gone"/> |
||||
</LinearLayout> |
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
<LinearLayout android:id="@+id/layout_prompt" |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical" |
||||
android:paddingBottom="@dimen/vertical_page_margin" |
||||
android:paddingLeft="@dimen/horizontal_page_margin" |
||||
android:paddingRight="@dimen/horizontal_page_margin" |
||||
android:paddingTop="@dimen/vertical_page_margin" |
||||
tools:context=".I2PDPermsAskerActivity"> |
||||
|
||||
<TextView |
||||
android:id="@+id/textview_explanation" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginBottom="@dimen/horizontal_page_margin" |
||||
android:text="SD card write access is required to write the keys and other files to the I2PD folder on SD card." |
||||
/> |
||||
|
||||
<Button |
||||
android:id="@+id/button_ok" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="OK" |
||||
/> |
||||
</LinearLayout> |
@ -1,11 +1,18 @@
@@ -1,11 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<string name="app_name">i2pd</string> |
||||
<string name="i2pd_started">i2pd started</string> |
||||
<string name="i2pd_service_started">i2pd service started</string> |
||||
<string name="i2pd_service_stopped">i2pd service stopped</string> |
||||
<string name="action_quit">Quit</string> |
||||
<string name="action_graceful_quit">Graceful Quit</string> |
||||
<string name="graceful_quit_is_already_in_progress">Graceful quit is already in progress</string> |
||||
<string name="graceful_quit_is_in_progress">Graceful quit is in progress</string> |
||||
<string name="action_stop">Stop</string> |
||||
<string name="action_graceful_stop">Graceful Stop</string> |
||||
<string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string> |
||||
<string name="graceful_stop_is_in_progress">Graceful stop is in progress</string> |
||||
<string name="already_stopped">Already stopped</string> |
||||
<string name="uninitialized">i2pd initializing</string> |
||||
<string name="starting">i2pd is starting</string> |
||||
<string name="jniLibraryLoaded">i2pd: loaded JNI libraries</string> |
||||
<string name="startedOkay">i2pd started</string> |
||||
<string name="startFailed">i2pd start failed</string> |
||||
<string name="gracefulShutdownInProgress">i2pd: graceful shutdown in progress</string> |
||||
<string name="stopped">i2pd has stopped</string> |
||||
<string name="remaining">remaining</string> |
||||
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string> |
||||
</resources> |
||||
|
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
<resources> |
||||
|
||||
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. --> |
||||
|
||||
<dimen name="margin_tiny">4dp</dimen> |
||||
<dimen name="margin_small">8dp</dimen> |
||||
<dimen name="margin_medium">16dp</dimen> |
||||
<dimen name="margin_large">32dp</dimen> |
||||
<dimen name="margin_huge">64dp</dimen> |
||||
|
||||
<!-- Semantic definitions --> |
||||
|
||||
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen> |
||||
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen> |
||||
|
||||
</resources> |
@ -1,245 +0,0 @@
@@ -1,245 +0,0 @@
|
||||
package org.purplei2p.i2pd; |
||||
|
||||
import java.io.PrintWriter; |
||||
import java.io.StringWriter; |
||||
import java.util.Timer; |
||||
import java.util.TimerTask; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.app.Activity; |
||||
import android.content.ComponentName; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.content.ServiceConnection; |
||||
import android.os.Build; |
||||
import android.os.Bundle; |
||||
import android.os.IBinder; |
||||
import android.util.Log; |
||||
import android.view.Menu; |
||||
import android.view.MenuItem; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
|
||||
public class I2PD extends Activity { |
||||
private static final String TAG = "i2pd"; |
||||
|
||||
private TextView textView; |
||||
|
||||
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); |
||||
|
||||
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = |
||||
new DaemonSingleton.StateUpdateListener() { |
||||
|
||||
@Override |
||||
public void daemonStateUpdate() { |
||||
runOnUiThread(new Runnable(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
if(textView==null)return; |
||||
Throwable tr = daemon.getLastThrowable(); |
||||
if(tr!=null) { |
||||
textView.setText(throwableToString(tr)); |
||||
return; |
||||
} |
||||
DaemonSingleton.State state = daemon.getState(); |
||||
textView.setText(String.valueOf(state)+ |
||||
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")); |
||||
} catch (Throwable tr) { |
||||
Log.e(TAG,"error ignored",tr); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
|
||||
textView = new TextView(this); |
||||
setContentView(textView); |
||||
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); |
||||
daemonStateUpdatedListener.daemonStateUpdate(); |
||||
|
||||
//set the app be foreground
|
||||
doBindService(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onDestroy() { |
||||
super.onDestroy(); |
||||
localDestroy(); |
||||
} |
||||
|
||||
private void localDestroy() { |
||||
textView = null; |
||||
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener); |
||||
Timer gracefulQuitTimer = getGracefulQuitTimer(); |
||||
if(gracefulQuitTimer!=null) { |
||||
gracefulQuitTimer.cancel(); |
||||
setGracefulQuitTimer(null); |
||||
} |
||||
try{ |
||||
doUnbindService(); |
||||
}catch(Throwable tr){ |
||||
Log.e(TAG, "", tr); |
||||
} |
||||
} |
||||
|
||||
private CharSequence throwableToString(Throwable tr) { |
||||
StringWriter sw = new StringWriter(8192); |
||||
PrintWriter pw = new PrintWriter(sw); |
||||
tr.printStackTrace(pw); |
||||
pw.close(); |
||||
return sw.toString(); |
||||
} |
||||
|
||||
// private LocalService mBoundService;
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() { |
||||
public void onServiceConnected(ComponentName className, IBinder service) { |
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
// interact with the service. Because we have bound to a explicit
|
||||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
// mBoundService = ((LocalService.LocalBinder)service).getService();
|
||||
|
||||
// Tell the user about this for our demo.
|
||||
// Toast.makeText(Binding.this, R.string.local_service_connected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
} |
||||
|
||||
public void onServiceDisconnected(ComponentName className) { |
||||
// This is called when the connection with the service has been
|
||||
// unexpectedly disconnected -- that is, its process crashed.
|
||||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
// mBoundService = null;
|
||||
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
} |
||||
}; |
||||
|
||||
|
||||
private boolean mIsBound; |
||||
|
||||
private void doBindService() { |
||||
// Establish a connection with the service. We use an explicit
|
||||
// class name because we want a specific service implementation that
|
||||
// we know will be running in our own process (and thus won't be
|
||||
// supporting component replacement by other applications).
|
||||
bindService(new Intent(this, |
||||
ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); |
||||
mIsBound = true; |
||||
} |
||||
|
||||
private void doUnbindService() { |
||||
if (mIsBound) { |
||||
// Detach our existing connection.
|
||||
unbindService(mConnection); |
||||
mIsBound = false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onCreateOptionsMenu(Menu menu) { |
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.options_main, menu); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onOptionsItemSelected(MenuItem item) { |
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId(); |
||||
|
||||
switch(id){ |
||||
case R.id.action_quit: |
||||
quit(); |
||||
return true; |
||||
case R.id.action_graceful_quit: |
||||
gracefulQuit(); |
||||
return true; |
||||
} |
||||
|
||||
return super.onOptionsItemSelected(item); |
||||
} |
||||
|
||||
@SuppressLint("NewApi") |
||||
private void quit() { |
||||
try { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
finishAndRemoveTask(); |
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
||||
finishAffinity(); |
||||
} else { |
||||
//moveTaskToBack(true);
|
||||
finish(); |
||||
} |
||||
}catch (Throwable tr) { |
||||
Log.e(TAG, "", tr); |
||||
} |
||||
try{ |
||||
daemon.stopDaemon(); |
||||
}catch (Throwable tr) { |
||||
Log.e(TAG, "", tr); |
||||
} |
||||
System.exit(0); |
||||
} |
||||
|
||||
private Timer gracefulQuitTimer; |
||||
private final Object gracefulQuitTimerLock = new Object(); |
||||
private void gracefulQuit() { |
||||
if(getGracefulQuitTimer()!=null){ |
||||
Toast.makeText(this, R.string.graceful_quit_is_already_in_progress, |
||||
Toast.LENGTH_SHORT).show(); |
||||
return; |
||||
} |
||||
Toast.makeText(this, R.string.graceful_quit_is_in_progress, |
||||
Toast.LENGTH_SHORT).show(); |
||||
new Thread(new Runnable(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
try{ |
||||
Log.d(TAG, "grac stopping"); |
||||
if(daemon.isStartedOkay()) { |
||||
daemon.stopAcceptingTunnels(); |
||||
Timer gracefulQuitTimer = new Timer(true); |
||||
setGracefulQuitTimer(gracefulQuitTimer); |
||||
gracefulQuitTimer.schedule(new TimerTask(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
quit(); |
||||
} |
||||
|
||||
}, 10*60*1000/*milliseconds*/); |
||||
}else{ |
||||
quit(); |
||||
} |
||||
} catch(Throwable tr) { |
||||
Log.e(TAG,"",tr); |
||||
} |
||||
} |
||||
|
||||
},"gracQuitInit").start(); |
||||
} |
||||
|
||||
private Timer getGracefulQuitTimer() { |
||||
synchronized (gracefulQuitTimerLock) { |
||||
return gracefulQuitTimer; |
||||
} |
||||
} |
||||
|
||||
private void setGracefulQuitTimer(Timer gracefulQuitTimer) { |
||||
synchronized (gracefulQuitTimerLock) { |
||||
this.gracefulQuitTimer = gracefulQuitTimer; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,285 @@
@@ -0,0 +1,285 @@
|
||||
package org.purplei2p.i2pd; |
||||
|
||||
import java.io.PrintWriter; |
||||
import java.io.StringWriter; |
||||
import java.util.Timer; |
||||
import java.util.TimerTask; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.ComponentName; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.content.ServiceConnection; |
||||
import android.os.Bundle; |
||||
import android.os.IBinder; |
||||
import android.util.Log; |
||||
import android.view.Menu; |
||||
import android.view.MenuItem; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
|
||||
public class I2PDActivity extends Activity { |
||||
private static final String TAG = "i2pdActvt"; |
||||
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; |
||||
|
||||
private TextView textView; |
||||
|
||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); |
||||
|
||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = |
||||
new DaemonSingleton.StateUpdateListener() { |
||||
|
||||
@Override |
||||
public void daemonStateUpdate() { |
||||
runOnUiThread(new Runnable(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
if(textView==null)return; |
||||
Throwable tr = daemon.getLastThrowable(); |
||||
if(tr!=null) { |
||||
textView.setText(throwableToString(tr)); |
||||
return; |
||||
} |
||||
DaemonSingleton.State state = daemon.getState(); |
||||
textView.setText( |
||||
String.valueOf(state)+ |
||||
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ |
||||
(DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") |
||||
); |
||||
} catch (Throwable tr) { |
||||
Log.e(TAG,"error ignored",tr); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
private static volatile long graceStartedMillis; |
||||
private static final Object graceStartedMillis_LOCK=new Object(); |
||||
|
||||
private static String formatGraceTimeRemaining() { |
||||
long remainingSeconds; |
||||
synchronized (graceStartedMillis_LOCK){ |
||||
remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); |
||||
} |
||||
long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); |
||||
long remSec=remainingSeconds-remainingMinutes*60; |
||||
return remainingMinutes+":"+(remSec/10)+remSec%10; |
||||
} |
||||
|
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
|
||||
textView = new TextView(this); |
||||
setContentView(textView); |
||||
daemon.addStateChangeListener(daemonStateUpdatedListener); |
||||
daemonStateUpdatedListener.daemonStateUpdate(); |
||||
|
||||
//set the app be foreground
|
||||
doBindService(); |
||||
|
||||
final Timer gracefulQuitTimer = getGracefulQuitTimer(); |
||||
if(gracefulQuitTimer!=null){ |
||||
long gracefulStopAtMillis; |
||||
synchronized (graceStartedMillis_LOCK) { |
||||
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; |
||||
} |
||||
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected void onDestroy() { |
||||
super.onDestroy(); |
||||
textView = null; |
||||
daemon.removeStateChangeListener(daemonStateUpdatedListener); |
||||
//cancelGracefulStop();
|
||||
try{ |
||||
doUnbindService(); |
||||
}catch(Throwable tr){ |
||||
Log.e(TAG, "", tr); |
||||
} |
||||
} |
||||
|
||||
private static void cancelGracefulStop() { |
||||
Timer gracefulQuitTimer = getGracefulQuitTimer(); |
||||
if(gracefulQuitTimer!=null) { |
||||
gracefulQuitTimer.cancel(); |
||||
setGracefulQuitTimer(null); |
||||
} |
||||
} |
||||
|
||||
private CharSequence throwableToString(Throwable tr) { |
||||
StringWriter sw = new StringWriter(8192); |
||||
PrintWriter pw = new PrintWriter(sw); |
||||
tr.printStackTrace(pw); |
||||
pw.close(); |
||||
return sw.toString(); |
||||
} |
||||
|
||||
// private LocalService mBoundService;
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() { |
||||
public void onServiceConnected(ComponentName className, IBinder service) { |
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
// interact with the service. Because we have bound to a explicit
|
||||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
// mBoundService = ((LocalService.LocalBinder)service).getService();
|
||||
|
||||
// Tell the user about this for our demo.
|
||||
// Toast.makeText(Binding.this, R.string.local_service_connected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
} |
||||
|
||||
public void onServiceDisconnected(ComponentName className) { |
||||
// This is called when the connection with the service has been
|
||||
// unexpectedly disconnected -- that is, its process crashed.
|
||||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
// mBoundService = null;
|
||||
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
} |
||||
}; |
||||
|
||||
|
||||
private static volatile boolean mIsBound; |
||||
|
||||
private void doBindService() { |
||||
synchronized (I2PDActivity.class) { |
||||
if (mIsBound) return; |
||||
// Establish a connection with the service. We use an explicit
|
||||
// class name because we want a specific service implementation that
|
||||
// we know will be running in our own process (and thus won't be
|
||||
// supporting component replacement by other applications).
|
||||
bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); |
||||
mIsBound = true; |
||||
} |
||||
} |
||||
|
||||
private void doUnbindService() { |
||||
synchronized (I2PDActivity.class) { |
||||
if (mIsBound) { |
||||
// Detach our existing connection.
|
||||
unbindService(mConnection); |
||||
mIsBound = false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean onCreateOptionsMenu(Menu menu) { |
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.options_main, menu); |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onOptionsItemSelected(MenuItem item) { |
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId(); |
||||
|
||||
switch(id){ |
||||
case R.id.action_stop: |
||||
i2pdStop(); |
||||
return true; |
||||
case R.id.action_graceful_stop: |
||||
i2pdGracefulStop(); |
||||
return true; |
||||
} |
||||
|
||||
return super.onOptionsItemSelected(item); |
||||
} |
||||
|
||||
private void i2pdStop() { |
||||
cancelGracefulStop(); |
||||
new Thread(new Runnable(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
Log.d(TAG, "stopping"); |
||||
try{ |
||||
daemon.stopDaemon(); |
||||
}catch (Throwable tr) { |
||||
Log.e(TAG, "", tr); |
||||
} |
||||
} |
||||
|
||||
},"stop").start(); |
||||
} |
||||
|
||||
private static volatile Timer gracefulQuitTimer; |
||||
|
||||
private void i2pdGracefulStop() { |
||||
if(daemon.getState()==DaemonSingleton.State.stopped){ |
||||
Toast.makeText(this, R.string.already_stopped, |
||||
Toast.LENGTH_SHORT).show(); |
||||
return; |
||||
} |
||||
if(getGracefulQuitTimer()!=null){ |
||||
Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, |
||||
Toast.LENGTH_SHORT).show(); |
||||
return; |
||||
} |
||||
Toast.makeText(this, R.string.graceful_stop_is_in_progress, |
||||
Toast.LENGTH_SHORT).show(); |
||||
new Thread(new Runnable(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
try{ |
||||
Log.d(TAG, "grac stopping"); |
||||
if(daemon.isStartedOkay()) { |
||||
daemon.stopAcceptingTunnels(); |
||||
long gracefulStopAtMillis; |
||||
synchronized (graceStartedMillis_LOCK) { |
||||
graceStartedMillis = System.currentTimeMillis(); |
||||
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; |
||||
} |
||||
rescheduleGraceStop(null,gracefulStopAtMillis); |
||||
}else{ |
||||
i2pdStop(); |
||||
} |
||||
} catch(Throwable tr) { |
||||
Log.e(TAG,"",tr); |
||||
} |
||||
} |
||||
|
||||
},"gracInit").start(); |
||||
} |
||||
|
||||
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { |
||||
if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); |
||||
final Timer gracefulQuitTimer = new Timer(true); |
||||
setGracefulQuitTimer(gracefulQuitTimer); |
||||
gracefulQuitTimer.schedule(new TimerTask(){ |
||||
|
||||
@Override |
||||
public void run() { |
||||
i2pdStop(); |
||||
} |
||||
|
||||
}, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); |
||||
final TimerTask tickerTask = new TimerTask() { |
||||
@Override |
||||
public void run() { |
||||
daemonStateUpdatedListener.daemonStateUpdate(); |
||||
} |
||||
}; |
||||
gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); |
||||
} |
||||
|
||||
private static Timer getGracefulQuitTimer() { |
||||
return gracefulQuitTimer; |
||||
} |
||||
|
||||
private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { |
||||
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; |
||||
} |
||||
} |
@ -0,0 +1,171 @@
@@ -0,0 +1,171 @@
|
||||
package org.purplei2p.i2pd; |
||||
|
||||
import android.Manifest; |
||||
import android.app.Activity; |
||||
import android.content.Intent; |
||||
import android.content.pm.PackageManager; |
||||
import android.os.Bundle; |
||||
import android.view.View; |
||||
import android.widget.Button; |
||||
import android.widget.TextView; |
||||
|
||||
import java.lang.reflect.Method; |
||||
|
||||
//dangerous perms, per https://developer.android.com/guide/topics/permissions/normal-permissions.html :
|
||||
//android.permission.WRITE_EXTERNAL_STORAGE
|
||||
public class I2PDPermsAskerActivity extends Activity { |
||||
|
||||
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0; |
||||
|
||||
private Button button_request_write_ext_storage_perms; |
||||
private TextView textview_retry; |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
//if less than Android 6, no runtime perms req system present
|
||||
if (android.os.Build.VERSION.SDK_INT < 23) { |
||||
startMainActivity(); |
||||
return; |
||||
} |
||||
|
||||
|
||||
setContentView(R.layout.activity_perms_asker); |
||||
button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms); |
||||
textview_retry = (TextView) findViewById(R.id.textview_retry); |
||||
|
||||
button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
request_write_ext_storage_perms(); |
||||
} |
||||
}); |
||||
request_write_ext_storage_perms(); |
||||
} |
||||
|
||||
private void request_write_ext_storage_perms() { |
||||
|
||||
textview_retry.setVisibility(TextView.GONE); |
||||
button_request_write_ext_storage_perms.setVisibility(Button.GONE); |
||||
|
||||
Method methodCheckPermission; |
||||
Method method_shouldShowRequestPermissionRationale; |
||||
Method method_requestPermissions; |
||||
try { |
||||
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class); |
||||
method_shouldShowRequestPermissionRationale = |
||||
getClass().getMethod("shouldShowRequestPermissionRationale", String.class); |
||||
method_requestPermissions = |
||||
getClass().getMethod("requestPermissions", String[].class, int.class); |
||||
} catch (NoSuchMethodException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
Integer resultObj; |
||||
try { |
||||
resultObj = (Integer) methodCheckPermission.invoke( |
||||
this, Manifest.permission.WRITE_EXTERNAL_STORAGE); |
||||
} catch (Throwable e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
if (resultObj != PackageManager.PERMISSION_GRANTED) { |
||||
|
||||
// Should we show an explanation?
|
||||
Boolean aBoolean; |
||||
try { |
||||
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this, |
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
if (aBoolean) { |
||||
|
||||
// Show an explanation to the user *asynchronously* -- don't block
|
||||
// this thread waiting for the user's response! After the user
|
||||
// sees the explanation, try again to request the permission.
|
||||
|
||||
showExplanation(); |
||||
|
||||
} else { |
||||
|
||||
// No explanation needed, we can request the permission.
|
||||
|
||||
try { |
||||
method_requestPermissions.invoke(this, |
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, |
||||
PERMISSION_WRITE_EXTERNAL_STORAGE); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} else startMainActivity(); |
||||
} |
||||
|
||||
@Override |
||||
public void onRequestPermissionsResult(int requestCode, |
||||
String permissions[], int[] grantResults) { |
||||
switch (requestCode) { |
||||
case PERMISSION_WRITE_EXTERNAL_STORAGE: { |
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0 |
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) { |
||||
|
||||
// permission was granted, yay! Do the
|
||||
// contacts-related task you need to do.
|
||||
|
||||
startMainActivity(); |
||||
|
||||
} else { |
||||
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
textview_retry.setText("SD card write permission denied, you need to allow this to continue"); |
||||
textview_retry.setVisibility(TextView.VISIBLE); |
||||
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
// other 'case' lines to check for other
|
||||
// permissions this app might request.
|
||||
} |
||||
} |
||||
|
||||
private void startMainActivity() { |
||||
startActivity(new Intent(this, I2PDActivity.class)); |
||||
finish(); |
||||
} |
||||
|
||||
private static final int SHOW_EXPLANATION_REQUEST = 1; // The request code
|
||||
private void showExplanation() { |
||||
Intent intent = new Intent(this, I2PDPermsExplanationActivity.class); |
||||
startActivityForResult(intent, SHOW_EXPLANATION_REQUEST); |
||||
} |
||||
|
||||
@Override |
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
||||
// Check which request we're responding to
|
||||
if (requestCode == SHOW_EXPLANATION_REQUEST) { |
||||
// Make sure the request was successful
|
||||
if (resultCode == RESULT_OK) { |
||||
// Request the permission
|
||||
Method method_requestPermissions; |
||||
try { |
||||
method_requestPermissions = |
||||
getClass().getMethod("requestPermissions", String[].class, int.class); |
||||
} catch (NoSuchMethodException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
try { |
||||
method_requestPermissions.invoke(this, |
||||
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, |
||||
PERMISSION_WRITE_EXTERNAL_STORAGE); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} else { |
||||
finish(); //close the app
|
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
package org.purplei2p.i2pd; |
||||
|
||||
import android.app.ActionBar; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
import android.app.Activity; |
||||
import android.view.View; |
||||
import android.widget.Button; |
||||
|
||||
public class I2PDPermsExplanationActivity extends Activity { |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_perms_explanation); |
||||
ActionBar actionBar = getActionBar(); |
||||
if(actionBar!=null)actionBar.setHomeButtonEnabled(false); |
||||
Button button_ok = (Button) findViewById(R.id.button_ok); |
||||
button_ok.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
returnFromActivity(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private void returnFromActivity() { |
||||
Intent data = new Intent(); |
||||
Activity parent = getParent(); |
||||
if (parent == null) { |
||||
setResult(Activity.RESULT_OK, data); |
||||
} else { |
||||
parent.setResult(Activity.RESULT_OK, data); |
||||
} |
||||
finish(); |
||||
} |
||||
|
||||
} |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
[Unit] |
||||
Description=I2P Router written in C++ |
||||
After=network.target |
||||
|
||||
[Service] |
||||
User=i2pd |
||||
Group=i2pd |
||||
RuntimeDirectory=i2pd |
||||
RuntimeDirectoryMode=0700 |
||||
Type=simple |
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service |
||||
ExecReload=/bin/kill -HUP $MAINPID |
||||
PIDFile=/var/run/i2pd/i2pd.pid |
||||
### Uncomment, if auto restart needed |
||||
#Restart=on-failure |
||||
|
||||
### Use SIGINT for graceful stop daemon. |
||||
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die. |
||||
KillSignal=SIGINT |
||||
TimeoutStopSec=10m |
||||
|
||||
# If you have problems with hanging i2pd, you can try enable this |
||||
#LimitNOFILE=4096 |
||||
PrivateDevices=yes |
||||
|
||||
[Install] |
||||
WantedBy=multi-user.target |
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
../i2pd.service |
@ -0,0 +1,31 @@
@@ -0,0 +1,31 @@
|
||||
[Unit] |
||||
Description=I2P Router written in C++ |
||||
Documentation=man:i2pd(1) https://i2pd.readthedocs.io/en/latest/ |
||||
After=network.target |
||||
|
||||
[Service] |
||||
User=i2pd |
||||
Group=i2pd |
||||
RuntimeDirectory=i2pd |
||||
RuntimeDirectoryMode=0700 |
||||
LogsDirectory=i2pd |
||||
LogsDirectoryMode=0700 |
||||
Type=simple |
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service |
||||
ExecReload=/bin/kill -HUP $MAINPID |
||||
PIDFile=/var/run/i2pd/i2pd.pid |
||||
### Uncomment, if auto restart needed |
||||
#Restart=on-failure |
||||
|
||||
KillSignal=SIGQUIT |
||||
# If you have the patience waiting 10 min on restarting/stopping it, uncomment this. |
||||
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die. |
||||
#KillSignal=SIGINT |
||||
#TimeoutStopSec=10m |
||||
|
||||
# If you have problems with hanging i2pd, you can try enable this |
||||
#LimitNOFILE=4096 |
||||
PrivateDevices=yes |
||||
|
||||
[Install] |
||||
WantedBy=multi-user.target |
@ -0,0 +1,102 @@
@@ -0,0 +1,102 @@
|
||||
%define git_hash %(git rev-parse HEAD | cut -c -7) |
||||
|
||||
Name: i2pd-git |
||||
Version: 2.18.0 |
||||
Release: git%{git_hash}%{?dist} |
||||
Summary: I2P router written in C++ |
||||
Conflicts: i2pd |
||||
|
||||
License: BSD |
||||
URL: https://github.com/PurpleI2P/i2pd |
||||
Source0: https://github.com/PurpleI2P/i2pd/archive/openssl/i2pd-openssl.tar.gz |
||||
|
||||
%if 0%{?rhel} == 7 |
||||
BuildRequires: cmake3 |
||||
%else |
||||
BuildRequires: cmake |
||||
%endif |
||||
|
||||
BuildRequires: chrpath |
||||
BuildRequires: gcc-c++ |
||||
BuildRequires: zlib-devel |
||||
BuildRequires: boost-devel |
||||
BuildRequires: openssl-devel |
||||
BuildRequires: miniupnpc-devel |
||||
BuildRequires: systemd-units |
||||
|
||||
Requires: systemd |
||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd |
||||
|
||||
%description |
||||
C++ implementation of I2P. |
||||
|
||||
%prep |
||||
%setup -q |
||||
|
||||
|
||||
%build |
||||
cd build |
||||
%if 0%{?rhel} == 7 |
||||
%cmake3 \ |
||||
-DWITH_LIBRARY=OFF \ |
||||
-DWITH_UPNP=ON \ |
||||
-DWITH_HARDENING=ON \ |
||||
-DBUILD_SHARED_LIBS:BOOL=OFF |
||||
%else |
||||
%cmake \ |
||||
-DWITH_LIBRARY=OFF \ |
||||
-DWITH_UPNP=ON \ |
||||
-DWITH_HARDENING=ON \ |
||||
-DBUILD_SHARED_LIBS:BOOL=OFF |
||||
%endif |
||||
|
||||
make %{?_smp_mflags} |
||||
|
||||
|
||||
%install |
||||
cd build |
||||
chrpath -d i2pd |
||||
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd |
||||
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf |
||||
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf |
||||
install -d -m 755 %{buildroot}%{_datadir}/i2pd |
||||
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates |
||||
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service |
||||
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd |
||||
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd |
||||
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates |
||||
|
||||
|
||||
%pre |
||||
getent group i2pd >/dev/null || %{_sbindir}/groupadd -r i2pd |
||||
getent passwd i2pd >/dev/null || \ |
||||
%{_sbindir}/useradd -r -g i2pd -s %{_sbindir}/nologin \ |
||||
-d %{_sharedstatedir}/i2pd -c 'I2P Service' i2pd |
||||
|
||||
|
||||
%post |
||||
%systemd_post i2pd.service |
||||
|
||||
|
||||
%preun |
||||
%systemd_preun i2pd.service |
||||
|
||||
|
||||
%postun |
||||
%systemd_postun_with_restart i2pd.service |
||||
|
||||
|
||||
%files |
||||
%doc LICENSE README.md |
||||
%{_sbindir}/i2pd |
||||
%{_datadir}/i2pd/certificates |
||||
%config(noreplace) %{_sysconfdir}/i2pd/* |
||||
/%{_unitdir}/i2pd.service |
||||
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd |
||||
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd |
||||
%{_sharedstatedir}/i2pd/certificates |
||||
|
||||
|
||||
%changelog |
||||
* Thu Feb 01 2018 r4sas <r4sas@i2pmail.org> - 2.18.0 |
||||
- Initial i2pd-git based on i2pd 2.18.0-1 spec |
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
[Unit] |
||||
Description=I2P Router written in C++ |
||||
After=network.target |
||||
|
||||
[Service] |
||||
User=i2pd |
||||
Group=i2pd |
||||
RuntimeDirectory=i2pd |
||||
RuntimeDirectoryMode=0700 |
||||
Type=simple |
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service |
||||
ExecReload=/bin/kill -HUP $MAINPID |
||||
PIDFile=/var/run/i2pd/i2pd.pid |
||||
### Uncomment, if auto restart needed |
||||
#Restart=on-failure |
||||
|
||||
### Use SIGINT for graceful stop daemon. |
||||
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die. |
||||
KillSignal=SIGINT |
||||
TimeoutStopSec=10m |
||||
|
||||
# If you have problems with hunging i2pd, you can try enable this |
||||
#LimitNOFILE=4096 |
||||
PrivateDevices=yes |
||||
|
||||
[Install] |
||||
WantedBy=multi-user.target |
@ -1,24 +0,0 @@
@@ -1,24 +0,0 @@
|
||||
#!/bin/sh |
||||
|
||||
ARGS="" |
||||
if [ "${ENABLE_IPV6}" != "" ]; then |
||||
ARGS="${ARGS} –ipv6" |
||||
fi |
||||
|
||||
if [ "${LOGLEVEL}" != "" ]; then |
||||
ARGS="${ARGS} –loglevel=${LOGLEVEL}" |
||||
fi |
||||
|
||||
if [ "${ENABLE_AUTH}" != "" ]; then |
||||
ARGS="${ARGS} –http.auth" |
||||
fi |
||||
|
||||
|
||||
# To make ports exposeable |
||||
DEFAULT_ARGS=" –http.address=0.0.0.0 –httpproxy.address=0.0.0.0 -socksproxy.address=0.0.0.0 –sam.address=0.0.0.0 –bob.address=0.0.0.0 –i2cp.address=0.0.0.0 –i2pcontrol.port=0.0.0.0 –upnp.enabled=false -service " |
||||
|
||||
mkdir -p /var/lib/i2pd && chown -R i2pd:nobody /var/lib/i2pd && chmod u+rw /var/lib/i2pd |
||||
|
||||
gosu i2pd i2pd $DEFAULT_ARGS $ARGS |
||||
|
||||
|
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
#include "CPU.h" |
||||
#if defined(__x86_64__) || defined(__i386__) |
||||
#include <cpuid.h> |
||||
#endif |
||||
#include "Log.h" |
||||
|
||||
#ifndef bit_AES |
||||
#define bit_AES (1 << 25) |
||||
#endif |
||||
#ifndef bit_AVX |
||||
#define bit_AVX (1 << 28) |
||||
#endif |
||||
|
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace cpu |
||||
{ |
||||
bool aesni = false; |
||||
bool avx = false; |
||||
|
||||
void Detect() |
||||
{ |
||||
#if defined(__x86_64__) || defined(__i386__) |
||||
int info[4]; |
||||
__cpuid(0, info[0], info[1], info[2], info[3]); |
||||
if (info[0] >= 0x00000001) { |
||||
__cpuid(0x00000001, info[0], info[1], info[2], info[3]); |
||||
aesni = info[2] & bit_AES; // AESNI
|
||||
avx = info[2] & bit_AVX; // AVX
|
||||
} |
||||
#endif |
||||
if(aesni) |
||||
{ |
||||
LogPrint(eLogInfo, "AESNI enabled"); |
||||
} |
||||
if(avx) |
||||
{ |
||||
LogPrint(eLogInfo, "AVX enabled"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
#ifndef LIBI2PD_CPU_H |
||||
#define LIBI2PD_CPU_H |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace cpu |
||||
{ |
||||
extern bool aesni; |
||||
extern bool avx; |
||||
|
||||
void Detect(); |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
#ifndef CRYPTO_WORKER_H_ |
||||
#define CRYPTO_WORKER_H_ |
||||
|
||||
#include <condition_variable> |
||||
#include <mutex> |
||||
#include <deque> |
||||
#include <thread> |
||||
#include <vector> |
||||
#include <memory> |
||||
|
||||
namespace i2p |
||||
{ |
||||
namespace worker |
||||
{ |
||||
template<typename Caller> |
||||
struct ThreadPool |
||||
{ |
||||
typedef std::function<void(void)> ResultFunc; |
||||
typedef std::function<ResultFunc(void)> WorkFunc; |
||||
typedef std::pair<std::shared_ptr<Caller>, WorkFunc> Job; |
||||
typedef std::mutex mtx_t; |
||||
typedef std::unique_lock<mtx_t> lock_t; |
||||
typedef std::condition_variable cond_t; |
||||
ThreadPool(int workers) |
||||
{ |
||||
stop = false; |
||||
if(workers > 0) |
||||
{ |
||||
while(workers--) |
||||
{ |
||||
threads.emplace_back([this] { |
||||
for (;;) |
||||
{ |
||||
Job job; |
||||
{ |
||||
lock_t lock(this->queue_mutex); |
||||
this->condition.wait( |
||||
lock, [this] { return this->stop || !this->jobs.empty(); }); |
||||
if (this->stop && this->jobs.empty()) return; |
||||
job = std::move(this->jobs.front()); |
||||
this->jobs.pop_front(); |
||||
} |
||||
ResultFunc result = job.second(); |
||||
job.first->GetService().post(result); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
void Offer(const Job & job) |
||||
{ |
||||
{ |
||||
lock_t lock(queue_mutex); |
||||
if (stop) return; |
||||
jobs.emplace_back(job); |
||||
} |
||||
condition.notify_one(); |
||||
} |
||||
|
||||
~ThreadPool() |
||||
{ |
||||
{ |
||||
lock_t lock(queue_mutex); |
||||
stop = true; |
||||
} |
||||
condition.notify_all(); |
||||
for(auto &t: threads) t.join(); |
||||
} |
||||
|
||||
std::vector<std::thread> threads; |
||||
std::deque<Job> jobs; |
||||
mtx_t queue_mutex; |
||||
cond_t condition; |
||||
bool stop; |
||||
}; |
||||
} |
||||
} |
||||
|
||||
|
||||
#endif |
Loading…
Reference in new issue