nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret; if (info == NULL) return PR_FAILURE;   char scratch[PR_NETDB_BUF_SIZE]; PRHostEnt hostentry; char * proxyHost; info->GetProxyHost(&proxyHost); status = PR_GetHostByName(proxyHost, scratch, PR_NETDB_BUF_SIZE, &hostentry);
nsresult rv = info->GetProxyHost(&proxyHost);
nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout){   PRStatus status;   nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;   if (info == NULL) return PR_FAILURE;      // First, we need to look up our proxy...   char scratch[PR_NETDB_BUF_SIZE];   PRHostEnt hostentry;   char * proxyHost;   info->GetProxyHost(&proxyHost);   status = PR_GetHostByName(proxyHost, scratch, PR_NETDB_BUF_SIZE, &hostentry);   if (PR_SUCCESS != status) {      return status;   }   // Extract the proxy addr   PRIntn entEnum = 0;   PRNetAddr proxyAddr;   PRInt32 proxyPort;   info->GetProxyPort(&proxyPort);   entEnum = PR_EnumerateHostEnt(entEnum, &hostentry, proxyPort, &proxyAddr);   if (entEnum <= 0) {      return PR_FAILURE;   }   info->SetInternalProxyAddr(&proxyAddr);   // For now, we'll do this as a blocking connect,   // but with nspr 4.1, the necessary functions to   // do a non-blocking connect will be available   // Preserve the non-blocking state of the socket   PRBool nonblocking;   PRSocketOptionData sockopt;   sockopt.option = PR_SockOpt_Nonblocking;   status = PR_GetSocketOption(fd, &sockopt);   if (PR_SUCCESS != status) {      return status;   }   // Store blocking option   nonblocking = sockopt.value.non_blocking;   sockopt.option = PR_SockOpt_Nonblocking;   sockopt.value.non_blocking = false;   status = PR_SetSocketOption(fd, &sockopt);   if (PR_SUCCESS != status) {      return status;   }   // Now setup sockopts, so we can restore the value later.   sockopt.option = PR_SockOpt_Nonblocking;   sockopt.value.non_blocking = nonblocking;   // connect to the proxy server   status = fd->lower->methods->connect(fd->lower, &proxyAddr, timeout);    if (PR_SUCCESS != status) {      return status;   }   // We are now connected to the SOCKS proxy server.   // Now we will negotiate a connection to the desired server.      unsigned char request[22];   int request_len = 0;   unsigned char response[22];   int response_len = 0;   request[0] = 0x05; // SOCKS version 5   request[1] = 0x01; // number of auth procotols we recognize   // auth protocols   request[2] = 0x00; // no authentication required   // compliant implementations MUST implement GSSAPI   // and SHOULD implement username/password   // TODO: we don't   //request[3] = 0x01; // GSSAPI   //request[4] = 0x02; // username/password   request_len = 2 + request[1];   int write_len = PR_Write(fd, request, request_len);   if (write_len != request_len) {      return PR_FAILURE;   }   // get the server's response   response_len = 22;   response_len = PR_Read(fd, response, response_len);   if (response_len <= 0) {      return PR_FAILURE;   }   if (response[0] != 0x05) {      // it's a either not SOCKS or not our version      return PR_FAILURE;   }   switch (response[1]) {    case 0x00:      // no auth      break;    case 0x01:      // GSSAPI      // TODO: implement    case 0x02:      // username/password      // TODO: implement    default:      // unrecognized auth method      return PR_FAILURE;   }   // we are now authenticated, so lets tell   // the server where to connect to   request_len = 6;   request[0] = 0x05; // SOCKS version 5   request[1] = 0x01; // CONNECT command   request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)   if (PR_NetAddrFamily(addr) == PR_AF_INET) {            request[3] = 0x01; // encoding of destination address (1 == IPv4)      request_len += 4;            char * ip = (char*)(&addr->inet.ip);      request[4] = *ip++;      request[5] = *ip++;      request[6] = *ip++;      request[7] = *ip++;         } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {      request[3] = 0x04; // encoding of destination address (1 == IPv6)      request_len += 16;      char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);      request[4] = *ip++; request[5] = *ip++; request[6] = *ip++; request[7] = *ip++;      request[8] = *ip++; request[9] = *ip++; request[10] = *ip++; request[11] = *ip++;      request[12] = *ip++; request[13] = *ip++; request[14] = *ip++; request[15] = *ip++;      request[16] = *ip++; request[17] = *ip++; request[18] = *ip++; request[19] = *ip++;            // we're going to test to see if this address can      // be mapped back into IPv4 without loss. if so,      // we'll use IPv4 instead, as reliable SOCKS server       // support for IPv6 is probably questionable.            if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {	 request[3] = 0x01; // ipv4 encoding	 request[4] = request[16];	 request[5] = request[17];	 request[6] = request[18];	 request[7] = request[19];	 request_len -= 12;	       }         } else {      // Unknown address type	return PR_FAILURE;   }   // destination port   PRUint16 destPort = PR_NetAddrInetPort(addr);   request[request_len-1] = destPort >> 8;   request[request_len-2] = destPort;   if (PR_Write(fd, request, request_len) != request_len) {      // bad write      return PR_FAILURE;   }   response_len = 22;   response_len = PR_Read(fd, response, response_len);   if (response_len <= 0) {      // bad read      return PR_FAILURE;   }   if (response[0] != 0x05) {      // bad response      return PR_FAILURE;   }   if (response[1] != 0x00) {      // SOCKS server failed to connect      return PR_FAILURE;   }   // get external bound address (this is what    // the outside world sees as "us")   PRNetAddr extAddr;   PRUint16 extPort;   char *ip = nsnull;   switch (response[3]) {    case 0x01: // IPv4            extPort = (response[8] << 8) | response[9];            PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, &extAddr);            ip = (char*)(&extAddr.inet.ip);      *ip++ = response[4];      *ip++ = response[5];      *ip++ = response[6];      *ip++ = response[7];      break;    case 0x04: // IPv6      extPort = (response[20] << 8) | response[21];            PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, &extAddr);            ip = (char*)(&extAddr.ipv6.ip.pr_s6_addr);      *ip++ = response[4]; *ip++ = response[5]; *ip++ = response[6]; *ip++ = response[7];      *ip++ = response[8]; *ip++ = response[9]; *ip++ = response[10]; *ip++ = response[11];      *ip++ = response[12]; *ip++ = response[13]; *ip++ = response[14]; *ip++ = response[15];      *ip++ = response[16]; *ip++ = response[17]; *ip++ = response[18]; *ip++ = response[19];      break;    case 0x03: // FQDN (should not get this back)    default: // unknown format      // if we get here, we don't know our external address.      // however, as that's possibly not critical to the user,      // we let it slide.      PR_InitializeNetAddr(PR_IpAddrNull, 0, &extAddr);      //return PR_FAILURE;      break;   }   info->SetDestinationAddr((PRNetAddr*)addr);   info->SetExternalProxyAddr(&extAddr);   // restore non-blocking option   PR_SetSocketOption(fd, &sockopt);   // we're set-up and connected.    // this socket can be used as normal now.   return PR_SUCCESS;}