/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.io.*;
import java.net.*;

public class CommChannel {
 String host;
 int port;
 Socket sck;
 ServerSocket srv;
 InputStream sckin;
 OutputStream sckout;
 boolean connected;
 byte inbuf[];
 byte outbuf[];
 int inpos;
 int insize;
 int outpos;
 int curspeed;

 public static int BUFSIZE=1024;
 public static int SOTIMEOUT=2000;

 public CommChannel(String host,int port) throws Throwable {
  this.host=host;
  this.port=port;
  inbuf=new byte[BUFSIZE];
  outbuf=new byte[BUFSIZE];
  curspeed=BUFSIZE;
  if (host==null) {
   try {
    srv=new ServerSocket(port,5);
   } catch(Throwable e) {}
  }
  connect();
 }

 public CommChannel(ServerSocket srv) throws Throwable {
  this.host=host;
  this.port=port;
  inbuf=new byte[BUFSIZE];
  outbuf=new byte[BUFSIZE];
  curspeed=BUFSIZE;
  this.srv=srv;
  connect();
 }


 public void connect() throws Throwable {
  while(true) {
   try {
    if (host==null) {
     sck=srv.accept();
    } else {
     sck=new Socket(host,port);
    } 
    sck.setSoTimeout(0);
    break;
   } catch(Throwable t) {}

   Utils.sleep(ConfigDefs.BOXSERVER_RETRY_TIMEOUT*1000);
  }

  sckin=sck.getInputStream();
  sckout=sck.getOutputStream();
  connected=true;
 }

 public Socket get_client() {
  return sck;
 }

 public void flush_outbuf() throws Throwable {
  sckout.flush();
 }

 public void put_byte(int val) throws Throwable {
  int val1,val2;
 
  val1=(val>>4)&0x0f;
  val2=(val)&0x0f;

  val1+=65;
  val2+=65;

  sckout.write(val1);
  sckout.write(val2);
 }

 public void write_int(int val) throws Throwable {
  put_byte((val>>>24)&0xFF);
  put_byte((val>>>16)&0xFF);
  put_byte((val>>>8)&0xFF);
  put_byte((val>>>0)&0xFF);
 }

 public void write_string(String str) throws Throwable {
  if (str==null) {
   write_int(-1);
   return;  
  }

  int len=str.length();
  int i;

  write_int(len);

  for(i=0;i<len;i++) {
   put_byte((int)str.charAt(i));
  }

 }

 public void write_buf(byte[] b) throws Throwable {
  write_int(b.length);
  for(int i=0;i<b.length;i++) {
   put_byte((int)b[i]);
  }
 }

 public void write_buf(byte[] b,int size) throws Throwable {
  write_int(size);
  for(int i=0;i<size;i++) {
   put_byte((int)b[i]);
  }
 }

 public int get_byte() throws Throwable {
  int val,val2;
 
  val=sckin.read();

  if (val<0) return -1;

  val2=sckin.read();

  if (val2<0) return -1;

  val-=65;
  val2-=65;

  val&=0x0f;
  val2&=0x0f;

  return ((val<<4)|val2);
 }

 public int read_int() throws Throwable {
  int val=(get_byte()&0xff)<<24;
  val|=(get_byte()&0xff)<<16;
  val|=(get_byte()&0xff)<<8;
  val|=(get_byte()&0xff)<<0;
  return val;
 }

 public String read_string() throws Throwable {
  int len=read_int();

  if (len==-1) return null;

  byte str[]=new byte[len];

  for(int i=0;i<len;i++) {
   str[i]=(byte)get_byte();
  }

  return new String(str);
 }

 public byte[] read_buf() throws Throwable {
  int len=read_int();
  byte b[]=new byte[len];

  for(int i=0;i<len;i++) {
   b[i]=(byte)get_byte();
  }

  return b;
 }

 public int read_buf(byte b[],int off) throws Throwable {
  int len=read_int();
  for(int i=0;i<len;i++) {
   b[off+i]=(byte)get_byte();
  }

  return len;
 }

}
