libgit2/src/netops.c
Scott J. Goldman 901fbdad1b Define explicit _WIN32_WINNT version in makefile
Previously, it was defined in netops.c, but it's also needed in one of the
clar tests, so I figured we might as well just make it global for the
whole project.

Without it, the mingw32 linker won't resolve GetProcessId() (called from
the core/errors.c clar test) because of some conditionals in windows.h.
2012-05-07 00:05:02 -07:00

210 lines
4.4 KiB
C

/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef _WIN32
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/select.h>
# include <sys/time.h>
# include <netdb.h>
#else
# include <winsock2.h>
# include <Ws2tcpip.h>
# ifdef _MSC_VER
# pragma comment(lib, "Ws2_32.lib")
# endif
#endif
#include "git2/errors.h"
#include "common.h"
#include "netops.h"
#include "posix.h"
#include "buffer.h"
#ifdef GIT_WIN32
static void net_set_error(const char *str)
{
int size, error = WSAGetLastError();
LPSTR err_str = NULL;
size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
0, error, 0, (LPSTR)&err_str, 0, 0);
giterr_set(GITERR_NET, "%s: $s", str, err_str);
LocalFree(err_str);
}
#else
static void net_set_error(const char *str)
{
giterr_set(GITERR_NET, "%s: %s", str, strerror(errno));
}
#endif
void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, GIT_SOCKET fd)
{
memset(buf, 0x0, sizeof(gitno_buffer));
memset(data, 0x0, len);
buf->data = data;
buf->len = len;
buf->offset = 0;
buf->fd = fd;
}
int gitno_recv(gitno_buffer *buf)
{
int ret;
ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) {
net_set_error("Error receiving socket data");
return -1;
}
buf->offset += ret;
return ret;
}
/* Consume up to ptr and move the rest of the buffer to the beginning */
void gitno_consume(gitno_buffer *buf, const char *ptr)
{
size_t consumed;
assert(ptr - buf->data >= 0);
assert(ptr - buf->data <= (int) buf->len);
consumed = ptr - buf->data;
memmove(buf->data, ptr, buf->offset - consumed);
memset(buf->data + buf->offset, 0x0, buf->len - buf->offset);
buf->offset -= consumed;
}
/* Consume const bytes and move the rest of the buffer to the beginning */
void gitno_consume_n(gitno_buffer *buf, size_t cons)
{
memmove(buf->data, buf->data + cons, buf->len - buf->offset);
memset(buf->data + cons, 0x0, buf->len - buf->offset);
buf->offset -= cons;
}
int gitno_connect(GIT_SOCKET *sock, const char *host, const char *port)
{
struct addrinfo *info = NULL, *p;
struct addrinfo hints;
int ret;
GIT_SOCKET s = INVALID_SOCKET;
memset(&hints, 0x0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((ret = getaddrinfo(host, port, &hints, &info)) < 0) {
giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret));
return -1;
}
for (p = info; p != NULL; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (s == INVALID_SOCKET) {
net_set_error("error creating socket");
break;
}
if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
break;
/* If we can't connect, try the next one */
gitno_close(s);
s = INVALID_SOCKET;
}
/* Oops, we couldn't connect to any address */
if (s == INVALID_SOCKET && p == NULL) {
giterr_set(GITERR_OS, "Failed to connect to %s", host);
return -1;
}
freeaddrinfo(info);
*sock = s;
return 0;
}
int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags)
{
int ret;
size_t off = 0;
while (off < len) {
errno = 0;
ret = p_send(s, msg + off, len - off, flags);
if (ret < 0) {
net_set_error("Error sending data");
return -1;
}
off += ret;
}
return (int)off;
}
#ifdef GIT_WIN32
int gitno_close(GIT_SOCKET s)
{
return closesocket(s) == SOCKET_ERROR ? -1 : 0;
}
#else
int gitno_close(GIT_SOCKET s)
{
return close(s);
}
#endif
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec)
{
fd_set fds;
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = usec;
FD_ZERO(&fds);
FD_SET(buf->fd, &fds);
/* The select(2) interface is silly */
return select((int)buf->fd + 1, &fds, NULL, NULL, &tv);
}
int gitno_extract_host_and_port(char **host, char **port, const char *url, const char *default_port)
{
char *colon, *slash, *delim;
colon = strchr(url, ':');
slash = strchr(url, '/');
if (slash == NULL) {
giterr_set(GITERR_NET, "Malformed URL: missing /");
return -1;
}
if (colon == NULL) {
*port = git__strdup(default_port);
} else {
*port = git__strndup(colon + 1, slash - colon - 1);
}
GITERR_CHECK_ALLOC(*port);
delim = colon == NULL ? slash : colon;
*host = git__strndup(url, delim - url);
GITERR_CHECK_ALLOC(*host);
return 0;
}