Example #1
0
void CRedirectSOCKS_Thread::StartRedirect()
{	
	char svn;
	if(xRead(m_sClientSocket, &svn, 1)<1) { xClose(m_sClientSocket); return; }

	switch(svn)
	{
	case 69:
		break;
	case 4:
		{
			struct socks4_hdr hdr4; sockaddr_in addrHost; int sServer;

			if(xRead(m_sClientSocket,&hdr4.cd,sizeof(hdr4)-2)<1) { xClose(m_sClientSocket); return; }

			if(hdr4.cd==SOCKS4_CONNECT)
			{
				memset(&addrHost, 0, sizeof(addrHost)); addrHost.sin_family=AF_INET;
				addrHost.sin_port=hdr4.destport; addrHost.sin_addr.s_addr=hdr4.destaddr;
				
				sServer=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
				
				if(connect(sServer,(sockaddr*)&addrHost, sizeof(addrHost))==SOCKET_ERROR)
				{
					hdr4.vn=0; hdr4.cd=SOCKS4_REJECT;
					memset(&hdr4.userid, 0, 1024);
					xWrite(m_sClientSocket, (char*)&hdr4, 8);
					xClose(m_sClientSocket);
					return;
				}

				hdr4.vn=0; hdr4.cd=SOCKS4_GRANT;
				memset(&hdr4.userid, 0, 1024);
				xWrite(m_sClientSocket, (char*)&hdr4, 8);

				int iLen; char szBuf[1024]; fd_set fd;

				SET_SOCK_BLOCK(m_sClientSocket, 0); SET_SOCK_BLOCK(sServer, 0);

				while(true)
				{
					iLen=xRead(sServer, szBuf, sizeof(szBuf));
					if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); continue; }
					xWrite(m_sClientSocket, szBuf, iLen);

					iLen=xRead(m_sClientSocket, szBuf, sizeof(szBuf));
					if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); continue; }
					xWrite(sServer, szBuf, iLen);
				}

				xClose(m_sClientSocket); xClose(sServer);
			}

		}
		break;
	default:
		break;
	}
}
Example #2
0
JNL_Listen::JNL_Listen(short port, unsigned int which_interface)
{
  m_port=port;
  m_socket = ::socket(AF_INET,SOCK_STREAM,0);
  if (m_socket < 0) 
  {
  }
  else
  {
    struct sockaddr_in sin;
    SET_SOCK_BLOCK(m_socket,0);
#ifndef _WIN32
    int bflag = 1;
    setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, &bflag, sizeof(bflag));
#endif
    memset((char *) &sin, 0,sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons( (short) port );
    sin.sin_addr.s_addr = which_interface?which_interface:INADDR_ANY;
    if (::bind(m_socket,(struct sockaddr *)&sin,sizeof(sin))) 
    {
      closesocket(m_socket);
      m_socket=-1;
    }
    else
    {  
      if (::listen(m_socket,8)==-1) 
      {
        closesocket(m_socket);
        m_socket=-1;
      }
    }
  }
}
Example #3
0
void JNL_Connection::connect(char *hostname, int port)
{
  close(1);
  m_remote_port=(short)port;
  m_socket=::socket(AF_INET,SOCK_STREAM,0);
  if (m_socket==INVALID_SOCKET)
  {
    m_errorstr="creating socket";
    m_state=STATE_ERROR;
  }
  else
  {
    SET_SOCK_BLOCK(m_socket,0);
    strncpy(m_host,hostname,sizeof(m_host)-1);
    m_host[sizeof(m_host)-1]=0;
    memset(&m_saddr,0,sizeof(m_saddr));
    if (!m_host[0])
    {
      m_errorstr="empty hostname";
      m_state=STATE_ERROR;
    }
    else
    {
      m_state=STATE_RESOLVING;
      m_saddr.sin_family=AF_INET;
      m_saddr.sin_port=htons((unsigned short)port);
      m_saddr.sin_addr.s_addr=inet_addr(hostname);
    }
  }
}
Example #4
0
int connect_no_timeout(unsigned int sockfd,
						const struct sockaddr *addr,
						int addrlen,
						struct timeval *timeout)
{
	int error = 0, ret;
	int error_len;

