| 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 | |