/* * Copyright 2012 The Stanford MobiSocial Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package mobisocial.musubi.nearby.scanner; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.nio.ByteBuffer; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import mobisocial.crypto.IBHashedIdentity; import mobisocial.musubi.App; import mobisocial.musubi.model.DbContactAttributes; import mobisocial.musubi.model.MIdentity; import mobisocial.musubi.model.helpers.IdentitiesManager; import mobisocial.musubi.nearby.item.NearbyItem; import mobisocial.musubi.nearby.item.NearbyStranger; import mobisocial.musubi.ui.MusubiBaseActivity; import android.app.Activity; import android.net.Uri; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.MulticastLock; import android.util.Log; /** * Scans the LAN for nearby content. * */ public class MulticastScannerTask extends NearbyScannerTask { boolean DBG = MusubiBaseActivity.DBG; public static final String NEARBY_GROUP = "239.5.5.0"; public static final int NEARBY_PORT = 9178; public static final int PROTOCOL_BROADCAST_URI = 0x853000; private final Activity mContext; private final WifiManager mWifiManager; private final Set<Uri> mSeenUris = new HashSet<Uri>(); private MulticastSocket mSocket; private MulticastLock mLock; private String mWifiBSSID; private String mWifiSSID; private IdentitiesManager identitiesManager_; public MulticastScannerTask(Activity context, WifiManager manager) { mContext = context; mWifiManager = manager; identitiesManager_ = new IdentitiesManager(App.getDatabaseSource(context)); } @Override protected void onPreExecute() { if (mWifiManager == null) { Log.d(TAG, "No wifi available."); return; } mLock = mWifiManager.createMulticastLock("msb-scanner"); mLock.acquire(); try { mSocket = new MulticastSocket(NEARBY_PORT); } catch (IOException e) { Log.w(TAG, "error multicasting", e); mSocket = null; } mWifiBSSID = mWifiManager.getConnectionInfo().getBSSID(); mWifiSSID = mWifiManager.getConnectionInfo().getSSID(); // Ignore this device's profile: mSeenUris.add(IdentitiesManager.uriForMyIBHashedIdentity()); } @Override protected List<NearbyItem> doInBackground(Void... params) { if (DBG) Log.d(TAG, "Scanning for nearby multicast..."); try { mSocket.joinGroup(InetAddress.getByName(NEARBY_GROUP)); } catch (IOException e) { Log.w(TAG, "Failed to listen on multicast", e); mSocket = null; } while (mSocket != null) { if (isCancelled()) { break; } try { byte[] buf = new byte[2048]; DatagramPacket recv = new DatagramPacket(buf, buf.length); mSocket.receive(recv); Uri friendUri = null; boolean acceptFriend = false; ByteBuffer packet = ByteBuffer.wrap(recv.getData()); String theirIp = recv.getAddress().getHostAddress(); int protocol = packet.getInt(); try { switch (protocol) { case PROTOCOL_BROADCAST_URI: { byte[] rest = new byte[recv.getLength() - 4]; packet.get(rest); friendUri = Uri.parse(new String(rest)); break; } /*case MulticastBroadcastTask.PROTOCOL_FRIEND_REQUEST: { acceptFriend = true; byte[] rest = new byte[recv.getLength() - 4]; packet.get(rest); friendUri = Uri.parse(new String(rest)); break; }*/ default: { String uriStr = new String(recv.getData(), 0, recv.getLength()); friendUri = Uri.parse(uriStr); } } } catch (Exception e) { if (DBG) Log.e(TAG, "Error processing packet", e); } if (friendUri == null || mSeenUris.contains(friendUri)) { continue; } IBHashedIdentity hid = IdentitiesManager.ibHashedIdentityForUri(friendUri); MIdentity ident = identitiesManager_.getIdentityForIBHashedIdentity(hid); if (ident.contactId_ == null && acceptFriend) { //TODO: add to android contact book } if (ident.contactId_ != null) { //TODO: ident.contactId_ may not make any sense to this call. //Also are attributes on musubi contacts or identities? DbContactAttributes.update(mContext, ident.contactId_, DbContactAttributes.ATTR_NEARBY_TIMESTAMP, Long.toString(new Date().getTime())); DbContactAttributes.update(mContext, ident.contactId_, DbContactAttributes.ATTR_LAN_IP, theirIp); DbContactAttributes.update(mContext, ident.contactId_, DbContactAttributes.ATTR_WIFI_BSSID, mWifiBSSID); DbContactAttributes.update(mContext, ident.contactId_, DbContactAttributes.ATTR_WIFI_SSID, mWifiSSID); } // TODO: User user = FriendRequest.parseUri(friendUri); String name = friendUri.getQueryParameter("name"); if (name == null) { name = "Unknown"; } addNearbyItem(new NearbyStranger(mContext, name, friendUri, null)); mSeenUris.add(friendUri); } catch (IOException e) { Log.e(TAG, "Error receiving multicast", e); mSocket = null; } } Log.d(TAG, "Done scanning lan"); mLock.release(); return null; } }