	fd_set rset, wset;

	if (timeout == NULL)	{
		/* blocking mode */
		return connect(sockfd, addr, addrlen);
	}
	
	/* Set the socket to be non-blocking */
	SET_SOCK_BLOCK(sockfd, 0);

	fconnect(sockfd, addr, addrlen);

	FD_ZERO(&rset);
	FD_SET(sockfd, &rset);
	FD_ZERO(&wset);
	FD_SET(sockfd, &wset);

	if ((ret = fselect(sockfd + 1, &rset, &wset, NULL, timeout)) == 0) {
		return SOCKET_ERROR;
	}

	if (ret == SOCKET_ERROR) {
		return SOCKET_ERROR;
	}

	if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		error_len = sizeof(error);
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) == SOCKET_ERROR) {
			return SOCKET_ERROR;
		}
	} else {
		/* whoops: sockfd has disappeared */
		return SOCKET_ERROR;
	}

	/* Set the socket back to blocking
	ioctlsocket(sockfd, FIONBIO, &block);
	*/

	if (error) { 
		return SOCKET_ERROR;
	}

	return 0;
}
Example #5
0
void JNL_Connection::connect(int s, struct sockaddr_in *loc)
{
  close(1);
  m_socket=s;
  m_remote_port=0;
  m_dns=NULL;
  if (loc) *m_saddr=*loc;
  else memset(m_saddr,0,sizeof(struct sockaddr_in));
  if (m_socket != -1)
  {
    SET_SOCK_BLOCK(m_socket,0);
    m_state=STATE_CONNECTED;
  }
  else 
  {
    m_errorstr="invalid socket passed to connect";
    m_state=STATE_ERROR;
  }
}
Example #6
0
void JNL_Connection::connect(char *hostname, int port)
{
  close(1);
  m_remote_port=(short)port;
  m_socket=::socket(AF_INET,SOCK_STREAM,0);
  if (m_socket==-1)
  {
    m_errorstr="creating socket";
    m_state=STATE_ERROR;
  }
  else
  {
    if (m_localinterfacereq != INADDR_ANY)
    {
      sockaddr_in sa={0,};
      sa.sin_family=AF_INET;
      sa.sin_addr.s_addr=m_localinterfacereq;
      bind(m_socket,(struct sockaddr *)&sa,16);
    }
    SET_SOCK_BLOCK(m_socket,0);
    strncpy(m_host,hostname,sizeof(m_host)-1);
    m_host[sizeof(m_host)-1]=0;
    memset(m_saddr,0,sizeof(struct sockaddr_in));
    if (!m_host[0])
    {
      m_errorstr="empty hostname";
      m_state=STATE_ERROR;
    }
    else
    {
      m_state=STATE_RESOLVING;
      m_saddr->sin_family=AF_INET;
      m_saddr->sin_port=htons((unsigned short)port);
      m_saddr->sin_addr.s_addr=inet_addr(hostname);
    }
  }
}
Example #7
0
void CRedirectHTTPS_Thread::StartRedirect()
{	m_sServerSocket=INVALID_SOCKET; m_iConnections=0;
	int iErr=1; bool bFinished=false; while(!bFinished && g_pMainCtrl->m_bRunning) {
		url uURL; char szBuffer[MAX_PATH]; bool bGet=false;

		// Receive the proxy request
		if(!m_sClientSocket.RecvLineIRC(szBuffer, MAX_PATH)) { bFinished=true; break; }
		CString sBuffer(szBuffer);
		// Fail if there is no url
		// if(!sBuffer.Token(1, " ").Compare("")) { bFinished=true; break; }

		if(!sBuffer.Compare("")) { bFinished=true; break; }

		if(!sBuffer.Token(0, " ").CompareNoCase("GET")) { // GET method
			bGet=true;
			// Parse the url
			if(!ParseURL(sBuffer.Token(1, " ").CStr(), &uURL)) { bFinished=true; break; }
			// Fail if the protocol isnt http
			if(uURL.sProto.Compare("http")) { bFinished=true; break; }
		} else if(!sBuffer.Token(0, " ").CompareNoCase("CONNECT")) { // CONNECT method
			bGet=false;
			// Parse the host
			uURL.sProto.Assign("connect");
			uURL.sReq.Assign("");
			uURL.sHost.Assign(sBuffer.Token(1, " ").Token(0, ":"));
			if(!sBuffer.Token(1, " ").Token(1, ":").CStr()) { bFinished=true; break; }
			uURL.iPort=atoi(sBuffer.Token(1, " ").Token(1, ":").CStr());
			if(!uURL.iPort) uURL.iPort=80; }

		// Get the rest of the request
		CString sMethod(sBuffer.Token(0, " ")); if(!sMethod.Compare("")) { bFinished=true; break; }
		CString sHTTPSVer(sBuffer.Token(2, " ")); if(!sHTTPSVer.Compare("")) { bFinished=true; break; }
		CString sOldHost(uURL.sHost);

#ifdef DBGCONSOLE
		if(bGet)
			g_pMainCtrl->m_cConsDbg.Log(5, "CRedirectHTTPS(0x%8.8Xh): %s %s %s...\n", m_pRedirHTTPS, sMethod.CStr(), uURL.sReq.CStr(), sHTTPSVer.CStr());
		else
			g_pMainCtrl->m_cConsDbg.Log(5, "CRedirectHTTPS(0x%8.8Xh): %s %s:%d %s...\n", m_pRedirHTTPS, sMethod.CStr(), uURL.sHost.CStr(), uURL.iPort, sHTTPSVer.CStr());
#endif

		char szBuf[4096]; strcpy(szBuf, "bla");
		if(bGet) {
			if(!m_sClientSocket.Recv(szBuf, sizeof(szBuf)))
			{	m_sClientSocket.Disconnect(); return; }
		} else {
			while(strcmp(szBuf, "")) // Loop while headers arent finished
				if(!m_sClientSocket.RecvLineIRC(szBuf, 4096)) { bFinished=true; break; }
			if(bFinished) break; }

		CString sReqBuf;
		if(bGet)
			sReqBuf.Format("%s %s %s\r\n%s", sMethod.CStr(), uURL.sReq.CStr(), sHTTPSVer.CStr(), szBuf);
		else
			sReqBuf.Format("HTTP/1.0 200 Connection established\r\n\r\n");

		m_sServerSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(!m_sServerSocket.IsConnected())
		{	m_sClientSocket.Disconnect(); return; }

		// Connect to the server
		if(!m_sServerSocket.Connect(uURL.sHost.CStr(), uURL.iPort)) // Connect failed, exit
		{	
#ifdef DBGCONSOLE
			g_pMainCtrl->m_cConsDbg.Log(5, "CRedirectHTTPS(0x%8.8Xh): Cannot connect to %s:%d (%s)...\n", m_pRedirHTTPS, uURL.sHost.CStr(), uURL.iPort, uURL.sReq.CStr());
#endif
			m_sClientSocket.Disconnect(); m_sServerSocket.Disconnect(); return; }

		if(bGet) {
			if(!m_sServerSocket.Write(sReqBuf.CStr(), sReqBuf.GetLength()))
			{	m_sClientSocket.Disconnect(); m_sServerSocket.Disconnect(); return; }
		} else {
			if(!m_sClientSocket.Write(sReqBuf.CStr(), sReqBuf.GetLength()))
			{	m_sClientSocket.Disconnect(); m_sServerSocket.Disconnect(); return; }
		}

		int iLen; fd_set fd;
		SET_SOCK_BLOCK(m_sClientSocket.GetSocket(), 0);
		SET_SOCK_BLOCK(m_sServerSocket.GetSocket(), 0);

		if(bGet) {
			while(true)
			{	memset(szBuffer, 0, sizeof(szBuffer));
				if(!m_sClientSocket.RecvLineIRC(szBuffer, sizeof(szBuffer))) { Sleep(10); break; }
				if(strcmp(szBuffer, "")) {
					sBuffer.Assign(szBuffer);
					if(!sBuffer.Token(0, " ").Compare("GET"))
					{	// Fail if there is no url
						if(!sBuffer.Token(1, " ").Compare("")) { bFinished=true; break; }
						// Parse the url
						if(!ParseURL(sBuffer.Token(1, " ").CStr(), &uURL)) break;
						// Fail if the protocol isnt http
						if(uURL.sProto.Compare("http")) { bFinished=true; break; }
						// Get the rest of the request
						CString sMethod(sBuffer.Token(0, " ")); if(!sMethod.Compare("")) { bFinished=true; break; }
						CString sHTTPSVer(sBuffer.Token(2, " ")); if(!sHTTPSVer.Compare("")) { bFinished=true; break; }
						sBuffer.Format("%s %s %s\r\n", sMethod.CStr(), uURL.sReq.CStr(), sHTTPSVer.CStr());
						if(uURL.sHost.Compare(sOldHost))
						{	m_sServerSocket.Disconnect();

							if(!m_sServerSocket.Connect(uURL.sHost.CStr(), uURL.iPort)) // Connect failed, exit
							{	
#ifdef DBGCONSOLE
								g_pMainCtrl->m_cConsDbg.Log(5, "CRedirectHTTPS(0x%8.8Xh): Cannot connect to %s:%d (%s)...\n", m_pRedirHTTPS, uURL.sHost.CStr(), uURL.iPort, uURL.sReq.CStr());
#endif
								m_sClientSocket.Disconnect(); m_sServerSocket.Disconnect(); return; }
							
							sOldHost.Assign(uURL.sHost); }
					}
					else
					{	sBuffer.Append("\r\n"); }
				if(!m_sServerSocket.Write(sBuffer.CStr(), sBuffer.GetLength())) break; }

				m_sServerSocket.Recv(szBuf, sizeof(szBuf), &iLen);
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				m_sClientSocket.Write(szBuf, iLen);
			}
		} else {
			while(true) {
				m_sClientSocket.Recv(szBuf, sizeof(szBuf), &iLen);
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				m_sServerSocket.Write(szBuf, iLen);

				m_sServerSocket.Recv(szBuf, sizeof(szBuf), &iLen);
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				m_sClientSocket.Write(szBuf, iLen);
			}
		}

		m_sClientSocket.Disconnect(); m_sServerSocket.Disconnect();
		bFinished=true;
	}
}
Example #8
0
void CRedirectHTTP_Thread::StartRedirect()
{	m_sServerSocket=INVALID_SOCKET; m_iConnections=0;
	int iErr=1; bool bFinished=false; while(!bFinished) {
		url uURL; char szBuffer[MAX_PATH]; bool bGet=false;

		// Receive the proxy request
		if(!recv_line_irc(m_sClientSocket, szBuffer, MAX_PATH, NULL)) { bFinished=true; break; }
		CString sBuffer(szBuffer);
		// Fail if there is no url
		// if(!sBuffer.Token(1, " ").Compare("")) { bFinished=true; break; }

		if(!sBuffer.Compare("")) { bFinished=true; break; }

		if(!sBuffer.Token(0, " ").CompareNoCase("GET")) { // GET method
			bGet=true;
			// Parse the url
			if(!ParseURL(sBuffer.Token(1, " ").CStr(), &uURL)) { bFinished=true; break; }
			// Fail if the protocol isnt http
			if(uURL.sProto.Compare("http")) { bFinished=true; break; }
		} else if(!sBuffer.Token(0, " ").CompareNoCase("CONNECT")) { // CONNECT method
			bGet=false;
			// Parse the host
			uURL.sProto.Assign("connect");
			uURL.sReq.Assign("");
			uURL.sHost.Assign(sBuffer.Token(1, " ").Token(0, ":"));
			if(!sBuffer.Token(1, " ").Token(1, ":").CStr()) { bFinished=true; break; }
			uURL.iPort=atoi(sBuffer.Token(1, " ").Token(1, ":").CStr());
			if(!uURL.iPort) uURL.iPort=80; }

		// Get the rest of the request
		CString sMethod(sBuffer.Token(0, " ")); if(!sMethod.Compare("")) { bFinished=true; break; }
		CString sHTTPVer(sBuffer.Token(2, " ")); if(!sHTTPVer.Compare("")) { bFinished=true; break; }
		CString sOldHost(uURL.sHost);

#ifdef DBGCONSOLE
		if(bGet)
			g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): %s %s %s...\n", m_pRedirHTTP, sMethod.CStr(), uURL.sReq.CStr(), sHTTPVer.CStr());
		else
			g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): %s %s:%d %s...\n", m_pRedirHTTP, sMethod.CStr(), uURL.sHost.CStr(), uURL.iPort, sHTTPVer.CStr());
