9c34a3b02d329f2ea9496e9d485eec0778ee874d
[doldaconnect.git] / common / http.c
1 /*
2  *  Dolda Connect - Modular multiuser Direct Connect-style client
3  *  Copyright (C) 2007 Fredrik Tolf (fredrik@dolda2000.com)
4  *  
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *  
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *  
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/poll.h>
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <utils.h>
31 #include <http.h>
32
33 #define STATE_SYN 0
34 #define STATE_TXREQ 1
35
36 void freeurl(struct hturlinfo *ui)
37 {
38     free(ui->host);
39     free(ui->path);
40     free(ui->query);
41     free(ui->fragment);
42     free(ui);
43 }
44
45 struct hturlinfo *parseurl(char *url)
46 {
47     char *p, *p2, *p3;
48     struct hturlinfo *ui;
49     
50     if(strncmp(url, "http://", 7))
51         return(NULL);
52     ui = memset(smalloc(sizeof(*ui)), 0, sizeof(*ui));
53     p = url + 7;
54     if((p2 = strchr(p, '/')) != NULL)
55         *(p2++) = 0;
56     if((p3 = strrchr(p, ':')) != NULL) {
57         *(p3++) = 0;
58         ui->port = atoi(p3);
59     } else {
60         ui->port = 80;
61     }
62     ui->host = sstrdup(p);
63     if(p2 == NULL) {
64         ui->path = sstrdup("/");
65     } else {
66         p = p2;
67         if((p2 = strchr(p, '?')) != NULL)
68             *(p2++) = 0;
69         ui->path = sstrdup(p);
70     }
71     if(p2 == NULL) {
72         ui->query = sstrdup("");
73     } else {
74         p = p2;
75         if((p2 = strchr(p, '#')) != NULL)
76             *(p2++) = 0;
77         ui->query = sstrdup(p);
78     }
79     if(p2 == NULL) {
80         ui->fragment = sstrdup("");
81     } else {
82         ui->fragment = sstrdup(p2);
83     }
84     return(ui);
85 }
86
87 static struct hturlinfo *dupurl(struct hturlinfo *ui)
88 {
89     struct hturlinfo *new;
90     
91     new = memset(smalloc(sizeof(*new)), 0, sizeof(*new));
92     new->host = sstrdup(ui->host);
93     new->port = ui->port;
94     new->path = sstrdup(ui->path);
95     new->query = sstrdup(ui->query);
96     new->fragment = sstrdup(ui->fragment);
97     return(new);
98 }
99
100 static struct addrinfo *resolvtcp(char *name, int port)
101 {
102     struct addrinfo hint, *ret;
103     char tmp[32];
104     
105     memset(&hint, 0, sizeof(hint));
106     hint.ai_socktype = SOCK_STREAM;
107     hint.ai_flags = AI_NUMERICSERV | AI_CANONNAME;
108     snprintf(tmp, sizeof(tmp), "%i", port);
109     if(!getaddrinfo(name, tmp, &hint, &ret))
110         return(ret);
111     return(NULL);
112 }
113
114 void freehtconn(struct htconn *cn)
115 {
116     if(cn->outbuf != NULL)
117         free(cn->outbuf);
118     if(cn->inbuf != NULL)
119         free(cn->inbuf);
120     freeurl(cn->url);
121     freeaddrinfo(cn->ailist);
122     if(cn->fd != -1)
123         close(cn->fd);
124     free(cn);
125 }
126
127 struct htconn *htconnect(struct hturlinfo *ui)
128 {
129     struct htconn *cn;
130     
131     cn = memset(smalloc(sizeof(*cn)), 0, sizeof(*cn));
132     cn->fd = -1;
133     cn->url = dupurl(ui);
134     cn->ailist = resolvtcp(ui->host, ui->port);
135     return(cn);
136 }
137
138 int htpollflags(struct htconn *hc)
139 {
140     int ret;
141     
142     ret = POLLIN;
143     if(hc->outbufdata > 0)
144         ret |= POLLOUT;
145     return(ret);
146 }
147
148 int htprocess(struct htconn *hc)
149 {
150     int ret;
151     socklen_t optlen;
152     
153     if(hc->state == STATE_SYN) {
154         if(hc->fd != -1) {
155             optlen = sizeof(ret);
156             getsockopt(hc->fd, SOL_SOCKET, SO_ERROR, &ret, &optlen);
157             if(ret) {
158                 hc->fd = -1;
159             } else {
160                 hc->state = STATE_TXREQ;
161             }
162         }
163         if(hc->fd == -1) {
164             if(hc->curai == NULL)
165                 hc->curai = hc->ailist;
166             else
167                 hc->curai = hc->curai->ai_next;
168             if(hc->curai == NULL) {
169                 /* Bleh! Linux and BSD don't share any good
170                  * errno for this. */
171                 errno = ENOENT;
172                 return(-1);
173             }
174         }
175     }
176     return(0);
177 }