/** * Copyright (C) 2008 Happy Fish / YuQing * * FastDFS Java Client may be copied only under the terms of the GNU Lesser * General Public License (LGPL). * Please visit the FastDFS Home Page http://www.csource.org/ for more detail. */ package org.csource.fastdfs; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; import java.net.Socket; /** * Tracker client * @author Happy Fish / YuQing * @version Version 1.19 */ public class TrackerClient { protected TrackerGroup tracker_group; protected byte errno; /** * constructor with global tracker group */ public TrackerClient() { this.tracker_group = ClientGlobal.g_tracker_group; } /** * constructor with specified tracker group * @param tracker_group the tracker group object */ public TrackerClient(TrackerGroup tracker_group) { this.tracker_group = tracker_group; } /** * get the error code of last call * @return the error code of last call */ public byte getErrorCode() { return this.errno; } /** * get a connection to tracker server * @return tracker server Socket object, return null if fail */ public TrackerServer getConnection() throws IOException { return this.tracker_group.getConnection(); } /** * query storage server to upload file * @param trackerServer the tracker server * @return storage server Socket object, return null if fail */ public StorageServer getStoreStorage(TrackerServer trackerServer) throws IOException { final String groupName = null; return this.getStoreStorage(trackerServer, groupName); } /** * query storage server to upload file * @param trackerServer the tracker server * @param groupName the group name to upload file to, can be empty * @return storage server object, return null if fail */ public StorageServer getStoreStorage(TrackerServer trackerServer, String groupName) throws IOException { byte[] header; String ip_addr; int port; byte cmd; int out_len; boolean bNewConnection; byte store_path; Socket trackerSocket; if (trackerServer == null) { trackerServer = getConnection(); if (trackerServer == null) { return null; } bNewConnection = true; } else { bNewConnection = false; } trackerSocket = trackerServer.getSocket(); OutputStream out = trackerSocket.getOutputStream(); try { if (groupName == null || groupName.length() == 0) { cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE; out_len = 0; } else { cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE; out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } header = ProtoCommon.packHeader(cmd, out_len, (byte)0); out.write(header); if (groupName != null && groupName.length() > 0) { byte[] bGroupName; byte[] bs; int group_len; bs = groupName.getBytes(ClientGlobal.g_charset); bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN]; if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) { group_len = bs.length; } else { group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } Arrays.fill(bGroupName, (byte)0); System.arraycopy(bs, 0, bGroupName, 0, group_len); out.write(bGroupName); } ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), ProtoCommon.TRACKER_PROTO_CMD_RESP, ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN); this.errno = pkgInfo.errno; if (pkgInfo.errno != 0) { return null; } ip_addr = new String(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN, ProtoCommon.FDFS_IPADDR_SIZE-1).trim(); port = (int)ProtoCommon.buff2long(pkgInfo.body, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ProtoCommon.FDFS_IPADDR_SIZE-1); store_path = pkgInfo.body[ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN - 1]; return new StorageServer(ip_addr, port, store_path); } catch(IOException ex) { if (!bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } throw ex; } finally { if (bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } } } /** * query storage servers to upload file * @param trackerServer the tracker server * @param groupName the group name to upload file to, can be empty * @return storage servers, return null if fail */ public StorageServer[] getStoreStorages(TrackerServer trackerServer, String groupName) throws IOException { byte[] header; String ip_addr; int port; byte cmd; int out_len; boolean bNewConnection; Socket trackerSocket; if (trackerServer == null) { trackerServer = getConnection(); if (trackerServer == null) { return null; } bNewConnection = true; } else { bNewConnection = false; } trackerSocket = trackerServer.getSocket(); OutputStream out = trackerSocket.getOutputStream(); try { if (groupName == null || groupName.length() == 0) { cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ALL; out_len = 0; } else { cmd = ProtoCommon.TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL; out_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } header = ProtoCommon.packHeader(cmd, out_len, (byte)0); out.write(header); if (groupName != null && groupName.length() > 0) { byte[] bGroupName; byte[] bs; int group_len; bs = groupName.getBytes(ClientGlobal.g_charset); bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN]; if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) { group_len = bs.length; } else { group_len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } Arrays.fill(bGroupName, (byte)0); System.arraycopy(bs, 0, bGroupName, 0, group_len); out.write(bGroupName); } ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), ProtoCommon.TRACKER_PROTO_CMD_RESP, -1); this.errno = pkgInfo.errno; if (pkgInfo.errno != 0) { return null; } if (pkgInfo.body.length < ProtoCommon.TRACKER_QUERY_STORAGE_STORE_BODY_LEN) { this.errno = ProtoCommon.ERR_NO_EINVAL; return null; } int ipPortLen = pkgInfo.body.length - (ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + 1); final int recordLength = ProtoCommon.FDFS_IPADDR_SIZE - 1 + ProtoCommon.FDFS_PROTO_PKG_LEN_SIZE; if (ipPortLen % recordLength != 0) { this.errno = ProtoCommon.ERR_NO_EINVAL; return null; } int serverCount = ipPortLen / recordLength; if (serverCount > 16) { this.errno = ProtoCommon.ERR_NO_ENOSPC; return null; } StorageServer[] results = new StorageServer[serverCount]; byte store_path = pkgInfo.body[pkgInfo.body.length - 1]; int offset = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; for (int i=0; i decoder = new ProtoStructDecoder(); return decoder.decode(pkgInfo.body, StructGroupStat.class, StructGroupStat.getFieldsTotalSize()); } catch(IOException ex) { if (!bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } throw ex; } catch(Exception ex) { ex.printStackTrace(); this.errno = ProtoCommon.ERR_NO_EINVAL; return null; } finally { if (bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } } } /** * query storage server stat info of the group * @param trackerServer the tracker server * @param groupName the group name of storage server * @return storage server stat array, return null if fail */ public StructStorageStat[] listStorages(TrackerServer trackerServer, String groupName) throws IOException { final String storageIpAddr = null; return this.listStorages(trackerServer, groupName, storageIpAddr); } /** * query storage server stat info of the group * @param trackerServer the tracker server * @param groupName the group name of storage server * @param storageIpAddr the storage server ip address, can be null or empty * @return storage server stat array, return null if fail */ public StructStorageStat[] listStorages(TrackerServer trackerServer, String groupName, String storageIpAddr) throws IOException { byte[] header; byte[] bGroupName; byte[] bs; int len; boolean bNewConnection; Socket trackerSocket; if (trackerServer == null) { trackerServer = getConnection(); if (trackerServer == null) { return null; } bNewConnection = true; } else { bNewConnection = false; } trackerSocket = trackerServer.getSocket(); OutputStream out = trackerSocket.getOutputStream(); try { bs = groupName.getBytes(ClientGlobal.g_charset); bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN]; if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) { len = bs.length; } else { len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } Arrays.fill(bGroupName, (byte)0); System.arraycopy(bs, 0, bGroupName, 0, len); int ipAddrLen; byte[] bIpAddr; if (storageIpAddr != null && storageIpAddr.length() > 0) { bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset); if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE) { ipAddrLen = bIpAddr.length; } else { ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1; } } else { bIpAddr = null; ipAddrLen = 0; } header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_LIST_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte)0); byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen]; System.arraycopy(header, 0, wholePkg, 0, header.length); System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length); if (ipAddrLen > 0) { System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen); } out.write(wholePkg); ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), ProtoCommon.TRACKER_PROTO_CMD_RESP, -1); this.errno = pkgInfo.errno; if (pkgInfo.errno != 0) { return null; } ProtoStructDecoder decoder = new ProtoStructDecoder(); return decoder.decode(pkgInfo.body, StructStorageStat.class, StructStorageStat.getFieldsTotalSize()); } catch(IOException ex) { if (!bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } throw ex; } catch(Exception ex) { ex.printStackTrace(); this.errno = ProtoCommon.ERR_NO_EINVAL; return null; } finally { if (bNewConnection) { try { trackerServer.close(); } catch(IOException ex1) { ex1.printStackTrace(); } } } } /** * delete a storage server from the tracker server * @param trackerServer the connected tracker server * @param groupName the group name of storage server * @param storageIpAddr the storage server ip address * @return true for success, false for fail */ private boolean deleteStorage(TrackerServer trackerServer, String groupName, String storageIpAddr) throws IOException { byte[] header; byte[] bGroupName; byte[] bs; int len; Socket trackerSocket; trackerSocket = trackerServer.getSocket(); OutputStream out = trackerSocket.getOutputStream(); bs = groupName.getBytes(ClientGlobal.g_charset); bGroupName = new byte[ProtoCommon.FDFS_GROUP_NAME_MAX_LEN]; if (bs.length <= ProtoCommon.FDFS_GROUP_NAME_MAX_LEN) { len = bs.length; } else { len = ProtoCommon.FDFS_GROUP_NAME_MAX_LEN; } Arrays.fill(bGroupName, (byte)0); System.arraycopy(bs, 0, bGroupName, 0, len); int ipAddrLen; byte[] bIpAddr = storageIpAddr.getBytes(ClientGlobal.g_charset); if (bIpAddr.length < ProtoCommon.FDFS_IPADDR_SIZE) { ipAddrLen = bIpAddr.length; } else { ipAddrLen = ProtoCommon.FDFS_IPADDR_SIZE - 1; } header = ProtoCommon.packHeader(ProtoCommon.TRACKER_PROTO_CMD_SERVER_DELETE_STORAGE, ProtoCommon.FDFS_GROUP_NAME_MAX_LEN + ipAddrLen, (byte)0); byte[] wholePkg = new byte[header.length + bGroupName.length + ipAddrLen]; System.arraycopy(header, 0, wholePkg, 0, header.length); System.arraycopy(bGroupName, 0, wholePkg, header.length, bGroupName.length); System.arraycopy(bIpAddr, 0, wholePkg, header.length + bGroupName.length, ipAddrLen); out.write(wholePkg); ProtoCommon.RecvPackageInfo pkgInfo = ProtoCommon.recvPackage(trackerSocket.getInputStream(), ProtoCommon.TRACKER_PROTO_CMD_RESP, 0); this.errno = pkgInfo.errno; return pkgInfo.errno == 0; } /** * delete a storage server from the global FastDFS cluster * @param groupName the group name of storage server * @param storageIpAddr the storage server ip address * @return true for success, false for fail */ public boolean deleteStorage(String groupName, String storageIpAddr) throws IOException { return this.deleteStorage(ClientGlobal.g_tracker_group, groupName, storageIpAddr); } /** * delete a storage server from the FastDFS cluster * @param trackerGroup the tracker server group * @param groupName the group name of storage server * @param storageIpAddr the storage server ip address * @return true for success, false for fail */ public boolean deleteStorage(TrackerGroup trackerGroup, String groupName, String storageIpAddr) throws IOException { int serverIndex; int notFoundCount; TrackerServer trackerServer; notFoundCount = 0; for (serverIndex=0; serverIndex