packages feed

socket-0.8.1.0: platform/win32/cbits/hs_socket.c

#include <hs_socket.h>

int hs_socket_init() {
  static int has_already_been_initialised = 0;

  if (!has_already_been_initialised) {
    WSADATA wsaData;

    int ini = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (ini != NO_ERROR) {
      WSACleanup();
      return -1;
    } else {
      has_already_been_initialised = 1;
    }
  }
  return 0;
};

int hs_socket(int domain, int type, int protocol, int *err) {
  if (!hs_socket_init()) {
    u_long iMode = 1;
    int fd = socket(domain, type, protocol);
    if (fd >= 0) {
      if (!ioctlsocket(fd, FIONBIO, &iMode)) {
        return fd;
      } else {
        closesocket(fd);
      }
    }
  }
  *err = WSAGetLastError();
  return -1;
};

int hs_bind(int sockfd, const struct sockaddr *name, int namelen, int *err) {
  int i = bind(sockfd, name, namelen);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_connect(int sockfd, const struct sockaddr *name, int namelen, int *err) {
  int i = connect(sockfd, name, namelen);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

/**
* Determine a sockets connection status.
*
* Return values:
*   0: connection established
*   1: connection pending
*   2: connection failed
*   3: select or getsockopt failed
*
* The operation will block for the least possible time interval (1 micro second)
* and is not used as it is supposed to be used as we don't want to block.
* Haskell's RTS is used to wait and poll this operation from time to time.
*/
int hs_connect_status (int sockfd, int *err) {
  int errlen = sizeof(int);
  struct timeval timeout = {0,1};
  fd_set writefds;
  fd_set exceptfds;

  FD_ZERO(&writefds);
  FD_ZERO(&exceptfds);
  FD_SET(sockfd, &writefds);
  FD_SET(sockfd, &exceptfds);

  switch (select(sockfd, NULL, &writefds, &exceptfds, &timeout)) {
    case 0:
      return 1;   // Connection pending.
    case 1:
      if (FD_ISSET(sockfd, &writefds)) {
        return 0; // Connection established.
      }
      if (FD_ISSET(sockfd, &exceptfds) && !getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char*) err, &errlen)) {
        return 2; // Connection failed.
      }
    default:
      *err = WSAGetLastError();
      return -1; // select or getsockopt failed.
  }
}

int hs_listen (int sockfd, int backlog, int *err) {
  int i = listen(sockfd, backlog);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_accept(int fd, struct sockaddr *addr, int *addrlen, int *err) {
  u_long iMode = 1;
  int ft = accept(fd, addr, addrlen);
  if (ft >= 0) {
    if (!ioctlsocket(ft, FIONBIO, &iMode)) {
      return ft;
    } else {
      closesocket(ft);
    }
  }
  *err = WSAGetLastError();
  return ft;
}

int hs_close(int sockfd, int *err) {
  int i = closesocket(sockfd);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_send    (int sockfd, const void *buf, size_t len, int flags, int *err) {
  int i = send(sockfd, buf, len, flags);
  if (i < 0) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_recv    (int sockfd,       void *buf, size_t len, int flags, int *err) {
  int i = recv(sockfd, buf, len, flags);
  if (i < 0) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_sendto  (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, int addrlen, int *err) {
  int i = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
  if (i < 0) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_recvfrom(int sockfd,       void *buf, size_t len, int flags, struct sockaddr *src_addr, int *addrlen, int *err) {
  int i = recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
  if (i < 0) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_getsockopt(int sockfd, int level, int option_name,       void *option_value, int *option_len, int *err) {
  int i = getsockopt(sockfd, level, option_name, option_value, option_len);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

int hs_setsockopt(int sockfd, int level, int option_name, const void *option_value, int  option_len, int *err) {
  int i = setsockopt(sockfd, level, option_name, option_value, option_len);
  if (i) {
    *err = WSAGetLastError();
  }
  return i;
};

int  hs_getaddrinfo(const char *node, const char *service,
                    const struct addrinfo *hints,
                    struct addrinfo **res) {
  if (hs_socket_init() != 0) {
    return -1;
  }
  return getaddrinfo(node, service, hints, res);
};

int  hs_getnameinfo(const struct sockaddr *sa, int salen,
                    char *host, int hostlen,
                    char *serv, int servlen, int flags) {
  if (hs_socket_init() != 0) {
    return -1;
  }
  return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
};

void hs_freeaddrinfo(struct addrinfo *res) {
  freeaddrinfo(res);
  return;
};

int hs_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen, int *err) {
  int i = getsockname(fd, addr, addrlen);
  if (i < 0) {
    *err = WSAGetLastError();
  }
  return i;
}