* added some socket stuff
[citadel.git] / ctdlsh / src / sockets.c
1 /*
2  *
3  */
4
5 #include <config.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/time.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <netdb.h>
16 #include <string.h>
17 #include <pwd.h>
18 #include <errno.h>
19 #include <stdarg.h>
20
21 #ifndef INADDR_NONE
22 #define INADDR_NONE 0xffffffff
23 #endif
24
25 int sock_connect(char *host, char *service, char *protocol)
26 {
27         struct hostent *phe;
28         struct servent *pse;
29         struct protoent *ppe;
30         struct sockaddr_in sin;
31         struct sockaddr_in egress_sin;
32         int s, type;
33
34         if (host == NULL) return(-1);
35         if (service == NULL) return(-1);
36         if (protocol == NULL) return(-1);
37
38         memset(&sin, 0, sizeof(sin));
39         sin.sin_family = AF_INET;
40
41         pse = getservbyname(service, protocol);
42         if (pse) {
43                 sin.sin_port = pse->s_port;
44         } else if ((sin.sin_port = htons((u_short) atoi(service))) == 0) {
45                 fprintf(stderr, "Can't get %s service entry: %s\n",
46                         service, strerror(errno));
47                 return(-1);
48         }
49         phe = gethostbyname(host);
50         if (phe) {
51                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
52         } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
53                 fprintf(stderr, "Can't get %s host entry: %s\n",
54                         host, strerror(errno));
55                 return(-1);
56         }
57         if ((ppe = getprotobyname(protocol)) == 0) {
58                 fprintf(stderr, "Can't get %s protocol entry: %s\n",
59                         protocol, strerror(errno));
60                 return(-1);
61         }
62         if (!strcmp(protocol, "udp")) {
63                 type = SOCK_DGRAM;
64         } else {
65                 type = SOCK_STREAM;
66         }
67
68         s = socket(PF_INET, type, ppe->p_proto);
69         if (s < 0) {
70                 fprintf(stderr, "Can't create socket: %s\n", strerror(errno));
71                 return(-1);
72         }
73
74         /* Now try to connect to the remote host. */
75         if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
76                 fprintf(stderr, "Can't connect to %s:%s: %s\n",
77                         host, service, strerror(errno));
78                 close(s);
79                 return(-1);
80         }
81
82         return (s);
83 }
84
85
86
87 /*
88  * sock_read_to() - input binary data from socket, with a settable timeout.
89  * Returns the number of bytes read, or -1 for error.
90  * If keep_reading_until_full is nonzero, we keep reading until we get the number of requested bytes
91  */
92 int sock_read_to(int sock, char *buf, int bytes, int timeout, int keep_reading_until_full)
93 {
94         int len,rlen;
95         fd_set rfds;
96         struct timeval tv;
97         int retval;
98
99         len = 0;
100         while (len<bytes) {
101                 FD_ZERO(&rfds);
102                 FD_SET(sock, &rfds);
103                 tv.tv_sec = timeout;
104                 tv.tv_usec = 0;
105
106                 retval = select(sock+1, &rfds, NULL, NULL, &tv);
107
108                 if (FD_ISSET(sock, &rfds) == 0) {       /* timed out */
109                         fprintf(stderr, "sock_read() timed out.\n");
110                         return(-1);
111                 }
112
113                 rlen = read(sock, &buf[len], bytes-len);
114                 if (rlen<1) {
115                         fprintf(stderr, "sock_read() failed: %s\n",
116                                 strerror(errno));
117                         return(-1);
118                 }
119                 len = len + rlen;
120                 if (!keep_reading_until_full) return(len);
121         }
122         return(bytes);
123 }
124
125
126 /*
127  * sock_read() - input binary data from socket.
128  * Returns the number of bytes read, or -1 for error.
129  */
130 int sock_read(int sock, char *buf, int bytes, int keep_reading_until_full)
131 {
132         return sock_read_to(sock, buf, bytes, 30, keep_reading_until_full);
133 }
134
135
136 /*
137  * sock_write() - send binary to server.
138  * Returns the number of bytes written, or -1 for error.
139  */
140 int sock_write(int sock, char *buf, int nbytes)
141 {
142         int bytes_written = 0;
143         int retval;
144         while (bytes_written < nbytes) {
145                 retval = write(sock, &buf[bytes_written],
146                                nbytes - bytes_written);
147                 if (retval < 1) {
148                         return (-1);
149                 }
150                 bytes_written = bytes_written + retval;
151         }
152         return (bytes_written);
153 }
154
155
156
157 /*
158  * Input string from socket - implemented in terms of sock_read()
159  * 
160  */
161 int sock_getln(int sock, char *buf, int bufsize)
162 {
163         int i;
164
165         /* Read one character at a time.
166          */
167         for (i = 0;; i++) {
168                 if (sock_read(sock, &buf[i], 1, 1) < 0) return(-1);
169                 if (buf[i] == '\n' || i == (bufsize-1))
170                         break;
171         }
172
173         /* If we got a long line, discard characters until the newline.
174          */
175         if (i == (bufsize-1))
176                 while (buf[i] != '\n')
177                         if (sock_read(sock, &buf[i], 1, 1) < 0) return(-1);
178
179         /* Strip any trailing CR and LF characters.
180          */
181         buf[i] = 0;
182         while ( (i > 0)
183                 && ( (buf[i - 1]==13)
184                      || ( buf[i - 1]==10)) ) {
185                 i--;
186                 buf[i] = 0;
187         }
188         return(i);
189 }
190
191
192
193 /*
194  * sock_puts() - send line to server - implemented in terms of serv_write()
195  * Returns the number of bytes written, or -1 for error.
196  */
197 int sock_puts(int sock, char *buf)
198 {
199         int i, j;
200
201         i = sock_write(sock, buf, strlen(buf));
202         if (i<0) return(i);
203         j = sock_write(sock, "\n", 1);
204         if (j<0) return(j);
205         return(i+j);
206 }