0.10-pb4
[tetrinet.git] / sockets.c
blobfecc362c2caddc2461cdda7bdccb0a41c7a70e87
1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2 * This program is public domain.
4 * Socket routines.
5 */
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <netdb.h>
13 #include <netinet/in.h>
14 #include <sys/socket.h>
15 #include <sys/time.h>
16 #include <unistd.h>
17 #include "sockets.h"
18 #include "tetrinet.h"
20 static FILE *logfile;
22 /*************************************************************************/
24 static int lastchar = EOF;
26 int sgetc(int s)
28 int c;
29 char ch;
31 if (lastchar != EOF) {
32 c = lastchar;
33 lastchar = EOF;
34 return c;
36 if (read(s, &ch, 1) != 1)
37 return EOF;
38 c = ch & 0xFF;
39 return c;
42 int sungetc(int c, int s)
44 return lastchar = c;
47 /*************************************************************************/
49 /* Read a string, stopping with (and discarding) 0xFF as line terminator.
50 * If connection was broken, return NULL.
53 char *sgets(char *buf, int len, int s)
55 int c;
56 unsigned char *ptr = (unsigned char *) buf;
58 if (len == 0)
59 return NULL;
60 c = sgetc(s);
61 while (--len && (*ptr++ = c) != 0xFF && (c = sgetc(s)) >= 0)
63 if (c < 0)
64 return NULL;
65 if (c == 0xFF)
66 ptr--;
67 *ptr = 0;
68 if (log) {
69 if (!logfile)
70 logfile = fopen(logname, "a");
71 if (logfile) {
72 struct timeval tv;
73 gettimeofday(&tv, NULL);
74 fprintf(logfile, "[%d.%03d] <<< %s\n",
75 (int) tv.tv_sec, (int) tv.tv_usec/1000, buf);
76 fflush(logfile);
79 return buf;
82 /*************************************************************************/
84 /* Adds a 0xFF line terminator. */
86 int sputs(const char *str, int s)
88 unsigned char c = 0xFF;
89 int n = 0;
91 if (log) {
92 if (!logfile)
93 logfile = fopen(logname, "a");
94 if (logfile) {
95 struct timeval tv;
96 gettimeofday(&tv, NULL);
97 fprintf(logfile, "[%d.%03d] >>> %s\n",
98 (int) tv.tv_sec, (int) tv.tv_usec/1000, str);
101 if (*str != 0) {
102 n = write(s, str, strlen(str));
103 if (n <= 0)
104 return n;
106 if (write(s, &c, 1) <= 0)
107 return n;
108 return n+1;
111 /*************************************************************************/
113 /* Adds a 0xFF line terminator. */
115 int sockprintf(int s, const char *fmt, ...)
117 va_list args;
118 char buf[16384]; /* Really huge, to try and avoid truncation */
120 va_start(args, fmt);
121 vsnprintf(buf, sizeof(buf), fmt, args);
122 return sputs(buf, s);
125 /*************************************************************************/
126 /*************************************************************************/
128 int conn(const char *host, int port, char ipbuf[4])
130 #ifdef HAVE_IPV6
131 char hbuf[NI_MAXHOST];
132 struct addrinfo hints, *res, *res0;
133 char service[11];
134 #else
135 struct hostent *hp;
136 struct sockaddr_in sa;
137 #endif
138 int sock = -1;
140 #ifdef HAVE_IPV6
141 snprintf(service, sizeof(service), "%d", port);
142 memset(&hints, 0, sizeof(hints));
143 hints.ai_family = AF_UNSPEC;
144 hints.ai_socktype = SOCK_STREAM;
145 if (getaddrinfo(host, service, &hints, &res0))
146 return -1;
147 for (res = res0; res; res = res->ai_next) {
148 int errno_save;
149 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
150 if (sock < 0)
151 continue;
152 getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
153 NULL, 0, 0);
154 if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) {
155 if (ipbuf) {
156 if (res->ai_family == AF_INET6) {
157 struct sockaddr_in6 *sin6 =
158 (struct sockaddr_in6 *)(res->ai_addr);
159 memcpy(ipbuf, (char *)(&sin6->sin6_addr) + 12, 4);
160 } else {
161 struct sockaddr_in *sin =
162 (struct sockaddr_in *)(res->ai_addr);
163 memcpy(ipbuf, &sin->sin_addr, 4);
166 break;
168 errno_save = errno;
169 close(sock);
170 sock = -1;
171 errno = errno_save;
173 freeaddrinfo(res0);
174 #else /* !HAVE_IPV6 */
175 memset(&sa, 0, sizeof(sa));
176 if (!(hp = gethostbyname(host)))
177 return -1;
178 memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
179 sa.sin_family = hp->h_addrtype;
180 sa.sin_port = htons((unsigned short)port);
181 if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
182 return -1;
183 if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
184 int errno_save = errno;
185 close(sock);
186 errno = errno_save;
187 return -1;
189 if (ipbuf)
190 memcpy(retbuf, &sa.sin_addr, 4);
191 #endif
193 return sock;
196 /*************************************************************************/
198 void disconn(int s)
200 shutdown(s, 2);
201 close(s);
204 /*************************************************************************/