Hi, <br><br>I am working on a simple external to do HTTP requests from PD. The idea is to implement a simple way to send and receive simple data to a web server. This is intended to work together with a set of classes that will interpret the GET variables as key and values pairs where the values can be similar to FUDI protocol messages. The web page would then answer with a FUDI message or so. I don't use Python because I want it to be very fast, totally portable and easy to install. (I also agree with Hans regarding small tools to make a constellation of low level objects) 
<br><br>Here are my bugs : perhaps I am not very good yet with strings in C, but I have several errors when I try to execute this code from within PD as an external. Well, when I get malloc errors, it must be only about memory size arithmetics, but when it gets into segmentation faults, I was just wondering if it could be because cURL starts a new thread. I think that thread are not much appropriate in PD's context. Do you think this is the problem, or I am just still a bit bad with memory maths ? 
<br><br>Also, if you have ideas about this external, please don't hesitate. I think I will rename it to http, as it is not intended in downloading whole files, but just for simple HTTP requests.<br><br>See below for the current code, the makefile and one of the errors it creates. 
<br><br>Alexandre Quessy<br><a href="http://alexandre.quessy.net">http://alexandre.quessy.net</a><br><br>============================= error when using it ====================<br><br>pd wget-help.pd <br>STACK_END old=0xbf9e5ffc; new=0xbf9efffc
<br>PDP: pure data packet<br>PDP: version 0.12.4<br>* About to connect() to <a href="http://alexandre.quessy.net">alexandre.quessy.net</a> port 80<br>*&nbsp;&nbsp; Trying 64.15.134.165... * connected<br>* Connected to <a href="http://alexandre.quessy.net">
alexandre.quessy.net</a> (<a href="http://64.15.134.165">64.15.134.165</a>) port 80<br>&gt; GET /pd/curlme.php?asd=qwe+123 HTTP/1.1<br>User-Agent: Pure Data<br>Host: <a href="http://alexandre.quessy.net">alexandre.quessy.net
</a><br>Accept: */*<br><br>&lt; HTTP/1.1 200 OK<br>&lt; Date: Mon, 19 Jun 2006 16:03:44 GMT<br>&lt; Server: Apache<br>&lt; X-Powered-By: PHP/4.3.10-16<br>&lt; Connection: close<br>&lt; Transfer-Encoding: chunked<br>&lt; Content-Type: text/html
<br>* Closing connection #0<br>socket receive error: Connection reset by peer (104)<br>Erreur de segmentation<br><br>================== makefile ====================================<br>
<br>
all: wget.pd_linux<br>
&nbsp;&nbsp;&nbsp; @echo &quot;making wget&quot;<br>
<br>
wget.pd_linux: wget.c <br>
&nbsp;&nbsp;&nbsp; gcc -DPD -O2 -funroll-loops -fomit-frame-pointer \<br>
&nbsp;&nbsp;&nbsp; &nbsp; -Wall -W -Wshadow -Wstrict-prototypes \<br>
&nbsp;&nbsp;&nbsp; &nbsp; -Wno-unused -Wno-parentheses -Wno-switch -o wget.o -c wget.c<br>
&nbsp;&nbsp;&nbsp; ld -export_dynamic -shared -o wget.pd_linux wget.o -lcurl -lc -lm<br>
&nbsp;&nbsp;&nbsp; strip --strip-unneeded wget.pd_linux<br>
&nbsp;&nbsp;&nbsp; rm wget.o<br>
<br><br><br>================== code : wget.c ================================<br><br>/**<br>&nbsp;* [wget] is a Pure Data object for simple HTTP requests.<br>&nbsp;*<br>&nbsp;* @url <a href="http://alexandre.quessy.net/">http://alexandre.quessy.net/
</a><br>&nbsp;* @author Alexandre Quessy &lt;<a href="mailto:alexandre@quessy.net">alexandre@quessy.net</a>&gt;<br>&nbsp;* @license GNU General Public License 2006<br>&nbsp;*/<br>#define PDWGET_VERSION &quot;0.1.0&quot;<br><br>/* PD includes */
<br>#include &quot;m_pd.h&quot;<br><br>/* cURL and standard C libraries */<br>#include &lt;curl/curl.h&gt;<br>#include &lt;string.h&gt;<br>#include &lt;stdlib.h&gt;<br><br>/* Download callback function prototype */<br>size_t wget_callBack(void *ptr, size_t size, size_t nmemb, void *x);
<br><br>/** <br>&nbsp;* variables of the pd object <br>&nbsp;*/<br>typedef struct wget {<br>&nbsp; t_object x_ob; /* The instance. Contains inlets and outlets */<br>&nbsp; t_outlet *x_outlet0; /* result string */<br>&nbsp; t_outlet *x_outlet1; /* HTTP error codes */
<br>} t_wget;<br><br><br><br>/** <br>&nbsp;* HTTP request.<br>&nbsp;*/<br>void wget_request(t_wget *x, t_symbol *s, int argc, t_atom *argv) {<br>&nbsp;&nbsp;&nbsp; post(&quot;wget : called request.&quot;);<br>&nbsp;&nbsp;&nbsp; //curl_global_init(CURL_GLOBAL_NOTHING);//CURL_GLOBAL_ALL
<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //t_symbol *sym_tmp = atom_getsymbol(&amp;argv[0]);<br>&nbsp;&nbsp;&nbsp; if (argc &lt; 1) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; post(&quot;wget : Error : needs arguments.&quot;);<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp; t_symbol *sym_tmp = atom_getsymbolarg(0, argc, argv);
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; char *url = sym_tmp-&gt;s_name;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; post(&quot;wget : requesting : %s&quot;, url);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; /* cURL context */<br>&nbsp;&nbsp;&nbsp; CURL *pContext = curl_easy_init();<br>&nbsp;&nbsp;&nbsp; if (pContext == NULL) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; post(&quot;wget : Error :&nbsp; Null cURL handle.&quot;);
<br>&nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* cURL options */<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; CURLcode pCode = curl_easy_setopt(pContext, CURLOPT_URL, url);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_WRITEFUNCTION, wget_callBack, (void *) x);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_VERBOSE, 1);
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_HEADER, 0);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_NOPROGRESS, 1);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_USERAGENT, &quot;Pure Data&quot;);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_NOSIGNAL, 1);
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_setopt(pContext, CURLOPT_TIMEOUT, (long) 5);<br><br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* cURL performing */<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; post(&quot;wget : Performing the request.&quot;);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; const CURLcode result = curl_easy_perform(pContext);
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(CURLE_OK != result) {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; post(&quot;wget : Error from cURL: %s&quot;, curl_easy_strerror(result));<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* HTTP code */<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; long lHttpCode;
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; curl_easy_getinfo(pContext, CURLINFO_RESPONSE_CODE, &amp;lHttpCode);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; post(&quot;wget : HTTP response code: %ld &quot;, lHttpCode);<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //outlet_float(x-&gt;x_outlet1, (float) lHttpCode);
<br>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; post(&quot;[wget] cleaning up...&quot;);<br>&nbsp;&nbsp;&nbsp; /* cURL cleanup */<br>&nbsp;&nbsp;&nbsp; curl_easy_cleanup(pContext);<br>&nbsp;&nbsp;&nbsp; post(&quot;[wget] Local cleaned up.&quot;);<br>&nbsp;&nbsp;&nbsp; //curl_global_cleanup();
<br>&nbsp;&nbsp;&nbsp; post(&quot;[wget] Global cleaned up.&quot;);<br>&nbsp;&nbsp;&nbsp; //outlet_list(x-&gt;x_outlet0, gensym(&quot;A_FLOAT&quot;), numCols+1, &amp;atoms); // &amp;atoms ??<br>&nbsp;&nbsp;&nbsp; } // else<br>}<br><br>/** <br>&nbsp;* The representation of the class in PD.
<br>&nbsp;*/<br>t_class *wget_class;<br><br>/** <br>&nbsp;* constructor <br>&nbsp;*/<br>void *wget_new(t_symbol *selector, int argc, t_atom *argv) {<br>&nbsp;&nbsp;&nbsp; post(&quot;wget : creating a new object.&quot;);<br>&nbsp;&nbsp;&nbsp; t_wget *x = (t_wget *) pd_new(wget_class);
<br>&nbsp;&nbsp;&nbsp; x-&gt;x_outlet0 = outlet_new(&amp;x-&gt;x_ob, gensym(&quot;list&quot;));<br>&nbsp;&nbsp;&nbsp; x-&gt;x_outlet1 = outlet_new(&amp;x-&gt;x_ob, gensym(&quot;float&quot;));<br>&nbsp;&nbsp;&nbsp; return (void *)x;<br>}<br><br>/** <br>&nbsp;* setup <br>&nbsp;*/
<br>void wget_setup(void) {<br>&nbsp;&nbsp;&nbsp; curl_global_init(CURL_GLOBAL_NOTHING);<br>&nbsp;&nbsp;&nbsp; wget_class = class_new(gensym(&quot;wget&quot;), (t_newmethod) wget_new, 0, sizeof(t_wget), 0, A_GIMME, 0);<br>&nbsp;&nbsp;&nbsp; class_addmethod(wget_class, (t_method)wget_request, gensym(&quot;request&quot;), A_GIMME, 0);
<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; post(&quot;----------------------------------------------------&quot;);<br>&nbsp;&nbsp;&nbsp; post(&quot; [wget] %s (c) GPL Copyleft 2006 Alexandre Quessy&quot;, PDWGET_VERSION);<br>&nbsp;&nbsp;&nbsp; post(&quot; Simple HTTP requests for Pure Data.&quot;);
<br>&nbsp;&nbsp;&nbsp; post(&quot;----------------------------------------------------&quot;);<br>}<br><br>/** <br>&nbsp;* Callback implementation<br>&nbsp;*/<br>size_t wget_callBack(void *ptr, size_t size, size_t nmemb, void *x) {<br>&nbsp;&nbsp;&nbsp; size_t totalSize = nmemb * size;
<br>&nbsp;&nbsp;&nbsp; char *dest = malloc(totalSize + 1); //(sizeof(char))<br>&nbsp;&nbsp;&nbsp; strcpy(dest, (char *) ptr);<br>&nbsp;&nbsp;&nbsp; post(&quot;[wget] : Getting data.&quot;);<br>&nbsp;&nbsp;&nbsp; dest[totalSize] = '\0';<br>&nbsp;&nbsp;&nbsp; post(&quot;result :&quot;);<br>&nbsp;&nbsp;&nbsp; post(&quot;===============================&quot;);
<br>&nbsp;&nbsp;&nbsp; post(&quot;%s&quot;, dest);<br>&nbsp;&nbsp;&nbsp; post(&quot;===============================&quot;);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //outlet_symbol(((t_wget *)x)-&gt;x_outlet0, gensym(dest));<br>&nbsp;&nbsp;&nbsp; //free(dest);<br>&nbsp;&nbsp;&nbsp; return(totalSize);<br>}<br>
<br><br><br><br><br>