#endif

		char szBuf[4096]; strcpy(szBuf, "bla");
		if(bGet) {
			if(xRead(m_sClientSocket, szBuf, sizeof(szBuf))<1)
			{	xClose(m_sClientSocket); return; }
		} else {
			while(strcmp(szBuf, "")) // Loop while headers arent finished
				if(!recv_line_irc(m_sClientSocket, szBuf, 4096, NULL)) { bFinished=true; break; }
			if(bFinished) break; }

		CString sReqBuf;
		if(bGet)
			sReqBuf.Format("%s %s %s\r\n%s", sMethod.CStr(), uURL.sReq.CStr(), sHTTPVer.CStr(), szBuf);
		else
			sReqBuf.Format("HTTP/1.0 200 Connection established\r\n\r\n");

		m_sServerSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if(m_sServerSocket==SOCKET_ERROR || m_sServerSocket==INVALID_SOCKET)
		{	xClose(m_sClientSocket); return; }

		// Fill in sockaddr and resolve the host
		sockaddr_in ssin; memset(&ssin, 0, sizeof(ssin));
		ssin.sin_family=AF_INET; ssin.sin_port=htons(uURL.iPort);
		ssin.sin_addr.s_addr=ResolveAddress(uURL.sHost.CStr());
		if(ssin.sin_addr.s_addr==INADDR_NONE) // The host couldn't be resolved, exit
		{
#ifdef DBGCONSOLE
			g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): %s could not be resolved (%s)...\n", m_pRedirHTTP, uURL.sHost.CStr(), uURL.sReq.CStr());
