diff --git a/android/BOINC/res/layout/status_layout_error.xml b/android/BOINC/res/layout/status_layout_error.xml
deleted file mode 100644
index 95a311d510..0000000000
--- a/android/BOINC/res/layout/status_layout_error.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/BOINC/res/layout/status_layout_launching.xml b/android/BOINC/res/layout/status_layout_launching.xml
deleted file mode 100644
index d6665cb368..0000000000
--- a/android/BOINC/res/layout/status_layout_launching.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/android/BOINC/res/layout/status_layout_noproject.xml b/android/BOINC/res/layout/status_layout_noproject.xml
deleted file mode 100644
index cf9c485fc4..0000000000
--- a/android/BOINC/res/layout/status_layout_noproject.xml
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/BOINC/res/values/configuration.xml b/android/BOINC/res/values/configuration.xml
index bc70f77c16..9153257f72 100644
--- a/android/BOINC/res/values/configuration.xml
+++ b/android/BOINC/res/values/configuration.xml
@@ -30,5 +30,5 @@
true
true
false
- true
+ false
diff --git a/android/BOINC/res/values/strings.xml b/android/BOINC/res/values/strings.xml
index dbd3e5d31f..bdb4129a0e 100644
--- a/android/BOINC/res/values/strings.xml
+++ b/android/BOINC/res/values/strings.xml
@@ -30,6 +30,7 @@
boinc
/data/data/edu.berkeley.boinc/client/
+ ca-bundle.crt
gui_rpc_auth.cfg
@@ -105,15 +106,15 @@
Reading preferences…
OK
- Battery
+ Calculate on Battery
Calculation while running on battery
Calculation only when connected to charger
Maximal used storage space (in %)
Storage left unused (in GB)
Data transfer limit (daily, in MB)
- Use only WiFi
- Transfer only on WiFi
- Transfer on all networks
+ Fetch work only on WiFi
+ Transfer project work only on WiFi connection
+ Transfer project work on all networks
Autostart
BOINC starts on boot up
Start BOINC manually
@@ -153,17 +154,5 @@
Refresh
AndroidBOINC manager messages:
BOINC Client messages:
- error
- error
- Launching
- no project
- email
- long
- Password
- Project
- ca-bundle.crt
-
-
-
diff --git a/android/BOINC/src/edu/berkeley/boinc/AndroidBOINCActivity.java b/android/BOINC/src/edu/berkeley/boinc/AndroidBOINCActivity.java
deleted file mode 100644
index a14542f446..0000000000
--- a/android/BOINC/src/edu/berkeley/boinc/AndroidBOINCActivity.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*******************************************************************************
- * This file is part of BOINC.
- * http://boinc.berkeley.edu
- * Copyright (C) 2012 University of California
- *
- * BOINC is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * BOINC 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with BOINC. If not, see .
- ******************************************************************************/
-package edu.berkeley.boinc;
-
-import edu.berkeley.boinc.client.ClientStatus;
-import edu.berkeley.boinc.client.Monitor;
-import android.app.TabActivity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.res.Resources;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-import android.widget.TabHost;
-import android.widget.TabHost.TabSpec;
-import android.widget.Toast;
-
-public class AndroidBOINCActivity extends TabActivity {
-
- private final String TAG = "AndroidBOINCActivity";
-
- private Monitor monitor;
- public static ClientStatus client;
-
- private Boolean mIsBound;
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- // This is called when the connection with the service has been established, getService returns the Monitor object that is needed to call functions.
- monitor = ((Monitor.LocalBinder)service).getService();
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This should not happen
- monitor = null;
- Toast.makeText(getApplicationContext(), "service disconnected", Toast.LENGTH_SHORT).show();
- }
- };
-
- private void doBindService() {
- // Service has to be started "sticky" by the first instance that uses it. It causes the service to stay around, even when all Activities are destroyed (on purpose or by the system)
- // check whether service already started by BootReceiver is done within the service.
- startService(new Intent(this,Monitor.class));
-
- // Establish a connection with the service, onServiceConnected gets called when
- bindService(new Intent(this, Monitor.class), mConnection, 0);
- mIsBound = true;
- }
-
- private void doUnbindService() {
- if (mIsBound) {
- // Detach existing connection.
- unbindService(mConnection);
- mIsBound = false;
- }
- }
-
- @Override
- protected void onDestroy() {
- Log.d(TAG, "onDestroy");
- doUnbindService();
- super.onDestroy();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- Log.d(TAG, "onCreate");
-
- //bind monitor service
- doBindService();
-
- //setup tab layout
- setupTabLayout();
- }
-
- public static void logMessage(Context ctx, String tag, String message) {
- Intent testLog = new Intent();
- testLog.setAction("edu.berkeley.boinc.log");
- testLog.putExtra("message", message);
- testLog.putExtra("tag", tag);
- ctx.sendBroadcast(testLog);
- }
-
- /*
- * setup tab layout.
- * which tabs should be set up is defined in resources file: /res/values/configuration.xml
- */
- private void setupTabLayout() {
-
- Resources res = getResources();
- TabHost tabHost = getTabHost();
-
- if(res.getBoolean(R.bool.tab_status)) {
- TabSpec statusSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_status));
- statusSpec.setIndicator(getResources().getString(R.string.tab_status), getResources().getDrawable(R.drawable.icon_status_tab));
- Intent statusIntent = new Intent(this,StatusActivity.class);
- statusSpec.setContent(statusIntent);
- tabHost.addTab(statusSpec);
- }
-
- if(res.getBoolean(R.bool.tab_tasks)) {
- TabSpec tasksSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_tasks));
- tasksSpec.setIndicator(getResources().getString(R.string.tab_tasks), getResources().getDrawable(R.drawable.icon_tasks_tab));
- Intent tasksIntent = new Intent(this,TasksActivity.class);
- tasksSpec.setContent(tasksIntent);
- tabHost.addTab(tasksSpec);
- }
-
- if(res.getBoolean(R.bool.tab_transfers)) {
- TabSpec transSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_transfers));
- transSpec.setIndicator(getResources().getString(R.string.tab_transfers), getResources().getDrawable(R.drawable.icon_trans_tab));
- Intent transIntent = new Intent(this,TransActivity.class);
- transSpec.setContent(transIntent);
- tabHost.addTab(transSpec);
- }
-
- if(res.getBoolean(R.bool.tab_preferences)) {
- TabSpec prefsSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_preferences));
- prefsSpec.setIndicator(getResources().getString(R.string.tab_preferences), getResources().getDrawable(R.drawable.icon_prefs_tab));
- Intent prefsIntent = new Intent(this,PrefsActivity.class);
- prefsSpec.setContent(prefsIntent);
- tabHost.addTab(prefsSpec);
- }
-
- if(res.getBoolean(R.bool.tab_projects)) {
- TabSpec projectsSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_projects));
- projectsSpec.setIndicator(getResources().getString(R.string.tab_projects), getResources().getDrawable(R.drawable.icon_projects_tab));
- Intent projectsIntent = new Intent(this,ProjectsActivity.class);
- projectsSpec.setContent(projectsIntent);
- tabHost.addTab(projectsSpec);
- }
-
- if(res.getBoolean(R.bool.tab_messages)) {
- TabSpec msgsSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_messages));
- msgsSpec.setIndicator(getResources().getString(R.string.tab_messages), getResources().getDrawable(R.drawable.icon_msgs_tab));
- Intent msgsIntent = new Intent(this,MsgsActivity.class);
- msgsSpec.setContent(msgsIntent);
- tabHost.addTab(msgsSpec);
- }
-
- if(res.getBoolean(R.bool.tab_debug)) {
- TabSpec debugSpec = tabHost.newTabSpec(getResources().getString(R.string.tab_debug));
- debugSpec.setIndicator(getResources().getString(R.string.tab_debug), getResources().getDrawable(R.drawable.icon_debug_tab));
- Intent debugIntent = new Intent(this,DebugActivity.class);
- debugSpec.setContent(debugIntent);
- tabHost.addTab(debugSpec);
- }
-
- Log.d(TAG,"tab layout setup done");
-
- AndroidBOINCActivity.logMessage(this, TAG, "tab setup finished");
- }
-}
diff --git a/android/BOINC/src/edu/berkeley/boinc/PrefsActivity.java b/android/BOINC/src/edu/berkeley/boinc/PrefsActivity.java
index df80e31290..3c3c1d932c 100644
--- a/android/BOINC/src/edu/berkeley/boinc/PrefsActivity.java
+++ b/android/BOINC/src/edu/berkeley/boinc/PrefsActivity.java
@@ -71,7 +71,7 @@ public class PrefsActivity extends Activity implements OnClickListener {
private BroadcastReceiver mClientStatusChangeRec = new BroadcastReceiver() {
@Override
public void onReceive(Context context,Intent intent) {
- Log.d(TAG+"-localClientStatusRecNoisy","received");
+ //Log.d(TAG+"-localClientStatusRecNoisy","received");
if(dataOutdated) { //cause activity to re-init layout
Log.d(TAG, "data was outdated, go directly to reinitPrefsLayout");
dataOutdated = false;
@@ -150,7 +150,7 @@ public class PrefsActivity extends Activity implements OnClickListener {
Log.d(TAG, "readPrefs: null, return false");
return false;
}
- Log.d(TAG, "readPrefs done");
+ //Log.d(TAG, "readPrefs done");
return true;
}
@@ -164,7 +164,7 @@ public class PrefsActivity extends Activity implements OnClickListener {
//init layout instead
reinitPrefsLayout();
} else {
- Log.d(TAG, "loadSettings outdated: " + dataOutdated );
+ //Log.d(TAG, "loadSettings outdated: " + dataOutdated );
if(dataOutdated) { //data is not present or not current, show loading instead!
setContentView(R.layout.prefs_layout_loading);
} else {
@@ -178,6 +178,8 @@ public class PrefsActivity extends Activity implements OnClickListener {
((PrefsListItemWrapperDouble)data.get(5)).status = clientPrefs.daily_xfer_limit_mb;
listAdapter.notifyDataSetChanged(); //force list adapter to refresh
+
+ //Log.d(TAG,"max used pct: " + clientPrefs.disk_max_used_pct);
}
}
}
@@ -273,7 +275,7 @@ public class PrefsActivity extends Activity implements OnClickListener {
edit.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
break;
default:
- Log.d(TAG,"onCreateDialog, couldnt match ID");
+ Log.d(TAG,"onCreateDialog, couldnt match ID");
break;
}
@@ -310,7 +312,7 @@ public class PrefsActivity extends Activity implements OnClickListener {
break;
case R.string.prefs_disk_min_free_gb_header:
tmp=tmp.replaceAll(",","."); //replace e.g. European decimal seperator "," by "."
- clientPrefs.disk_max_used_gb = Double.parseDouble(tmp);
+ clientPrefs.disk_min_free_gb = Double.parseDouble(tmp);
monitor.setPrefs(clientPrefs);
dataOutdated = true; //async write of client prefs started, data out dated until broadcast
break;
diff --git a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
index 4a97e6d36e..0d99860b53 100644
--- a/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
+++ b/android/BOINC/src/edu/berkeley/boinc/client/Monitor.java
@@ -25,8 +25,10 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.HashMap;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
@@ -490,33 +492,31 @@ public class Monitor extends Service{
private Boolean startUp() {
-
- Boolean connect = connectClient(); //try to connect, if client got started in previous life-cycle
-
- if(!connect) { //if connect did not work, start new client instance and run connect attempts in loop
-
- Integer counter = 0;
- Boolean setup = setupClient();
- if(!setup) {
- return false; //setup failed
- }
-
- //try to connect to executed Client in loop
- while(!(connect=connectClient()) && (counter pMap = new HashMap();
+ String [] processLinesAr = sb.toString().split("\n");
+ for(String line : processLinesAr)
+ {
+ Integer pid;
+ String packageName;
+ String [] comps = line.split("[\\s]+");
+ if(comps.length != 9) {continue;}
+ pid = Integer.parseInt(comps[1]);
+ packageName = comps[8];
+ pMap.put(packageName, pid);
+ //Log.d(TAG,"added: " + packageName + pid);
+ }
+
+ //find required pid
+ return pMap.get(processName);
+ }
}
private final class ProjectAttachAsync extends AsyncTask {
@@ -785,6 +819,7 @@ public class Monitor extends Service{
Log.d(TAG, "doInBackground");
Boolean retval1 = rpc.setGlobalPrefsOverrideStruct(params[0]); //set new override settings
Boolean retval2 = rpc.readGlobalPrefsOverride(); //trigger reload of override settings
+ Log.d(TAG,retval1.toString() + retval2);
if(retval1 && retval2) {
Log.d(TAG, "successful.");
return true;
diff --git a/android/BOINC/src/edu/berkeley/boinc/debug/Debugging.java b/android/BOINC/src/edu/berkeley/boinc/debug/Debugging.java
index db893f4e9a..2dda2b32ae 100644
--- a/android/BOINC/src/edu/berkeley/boinc/debug/Debugging.java
+++ b/android/BOINC/src/edu/berkeley/boinc/debug/Debugging.java
@@ -21,5 +21,5 @@ package edu.berkeley.boinc.debug;
public class Debugging {
static public Boolean PERFORMANCE = false;
- static public Boolean DATA = false;
+ static public Boolean DATA = false;
}
diff --git a/android/BOINC/src/edu/berkeley/boinc/debug/Logging.java b/android/BOINC/src/edu/berkeley/boinc/debug/Logging.java
index 2f97142d2c..e0cf83be2a 100644
--- a/android/BOINC/src/edu/berkeley/boinc/debug/Logging.java
+++ b/android/BOINC/src/edu/berkeley/boinc/debug/Logging.java
@@ -20,8 +20,8 @@ package edu.berkeley.boinc.debug;
public class Logging {
- static public Boolean DEBUG = true;
- static public Boolean INFO = true;
+ static public Boolean DEBUG = false;
+ static public Boolean INFO = false;
static public Boolean ERROR = true;
static public Boolean WARNING = true;
diff --git a/android/BOINC/src/edu/berkeley/boinc/receiver/ClientStatusChangeReceiver.java b/android/BOINC/src/edu/berkeley/boinc/receiver/ClientStatusChangeReceiver.java
deleted file mode 100644
index 2f52998f00..0000000000
--- a/android/BOINC/src/edu/berkeley/boinc/receiver/ClientStatusChangeReceiver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * This file is part of BOINC.
- * http://boinc.berkeley.edu
- * Copyright (C) 2012 University of California
- *
- * BOINC is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * BOINC 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with BOINC. If not, see .
- ******************************************************************************/
-package edu.berkeley.boinc.receiver;
-
-import edu.berkeley.boinc.client.ClientStatus;
-import edu.berkeley.boinc.client.Monitor;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-public class ClientStatusChangeReceiver extends BroadcastReceiver {
-
- private ClientStatus status;
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d("ClientStatusChangeReceiver", "onReceive");
-
- //set status of client
- status = Monitor.getClientStatus();
-
- }
-
-}
diff --git a/client/app_control.cpp b/client/app_control.cpp
index 196efe1753..03432607c8 100644
--- a/client/app_control.cpp
+++ b/client/app_control.cpp
@@ -420,8 +420,9 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
strcpy(buf, "");
if (temporary_exit_file_present(x, buf)) {
handle_temporary_exit(will_restart, x, buf);
+ } else {
+ handle_premature_exit(will_restart);
}
- handle_premature_exit(will_restart);
break;
case 0xc000013a: // control-C??
case 0x40010004: // vista shutdown?? can someone explain this?
diff --git a/client/client_state.cpp b/client/client_state.cpp
index 0ff7e6ff31..6e32dcf329 100644
--- a/client/client_state.cpp
+++ b/client/client_state.cpp
@@ -768,6 +768,13 @@ bool CLIENT_STATE::poll_slow_events() {
start_cpu_benchmarks();
}
+#ifdef _WIN32
+ if (have_sysmon_msg) {
+ msg_printf(NULL, MSG_INFO, sysmon_msg);
+ have_sysmon_msg = false;
+ }
+#endif
+
bool old_user_active = user_active;
user_active = !host_info.users_idle(
check_all_logins, global_prefs.idle_time_to_run
@@ -836,7 +843,10 @@ bool CLIENT_STATE::poll_slow_events() {
//
first = false;
if (suspend_reason) {
- print_suspend_tasks_message(suspend_reason);
+ msg_printf(NULL, MSG_INFO,
+ "Suspending computation - %s",
+ suspend_reason_string(suspend_reason)
+ );
}
}
tasks_suspended = (suspend_reason != 0);
diff --git a/client/client_state.h b/client/client_state.h
index 822a6fb906..d27ffebd70 100644
--- a/client/client_state.h
+++ b/client/client_state.h
@@ -501,9 +501,6 @@ extern double calculate_exponential_backoff(
int n, double MIN, double MAX
);
-extern void print_suspend_tasks_message(int);
-
-
//////// TIME-RELATED CONSTANTS ////////////
//////// CLIENT INTERNAL
diff --git a/client/cs_prefs.cpp b/client/cs_prefs.cpp
index 0b0099b483..feb6235536 100644
--- a/client/cs_prefs.cpp
+++ b/client/cs_prefs.cpp
@@ -285,33 +285,34 @@ int CLIENT_STATE::check_suspend_processing() {
}
}
- if (log_flags.cpu_sched) {
- if (old_gpu_suspend_reason && !gpu_suspend_reason) {
- msg_printf(NULL, MSG_INFO, "[cpu_sched] resuming GPU activity");
- request_schedule_cpus("GPU resumption");
- } else if (!old_gpu_suspend_reason && gpu_suspend_reason) {
- msg_printf(NULL, MSG_INFO, "[cpu_sched] suspending GPU activity");
- request_schedule_cpus("GPU suspension");
+ if (old_gpu_suspend_reason && !gpu_suspend_reason) {
+ if (log_flags.task) {
+ msg_printf(NULL, MSG_INFO, "[task] resuming GPU activity");
}
+ request_schedule_cpus("GPU resumption");
+ } else if (!old_gpu_suspend_reason && gpu_suspend_reason) {
+ if (log_flags.task) {
+ msg_printf(NULL, MSG_INFO, "[task] suspending GPU activity");
+ }
+ request_schedule_cpus("GPU suspension");
}
}
return 0;
}
-
-void print_suspend_tasks_message(int reason) {
- msg_printf(NULL, MSG_INFO, "Suspending computation - %s", suspend_reason_string(reason));
-}
-
-
int CLIENT_STATE::suspend_tasks(int reason) {
if (reason == SUSPEND_REASON_CPU_THROTTLE) {
if (log_flags.cpu_sched) {
msg_printf(NULL, MSG_INFO, "[cpu_sched] Suspending - CPU throttle");
}
} else {
- print_suspend_tasks_message(reason);
+ if (log_flags.task) {
+ msg_printf(NULL, MSG_INFO,
+ "[task] Suspending computation - %s",
+ suspend_reason_string(reason)
+ );
+ }
}
active_tasks.suspend_all(reason);
return 0;
@@ -324,7 +325,9 @@ int CLIENT_STATE::resume_tasks(int reason) {
}
active_tasks.unsuspend_all();
} else {
- msg_printf(NULL, MSG_INFO, "Resuming computation");
+ if (log_flags.task) {
+ msg_printf(NULL, MSG_INFO, "[task] Resuming computation");
+ }
active_tasks.unsuspend_all();
request_schedule_cpus("Resuming computation");
}
diff --git a/client/hostinfo_network.cpp b/client/hostinfo_network.cpp
index 7d1178020a..692dd404d0 100644
--- a/client/hostinfo_network.cpp
+++ b/client/hostinfo_network.cpp
@@ -63,21 +63,27 @@
// if value cant be read, default return false
//
bool HOST_INFO::host_wifi_online() {
- char wifipath[1024];
- snprintf(wifipath, sizeof(wifipath), "/sys/class/net/eth0/operstate");
+ char wifipath_pri[1024];
+ snprintf(wifipath_pri, sizeof(wifipath_pri), "/sys/class/net/eth0/operstate"); //location in Android 2.3
+ char wifipath_sec[1024];
+ snprintf(wifipath_sec, sizeof(wifipath_sec), "/sys/class/net/wlan0/operstate"); //location in Android 4
+
+ FILE *fsyswifi = fopen(wifipath_pri, "r");
+ if(!fsyswifi) { //primary location not available, try _sec
+ fsyswifi = fopen(wifipath_sec, "r");
+ }
- FILE *fsyswifi = fopen(wifipath, "r");
char wifi_state[64];
-
bool wifi_online = false;
if (fsyswifi) {
(void) fscanf(fsyswifi, "%s", &wifi_state);
fclose(fsyswifi);
+ } else {
+ LOGD("wifi adapter not found!");
}
if ((strcmp(wifi_state,"up")) == 0) { //operstate = up
- LOGD("wifi is online");
wifi_online = true;
}
diff --git a/db/constraints.sql b/db/constraints.sql
index 948de8fe37..e32daffb21 100644
--- a/db/constraints.sql
+++ b/db/constraints.sql
@@ -131,4 +131,4 @@ alter table assignment
add index asgn_target(target_type, target_id);
alter table job_file
- add index md5(md5);
+ add unique jf_md5(md5);
diff --git a/doc/links.php b/doc/links.php
index 64b25acaa7..343cc925ea 100644
--- a/doc/links.php
+++ b/doc/links.php
@@ -34,7 +34,12 @@ $info_sites = array(
"(survey of volunteer computing, including non-BOINC projects)"
),
array(
- "http://www.kd-web.info/clanky.php",
+ "http://www.rechenkraft.net/wiki/",
+ "Rechenkraft.net wiki",
+ "(German, English, Portuguese)"
+ ),
+ array(
+ "http://www.kd-web.info/#%21/boinc",
"Flash-based BOINC tutorials", "(in Czech, English, and Slovak)"
),
//array(
@@ -56,21 +61,21 @@ $info_sites = array(
"BOINC Argentina",
"(in Spanish)",
),
- array(
- "http://faq.boinc.de/",
- "Deutsche BOINC FAQ",
- "(in German)",
- ),
- array(
- "http://www.boincfrance.org/",
- "BOINCFrance.org",
- "(in French)",
- ),
- array(
- "http://www.crunching-family.at/wiki/",
- "Crunching Family Wiki",
- "(In German)",
- ),
+ //array(
+ // "http://faq.boinc.de/",
+ // "Deutsche BOINC FAQ",
+ // "(in German)",
+ //),
+ //array(
+ // "http://www.boincfrance.org/",
+ // "BOINCFrance.org",
+ // "(in French)",
+ //),
+ //array(
+ // "http://www.crunching-family.at/wiki/",
+ // "Crunching Family Wiki",
+ // "(In German)",
+ //),
array(
"http://www.angelfire.com/jkoulouris-boinc/",
"The Big BOINC! Projects and Chronology Page",
@@ -356,9 +361,7 @@ If you'd like to add a web site to this list, please
BOINC-related videos
";
diff --git a/html/inc/stats_sites.inc b/html/inc/stats_sites.inc
index 39908930c2..697fd5c09e 100644
--- a/html/inc/stats_sites.inc
+++ b/html/inc/stats_sites.inc
@@ -98,15 +98,15 @@ $stats_sites = array(
$team_stats_sites = array(
array("http://stats.czechnationalteam.cz/", "Czech National Team", "(in Czech)"),
array("http://www.boincitaly.org/", "BOINC.Italy"),
- array("http://www.spacepage.be/component/option,com_boinc/", "Spacepage"),
+ //array("http://www.spacepage.be/component/option,com_boinc/", "Spacepage"),
array("http://boinc.radax.net/de_boinc.htm", "BOINC@Austria"),
- array("http://www.myboinc.com/scores/", "L'Alliance Francophone"),
+ //array("http://www.myboinc.com/scores/", "L'Alliance Francophone"),
array("http://boincdenmark.dk/", "BOINC@Denmark", "(Danish)"),
array("http://boincdenmark.dk/default_en.html", "BOINC@Denmark", "(English)"),
- array("http://www.bigbee.be/comp/boinc/index.php",
- "Boinc.be team stats",
- ""
- ),
+ //array("http://www.bigbee.be/comp/boinc/index.php",
+ // "Boinc.be team stats",
+ // ""
+ //),
array("http://www.seti-teamartbell.com/", "Team Art Bell", ""),
array("http://www.crunchers-freiburg.de/", "crunchers@freiburg", "(German)"),
);
@@ -131,10 +131,10 @@ $sig_sites = array(
"http://boinc.mundayweb.com",
"(User-configurable stats counters. Cool!)"
),
- array("http://www.bigbee.be/comp/boinc/",
- "boinc.be",
- ""
- ),
+ //array("http://www.bigbee.be/comp/boinc/",
+ // "boinc.be",
+ // ""
+ //),
array("http://www.boincstats.com/page/faq.php#3",
"BOINCstats",
"by Willy de Zutter"
diff --git a/html/inc/submit_util.inc b/html/inc/submit_util.inc
index 2e51905067..70ab8deda5 100644
--- a/html/inc/submit_util.inc
+++ b/html/inc/submit_util.inc
@@ -21,6 +21,29 @@
require_once("../inc/submit_db.inc");
+function error($s) {
+ echo "error: $s\n";
+ echo "\n$s\n\n";
+ exit;
+}
+
+function authenticate_user($r, $app) {
+ $auth = (string)$r->authenticator;
+ if (!$auth) error("no authenticator");
+ $auth = BoincDb::escape_string($auth);
+ $user = BoincUser::lookup("authenticator='$auth'");
+ if (!$user) error("bad authenticator");
+ $user_submit = BoincUserSubmit::lookup_userid($user->id);
+ if (!$user_submit) error("no submit access");
+ if ($app && !$user_submit->submit_all) {
+ $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id");
+ if (!$usa) {
+ error("no submit access");
+ }
+ }
+ return array($user, $user_submit);
+}
+
// given its WUs, compute params of a batch
// NOTE: eventually this should be done by server components
// (transitioner, validator etc.) as jobs complete or time out
diff --git a/html/user/job_file.php b/html/user/job_file.php
new file mode 100644
index 0000000000..9e01ad5d17
--- /dev/null
+++ b/html/user/job_file.php
@@ -0,0 +1,196 @@
+.
+
+// Web RPCs for managing job input files on the server.
+//
+// Issues:
+//
+// 1) how are files named?
+// Their name is a function of their MD5.
+// This eliminates issues related to file immutability
+//
+// 2) how do we keep track of the files?
+// In the MySQL database, in a table called job_files.
+// Each row describes a file currently on the server.
+// In addition, we maintain a table batch_file_assoc to record
+// that a file is used by a particular batch.
+// (Note: the association could be at the job level instead.
+// but this way is more efficient if all the jobs in a batch use
+// a particular file.)
+//
+// 3) how do we clean up unused files?
+// A daemon (job_file_deleter) deletes files for which
+// - the delete date (if given) is in the past, and
+// - there are no associations to active batches
+//
+// 4) what are the RPC operations?
+// query_files
+// in:
+// authenticator
+// list of MD5s
+// batch ID (optional)
+// new delete time (optional)
+// out:
+// error message,
+// or list of files (indices in the MD5 list) not present on server
+// action: for each MD5 in in the input list:
+// if present on server
+// update delete time
+// create batch/file association
+// add MD5 to output list
+// upload_files
+// in:
+// authenticator
+// delete time (optional)
+// batch ID (optional)
+// list of MD5s
+// files (as multipart attachments)
+// out:
+// error message, or success
+// action:
+// for each file in list
+// move to project download dir w/ appropriate name
+// create job_files record
+// create batch_file_assoc record if needed
+
+error_reporting(E_ALL);
+ini_set('display_errors', true);
+ini_set('display_startup_errors', true);
+
+require_once("../inc/boinc_db.inc");
+require_once("../inc/dir_hier.inc");
+require_once("../inc/xml.inc");
+require_once("../inc/submit_util.inc");
+
+// the physical name of a file is jf_(md5).
+// Prepend the jf_ to make the source of the file clear
+//
+function job_file_name($md5) {
+ return "jf_$md5";
+}
+
+function query_files($r) {
+ list($user, $user_submit) = authenticate_user($r, null);
+ $absent_files = array();
+ $now = time();
+ $delete_time = (int)$r->delete_time;
+ $batch_id = (int)$r->delete_time;
+ $fanout = parse_config(get_config(), "");
+ $i = 0;
+ foreach($r->md5 as $f) {
+ $md5 = (string)$f;
+ echo "processing $md5\n";
+ $fname = job_file_name($md5);
+ $path = dir_hier_path($fname, "../../download", $fanout);
+
+ // if the job_file record is there,
+ // update the delete time first to avoid race condition
+ // with job file deleter
+ //
+ $job_file = BoincJobFile::lookup_md5($md5);
+ if ($job_file && $job_file->delete_time < $delete_time) {
+ $retval = $job_file::update("delete_time=$delete_time");
+ if ($retval) {
+ xml_error(-1, "job_file::update() failed");
+ }
+ }
+ if (file_exists($path)) {
+ // create the DB record if needed
+ //
+ if (!$job_file) {
+ BoincJobFile::insert(
+ "(md5, create_time, delete_time) values ('$md5', $now, $delete_time)"
+ );
+ }
+ } else {
+ if ($job_file) {
+ $job_file->delete();
+ }
+ $absent_files[] = $i;
+ }
+ $i++;
+ }
+ echo "\n";
+ foreach ($absent_files as $i) {
+ echo "$i\n";
+ }
+ echo "\n";
+}
+
+// upload_files
+// in: list of MD5s, and the files themselves as multipart attachment
+// out: error code
+//
+function upload_files($r) {
+ list($user, $user_submit) = authenticate_user($r, null);
+ $fanout = parse_config(get_config(), "");
+ $delete_time = (int)$r->delete_time;
+ print_r($_FILES);
+ $i = 0;
+ foreach ($r->md5 as $f) {
+ $md5 = (string)$f;
+ $name = "file_$i";
+ $tmp_name = $_FILES[$name]['tmp_name'];
+ if (!is_uploaded_file($tmp_name)) {
+ xml_error(-1, "$tmp_name is not an uploaded file");
+ }
+ $fname = job_file_name($md5);
+ $path = dir_hier_path($fname, "../../download", $fanout);
+ rename($tmp_name, $path);
+ $now = time();
+ $id = BoincJobFile::insert(
+ "(md5, create_time, delete_time) values ('$md5', $now, $delete_time)"
+ );
+ if (!$id) {
+ xml_error(-1, "BoincJobFile::insert() failed");
+ }
+ $i++;
+ }
+ echo "\n";
+}
+
+if (0) {
+$r = simplexml_load_string("\n0\n 80bf244b43fb5d39541ea7011883b7e0\n a6037b05afb05f36e6a85a7c5138cbc1\n\n ");
+submit_batch($r);
+exit;
+}
+if (0) {
+ $r = simplexml_load_string("\n157f96a018b0b2f2b466e2ce3c7f54db\n1\n80bf244b43fb5d39541ea7011883b7e0\na6037b05afb05f36e6a85a7c5138cbc1\n");
+ upload_files($r);
+ exit;
+}
+
+xml_header();
+$r = simplexml_load_string($_POST['request']);
+if (!$r) {
+ xml_error(-1, "can't parse request message");
+}
+
+switch($r->getName()) {
+case 'query_files':
+ query_files($r);
+ break;
+case 'upload_files':
+ echo "foo\n";
+ upload_files($r);
+ break;
+default:
+ xml_error(-1, "no such action");
+}
+
+?>
diff --git a/html/user/submit_rpc_handler.php b/html/user/submit_rpc_handler.php
index 2abeec8d44..76ed358645 100644
--- a/html/user/submit_rpc_handler.php
+++ b/html/user/submit_rpc_handler.php
@@ -30,28 +30,6 @@ error_reporting(E_ALL);
ini_set('display_errors', true);
ini_set('display_startup_errors', true);
-function error($s) {
- echo "\n$s\n\n";
- exit;
-}
-
-function authenticate_user($r, $app) {
- $auth = (string)$r->authenticator;
- if (!$auth) error("no authenticator");
- $auth = BoincDb::escape_string($auth);
- $user = BoincUser::lookup("authenticator='$auth'");
- if (!$user) error("bad authenticator");
- $user_submit = BoincUserSubmit::lookup_userid($user->id);
- if (!$user_submit) error("no submit access");
- if ($app && !$user_submit->submit_all) {
- $usa = BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id");
- if (!$usa) {
- error("no submit access");
- }
- }
- return array($user, $user_submit);
-}
-
function get_app($r) {
$name = (string)($r->batch->app_name);
$name = BoincDb::escape_string($name);
@@ -183,16 +161,13 @@ function submit_batch($r) {
if ($batch_id) {
$batch = BoincBatch::lookup_id($batch_id);
if (!$batch) {
- echo "no batch $batch_id\n";
- exit;
+ error("no batch $batch_id");
}
if ($batch->user_id != $user->id) {
- echo "not owner\n";
- exit;
+ error("not owner");
}
if ($batch->state != BATCH_STATE_INIT) {
- echo "batch not in init state\n";
- exit;
+ error("batch not in init state");
}
}
@@ -208,8 +183,7 @@ function submit_batch($r) {
$cmd = "cd ../../bin; ./adjust_user_priority --user $user->id --flops $total_flops --app $app->name";
$x = system($cmd);
if (!is_numeric($x) || (double)$x == 0) {
- echo "adjust_user_priority returned $x\n";
- exit;
+ error("adjust_user_priority returned $x");
}
$let = (double)$x;
diff --git a/lib/cc_config.h b/lib/cc_config.h
index dbdbe087b1..161cf2e1eb 100644
--- a/lib/cc_config.h
+++ b/lib/cc_config.h
@@ -46,7 +46,7 @@ struct LOG_FLAGS {
bool sched_ops;
// interactions with schedulers
bool task;
- // task start and finish
+ // task start and finish, and suspend/resume
// off by default; intended for developers and testers
//
diff --git a/samples/condor/Makefile b/samples/condor/Makefile
index 8bf801bbe5..1256089580 100644
--- a/samples/condor/Makefile
+++ b/samples/condor/Makefile
@@ -1,9 +1,10 @@
all: boinc_gahp
-boinc_gahp: boinc_gahp.cpp curl.cpp
+boinc_gahp: boinc_gahp.cpp boinc_gahp.h curl.cpp curl.h
g++ -g -O0 -I../../lib \
-o boinc_gahp boinc_gahp.cpp curl.cpp \
-L../../lib -lboinc -lpthread -lcurl
-curl_test: curl.cpp
- g++ -o curl_test curl.cpp -lcurl
+test: test.cpp curl.cpp
+ g++ -g -o test -I../../lib \
+ test.cpp curl.cpp -lcurl
diff --git a/samples/condor/boinc_gahp.cpp b/samples/condor/boinc_gahp.cpp
index 650a979712..7d3cb63735 100644
--- a/samples/condor/boinc_gahp.cpp
+++ b/samples/condor/boinc_gahp.cpp
@@ -58,74 +58,10 @@ struct COMMAND {
typedef map COMMANDS;
COMMANDS commands;
-struct INFILE {
- char src_path[256];
- char dst_path[256];
-};
-
-struct JOB {
- char job_name[256];
- string cmdline_args;
- vector infiles;
- bool all_output_files;
- vector outfiles;
-};
-
-struct LOCAL_FILE {
- char md5[64];
- double nbytes;
-};
-
-struct SUBMIT_REQ {
- char batch_name[256];
- char app_name[256];
- vector jobs;
- map local_files;
- // maps local path to info about file
- int batch_id;
-};
-
int compute_md5(string path, LOCAL_FILE& f) {
return md5_file(path.c_str(), f.md5, f.nbytes);
}
-int create_batch(SUBMIT_REQ& sr) {
- char request[1024];
- char url[1024];
- sprintf(request,
- "\n"
- " %s\n"
- " \n"
- " %s\n"
- " %s\n"
- " \n"
- "\n",
- authenticator,
- sr.batch_name,
- sr.app_name
- );
- sprintf(url, "%ssubmit_rpc_handler.php", project_url);
- FILE* reply = tmpfile();
- vector x;
- int retval = do_http_post(url, request, reply, x);
- if (retval) {
- fclose(reply);
- return retval;
- }
- char buf[256];
- sr.batch_id = 0;
- fseek(reply, 0, SEEK_SET);
- while (fgets(buf, 256, reply)) {
- if (parse_int(buf, "", sr.batch_id)) break;
- }
- fclose(reply);
- if (sr.batch_id == 0) {
- return -1;
- }
- return 0;
-}
-
-
// Get a list of the input files used by the batch.
// Get their MD5s.
// See if they're already on the server.
@@ -148,7 +84,7 @@ int process_input_files(SUBMIT_REQ& req) {
}
// compute the MD5s of these files,
- // and make a map from filename to MD5 and other info (LOCAL_FILE)
+ // and make a map from path to MD5 and size (LOCAL_FILE)
//
set::iterator iter = unique_paths.begin();
while (iter != unique_paths.end()) {
@@ -161,69 +97,43 @@ int process_input_files(SUBMIT_REQ& req) {
}
// ask the server which files it doesn't already have.
- // We send it the batch ID and a list of (filename, MD5) pairs.
- // It
- // - creates batch_file_assoc records for all the files
- // (to avoid race condition w/ file deletion)
- // - returns the list of filenames it doesn't have.
//
- string req_msg;
- req_msg = "\n";
map::iterator map_iter;
map_iter = req.local_files.begin();
- sprintf(buf, "%d\n", req.batch_id);
- req_msg += string(buf);
+ vector md5s, paths;
+ vector absent_files;
while (map_iter != req.local_files.end()) {
LOCAL_FILE lf = map_iter->second;
- string name = map_iter->first;
- sprintf(buf,
- "\n"
- " %s\n"
- " %s\n"
- "\n",
- name.c_str(),
- lf.md5
- );
- req_msg += string(buf);
+ paths.push_back(map_iter->first);
+ md5s.push_back(lf.md5);
iter++;
}
- req_msg += "\n";
- vector send_files;
- FILE* reply = tmpfile();
- retval = do_http_post(project_url, req_msg.c_str(), reply, send_files);
- fseek(reply, 0, SEEK_SET);
- vector missing_files;
- string missing_file;
- while (fgets(buf, 256, reply)) {
- if (parse_str(buf, "", missing_file)) {
- missing_files.push_back(missing_file);
- continue;
- }
- }
- fclose(reply);
+ retval = query_files(
+ project_url,
+ authenticator,
+ req.batch_id,
+ md5s,
+ paths,
+ absent_files
+ );
+ if (retval) return retval;
// upload the missing files.
- // Send a list of the MD5s so the server doesn't have to compute them.
//
- req_msg = "\n";
- for (i=0; isecond;
- sprintf(buf, "%s\n", lf.md5);
- req_msg += string(buf);
+ vector upload_md5s, upload_paths;
+ for (unsigned int i=0; i\n"
- "%s\n"
- "%d\n",
- authenticator,
- req.batch_id
- );
- string request = buf;
- for (unsigned int i=0; i\n";
- if (!job.cmdline_args.empty()) {
- request += "" + job.cmdline_args + "\n";
- }
- for (unsigned int j=0; j::iterator iter = req.local_files.find(infile.src_path);
- LOCAL_FILE& lf = iter->second;
- sprintf(buf,
- "\n"
- "local\n"
- "%s\n"
- "\n",
- lf.md5
- );
- request += buf;
- }
- request += "\n";
- }
- request += "\n";
- sprintf(url, "%ssubmit_rpc_handler.php", project_url);
- FILE* reply = tmpfile();
- vector x;
- int retval = do_http_post(url, request.c_str(), reply, x);
- if (retval) {
- fclose(reply);
- return retval;
- }
- fseek(reply, 0, SEEK_SET);
- while (fgets(buf, 256, reply)) {
- }
- fclose(reply);
- return 0;
-}
-
// To avoid a race condition with file deletion:
// - create a batch record
// - create batch/file associations, and upload files
@@ -327,7 +187,7 @@ void handle_boinc_submit(COMMAND& c, char* p) {
printf("error parsing request: %d\n", retval);
return;
}
- retval = create_batch(req);
+ retval = create_batch(project_url, authenticator, req);
if (retval) {
printf("error creating batch: %d\n", retval);
return;
@@ -337,7 +197,7 @@ void handle_boinc_submit(COMMAND& c, char* p) {
printf("error processing input files: %d\n", retval);
return;
}
- retval = submit_jobs(req);
+ retval = submit_jobs(project_url, authenticator, req);
if (retval) {
printf("error submitting jobs: %d\n", retval);
return;
diff --git a/samples/condor/boinc_gahp.h b/samples/condor/boinc_gahp.h
new file mode 100644
index 0000000000..c98e9a1ba0
--- /dev/null
+++ b/samples/condor/boinc_gahp.h
@@ -0,0 +1,51 @@
+// This file is part of BOINC.
+// http://boinc.berkeley.edu
+// Copyright (C) 2013 University of California
+//
+// BOINC is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// BOINC 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 Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with BOINC. If not, see .
+
+#include