1
2#include "pipe/p_compiler.h"
3#include "util/u_network.h"
4#include "util/u_debug.h"
5#include "util/u_string.h"
6
7#include <stdio.h>
8#if defined(PIPE_OS_WINDOWS)
9#  include <winsock2.h>
10#  include <windows.h>
11#  include <ws2tcpip.h>
12#elif defined(PIPE_OS_UNIX)
13#  include <sys/socket.h>
14#  include <netinet/in.h>
15#  include <unistd.h>
16#  include <fcntl.h>
17#  include <netdb.h>
18#else
19#  warning "No socket implementation"
20#endif
21
22boolean
23u_socket_init(void)
24{
25#if defined(PIPE_OS_WINDOWS)
26   WORD wVersionRequested;
27   WSADATA wsaData;
28   int err;
29
30   /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
31   wVersionRequested = MAKEWORD(1, 1);
32
33   err = WSAStartup(wVersionRequested, &wsaData);
34   if (err != 0) {
35      debug_printf("WSAStartup failed with error: %d\n", err);
36      return FALSE;
37   }
38   return TRUE;
39#elif defined(PIPE_HAVE_SOCKETS)
40   return TRUE;
41#else
42   return FALSE;
43#endif
44}
45
46void
47u_socket_stop(void)
48{
49#if defined(PIPE_OS_WINDOWS)
50   WSACleanup();
51#endif
52}
53
54void
55u_socket_close(int s)
56{
57   if (s < 0)
58      return;
59
60#if defined(PIPE_OS_UNIX)
61   shutdown(s, SHUT_RDWR);
62   close(s);
63#elif defined(PIPE_OS_WINDOWS)
64   shutdown(s, SD_BOTH);
65   closesocket(s);
66#else
67   assert(0);
68#endif
69}
70
71int u_socket_accept(int s)
72{
73#if defined(PIPE_HAVE_SOCKETS)
74   return accept(s, NULL, NULL);
75#else
76   return -1;
77#endif
78}
79
80int
81u_socket_send(int s, void *data, size_t size)
82{
83#if defined(PIPE_HAVE_SOCKETS)
84   return send(s, data, size, 0);
85#else
86   return -1;
87#endif
88}
89
90int
91u_socket_peek(int s, void *data, size_t size)
92{
93#if defined(PIPE_HAVE_SOCKETS)
94   return recv(s, data, size, MSG_PEEK);
95#else
96   return -1;
97#endif
98}
99
100int
101u_socket_recv(int s, void *data, size_t size)
102{
103#if defined(PIPE_HAVE_SOCKETS)
104   return recv(s, data, size, 0);
105#else
106   return -1;
107#endif
108}
109
110int
111u_socket_connect(const char *hostname, uint16_t port)
112{
113#if defined(PIPE_HAVE_SOCKETS)
114   int s, r;
115   struct addrinfo hints, *addr;
116   char portString[20];
117
118   memset(&hints, 0, sizeof hints);
119   hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
120   hints.ai_socktype = SOCK_STREAM;
121
122   snprintf(portString, sizeof(portString), "%d", port);
123
124   r = getaddrinfo(hostname, portString, NULL, &addr);
125   if (r != 0) {
126      return -1;
127   }
128
129   s = socket(addr->ai_family, SOCK_STREAM, IPPROTO_TCP);
130   if (s < 0) {
131      freeaddrinfo(addr);
132      return -1;
133   }
134
135   if (connect(s, addr->ai_addr, (int) addr->ai_addrlen)) {
136      u_socket_close(s);
137      freeaddrinfo(addr);
138      return -1;
139   }
140
141   freeaddrinfo(addr);
142
143   return s;
144#else
145   assert(0);
146   return -1;
147#endif
148}
149
150int
151u_socket_listen_on_port(uint16_t portnum)
152{
153#if defined(PIPE_HAVE_SOCKETS)
154   int s;
155   struct sockaddr_in sa;
156   memset(&sa, 0, sizeof(struct sockaddr_in));
157
158   sa.sin_family = AF_INET;
159   sa.sin_port = htons(portnum);
160
161   s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
162   if (s < 0)
163      return -1;
164
165   if (bind(s, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) == -1) {
166      u_socket_close(s);
167      return -1;
168   }
169
170   listen(s, 1);
171
172   return s;
173#else
174   assert(0);
175   return -1;
176#endif
177}
178
179void
180u_socket_block(int s, boolean block)
181{
182#if defined(PIPE_OS_UNIX)
183   int old = fcntl(s, F_GETFL, 0);
184   if (old == -1)
185      return;
186
187   /* TODO obey block */
188   if (block)
189      fcntl(s, F_SETFL, old & ~O_NONBLOCK);
190   else
191      fcntl(s, F_SETFL, old | O_NONBLOCK);
192#elif defined(PIPE_OS_WINDOWS)
193   u_long iMode = block ? 0 : 1;
194   ioctlsocket(s, FIONBIO, &iMode);
195#else
196   assert(0);
197#endif
198}
199