#endif
			xClose(m_sClientSocket); xClose(m_sServerSocket); return; }

		// Connect to the server
		iErr=connect(m_sServerSocket, (sockaddr*)&ssin, sizeof(sockaddr_in));
		if(iErr==SOCKET_ERROR) // Connect failed, exit
		{	
#ifdef DBGCONSOLE
			g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): Cannot connect to %s:%d (%s)...\n", m_pRedirHTTP, uURL.sHost.CStr(), uURL.iPort, uURL.sReq.CStr());
#endif
			xClose(m_sClientSocket); xClose(m_sServerSocket); return; }

		if(bGet) {
			iErr=xWrite(m_sServerSocket, sReqBuf.CStr(), sReqBuf.GetLength());
			if(!iErr || iErr==SOCKET_ERROR) { xClose(m_sClientSocket); xClose(m_sServerSocket); return; }
		} else {
			iErr=xWrite(m_sClientSocket, sReqBuf.CStr(), sReqBuf.GetLength());
			if(!iErr || iErr==SOCKET_ERROR) { xClose(m_sClientSocket); xClose(m_sServerSocket); return; }
		}

		int iLen; fd_set fd;
		SET_SOCK_BLOCK(m_sClientSocket, 0); SET_SOCK_BLOCK(m_sServerSocket, 0);

		if(bGet) {
			while(true)
			{	memset(szBuffer, 0, sizeof(szBuffer));
				if(!recv_line_irc(m_sClientSocket, szBuffer, sizeof(szBuffer), NULL)) { Sleep(10); break; }
				if(strcmp(szBuffer, "")) {
					sBuffer.Assign(szBuffer);
					if(!sBuffer.Token(0, " ").Compare("GET"))
					{	// Fail if there is no url
						if(!sBuffer.Token(1, " ").Compare("")) { bFinished=true; break; }
						// Parse the url
						if(!ParseURL(sBuffer.Token(1, " ").CStr(), &uURL)) break;
						// Fail if the protocol isnt http
						if(uURL.sProto.Compare("http")) { bFinished=true; break; }
						// Get the rest of the request
						CString sMethod(sBuffer.Token(0, " ")); if(!sMethod.Compare("")) { bFinished=true; break; }
						CString sHTTPVer(sBuffer.Token(2, " ")); if(!sHTTPVer.Compare("")) { bFinished=true; break; }
						sBuffer.Format("%s %s %s\r\n", sMethod.CStr(), uURL.sReq.CStr(), sHTTPVer.CStr());
						if(uURL.sHost.Compare(sOldHost))
						{	xClose(m_sServerSocket);
							m_sServerSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
							if(m_sServerSocket==SOCKET_ERROR || m_sServerSocket==INVALID_SOCKET)
							{	xClose(m_sClientSocket); return; }
							
							// Fill in sockaddr and resolve the host
							sockaddr_in ssin; memset(&ssin, 0, sizeof(ssin));
							ssin.sin_family=AF_INET; ssin.sin_port=htons(uURL.iPort);
							ssin.sin_addr.s_addr=ResolveAddress(uURL.sHost.CStr());
							if(ssin.sin_addr.s_addr==INADDR_NONE) // The host couldn't be resolved, exit
							{
#ifdef DBGCONSOLE
								g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): %s could not be resolved (%s)...\n", m_pRedirHTTP, uURL.sHost.CStr(), uURL.sReq.CStr());
#endif
								xClose(m_sClientSocket); xClose(m_sServerSocket); return; }

							// Connect to the server
							iErr=connect(m_sServerSocket, (sockaddr*)&ssin, sizeof(sockaddr_in));
							if(iErr==SOCKET_ERROR) // Connect failed, exit
							{	
#ifdef DBGCONSOLE
								g_cMainCtrl.m_cConsDbg.Log(5, "CRedirectHTTP(0x%8.8Xh): Cannot connect to %s:%d (%s)...\n", m_pRedirHTTP, uURL.sHost.CStr(), uURL.iPort, uURL.sReq.CStr());
#endif
								xClose(m_sClientSocket); xClose(m_sServerSocket); return; }
							
							sOldHost.Assign(uURL.sHost); }
					}
					else
					{	sBuffer.Append("\r\n"); }
				if(xWrite(m_sServerSocket, sBuffer.CStr(), sBuffer.GetLength())<1) break; }

				iLen=xRead(m_sServerSocket, szBuf, sizeof(szBuf));
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				xWrite(m_sClientSocket, szBuf, iLen);
			}
		} else {
			while(true) {
				iLen=xRead(m_sClientSocket, szBuf, sizeof(szBuf));
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				xWrite(m_sServerSocket, szBuf, iLen);

				iLen=xRead(m_sServerSocket, szBuf, sizeof(szBuf));
				if(!iLen) break; if(iLen<0 && ERRNO!=EWOULDBLOCK) { Sleep(10); break; }
				xWrite(m_sClientSocket, szBuf, iLen);
			}
		}

		xClose(m_sClientSocket); xClose(m_sServerSocket);
		bFinished=true;
	}
}
Example #9
0
static unsigned WINAPI OscThreadProc(LPVOID p)
{
  JNL::open_socketlib();

  int sockcnt=0;
  WDL_Queue sendq;
  char hdr[16] = { 0 };
  strcpy(hdr, "#bundle");
  hdr[12]=1; // timetag=immediate

  int i;
  for (i=0; i < s_osc_handlers.GetSize(); ++i)
  {
    OscHandler* osc=s_osc_handlers.Get(i);
    osc->m_recvsock=osc->m_sendsock-1;

    if (osc->m_recv_enable)
    {
      osc->m_recvsock=socket(AF_INET, SOCK_DGRAM, 0);
      if (osc->m_recvsock >= 0)
      {
        int on=1;
        setsockopt(osc->m_recvsock, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
        if (!bind(osc->m_recvsock, (struct sockaddr*)&osc->m_recvaddr, sizeof(struct sockaddr))) 
        {
          SET_SOCK_BLOCK(osc->m_recvsock, false);
          ++sockcnt;
        }
        else
        {
          closesocket(osc->m_recvsock);
          osc->m_recvsock=-1;
        }
      }
    }

    if (osc->m_send_enable)
    {
      osc->m_sendsock=socket(AF_INET, SOCK_DGRAM, 0);
      if (osc->m_sendsock >= 0)
      {
        int on=1;
        setsockopt(osc->m_sendsock, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on));
        ++sockcnt;
      }
    }
  }

  if (sockcnt)
  {
    while (!s_threadquit)
    {
      char buf[MAX_OSC_MSG_LEN];
      bool hadmsg=false;

      for (i=0; i < s_osc_handlers.GetSize(); ++i)
      {
        OscHandler* osc=s_osc_handlers.Get(i);

        if (osc->m_recvsock >= 0)
        {
          buf[0]=0;
          int len=recvfrom(osc->m_recvsock, buf, sizeof(buf), 0, 0, 0);
          if (len > 0)
          { 
            // unpacking bundles becomes trivial
            // if we store the packet length as big-endian
            int tlen=len;
            REAPER_MAKEBEINTMEM((char*)&tlen);

            osc->m_mutex.Enter();
            osc->m_recvq.Add(&tlen, sizeof(int));
            osc->m_recvq.Add(buf, len);
            osc->m_mutex.Leave();

            if (osc->m_recv_enable&4) // just listening
            {
              int j;
              for (j=i+1; j < s_osc_handlers.GetSize(); ++j)
              {
                OscHandler* osc2=s_osc_handlers.Get(j);
                if (osc2->m_recv_enable && 
                    !memcmp(&osc2->m_recvaddr, &osc->m_recvaddr, sizeof(struct sockaddr_in)))
                {
                  osc2->m_mutex.Enter();
                  osc2->m_recvq.Add(&tlen, sizeof(int));
                  osc2->m_recvq.Add(buf, len);
                  osc2->m_mutex.Leave();
                }
              }
            }

            hadmsg=true;
          }
        }

        if (osc->m_sendsock >= 0 && osc->m_sendq.Available())
        {    
          sendq.Add(hdr, 16);

          osc->m_mutex.Enter();
          sendq.Add(osc->m_sendq.Get(), osc->m_sendq.Available());
          osc->m_sendq.Clear();
          osc->m_mutex.Leave();

          char* packetstart=(char*)sendq.Get();
          int packetlen=16;
          bool hasbundle=false;
          sendq.Advance(16);

          while (sendq.Available() >= sizeof(int))
          {
            int len=*(int*)sendq.Get(); // not advancing
            REAPER_MAKEBEINTMEM((char*)&len);

            if (len < 1 || len > MAX_OSC_MSG_LEN || len > sendq.Available()) break;             
            
            if (packetlen > 16 && packetlen+sizeof(int)+len > osc->m_maxpacketsz)
            {
              // packet is full
              if (!hasbundle)
              {
                packetstart += 20;
                packetlen -= 20;
              }

              if (s_threadquit) break;
              sendto(osc->m_sendsock, packetstart, packetlen, 0, (struct sockaddr*)&osc->m_sendaddr, sizeof(struct sockaddr));
              if (osc->m_sendsleep) Sleep(osc->m_sendsleep);

              packetstart=(char*)sendq.Get()-16; // safe since we padded the queue start
              memcpy(packetstart, hdr, 16);
              packetlen=16;
              hasbundle=false;
            }
         
            if (packetlen > 16) hasbundle=true;
            sendq.Advance(sizeof(int)+len);
            packetlen += sizeof(int)+len;
          }

          if (packetlen > 16)
          {
            if (!hasbundle)
            {
              packetstart += 20;
              packetlen -= 20;
            }

            if (s_threadquit) break;
            sendto(osc->m_sendsock, packetstart, packetlen, 0, (struct sockaddr*)&osc->m_sendaddr, sizeof(struct sockaddr));
            if (osc->m_sendsleep) Sleep(osc->m_sendsleep);
          }

          sendq.Clear();
          hadmsg=true;
        }
      }

      if (!hadmsg) Sleep(1);
    }
  }

  // s_threadquit:
  for (i=0; i < s_osc_handlers.GetSize(); ++i)
  {
    OscHandler* osc=s_osc_handlers.Get(i);
    if (osc->m_recvsock >= 0)
    {
      shutdown(osc->m_recvsock, SHUT_RDWR);
      closesocket(osc->m_recvsock);
      osc->m_recvsock=-1;
    }
    if (osc->m_sendsock >= 0)
    {
      shutdown(osc->m_sendsock, SHUT_RDWR);
      closesocket(osc->m_sendsock);
      osc->m_sendsock=-1;
    }
  }

  JNL::close_socketlib();
  return 0;
}