1 | /* $Id: minisoap.c,v 1.18 2009/12/04 11:29:18 nanard Exp $ */ |
---|
2 | /* Project : miniupnp |
---|
3 | * Author : Thomas Bernard |
---|
4 | * Copyright (c) 2005-2009 Thomas Bernard |
---|
5 | * This software is subject to the conditions detailed in the |
---|
6 | * LICENCE file provided in this distribution. |
---|
7 | * |
---|
8 | * Minimal SOAP implementation for UPnP protocol. |
---|
9 | */ |
---|
10 | #include <stdio.h> |
---|
11 | #include <string.h> |
---|
12 | #ifdef WIN32 |
---|
13 | #include <io.h> |
---|
14 | #include <winsock2.h> |
---|
15 | #define snprintf _snprintf |
---|
16 | #else |
---|
17 | #include <unistd.h> |
---|
18 | #include <sys/types.h> |
---|
19 | #include <sys/socket.h> |
---|
20 | #endif |
---|
21 | #include "minisoap.h" |
---|
22 | #include "miniupnpcstrings.h" |
---|
23 | |
---|
24 | /* only for malloc */ |
---|
25 | #include <stdlib.h> |
---|
26 | |
---|
27 | #ifdef WIN32 |
---|
28 | #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); |
---|
29 | #else |
---|
30 | #define PRINT_SOCKET_ERROR(x) perror(x) |
---|
31 | #endif |
---|
32 | |
---|
33 | /* httpWrite sends the headers and the body to the socket |
---|
34 | * and returns the number of bytes sent */ |
---|
35 | static int |
---|
36 | httpWrite(int fd, const char * body, int bodysize, |
---|
37 | const char * headers, int headerssize) |
---|
38 | { |
---|
39 | int n = 0; |
---|
40 | /*n = write(fd, headers, headerssize);*/ |
---|
41 | /*if(bodysize>0) |
---|
42 | n += write(fd, body, bodysize);*/ |
---|
43 | /* Note : my old linksys router only took into account |
---|
44 | * soap request that are sent into only one packet */ |
---|
45 | char * p; |
---|
46 | /* TODO: AVOID MALLOC */ |
---|
47 | p = malloc(headerssize+bodysize); |
---|
48 | if(!p) |
---|
49 | return 0; |
---|
50 | memcpy(p, headers, headerssize); |
---|
51 | memcpy(p+headerssize, body, bodysize); |
---|
52 | /*n = write(fd, p, headerssize+bodysize);*/ |
---|
53 | n = send(fd, p, headerssize+bodysize, 0); |
---|
54 | if(n<0) { |
---|
55 | PRINT_SOCKET_ERROR("send"); |
---|
56 | } |
---|
57 | /* disable send on the socket */ |
---|
58 | /* draytek routers dont seems to like that... */ |
---|
59 | #if 0 |
---|
60 | #ifdef WIN32 |
---|
61 | if(shutdown(fd, SD_SEND)<0) { |
---|
62 | #else |
---|
63 | if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ |
---|
64 | #endif |
---|
65 | PRINT_SOCKET_ERROR("shutdown"); |
---|
66 | } |
---|
67 | #endif |
---|
68 | free(p); |
---|
69 | return n; |
---|
70 | } |
---|
71 | |
---|
72 | /* self explanatory */ |
---|
73 | int soapPostSubmit(int fd, |
---|
74 | const char * url, |
---|
75 | const char * host, |
---|
76 | unsigned short port, |
---|
77 | const char * action, |
---|
78 | const char * body) |
---|
79 | { |
---|
80 | int bodysize; |
---|
81 | char headerbuf[512]; |
---|
82 | int headerssize; |
---|
83 | char portstr[8]; |
---|
84 | bodysize = (int)strlen(body); |
---|
85 | /* We are not using keep-alive HTTP connections. |
---|
86 | * HTTP/1.1 needs the header Connection: close to do that. |
---|
87 | * This is the default with HTTP/1.0 |
---|
88 | * Using HTTP/1.1 means we need to support chunked transfer-encoding : |
---|
89 | * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked |
---|
90 | * transfer encoding. */ |
---|
91 | /* Connection: Close is normally there only in HTTP/1.1 but who knows */ |
---|
92 | portstr[0] = '\0'; |
---|
93 | if(port != 80) |
---|
94 | snprintf(portstr, sizeof(portstr), ":%hu", port); |
---|
95 | headerssize = snprintf(headerbuf, sizeof(headerbuf), |
---|
96 | /* "POST %s HTTP/1.1\r\n" */ |
---|
97 | "POST %s HTTP/1.0\r\n" |
---|
98 | "Host: %s%s\r\n" |
---|
99 | "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" |
---|
100 | "Content-Length: %d\r\n" |
---|
101 | "Content-Type: text/xml\r\n" |
---|
102 | "SOAPAction: \"%s\"\r\n" |
---|
103 | "Connection: Close\r\n" |
---|
104 | "Cache-Control: no-cache\r\n" /* ??? */ |
---|
105 | "Pragma: no-cache\r\n" |
---|
106 | "\r\n", |
---|
107 | url, host, portstr, bodysize, action); |
---|
108 | #ifdef DEBUG |
---|
109 | printf("SOAP request : headersize=%d bodysize=%d\n", |
---|
110 | headerssize, bodysize); |
---|
111 | /*printf("%s", headerbuf);*/ |
---|
112 | #endif |
---|
113 | return httpWrite(fd, body, bodysize, headerbuf, headerssize); |
---|
114 | } |
---|
115 | |
---|
116 | |
---|