Skip to content

Instantly share code, notes, and snippets.

@LogIN-
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save LogIN-/c9372c5dafc17cdf9ce8 to your computer and use it in GitHub Desktop.

Select an option

Save LogIN-/c9372c5dafc17cdf9ce8 to your computer and use it in GitHub Desktop.
Check free port node native addon
#include <node.h>
#include <v8.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace node;
using namespace v8;
// Allocate a new TCP server socket, and return
// its handler
int allocateFreePort() {
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
if (errno == EMFILE) {
perror("Too many open files...");
return 0;
}
perror("Failed to allocate free port.");
exit(-1);
}
int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
return sock;
}
// Check whether the provided TCP port is available
// at the moment and return 1 if it's avaiable, zero otherwise
int checkFreePort(int port) {
int sock = allocateFreePort();
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(inet_addr("0.0.0.0"));
int error = bind(sock, (struct sockaddr*) &addr, sizeof(addr));
return error == 0;
}
Handle<Value> findFreePort(const Arguments& args) {
HandleScope scope;
struct timeval tv;
gettimeofday(&tv, 0);
srand(tv.tv_usec);
struct sockaddr_in addr;
int attempts;
int port;
for (attempts = 0; attempts < 100; ++attempts) {
port = 5000 + rand() % 100;
if (checkFreePort(port)) {
return scope.Close(Number::New(port));
}
}
socklen_t len = sizeof(addr);
addr.sin_port = 0;
while (addr.sin_port < 1024) {
usleep(10);
if (++attempts > 500) {
ThrowException(Exception::TypeError(String::New("Failed to reserve free port.")));
return scope.Close(Undefined());
}
int sock = allocateFreePort();
if (sock == 0) {
continue;
}
if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
if (errno == EADDRINUSE) {
/* address already in use */
continue;
}
ThrowException(Exception::TypeError(String::New("Failed bind() free port.")));
return scope.Close(Undefined());
}
if (getsockname(sock, (struct sockaddr*) &addr, &len) != 0) {
ThrowException(Exception::TypeError(String::New("Failed getsockname() ...")));
return scope.Close(Undefined());
}
}
return scope.Close(Number::New(addr.sin_port));
}
void init(Handle<Object> target) {
target->Set(String::NewSymbol("findFreePort"),
FunctionTemplate::New(findFreePort)->GetFunction());
}
NODE_MODULE(tue, init)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment