rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 This file is part of socklib, a cross-platform socket library.
|
nuclear@0
|
3
|
nuclear@0
|
4 Copyright (c) 2004 John Tsiombikas <nuclear@siggraph.org>
|
nuclear@0
|
5
|
nuclear@0
|
6 This library is free software; you can redistribute it and/or modify
|
nuclear@0
|
7 it under the terms of the GNU General Public License as published by
|
nuclear@0
|
8 the Free Software Foundation; either version 2 of the License, or
|
nuclear@0
|
9 (at your option) any later version.
|
nuclear@0
|
10
|
nuclear@0
|
11 This library is distributed in the hope that it will be useful,
|
nuclear@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@0
|
14 GNU General Public License for more details.
|
nuclear@0
|
15
|
nuclear@0
|
16 You should have received a copy of the GNU General Public License
|
nuclear@0
|
17 along with this library; if not, write to the Free Software
|
nuclear@0
|
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
nuclear@0
|
19 */
|
nuclear@0
|
20
|
nuclear@0
|
21 #include <stdio.h>
|
nuclear@0
|
22 #include <stdlib.h>
|
nuclear@0
|
23 #include <string.h>
|
nuclear@0
|
24 #include <errno.h>
|
nuclear@0
|
25
|
nuclear@0
|
26 #ifdef __unix__
|
nuclear@0
|
27 #define __USE_BSD
|
nuclear@0
|
28 #include <unistd.h>
|
nuclear@0
|
29 #include <fcntl.h>
|
nuclear@0
|
30 #include <sys/types.h>
|
nuclear@0
|
31 #include <sys/socket.h>
|
nuclear@0
|
32 #include <sys/ioctl.h>
|
nuclear@0
|
33 #include <sys/param.h>
|
nuclear@0
|
34 #include <sys/select.h>
|
nuclear@0
|
35 #include <netdb.h>
|
nuclear@0
|
36 #include <netinet/in.h>
|
nuclear@0
|
37 #include <arpa/inet.h>
|
nuclear@0
|
38
|
nuclear@0
|
39 #else /* assume win32 if not unix */
|
nuclear@0
|
40
|
nuclear@0
|
41 #include <winsock2.h>
|
nuclear@0
|
42
|
nuclear@0
|
43 #define MAXHOSTNAMELEN 255
|
nuclear@0
|
44 #define close(s) closesocket(s)
|
nuclear@0
|
45
|
nuclear@0
|
46 static int winsock_initialized;
|
nuclear@0
|
47 #endif /* __unix__ */
|
nuclear@0
|
48
|
nuclear@0
|
49 #include "socklib.h"
|
nuclear@0
|
50
|
nuclear@0
|
51 #ifdef _MSC_VER
|
nuclear@0
|
52 #define __func__ __FUNCTION__
|
nuclear@0
|
53 #endif /* _MSC_VER */
|
nuclear@0
|
54
|
nuclear@0
|
55 static int verbose = 1;
|
nuclear@0
|
56
|
nuclear@0
|
57 int sl_listen(int port) {
|
nuclear@0
|
58 int s;
|
nuclear@0
|
59 struct sockaddr_in addr;
|
nuclear@0
|
60 struct hostent *host;
|
nuclear@0
|
61 char host_name[MAXHOSTNAMELEN+1];
|
nuclear@0
|
62
|
nuclear@0
|
63 #ifndef __unix__
|
nuclear@0
|
64 if(!winsock_initialized) {
|
nuclear@0
|
65 WSADATA wsa_data;
|
nuclear@0
|
66 WSAStartup(MAKEWORD(1, 1), &wsa_data);
|
nuclear@0
|
67 winsock_initialized = 1;
|
nuclear@0
|
68 }
|
nuclear@0
|
69 #endif /* __unix__ */
|
nuclear@0
|
70
|
nuclear@0
|
71 if(gethostname(host_name, MAXHOSTNAMELEN+1) == -1) {
|
nuclear@0
|
72 if(verbose) perror("socklib error @ gethostname");
|
nuclear@0
|
73 return -1;
|
nuclear@0
|
74 }
|
nuclear@0
|
75
|
nuclear@0
|
76 if(!(host = gethostbyname(host_name))) {
|
nuclear@0
|
77 if(verbose) perror("socklib error @ gethostbyname");
|
nuclear@0
|
78 return -1;
|
nuclear@0
|
79 }
|
nuclear@0
|
80
|
nuclear@0
|
81 memset(&addr, 0, sizeof(struct sockaddr_in));
|
nuclear@0
|
82 addr.sin_family = host->h_addrtype;
|
nuclear@0
|
83 addr.sin_port = htons(port);
|
nuclear@0
|
84 addr.sin_addr.s_addr = INADDR_ANY;
|
nuclear@0
|
85
|
nuclear@0
|
86 if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@0
|
87 if(verbose) perror("socklib error @ socket");
|
nuclear@0
|
88 return -1;
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 if(bind(s, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
|
nuclear@0
|
92 if(verbose) perror("socklib error @ bind");
|
nuclear@0
|
93 close(s);
|
nuclear@0
|
94 return -1;
|
nuclear@0
|
95 }
|
nuclear@0
|
96
|
nuclear@0
|
97 if(listen(s, 5) == -1) {
|
nuclear@0
|
98 if(verbose) perror("socklib error @ listen");
|
nuclear@0
|
99 close(s);
|
nuclear@0
|
100 return -1;
|
nuclear@0
|
101 }
|
nuclear@0
|
102
|
nuclear@0
|
103 return s;
|
nuclear@0
|
104 }
|
nuclear@0
|
105
|
nuclear@0
|
106
|
nuclear@0
|
107 int sl_accept(int listening_socket) {
|
nuclear@0
|
108 return accept(listening_socket, 0, 0);
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 int sl_connect_tcp(char *ipaddr, const char *hostname, int port) {
|
nuclear@0
|
112 int s, must_free_ipaddr = 0;
|
nuclear@0
|
113 struct sockaddr_in addr;
|
nuclear@0
|
114 struct hostent *host;
|
nuclear@0
|
115
|
nuclear@0
|
116 #ifndef __unix__
|
nuclear@0
|
117 if(!winsock_initialized) {
|
nuclear@0
|
118 WSADATA wsa_data;
|
nuclear@0
|
119 WSAStartup(MAKEWORD(1, 1), &wsa_data);
|
nuclear@0
|
120 winsock_initialized = 1;
|
nuclear@0
|
121 }
|
nuclear@0
|
122 #endif /* __unix__ */
|
nuclear@0
|
123
|
nuclear@0
|
124 if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
|
nuclear@0
|
125 if(verbose) perror("socklib error @ socket");
|
nuclear@0
|
126 return -1;
|
nuclear@0
|
127 }
|
nuclear@0
|
128
|
nuclear@0
|
129 if(!ipaddr) {
|
nuclear@0
|
130 if(!hostname) return -1;
|
nuclear@0
|
131
|
nuclear@0
|
132 ipaddr = malloc(20);
|
nuclear@0
|
133 must_free_ipaddr = 1;
|
nuclear@0
|
134 host = gethostbyname(hostname);
|
nuclear@0
|
135
|
nuclear@0
|
136 if(!host) {
|
nuclear@0
|
137 if(verbose) perror("socklib error @ gethostbyname");
|
nuclear@0
|
138 free(ipaddr);
|
nuclear@0
|
139 return -1;
|
nuclear@0
|
140 }
|
nuclear@0
|
141
|
nuclear@0
|
142 strcpy(ipaddr, inet_ntoa(*((struct in_addr*)host->h_addr)));
|
nuclear@0
|
143 }
|
nuclear@0
|
144
|
nuclear@0
|
145 memset(&addr, 0, sizeof(struct sockaddr_in));
|
nuclear@0
|
146 addr.sin_family = AF_INET;
|
nuclear@0
|
147 addr.sin_port = htons(port);
|
nuclear@0
|
148 addr.sin_addr.s_addr = inet_addr(ipaddr);
|
nuclear@0
|
149
|
nuclear@0
|
150 if((connect(s, (struct sockaddr*)&addr, sizeof(struct sockaddr))) == -1) {
|
nuclear@0
|
151 if(verbose) perror("socklib error @ connect");
|
nuclear@0
|
152 if(must_free_ipaddr) free(ipaddr);
|
nuclear@0
|
153 return -1;
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 if(must_free_ipaddr) free(ipaddr);
|
nuclear@0
|
157 return s;
|
nuclear@0
|
158 }
|
nuclear@0
|
159
|
nuclear@0
|
160
|
nuclear@0
|
161 void sl_close_socket(int s) {
|
nuclear@0
|
162 char buffer[128];
|
nuclear@0
|
163
|
nuclear@0
|
164 shutdown(s, 1);
|
nuclear@0
|
165 while(recv(s, buffer, 128, 0));
|
nuclear@0
|
166 close(s);
|
nuclear@0
|
167 }
|
nuclear@0
|
168
|
nuclear@0
|
169 int sl_send_data(int s, const char *buffer, int size) {
|
nuclear@0
|
170 const char *ptr = buffer;
|
nuclear@0
|
171 const char *end = buffer + size;
|
nuclear@0
|
172
|
nuclear@0
|
173 while(ptr < end) {
|
nuclear@0
|
174 int bytes = send(s, ptr, end - ptr, 0);
|
nuclear@0
|
175 if(bytes == -1) {
|
nuclear@0
|
176 if(verbose) {
|
nuclear@0
|
177 char errstr[80];
|
nuclear@0
|
178 sprintf(errstr, "socklib error @ %s", __func__);
|
nuclear@0
|
179 perror(errstr);
|
nuclear@0
|
180 }
|
nuclear@0
|
181 return -1;
|
nuclear@0
|
182 }
|
nuclear@0
|
183 ptr += bytes;
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 return size;
|
nuclear@0
|
187 }
|
nuclear@0
|
188
|
nuclear@0
|
189 int sl_recv_data(int s, char *buffer, int size) {
|
nuclear@0
|
190 int bytes = recv(s, buffer, size, 0);
|
nuclear@0
|
191 if(bytes == -1) {
|
nuclear@0
|
192 if(verbose) {
|
nuclear@0
|
193 char errstr[80];
|
nuclear@0
|
194 sprintf(errstr, "socklib error @ %s", __func__);
|
nuclear@0
|
195 perror(errstr);
|
nuclear@0
|
196 }
|
nuclear@0
|
197 return -1;
|
nuclear@0
|
198 }
|
nuclear@0
|
199 return bytes;
|
nuclear@0
|
200 }
|
nuclear@0
|
201
|
nuclear@0
|
202
|
nuclear@0
|
203 /* if SL_CHK_IMMED is NOT specified then:
|
nuclear@0
|
204 * if timeout is 0: block forever, else block for so many milliseconds.
|
nuclear@0
|
205 */
|
nuclear@0
|
206 int sl_check_socket(int s, int flags, unsigned int timeout) {
|
nuclear@0
|
207 int res;
|
nuclear@0
|
208 fd_set rfds, wfds;
|
nuclear@0
|
209 struct timeval tv, *tvptr;
|
nuclear@0
|
210 tv.tv_sec = tv.tv_usec = 0;
|
nuclear@0
|
211
|
nuclear@0
|
212 tvptr = (flags & SL_CHK_IMMED) ? &tv : 0;
|
nuclear@0
|
213
|
nuclear@0
|
214 if(flags & SL_CHK_IMMED) {
|
nuclear@0
|
215 tvptr = &tv;
|
nuclear@0
|
216 } else {
|
nuclear@0
|
217 tvptr = timeout > 0 ? &tv : 0;
|
nuclear@0
|
218
|
nuclear@0
|
219 tv.tv_sec = timeout / 1000;
|
nuclear@0
|
220 tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
|
nuclear@0
|
221 }
|
nuclear@0
|
222
|
nuclear@0
|
223
|
nuclear@0
|
224 FD_ZERO(&rfds);
|
nuclear@0
|
225 FD_ZERO(&wfds);
|
nuclear@0
|
226
|
nuclear@0
|
227 if(flags & SL_CHK_READ) {
|
nuclear@0
|
228 FD_SET(s, &rfds);
|
nuclear@0
|
229 if((res = select(s+1, &rfds, 0, 0, tvptr)) == -1) {
|
nuclear@0
|
230 return -1;
|
nuclear@0
|
231 }
|
nuclear@0
|
232 return FD_ISSET(s, &rfds) ? 1 : 0;
|
nuclear@0
|
233 } else if(flags & SL_CHK_WRITE) {
|
nuclear@0
|
234 FD_SET(s, &wfds);
|
nuclear@0
|
235 if((res = select(s+1, 0, &wfds, 0, tvptr)) == -1) {
|
nuclear@0
|
236 return -1;
|
nuclear@0
|
237 }
|
nuclear@0
|
238 return FD_ISSET(s, &wfds) ? 1 : 0;
|
nuclear@0
|
239 }
|
nuclear@0
|
240
|
nuclear@0
|
241 return -1;
|
nuclear@0
|
242 }
|
nuclear@0
|
243
|
nuclear@0
|
244 void sl_set_verbosity(int vlevel) {
|
nuclear@0
|
245 verbose = vlevel;
|
nuclear@0
|
246 }
|