]> git.proxmox.com Git - libgit2.git/blob - src/netops.c
Merge pull request #444 from carlosmn/fetch-fixes
[libgit2.git] / src / netops.c
1 /*
2 * Copyright (C) 2009-2011 the libgit2 contributors
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7 #ifndef _WIN32
8 # include <sys/types.h>
9 # include <sys/socket.h>
10 # include <sys/select.h>
11 # include <netdb.h>
12 #else
13 # define _WIN32_WINNT 0x0501
14 # include <winsock2.h>
15 # include <Ws2tcpip.h>
16 # ifdef _MSC_VER
17 # pragma comment(lib, "Ws2_32.lib")
18 # endif
19 #endif
20
21
22 #include "git2/errors.h"
23
24 #include "common.h"
25 #include "netops.h"
26
27 void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, int fd)
28 {
29 memset(buf, 0x0, sizeof(gitno_buffer));
30 memset(data, 0x0, len);
31 buf->data = data;
32 buf->len = len;
33 buf->offset = 0;
34 buf->fd = fd;
35 }
36
37 int gitno_recv(gitno_buffer *buf)
38 {
39 int ret;
40
41 ret = recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
42 if (ret < 0)
43 return git__throw(GIT_EOSERR, "Failed to receive data: %s", strerror(errno));
44 if (ret == 0) /* Orderly shutdown, so exit */
45 return GIT_SUCCESS;
46
47 buf->offset += ret;
48
49 return ret;
50 }
51
52 /* Consume up to ptr and move the rest of the buffer to the beginning */
53 void gitno_consume(gitno_buffer *buf, const char *ptr)
54 {
55 size_t consumed;
56
57 assert(ptr - buf->data >= 0);
58 assert(ptr - buf->data <= (int) buf->len);
59
60 consumed = ptr - buf->data;
61
62 memmove(buf->data, ptr, buf->offset - consumed);
63 memset(buf->data + buf->offset, 0x0, buf->len - buf->offset);
64 buf->offset -= consumed;
65 }
66
67 /* Consume const bytes and move the rest of the buffer to the beginning */
68 void gitno_consume_n(gitno_buffer *buf, size_t cons)
69 {
70 memmove(buf->data, buf->data + cons, buf->len - buf->offset);
71 memset(buf->data + cons, 0x0, buf->len - buf->offset);
72 buf->offset -= cons;
73 }
74
75 int gitno_connect(const char *host, const char *port)
76 {
77 struct addrinfo *info, *p;
78 struct addrinfo hints;
79 int ret, error = GIT_SUCCESS;
80 GIT_SOCKET s;
81
82 memset(&hints, 0x0, sizeof(struct addrinfo));
83 hints.ai_family = AF_UNSPEC;
84 hints.ai_socktype = SOCK_STREAM;
85
86 ret = getaddrinfo(host, port, &hints, &info);
87 if (ret != 0) {
88 error = GIT_EOSERR;
89 info = NULL;
90 goto cleanup;
91 }
92
93 for (p = info; p != NULL; p = p->ai_next) {
94 s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
95 #ifdef GIT_WIN32
96 if (s == INVALID_SOCKET) {
97 #else
98 if (s < 0) {
99 #endif
100 error = GIT_EOSERR;
101 goto cleanup;
102 }
103
104 ret = connect(s, p->ai_addr, p->ai_addrlen);
105 /* If we can't connect, try the next one */
106 if (ret < 0) {
107 continue;
108 }
109
110 /* Return the socket */
111 error = s;
112 goto cleanup;
113 }
114
115 /* Oops, we couldn't connect to any address */
116 error = git__throw(GIT_EOSERR, "Failed to connect: %s", strerror(errno));
117
118 cleanup:
119 freeaddrinfo(info);
120 return error;
121 }
122
123 int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags)
124 {
125 int ret;
126 size_t off = 0;
127
128 while (off < len) {
129 errno = 0;
130
131 ret = send(s, msg + off, len - off, flags);
132 if (ret < 0)
133 return git__throw(GIT_EOSERR, "Error sending data: %s", strerror(errno));
134
135 off += ret;
136 }
137
138 return off;
139 }
140
141 #ifdef GIT_WIN32
142 int gitno_close(GIT_SOCKET s)
143 {
144 return closesocket(s) == SOCKET_ERROR ? -1 : 0;
145 }
146 #else
147 int gitno_close(GIT_SOCKET s)
148 {
149 return close(s);
150 }
151 #endif
152
153 int gitno_select_in(gitno_buffer *buf, long int sec, long int usec)
154 {
155 fd_set fds;
156 struct timeval tv;
157
158 tv.tv_sec = sec;
159 tv.tv_usec = usec;
160
161 FD_ZERO(&fds);
162 FD_SET(buf->fd, &fds);
163
164 /* The select(2) interface is silly */
165 return select(buf->fd + 1, &fds, NULL, NULL, &tv);
166 }
167
168 int gitno_extract_host_and_port(char **host, char **port, const char *url, const char *default_port)
169 {
170 char *colon, *slash, *delim;
171 int error = GIT_SUCCESS;
172
173 colon = strchr(url, ':');
174 slash = strchr(url, '/');
175
176 if (slash == NULL)
177 return git__throw(GIT_EOBJCORRUPTED, "Malformed URL: missing /");
178
179 if (colon == NULL) {
180 *port = git__strdup(default_port);
181 } else {
182 *port = git__strndup(colon + 1, slash - colon - 1);
183 }
184 if (*port == NULL)
185 return GIT_ENOMEM;;
186
187
188 delim = colon == NULL ? slash : colon;
189 *host = git__strndup(url, delim - url);
190 if (*host == NULL) {
191 free(*port);
192 error = GIT_ENOMEM;
193 }
194
195 return error;
196 }