File Coverage

deps/libgit2/src/libgit2/streams/socket.c
Criterion Covered Total %
statement 0 90 0.0
branch 0 44 0.0
condition n/a
subroutine n/a
pod n/a
total 0 134 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
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              
8             #include "streams/socket.h"
9              
10             #include "posix.h"
11             #include "netops.h"
12             #include "registry.h"
13             #include "stream.h"
14              
15             #ifndef _WIN32
16             # include
17             # include
18             # include
19             # include
20             # include
21             # include
22             # include
23             #else
24             # include
25             # include
26             # ifdef _MSC_VER
27             # pragma comment(lib, "ws2_32")
28             # endif
29             #endif
30              
31             #ifdef GIT_WIN32
32             static void net_set_error(const char *str)
33             {
34             int error = WSAGetLastError();
35             char * win32_error = git_win32_get_error_message(error);
36              
37             if (win32_error) {
38             git_error_set(GIT_ERROR_NET, "%s: %s", str, win32_error);
39             git__free(win32_error);
40             } else {
41             git_error_set(GIT_ERROR_NET, "%s", str);
42             }
43             }
44             #else
45 0           static void net_set_error(const char *str)
46             {
47 0           git_error_set(GIT_ERROR_NET, "%s: %s", str, strerror(errno));
48 0           }
49             #endif
50              
51 0           static int close_socket(GIT_SOCKET s)
52             {
53 0 0         if (s == INVALID_SOCKET)
54 0           return 0;
55              
56             #ifdef GIT_WIN32
57             if (SOCKET_ERROR == closesocket(s))
58             return -1;
59              
60             if (0 != WSACleanup()) {
61             git_error_set(GIT_ERROR_OS, "winsock cleanup failed");
62             return -1;
63             }
64              
65             return 0;
66             #else
67 0           return close(s);
68             #endif
69              
70             }
71              
72 0           static int socket_connect(git_stream *stream)
73             {
74 0           struct addrinfo *info = NULL, *p;
75             struct addrinfo hints;
76 0           git_socket_stream *st = (git_socket_stream *) stream;
77 0           GIT_SOCKET s = INVALID_SOCKET;
78             int ret;
79              
80             #ifdef GIT_WIN32
81             /* on win32, the WSA context needs to be initialized
82             * before any socket calls can be performed */
83             WSADATA wsd;
84              
85             if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
86             git_error_set(GIT_ERROR_OS, "winsock init failed");
87             return -1;
88             }
89              
90             if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2) {
91             WSACleanup();
92             git_error_set(GIT_ERROR_OS, "winsock init failed");
93             return -1;
94             }
95             #endif
96              
97 0           memset(&hints, 0x0, sizeof(struct addrinfo));
98 0           hints.ai_socktype = SOCK_STREAM;
99 0           hints.ai_family = AF_UNSPEC;
100              
101 0 0         if ((ret = p_getaddrinfo(st->host, st->port, &hints, &info)) != 0) {
102 0           git_error_set(GIT_ERROR_NET,
103             "failed to resolve address for %s: %s", st->host, p_gai_strerror(ret));
104 0           return -1;
105             }
106              
107 0 0         for (p = info; p != NULL; p = p->ai_next) {
108 0           s = socket(p->ai_family, p->ai_socktype | SOCK_CLOEXEC, p->ai_protocol);
109              
110 0 0         if (s == INVALID_SOCKET)
111 0           continue;
112              
113 0 0         if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0)
114 0           break;
115              
116             /* If we can't connect, try the next one */
117 0           close_socket(s);
118 0           s = INVALID_SOCKET;
119             }
120              
121             /* Oops, we couldn't connect to any address */
122 0 0         if (s == INVALID_SOCKET && p == NULL) {
    0          
123 0           git_error_set(GIT_ERROR_OS, "failed to connect to %s", st->host);
124 0           p_freeaddrinfo(info);
125 0           return -1;
126             }
127              
128 0           st->s = s;
129 0           p_freeaddrinfo(info);
130 0           return 0;
131             }
132              
133 0           static ssize_t socket_write(git_stream *stream, const char *data, size_t len, int flags)
134             {
135 0           git_socket_stream *st = (git_socket_stream *) stream;
136             ssize_t written;
137              
138 0           errno = 0;
139              
140 0 0         if ((written = p_send(st->s, data, len, flags)) < 0) {
141 0           net_set_error("error sending data");
142 0           return -1;
143             }
144              
145 0           return written;
146             }
147              
148 0           static ssize_t socket_read(git_stream *stream, void *data, size_t len)
149             {
150             ssize_t ret;
151 0           git_socket_stream *st = (git_socket_stream *) stream;
152              
153 0 0         if ((ret = p_recv(st->s, data, len, 0)) < 0)
154 0           net_set_error("error receiving socket data");
155              
156 0           return ret;
157             }
158              
159 0           static int socket_close(git_stream *stream)
160             {
161 0           git_socket_stream *st = (git_socket_stream *) stream;
162             int error;
163              
164 0           error = close_socket(st->s);
165 0           st->s = INVALID_SOCKET;
166              
167 0           return error;
168             }
169              
170 0           static void socket_free(git_stream *stream)
171             {
172 0           git_socket_stream *st = (git_socket_stream *) stream;
173              
174 0           git__free(st->host);
175 0           git__free(st->port);
176 0           git__free(st);
177 0           }
178              
179 0           static int default_socket_stream_new(
180             git_stream **out,
181             const char *host,
182             const char *port)
183             {
184             git_socket_stream *st;
185              
186 0 0         GIT_ASSERT_ARG(out);
187 0 0         GIT_ASSERT_ARG(host);
188 0 0         GIT_ASSERT_ARG(port);
189              
190 0           st = git__calloc(1, sizeof(git_socket_stream));
191 0 0         GIT_ERROR_CHECK_ALLOC(st);
192              
193 0           st->host = git__strdup(host);
194 0 0         GIT_ERROR_CHECK_ALLOC(st->host);
195              
196 0 0         if (port) {
197 0           st->port = git__strdup(port);
198 0 0         GIT_ERROR_CHECK_ALLOC(st->port);
199             }
200              
201 0           st->parent.version = GIT_STREAM_VERSION;
202 0           st->parent.connect = socket_connect;
203 0           st->parent.write = socket_write;
204 0           st->parent.read = socket_read;
205 0           st->parent.close = socket_close;
206 0           st->parent.free = socket_free;
207 0           st->s = INVALID_SOCKET;
208              
209 0           *out = (git_stream *) st;
210 0           return 0;
211             }
212              
213 0           int git_socket_stream_new(
214             git_stream **out,
215             const char *host,
216             const char *port)
217             {
218 0           int (*init)(git_stream **, const char *, const char *) = NULL;
219 0           git_stream_registration custom = {0};
220             int error;
221              
222 0 0         GIT_ASSERT_ARG(out);
223 0 0         GIT_ASSERT_ARG(host);
224 0 0         GIT_ASSERT_ARG(port);
225              
226 0 0         if ((error = git_stream_registry_lookup(&custom, GIT_STREAM_STANDARD)) == 0)
227 0           init = custom.init;
228 0 0         else if (error == GIT_ENOTFOUND)
229 0           init = default_socket_stream_new;
230             else
231 0           return error;
232              
233 0 0         if (!init) {
234 0           git_error_set(GIT_ERROR_NET, "there is no socket stream available");
235 0           return -1;
236             }
237              
238 0           return init(out, host, port);
239             }