ChangeLog update
[tetrinet.git] / sockets.c
blob6a770ed25ec3a219dcc9555062376bc1e3dc137f
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 <string.h>
18 #include "sockets.h"
19 #include "tetrinet.h"
21 static FILE *logfile;
23 /*************************************************************************/
25 static int lastchar = EOF;
27 int sgetc(int s)
29 int c;
30 char ch;
32 if (lastchar != EOF) {
33 c = lastchar;
34 lastchar = EOF;
35 return c;
37 if (read(s, &ch, 1) != 1)
38 return EOF;
39 c = ch & 0xFF;
40 return c;
43 int sungetc(int c, int s)
45 return lastchar = c;
48 /*************************************************************************/
50 /* Read a string, stopping with (and discarding) 0xFF as line terminator.
51 * If connection was broken, return NULL.
54 char *sgets(char *buf, int len, int s)
56 int c;
57 unsigned char *ptr = (unsigned char *) buf;
59 if (len == 0)
60 return NULL;
61 c = sgetc(s);
62 while (--len && (*ptr++ = c) != 0xFF && (c = sgetc(s)) >= 0)
64 if (c < 0)
65 return NULL;
66 if (c == 0xFF)
67 ptr--;
68 *ptr = 0;
69 if (log) {
70 if (!logfile)
71 logfile = fopen(logname, "a");
72 if (logfile) {
73 struct timeval tv;
74 gettimeofday(&tv, NULL);
75 fprintf(logfile, "[%d.%03d] <<< %s\n",
76 (int) tv.tv_sec, (int) tv.tv_usec/1000, buf);
77 fflush(logfile);
80 return buf;
83 /*************************************************************************/
85 /* Adds a 0xFF line terminator. */
87 int sputs(const char *str, int s)
89 unsigned char c = 0xFF;
90 int n = 0;
92 if (log) {
93 if (!logfile)
94 logfile = fopen(logname, "a");
95 if (logfile) {
96 struct timeval tv;
97 gettimeofday(&tv, NULL);
98 fprintf(logfile, "[%d.%03d] >>> %s\n",
99 (int) tv.tv_sec, (int) tv.tv_usec/1000, str);
102 if (*str != 0) {
103 n = write(s, str, strlen(str));
104 if (n <= 0)
105 return n;
107 if (write(s, &c, 1) <= 0)
108 return n;
109 return n+1;
112 /*************************************************************************/
114 /* Adds a 0xFF line terminator. */
116 int sockprintf(int s, const char *fmt, ...)
118 va_list args;
119 char buf[16384]; /* Really huge, to try and avoid truncation */
121 va_start(args, fmt);
122 vsnprintf(buf, sizeof(buf), fmt, args);
123 return sputs(buf, s);
126 /*************************************************************************/
127 /*************************************************************************/
129 int conn(const char *host, int port, char ipbuf[4])
131 #ifdef HAVE_IPV6
132 char hbuf[NI_MAXHOST];
133 struct addrinfo hints, *res, *res0;
134 char service[11];
135 #else
136 struct hostent *hp;
137 struct sockaddr_in sa;
138 #endif
139 int sock = -1;
141 #ifdef HAVE_IPV6
142 snprintf(service, sizeof(service), "%d", port);
143 memset(&hints, 0, sizeof(hints));
144 hints.ai_family = AF_UNSPEC;
145 hints.ai_socktype = SOCK_STREAM;
146 if (getaddrinfo(host, service, &hints, &res0))
147 return -1;
148 for (res = res0; res; res = res->ai_next) {
149 int errno_save;
150 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
151 if (sock < 0)
152 continue;
153 getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
154 NULL, 0, 0);
155 if (connect(sock, res->ai_addr, res->ai_addrlen) == 0) {
156 if (ipbuf) {
157 if (res->ai_family == AF_INET6) {
158 struct sockaddr_in6 *sin6 =
159 (struct sockaddr_in6 *)(res->ai_addr);
160 memcpy(ipbuf, (char *)(&sin6->sin6_addr) + 12, 4);
161 } else {
162 struct sockaddr_in *sin =
163 (struct sockaddr_in *)(res->ai_addr);
164 memcpy(ipbuf, &sin->sin_addr, 4);
167 break;
169 errno_save = errno;
170 close(sock);
171 sock = -1;
172 errno = errno_save;
174 freeaddrinfo(res0);
175 #else /* !HAVE_IPV6 */
176 memset(&sa, 0, sizeof(sa));
177 if (!(hp = gethostbyname(host)))
178 return -1;
179 memcpy((char *)&sa.sin_addr, hp->h_addr, hp->h_length);
180 sa.sin_family = hp->h_addrtype;
181 sa.sin_port = htons((unsigned short)port);
182 if ((sock = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
183 return -1;
184 if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
185 int errno_save = errno;
186 close(sock);
187 errno = errno_save;
188 return -1;
190 if (ipbuf)
191 memcpy(retbuf, &sa.sin_addr, 4);
192 #endif
194 return sock;
197 /*************************************************************************/
199 void disconn(int s)
201 shutdown(s, 2);
202 close(s);
205 /*************************************************************************/