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