

<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.amigaos.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Paul+Sadlik</id>
	<title>AmigaOS Documentation Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.amigaos.net/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Paul+Sadlik"/>
	<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/wiki/Special:Contributions/Paul_Sadlik"/>
	<updated>2026-06-04T16:11:31Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2019_DevCon&amp;diff=10900</id>
		<title>AmiWest 2019 DevCon</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2019_DevCon&amp;diff=10900"/>
		<updated>2019-10-06T23:48:24Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Syllabus */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Getting Ready =&lt;br /&gt;
&lt;br /&gt;
Be sure to have the AmigaOS 4.1 Final Edition SDK installed and ready to go. See [[AmiWest Setup]] for complete details on how to get ready.&lt;br /&gt;
&lt;br /&gt;
= Syllabus =&lt;br /&gt;
&lt;br /&gt;
We are aiming to cover the following topics:&lt;br /&gt;
&lt;br /&gt;
* ExecSG past/present/future&lt;br /&gt;
&lt;br /&gt;
* The 3rd party &amp;quot;Enhancer&amp;quot; Software pack or the original Amiga OS API?&lt;br /&gt;
&lt;br /&gt;
* The AmigaOS Daily Driver&lt;br /&gt;
&lt;br /&gt;
* A1222 Graphics Driver&lt;br /&gt;
&lt;br /&gt;
* Personal Projects. You are encouraged to bring your own personal projects to the DevCon where we, as a group, may be able to help you out.&lt;br /&gt;
&lt;br /&gt;
The DevCon will also be tailored to the group. If something is not interesting we can skip it and move on to something that is interesting. Class participation and feedback during the DevCon is mandatory - repeat, mandatory.&lt;br /&gt;
&lt;br /&gt;
= Schedule =&lt;br /&gt;
&lt;br /&gt;
We will start at 09:30 each day so please be there for 09:00. We&#039;ll have a lunch break around noon. There is no scheduled end time.&lt;br /&gt;
&lt;br /&gt;
== October 23 (Wednesday) ==&lt;br /&gt;
&lt;br /&gt;
* Introducing the ExecSG Team - Steven Solie&lt;br /&gt;
* Enhancer Software Core Walkthrough - Steven Solie&lt;br /&gt;
&lt;br /&gt;
== October 24 (Thursday) ==&lt;br /&gt;
&lt;br /&gt;
* Building a graphics driver for the A1222 - Tony Wyatt&lt;br /&gt;
* The Amiga Development Manifesto - Steven Solie&lt;br /&gt;
&lt;br /&gt;
== October 25 (Friday) ==&lt;br /&gt;
&lt;br /&gt;
AmiWest Classic Day&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10366</id>
		<title>AmigaOS Apps Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10366"/>
		<updated>2019-05-12T16:16:43Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you are interested in developing applications for AmigaOS please note that the [[DeveloperDoc:Main|Developer Section]] contains documentation that is useful for developing applications, device drivers, games and other programming projects on AmigaOS. The [[Tutorials:Main|Tutorial Section]] contains a couple of hands-on tutorials that are intended to allow beginning developers to get into programming with step-by-step examples. Finally, the [[Autodocs:Main|Autodocs section]] contains the well-known &#039;&#039;autodocs&#039;&#039;, function-by-function documentation of libraries and devices in the AmigaOS system.&lt;br /&gt;
&lt;br /&gt;
Additional assistance is available at [http://forum.hyperion-entertainment.com/ Hyperion Entertainment Forums] and [http://www.os4coding.net/ OS4 Coding].&lt;br /&gt;
&lt;br /&gt;
The following is a sampling of software development applications that may assist with development for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications, with the exception of the official AmigaOS Software Development Kit, is neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== adtools GNU Compiler Collection (GCC) ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;adtools&amp;quot; project is the Amiga development tools project that hosts a number of tools that can be used for cross-compiling between various platforms and developing applications for AmigaOS and other Amiga-like platforms.   The suite is based on the GCC compiler suite.  &lt;br /&gt;
&lt;br /&gt;
[https://github.com/sba1/adtools adtools webpage]&lt;br /&gt;
&lt;br /&gt;
== Amiga Image Storage System AISS ==&lt;br /&gt;
&lt;br /&gt;
The Amiga Image Storage System AISS is an environment to store, access and maintain toolbar images.  This can also be used in conjunction with AISS Viewer to easily locate and reference resources into development projects.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aiss.lha Amiga Image Storage System AISS OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aissview.lha AISS Viewer OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== AmigaOS Software Development Kit ==&lt;br /&gt;
&lt;br /&gt;
The official AmigaOS Software Development Kit contains everything needed to get started writing native applications for AmigaOS, including the AmigaOS native GCC compiler, support applications, autodocs, includes and headers.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS Software Development Kit download from Hyperion Entertainment]&lt;br /&gt;
&lt;br /&gt;
== AutoDoc Reader ==&lt;br /&gt;
&lt;br /&gt;
This is a great freeware program to view any text file (autodocs, C-header and others) with database and search options. This is very useful to read the autodocs from the Software Development Kit. Developers documentation in autodoc format is often needed in everyday work. Getting familiar with a lot of files and searching tons of text for desired information is not an easy task. That&#039;s where the idea of writing a program that could ease using autodocs originated.&lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Possibility of creating a database of ours autodocs files,&lt;br /&gt;
* Fast and easy documents browsing,&lt;br /&gt;
* Possibility of independent loading of autodocs not included in a base,&lt;br /&gt;
* Search engine for functions, methods and parameters,&lt;br /&gt;
* Easy usage with mouse or keyboard. &lt;br /&gt;
&lt;br /&gt;
The program can act as separate viewer or autodoc-viewing module for other software (e.g. DOpus or GED).&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/misc/AutoDocReader_1v65 AutoDoc Reader Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== Awk ==&lt;br /&gt;
&lt;br /&gt;
Awk, the powerful language to manipulate and process text files, is available for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/awk.lha Awk OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CMake ==&lt;br /&gt;
&lt;br /&gt;
CMake is a cross platform build tool used to easily build complex projects across different platforms with a single build process. It has been ported to&lt;br /&gt;
AmigaOS with the intention of making porting of various complex softwares easier for AmigaOS developers.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/cross/cmake.lha CMake OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CodeBench == &lt;br /&gt;
&lt;br /&gt;
CodeBench is an Integrated Development Environment (IDE).&lt;br /&gt;
&lt;br /&gt;
Designed purely for use on the latest version of AmigaOS, CodeBench is a management system that is modular to allow adaptation to various programming languages.&lt;br /&gt;
&lt;br /&gt;
The tabbed editor allowing multiple files to be open at any one time. Syntax highlighting and all the usual functions are included: Cut, Copy, Paste, Undo, Find, Replace, Indent etc. Blocks of pre-built code can also be inserted as well as handling highlighted blocks. Also supports color &amp;quot; themes&amp;quot; for familiarity.&lt;br /&gt;
&lt;br /&gt;
Utilising a &#039;project&#039; based system, all files are grouped together by type and are easily accessible from the Project Window. Editing is a simple matter of selecting the required file and it is opened in the built-in editor. Creating the finished article from the project is a one click event from the toolbar.&lt;br /&gt;
&lt;br /&gt;
[http://www.codebench.co.uk/ CodeBench webpage]&lt;br /&gt;
&lt;br /&gt;
== Cubic IDE ==&lt;br /&gt;
&lt;br /&gt;
The central component of Cubic IDE is GoldED, a fully-featured developers editor for selected versions of AmigaOS. Cubic IDE includes the Installation Wizard, an AmigaGuide authoring mode, LISP and Rexx support packages, the HTML editing environment Webworld and various other add-ons. Together, they form a set of tools for all steps of your development process, from writing source codes and installations over documentation to creation of a web site for your final product.&lt;br /&gt;
&lt;br /&gt;
The editor offers all functions you can expect from a modern program.&lt;br /&gt;
&lt;br /&gt;
* Unlimited undo and redo, configurable syntax highlighting, templates, folding, automatic backups, macro recording and extensive rexx support.&lt;br /&gt;
* Single document interface and multiple document interface (all texts in one window)&lt;br /&gt;
* Advanced layout and block functions.&lt;br /&gt;
* Very high speed&lt;br /&gt;
* Optional input aids including context-sensitive completion and automatic case correction.&lt;br /&gt;
* Plug-In interface&lt;br /&gt;
* Support for encryption&lt;br /&gt;
* Spellchecking&lt;br /&gt;
&lt;br /&gt;
All aspects of the Cubic IDE interface are configurable: fonts, colors, toolbars, menus, mouse, etc. Tabbed dialogs simplify the configuration. The software can handle an unlimited number of open screens and windows. Background processes like printing are multithreaded and do not block the user interface.  The editor recognizes file types and automatically adjusts the editing environment. For example, the menu will show compiler-specific functions after loading a C source code.&lt;br /&gt;
&lt;br /&gt;
Cubic IDE seamlessly integrates with SAS/C, vbcc, gcc and the StormC3 development environment.&lt;br /&gt;
&lt;br /&gt;
* Free C/C++ compiler and software development kit included for your convenience for AmigaOS.&lt;br /&gt;
* Revised online version of &amp;quot;The C Book&amp;quot; included for C beginners.&lt;br /&gt;
* Configurable references system for includes, source codes and other material helps you with finding information quickly. &lt;br /&gt;
* The QuickInfo function constantly shows information related to the word under the cursor (e.g. parameters of OS functions).&lt;br /&gt;
* Source level debugger support for StormC3 users (breakpoints are displayed next to the text).&lt;br /&gt;
* The editor automatically highlights matching brackets.&lt;br /&gt;
* Symbol browser lists all functions, structures, labels etc. defined in your source codes.&lt;br /&gt;
* Built-in grep support allows you to search patterns in a list of files.&lt;br /&gt;
&lt;br /&gt;
[https://www.softwareandcircuits.com/division/amiga/products/cubic/index.html Cubic IDE webpage]&lt;br /&gt;
&lt;br /&gt;
== Debug 101 ==&lt;br /&gt;
&lt;br /&gt;
Debug 101 is a source debugger for AmigaOS.  It contains many of the features found in other debuggers like GDB as well as a ReAction GUI.&lt;br /&gt;
&lt;br /&gt;
[http://www.os4depot.net/index.php?function=showfile&amp;amp;file=development/debug/db101.lha Debug 101 OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Emperor ==&lt;br /&gt;
&lt;br /&gt;
Emperor is a very powerful software to write GUI-based programs. There are C/C++- source codes that are generated by Emperor. They can be easily translated by an external C/C++-Compiler. Developer wanted to make parameterizing of the Graphical User Interface (GUI) and its macro-elements as easy as possible. Following standard-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Screens&lt;br /&gt;
* Windows&lt;br /&gt;
* Reaction gadgets&lt;br /&gt;
* Menus&lt;br /&gt;
* Popup-menus&lt;br /&gt;
* Requests&lt;br /&gt;
* ASL-requests&lt;br /&gt;
* Locale-catalogs &lt;br /&gt;
&lt;br /&gt;
Following NON-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Functionmacros&lt;br /&gt;
* Install-scripts&lt;br /&gt;
* ToolTypes&lt;br /&gt;
* Includes&lt;br /&gt;
* Libraries&lt;br /&gt;
* Declare variables&lt;br /&gt;
* InterConnection maps between gadgets&lt;br /&gt;
* Create list-arrays for gadgets &lt;br /&gt;
&lt;br /&gt;
With Emperor you are generating a complete C/C++-source code, which only must be compiled by an external compiler. Aim of this program is to assure software developer to create their programs (its source code) by Emperor, because the making of software (opening of windows, file- and fontrequests, menus etc.) is often equal and must not longer copied by programmers from other source codes. Emperor decrees about one or more macros for every GUI-element. Like the menus: here you must, for creating the complete Project-menu (open, close, save, print etc.) and its translation, (in Locale-&amp;quot;.catalog&amp;quot;-file) only select the corresponding entry in the list. This is also possible with requests e.g. by making a QuitRequest. These are called in the own source code as function &amp;quot;REQUESTNAME();&amp;quot;. But the program should also be for Amigans, who never programmed before, and want an easy way in the programming of AmigaOS-GUIs. &lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/guitool/emperor.lha Emperor OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Free Pascal ==&lt;br /&gt;
&lt;br /&gt;
Free Pascal is a professional Pascal compiler available for AmigaOS that can target many processor architectures.&lt;br /&gt;
&lt;br /&gt;
[https://blog.alb42.de/fpc-amigaos-4/ Free Pascal for AmigaOS webpage]&lt;br /&gt;
&lt;br /&gt;
== Gui4Cli ==&lt;br /&gt;
&lt;br /&gt;
Gui4Cli is a simple interpreted, event-driven language (no need for previous programming knowledge), which allows you to easily construct great-looking, resizable, font-sensitive GadTools GUIs which (among many other things) can be used to form command lines that can be sent to AmigaDOS or an ARexx port of an other program, for execution. It has many other capabilities too, things like directory &amp;amp; database listviews, maths evaluation, graphics, timers, commodities, file notifications, pipes, appicons etc. etc. With it you can control just about any aspect of the Amiga. Think of it as &amp;quot;Visual DOS&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[http://gui4cli.com/ami/gcmain.htm Gui4Cli webpage]&lt;br /&gt;
&lt;br /&gt;
== Hollywood ==&lt;br /&gt;
&lt;br /&gt;
Hollywood is a multimedia-oriented programming language that can be used to create graphical applications very easily. It was designed with the paradigm to make software creation as easy as possible in mind. Thus, Hollywood is suited for beginners and advanced users alike. Hollywood comes with an extensive function library (encompassing over 800 different commands) that simplifies the creation of games, presentations, and applications, to a great extent. Having been in development since 2002 it is a very mature and stable software package today.&lt;br /&gt;
&lt;br /&gt;
One of the highlights of Hollywood is its inbuilt cross-compiler which can be used to deploy software on many different platforms without having to change a single line of the code. The cross-compiler can compile for all platforms from any platform Hollywood is running on. For instance, you can compile macOS application bundles using the Windows version of Hollywood. There is even an optional add-on that can convert Hollywood applets into stand-alone APKs for release on Android! Android development has never been so easy!&lt;br /&gt;
&lt;br /&gt;
Hollywood is a light-weight, but still powerful programming language whose core is just about two megabytes in size and does not require any external components. Hence, it is ideal for creating programs which run right out of the box. In fact, Hollywood programs will run perfectly from an USB flash drive without any prior installation whatsoever.&lt;br /&gt;
&lt;br /&gt;
Platform architectures currently supported include AmigaOS, Android, iOS, MacOS, Windows, Linux and more.&lt;br /&gt;
&lt;br /&gt;
[https://www.hollywood-mal.com/ Hollywood webpage]&lt;br /&gt;
&lt;br /&gt;
== Lua / LOVE / tolua++ ==&lt;br /&gt;
&lt;br /&gt;
Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.&lt;br /&gt;
&lt;br /&gt;
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal&lt;br /&gt;
for configuration, scripting, and rapid prototyping.&lt;br /&gt;
&lt;br /&gt;
LOVE is an awesome framework you can use to make 2D games in Lua. It&#039;s free, open-source, and works on Windows, Mac OS X, Linux and AmigaOS.&lt;br /&gt;
&lt;br /&gt;
tolua++ is an extension of toLua, a tool to integrate C/C++ code with Lua. tolua++ includes new features oriented to c++, such as class templates.&lt;br /&gt;
&lt;br /&gt;
tolua is a tool that greatly simplifies the integration of C/C++ code with Lua. Based on a &amp;quot;cleaned&amp;quot; header file, tolua automatically generates the binding code to access C/C++ features from Lua. Using Lua-5.0 API and metamethod facilities, the current version automatically maps C/C++ constants, external variables, functions, namespace, classes, and methods to Lua. It also provides facilities to create Lua modules.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/liblua.lha Lua OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/game/love.lha LOVE OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/tolua.lha toula++ OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== MUIRexx ==&lt;br /&gt;
&lt;br /&gt;
MUIRexx is a program which serves as an interface between ARexx and MagicUserInterface (MUI).  MUIRexx does not provide complete access to all of the capabilities of MagicUserInterface (MUI), however, quite a lot of capability is implemented in MUIRexx such as notification, icon buttons, and application objects (objects that react to icons dropped on them), as well as many standard MUI objects.  Complete graphical user interfaces as well as full applications can be developed using MUIRexx and ARexx macros.  Additionally, it is also possible to dynamically change or add objects after the application has been created.&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/mui/MUIRexx_3_0a.lha MUIRexx Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== NoWinED ==&lt;br /&gt;
&lt;br /&gt;
NoWinED is a MUI-based TextEditor that can handle more files simultaneously, using different &amp;quot;pages&amp;quot; for each file. The fact that it is impossible to find a MUI TextEditor on Amiga powerful enough to be used instead of Notepad/Editpad and other editors does not have a reason.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Handling of multiple files through tabs that can be managed via titleButtons, a list, and/or an useful context menu which you can open if you click with right mouse button on right scroll titlebutton (this one appears when it&#039;s necessary)&lt;br /&gt;
* Context menus&lt;br /&gt;
* Search and replace module&lt;br /&gt;
* Search into opened files module&lt;br /&gt;
* File Drag &amp;amp; Drop: dragging one or more files on the NoWinED list the files will be opened in new tabs, dragging a file on a page will open it on the current page. Finally dragging more files on a tab will open the first file in the current tab, and the others in new pages (AROS lacks Drag &amp;amp; Drop)&lt;br /&gt;
* Basic texteditor features (C&amp;amp;P, select all, Undo, Redo, etc...). &lt;br /&gt;
* Usage from keyboard supported&lt;br /&gt;
* UTF support (you can load UTF files and export UTF with/without BOM or ASCII)&lt;br /&gt;
* CR/LF/CR+LF support (you can load any kind of txt file and export text with LF/CR/CR+LF)&lt;br /&gt;
* Wrapping process of your text at the column you want&lt;br /&gt;
* Backup of all opened files (you can set time between a backup process and another one)&lt;br /&gt;
* AutoSave of current file (you can set time between a autosave process and another one)&lt;br /&gt;
* Programmable Fn keys with independent profiles&lt;br /&gt;
* Graphic printout&lt;br /&gt;
&lt;br /&gt;
[http://shinkuro.altervista.org/amiga/software/nowined.htm NoWinED webpage]&lt;br /&gt;
&lt;br /&gt;
== PortablE ==&lt;br /&gt;
&lt;br /&gt;
PortablE is a recreation of the AmigaE programming language, along with many improvements, and the aim of being portable across many platforms.&lt;br /&gt;
&lt;br /&gt;
PortablE works by translating your E code into C++, and then using GCC to compile it into an executable that you can run.  But you don&#039;t need to worry about these details, because the PEGCC program will handle them for you. PortablE needs an installation of GCC, which is free &amp;amp; easily installed.&lt;br /&gt;
&lt;br /&gt;
[http://cshandley.co.uk/portable/ PortableE webpage]&lt;br /&gt;
&lt;br /&gt;
== ProAction ==&lt;br /&gt;
&lt;br /&gt;
A powerful interface between any Arexx enabled scripting language and the AmigaOS ReAction GUI system.  ProAction provides GUIs for script writers, using a unique &amp;quot;dual ARexx Port&amp;quot; approach.  ProAction itself is an ARexx host which provides functions for building and managing the GUI, then GUI events are sent as commands to an ARexx port managed by the script.&lt;br /&gt;
&lt;br /&gt;
It can be used from any language that can support an ARexx host. (ARexx (with rexxsupport.libray) python via arexx.so etc etc)&lt;br /&gt;
&lt;br /&gt;
[http://www.broad.ology.org.uk/amiga/proaction/index.html ProAction webpage]&lt;br /&gt;
&lt;br /&gt;
== SDK Browser ==&lt;br /&gt;
&lt;br /&gt;
The SDK Browser provides any Amiga Programmer a quick reference tool into the live AmigaOS Software Development Kit installation on your Amiga, via a 100% graphical (GUI) based tool. It can help you find the format (prototype) for any AmigaOS4.x system call as well as lookup a specific structure reference, method, tag item, what-have-you, quicker than any other tool. Or, you can simply use it as a great way to wander through the AmigaOS4.x development documentation (AutoDocs, Includes, etc.) to learn more about how to program for this great machine and its powerful operating system. There is a great deal of (largely untapped) power available with the &amp;quot;standard&amp;quot; OS if you only know where to look. &lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Fully multitasking search bar with start/stop and pause/resume. File pattern filter added to search bar, and maintained separately for each search type. Interact with results as they are found, or continue to use all other parts of the SDK Browser as the search continues in the background. Search will continue even when hidden or iconified, and is controllable from the commodity exchange as well. &lt;br /&gt;
* History Bar. Quickly return to any of the last 20 items that have been viewed previously. Browse forward or back with the arrow buttons, or pull down and select a new position within the browser history. The history bar works like a combination of a web browser forward and back buttons and a rotating 20 item tabbed display. Giving you the flexibility to quickly work with the last 20 items that have been referenced already. &lt;br /&gt;
* Support for more than one interface(API) found within the same library. If the XML file for a given library contains more than one interface for accessing that library, then the SDK Browser will create a new browsable Library tree for each interface and name them with their respective interface name. This is also why the Interface name was added to each library entry under the Library list. &lt;br /&gt;
* Faster than ever before using newly optimized viewing routines and less disk access.&lt;br /&gt;
* Function calls under &amp;quot;Commands&amp;quot; or an open view of any &amp;quot;Library&amp;quot; now displays just the description of the function call within the AutoDoc instead of displaying the entire AutoDoc and attempting to search for the start of the description. This makes for a cleaner an easier to read display, while the entire AutoDoc file is still instantly available by selecting the Library name itself, or browsing the &amp;quot;AutoDocs&amp;quot; directly. &lt;br /&gt;
* Quick find ANY item in the active list just by typing the first few letters of its name.&lt;br /&gt;
* New &amp;quot;Includes&amp;quot; browsing. Live browse the system includes using the new embedded directory scanner.&lt;br /&gt;
* Convenient &amp;quot;Send To&amp;quot; menu for launching a helpful set of external viewers right from the SDK Browser. Quickly open source files into the editor of your choice, or open HTML files directly into your web browser of choice. You can also launch the currently selected file with &amp;quot;MultiView&amp;quot;, &amp;quot;AmiPDF&amp;quot;, or even &amp;quot;Unarc&amp;quot; those archives. &lt;br /&gt;
* Improved interface handles all Library, Commands, AutoDocs, and Includes browsing under the &amp;quot;SDK&amp;quot; clicktab, while also giving the user a &amp;quot;Project&amp;quot; tab and directory scan lister for browsing their own project source or any where you need to, quickly and easily from one tool. &lt;br /&gt;
* Extensive keyboard controls to enhance the existing &amp;quot;mouse-over&amp;quot; focused movement keys and &amp;quot;mouse-wheel&amp;quot; support. &lt;br /&gt;
* Programmable SDK and search paths. &lt;br /&gt;
* Programmable EDITOR and WEBBROWSER tooltypes for use by the &amp;quot;Send To&amp;quot; menu.&lt;br /&gt;
&lt;br /&gt;
[http://bitbybitsoftwaregroup.com/sdkbrowser/index.php SDK Browser webpage]&lt;br /&gt;
&lt;br /&gt;
== vbcc ==&lt;br /&gt;
&lt;br /&gt;
vbcc is a highly optimizing portable and retargetable ISO C compiler available for AmigaOS. It supports ISO C according to ISO/IEC 9899:1989 and a subset of the new standard ISO/IEC 9899:1999 (C99).&lt;br /&gt;
&lt;br /&gt;
[http://sun.hasenbraten.de/vbcc/ vbcc webpage]&lt;br /&gt;
&lt;br /&gt;
== Vim ==&lt;br /&gt;
&lt;br /&gt;
Vim is a highly configurable text editor built to make creating and changing any kind of text very efficient. Vim is rock stable and is continuously being developed to become even better. Among its features are:&lt;br /&gt;
&lt;br /&gt;
* persistent, multi-level undo tree&lt;br /&gt;
* extensive plugin system&lt;br /&gt;
* support for hundreds of programming languages and file formats&lt;br /&gt;
* powerful search and replace&lt;br /&gt;
* integrates with many tools&lt;br /&gt;
&lt;br /&gt;
Please note that this is not a straight port of the upstream version. It includes a full MUI GUI with most of the bells and whistles found in Vim on any of the major platforms.  &amp;quot;TheBar&amp;quot; custom class must be installed for MUI for this version of Vim.&lt;br /&gt;
&lt;br /&gt;
[https://sourceforge.net/projects/spaden/ AmigaOS Vim webpage]&lt;br /&gt;
&lt;br /&gt;
[https://github.com/amiga-mui/thebar TheBar custom class webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10365</id>
		<title>AmigaOS Apps Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10365"/>
		<updated>2019-05-12T16:09:41Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaOS Software Development Kit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you are interested in developing applications for AmigaOS please note that the [[DeveloperDoc:Main|Developer Section]] contains documentation that is useful for developing applications, device drivers, games and other programming projects on AmigaOS. The [[Tutorials:Main|Tutorial Section]] contains a couple of hands-on tutorials that are intended to allow beginning developers to get into programming with step-by-step examples. Finally, the [[Autodocs:Main|Autodocs section]] contains the well-known &#039;&#039;autodocs&#039;&#039;, function-by-function documentation of libraries and devices in the AmigaOS system.&lt;br /&gt;
&lt;br /&gt;
Additional assistance is available at [http://forum.hyperion-entertainment.com/ Hyperion Entertainment Forums] and [http://www.os4coding.net/ OS4 Coding].&lt;br /&gt;
&lt;br /&gt;
The following is a sampling of software development applications that may assist with development for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications, with the exception of the official AmigaOS Software Development Kit, is neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Amiga Image Storage System AISS ==&lt;br /&gt;
&lt;br /&gt;
The Amiga Image Storage System AISS is an environment to store, access and maintain toolbar images.  This can also be used in conjunction with AISS Viewer to easily locate and reference resources into development projects.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aiss.lha Amiga Image Storage System AISS OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aissview.lha AISS Viewer OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== AmigaOS Software Development Kit ==&lt;br /&gt;
&lt;br /&gt;
The official AmigaOS Software Development Kit contains everything needed to get started writing native applications for AmigaOS, including the AmigaOS native GCC compiler, support applications, autodocs, includes and headers.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS Software Development Kit download from Hyperion Entertainment]&lt;br /&gt;
&lt;br /&gt;
== AutoDoc Reader ==&lt;br /&gt;
&lt;br /&gt;
This is a great freeware program to view any text file (autodocs, C-header and others) with database and search options. This is very useful to read the autodocs from the Software Development Kit. Developers documentation in autodoc format is often needed in everyday work. Getting familiar with a lot of files and searching tons of text for desired information is not an easy task. That&#039;s where the idea of writing a program that could ease using autodocs originated.&lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Possibility of creating a database of ours autodocs files,&lt;br /&gt;
* Fast and easy documents browsing,&lt;br /&gt;
* Possibility of independent loading of autodocs not included in a base,&lt;br /&gt;
* Search engine for functions, methods and parameters,&lt;br /&gt;
* Easy usage with mouse or keyboard. &lt;br /&gt;
&lt;br /&gt;
The program can act as separate viewer or autodoc-viewing module for other software (e.g. DOpus or GED).&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/misc/AutoDocReader_1v65 AutoDoc Reader Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== Awk ==&lt;br /&gt;
&lt;br /&gt;
Awk, the powerful language to manipulate and process text files, is available for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/awk.lha Awk OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CMake ==&lt;br /&gt;
&lt;br /&gt;
CMake is a cross platform build tool used to easily build complex projects across different platforms with a single build process. It has been ported to&lt;br /&gt;
AmigaOS with the intention of making porting of various complex softwares easier for AmigaOS developers.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/cross/cmake.lha CMake OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CodeBench == &lt;br /&gt;
&lt;br /&gt;
CodeBench is an Integrated Development Environment (IDE).&lt;br /&gt;
&lt;br /&gt;
Designed purely for use on the latest version of AmigaOS, CodeBench is a management system that is modular to allow adaptation to various programming languages.&lt;br /&gt;
&lt;br /&gt;
The tabbed editor allowing multiple files to be open at any one time. Syntax highlighting and all the usual functions are included: Cut, Copy, Paste, Undo, Find, Replace, Indent etc. Blocks of pre-built code can also be inserted as well as handling highlighted blocks. Also supports color &amp;quot; themes&amp;quot; for familiarity.&lt;br /&gt;
&lt;br /&gt;
Utilising a &#039;project&#039; based system, all files are grouped together by type and are easily accessible from the Project Window. Editing is a simple matter of selecting the required file and it is opened in the built-in editor. Creating the finished article from the project is a one click event from the toolbar.&lt;br /&gt;
&lt;br /&gt;
[http://www.codebench.co.uk/ CodeBench webpage]&lt;br /&gt;
&lt;br /&gt;
== Cubic IDE ==&lt;br /&gt;
&lt;br /&gt;
The central component of Cubic IDE is GoldED, a fully-featured developers editor for selected versions of AmigaOS. Cubic IDE includes the Installation Wizard, an AmigaGuide authoring mode, LISP and Rexx support packages, the HTML editing environment Webworld and various other add-ons. Together, they form a set of tools for all steps of your development process, from writing source codes and installations over documentation to creation of a web site for your final product.&lt;br /&gt;
&lt;br /&gt;
The editor offers all functions you can expect from a modern program.&lt;br /&gt;
&lt;br /&gt;
* Unlimited undo and redo, configurable syntax highlighting, templates, folding, automatic backups, macro recording and extensive rexx support.&lt;br /&gt;
* Single document interface and multiple document interface (all texts in one window)&lt;br /&gt;
* Advanced layout and block functions.&lt;br /&gt;
* Very high speed&lt;br /&gt;
* Optional input aids including context-sensitive completion and automatic case correction.&lt;br /&gt;
* Plug-In interface&lt;br /&gt;
* Support for encryption&lt;br /&gt;
* Spellchecking&lt;br /&gt;
&lt;br /&gt;
All aspects of the Cubic IDE interface are configurable: fonts, colors, toolbars, menus, mouse, etc. Tabbed dialogs simplify the configuration. The software can handle an unlimited number of open screens and windows. Background processes like printing are multithreaded and do not block the user interface.  The editor recognizes file types and automatically adjusts the editing environment. For example, the menu will show compiler-specific functions after loading a C source code.&lt;br /&gt;
&lt;br /&gt;
Cubic IDE seamlessly integrates with SAS/C, vbcc, gcc and the StormC3 development environment.&lt;br /&gt;
&lt;br /&gt;
* Free C/C++ compiler and software development kit included for your convenience for AmigaOS.&lt;br /&gt;
* Revised online version of &amp;quot;The C Book&amp;quot; included for C beginners.&lt;br /&gt;
* Configurable references system for includes, source codes and other material helps you with finding information quickly. &lt;br /&gt;
* The QuickInfo function constantly shows information related to the word under the cursor (e.g. parameters of OS functions).&lt;br /&gt;
* Source level debugger support for StormC3 users (breakpoints are displayed next to the text).&lt;br /&gt;
* The editor automatically highlights matching brackets.&lt;br /&gt;
* Symbol browser lists all functions, structures, labels etc. defined in your source codes.&lt;br /&gt;
* Built-in grep support allows you to search patterns in a list of files.&lt;br /&gt;
&lt;br /&gt;
[https://www.softwareandcircuits.com/division/amiga/products/cubic/index.html Cubic IDE webpage]&lt;br /&gt;
&lt;br /&gt;
== Debug 101 ==&lt;br /&gt;
&lt;br /&gt;
Debug 101 is a source debugger for AmigaOS.  It contains many of the features found in other debuggers like GDB as well as a ReAction GUI.&lt;br /&gt;
&lt;br /&gt;
[http://www.os4depot.net/index.php?function=showfile&amp;amp;file=development/debug/db101.lha Debug 101 OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Emperor ==&lt;br /&gt;
&lt;br /&gt;
Emperor is a very powerful software to write GUI-based programs. There are C/C++- source codes that are generated by Emperor. They can be easily translated by an external C/C++-Compiler. Developer wanted to make parameterizing of the Graphical User Interface (GUI) and its macro-elements as easy as possible. Following standard-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Screens&lt;br /&gt;
* Windows&lt;br /&gt;
* Reaction gadgets&lt;br /&gt;
* Menus&lt;br /&gt;
* Popup-menus&lt;br /&gt;
* Requests&lt;br /&gt;
* ASL-requests&lt;br /&gt;
* Locale-catalogs &lt;br /&gt;
&lt;br /&gt;
Following NON-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Functionmacros&lt;br /&gt;
* Install-scripts&lt;br /&gt;
* ToolTypes&lt;br /&gt;
* Includes&lt;br /&gt;
* Libraries&lt;br /&gt;
* Declare variables&lt;br /&gt;
* InterConnection maps between gadgets&lt;br /&gt;
* Create list-arrays for gadgets &lt;br /&gt;
&lt;br /&gt;
With Emperor you are generating a complete C/C++-source code, which only must be compiled by an external compiler. Aim of this program is to assure software developer to create their programs (its source code) by Emperor, because the making of software (opening of windows, file- and fontrequests, menus etc.) is often equal and must not longer copied by programmers from other source codes. Emperor decrees about one or more macros for every GUI-element. Like the menus: here you must, for creating the complete Project-menu (open, close, save, print etc.) and its translation, (in Locale-&amp;quot;.catalog&amp;quot;-file) only select the corresponding entry in the list. This is also possible with requests e.g. by making a QuitRequest. These are called in the own source code as function &amp;quot;REQUESTNAME();&amp;quot;. But the program should also be for Amigans, who never programmed before, and want an easy way in the programming of AmigaOS-GUIs. &lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/guitool/emperor.lha Emperor OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Free Pascal ==&lt;br /&gt;
&lt;br /&gt;
Free Pascal is a professional Pascal compiler available for AmigaOS that can target many processor architectures.&lt;br /&gt;
&lt;br /&gt;
[https://blog.alb42.de/fpc-amigaos-4/ Free Pascal for AmigaOS webpage]&lt;br /&gt;
&lt;br /&gt;
== adtools GNU Compiler Collection (GCC) ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;adtools&amp;quot; project is the Amiga development tools project that hosts a number of tools that can be used for cross-compiling between various platforms and developing applications for AmigaOS and other Amiga-like platforms.   The suite is based on the GCC compiler suite.  &lt;br /&gt;
&lt;br /&gt;
[https://github.com/sba1/adtools adtools webpage]&lt;br /&gt;
&lt;br /&gt;
== Gui4Cli ==&lt;br /&gt;
&lt;br /&gt;
Gui4Cli is a simple interpreted, event-driven language (no need for previous programming knowledge), which allows you to easily construct great-looking, resizable, font-sensitive GadTools GUIs which (among many other things) can be used to form command lines that can be sent to AmigaDOS or an ARexx port of an other program, for execution. It has many other capabilities too, things like directory &amp;amp; database listviews, maths evaluation, graphics, timers, commodities, file notifications, pipes, appicons etc. etc. With it you can control just about any aspect of the Amiga. Think of it as &amp;quot;Visual DOS&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[http://gui4cli.com/ami/gcmain.htm Gui4Cli webpage]&lt;br /&gt;
&lt;br /&gt;
== Hollywood ==&lt;br /&gt;
&lt;br /&gt;
Hollywood is a multimedia-oriented programming language that can be used to create graphical applications very easily. It was designed with the paradigm to make software creation as easy as possible in mind. Thus, Hollywood is suited for beginners and advanced users alike. Hollywood comes with an extensive function library (encompassing over 800 different commands) that simplifies the creation of games, presentations, and applications, to a great extent. Having been in development since 2002 it is a very mature and stable software package today.&lt;br /&gt;
&lt;br /&gt;
One of the highlights of Hollywood is its inbuilt cross-compiler which can be used to deploy software on many different platforms without having to change a single line of the code. The cross-compiler can compile for all platforms from any platform Hollywood is running on. For instance, you can compile macOS application bundles using the Windows version of Hollywood. There is even an optional add-on that can convert Hollywood applets into stand-alone APKs for release on Android! Android development has never been so easy!&lt;br /&gt;
&lt;br /&gt;
Hollywood is a light-weight, but still powerful programming language whose core is just about two megabytes in size and does not require any external components. Hence, it is ideal for creating programs which run right out of the box. In fact, Hollywood programs will run perfectly from an USB flash drive without any prior installation whatsoever.&lt;br /&gt;
&lt;br /&gt;
Platform architectures currently supported include AmigaOS, Android, iOS, MacOS, Windows, Linux and more.&lt;br /&gt;
&lt;br /&gt;
[https://www.hollywood-mal.com/ Hollywood webpage]&lt;br /&gt;
&lt;br /&gt;
== Lua / LOVE / tolua++ ==&lt;br /&gt;
&lt;br /&gt;
Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.&lt;br /&gt;
&lt;br /&gt;
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal&lt;br /&gt;
for configuration, scripting, and rapid prototyping.&lt;br /&gt;
&lt;br /&gt;
LOVE is an awesome framework you can use to make 2D games in Lua. It&#039;s free, open-source, and works on Windows, Mac OS X, Linux and AmigaOS.&lt;br /&gt;
&lt;br /&gt;
tolua++ is an extension of toLua, a tool to integrate C/C++ code with Lua. tolua++ includes new features oriented to c++, such as class templates.&lt;br /&gt;
&lt;br /&gt;
tolua is a tool that greatly simplifies the integration of C/C++ code with Lua. Based on a &amp;quot;cleaned&amp;quot; header file, tolua automatically generates the binding code to access C/C++ features from Lua. Using Lua-5.0 API and metamethod facilities, the current version automatically maps C/C++ constants, external variables, functions, namespace, classes, and methods to Lua. It also provides facilities to create Lua modules.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/liblua.lha Lua OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/game/love.lha LOVE OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/tolua.lha toula++ OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== MUIRexx ==&lt;br /&gt;
&lt;br /&gt;
MUIRexx is a program which serves as an interface between ARexx and MagicUserInterface (MUI).  MUIRexx does not provide complete access to all of the capabilities of MagicUserInterface (MUI), however, quite a lot of capability is implemented in MUIRexx such as notification, icon buttons, and application objects (objects that react to icons dropped on them), as well as many standard MUI objects.  Complete graphical user interfaces as well as full applications can be developed using MUIRexx and ARexx macros.  Additionally, it is also possible to dynamically change or add objects after the application has been created.&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/mui/MUIRexx_3_0a.lha MUIRexx Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== NoWinED ==&lt;br /&gt;
&lt;br /&gt;
NoWinED is a MUI-based TextEditor that can handle more files simultaneously, using different &amp;quot;pages&amp;quot; for each file. The fact that it is impossible to find a MUI TextEditor on Amiga powerful enough to be used instead of Notepad/Editpad and other editors does not have a reason.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Handling of multiple files through tabs that can be managed via titleButtons, a list, and/or an useful context menu which you can open if you click with right mouse button on right scroll titlebutton (this one appears when it&#039;s necessary)&lt;br /&gt;
* Context menus&lt;br /&gt;
* Search and replace module&lt;br /&gt;
* Search into opened files module&lt;br /&gt;
* File Drag &amp;amp; Drop: dragging one or more files on the NoWinED list the files will be opened in new tabs, dragging a file on a page will open it on the current page. Finally dragging more files on a tab will open the first file in the current tab, and the others in new pages (AROS lacks Drag &amp;amp; Drop)&lt;br /&gt;
* Basic texteditor features (C&amp;amp;P, select all, Undo, Redo, etc...). &lt;br /&gt;
* Usage from keyboard supported&lt;br /&gt;
* UTF support (you can load UTF files and export UTF with/without BOM or ASCII)&lt;br /&gt;
* CR/LF/CR+LF support (you can load any kind of txt file and export text with LF/CR/CR+LF)&lt;br /&gt;
* Wrapping process of your text at the column you want&lt;br /&gt;
* Backup of all opened files (you can set time between a backup process and another one)&lt;br /&gt;
* AutoSave of current file (you can set time between a autosave process and another one)&lt;br /&gt;
* Programmable Fn keys with independent profiles&lt;br /&gt;
* Graphic printout&lt;br /&gt;
&lt;br /&gt;
[http://shinkuro.altervista.org/amiga/software/nowined.htm NoWinED webpage]&lt;br /&gt;
&lt;br /&gt;
== PortablE ==&lt;br /&gt;
&lt;br /&gt;
PortablE is a recreation of the AmigaE programming language, along with many improvements, and the aim of being portable across many platforms.&lt;br /&gt;
&lt;br /&gt;
PortablE works by translating your E code into C++, and then using GCC to compile it into an executable that you can run.  But you don&#039;t need to worry about these details, because the PEGCC program will handle them for you. PortablE needs an installation of GCC, which is free &amp;amp; easily installed.&lt;br /&gt;
&lt;br /&gt;
[http://cshandley.co.uk/portable/ PortableE webpage]&lt;br /&gt;
&lt;br /&gt;
== ProAction ==&lt;br /&gt;
&lt;br /&gt;
A powerful interface between any Arexx enabled scripting language and the AmigaOS ReAction GUI system.  ProAction provides GUIs for script writers, using a unique &amp;quot;dual ARexx Port&amp;quot; approach.  ProAction itself is an ARexx host which provides functions for building and managing the GUI, then GUI events are sent as commands to an ARexx port managed by the script.&lt;br /&gt;
&lt;br /&gt;
It can be used from any language that can support an ARexx host. (ARexx (with rexxsupport.libray) python via arexx.so etc etc)&lt;br /&gt;
&lt;br /&gt;
[http://www.broad.ology.org.uk/amiga/proaction/index.html ProAction webpage]&lt;br /&gt;
&lt;br /&gt;
== SDK Browser ==&lt;br /&gt;
&lt;br /&gt;
The SDK Browser provides any Amiga Programmer a quick reference tool into the live AmigaOS Software Development Kit installation on your Amiga, via a 100% graphical (GUI) based tool. It can help you find the format (prototype) for any AmigaOS4.x system call as well as lookup a specific structure reference, method, tag item, what-have-you, quicker than any other tool. Or, you can simply use it as a great way to wander through the AmigaOS4.x development documentation (AutoDocs, Includes, etc.) to learn more about how to program for this great machine and its powerful operating system. There is a great deal of (largely untapped) power available with the &amp;quot;standard&amp;quot; OS if you only know where to look. &lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Fully multitasking search bar with start/stop and pause/resume. File pattern filter added to search bar, and maintained separately for each search type. Interact with results as they are found, or continue to use all other parts of the SDK Browser as the search continues in the background. Search will continue even when hidden or iconified, and is controllable from the commodity exchange as well. &lt;br /&gt;
* History Bar. Quickly return to any of the last 20 items that have been viewed previously. Browse forward or back with the arrow buttons, or pull down and select a new position within the browser history. The history bar works like a combination of a web browser forward and back buttons and a rotating 20 item tabbed display. Giving you the flexibility to quickly work with the last 20 items that have been referenced already. &lt;br /&gt;
* Support for more than one interface(API) found within the same library. If the XML file for a given library contains more than one interface for accessing that library, then the SDK Browser will create a new browsable Library tree for each interface and name them with their respective interface name. This is also why the Interface name was added to each library entry under the Library list. &lt;br /&gt;
* Faster than ever before using newly optimized viewing routines and less disk access.&lt;br /&gt;
* Function calls under &amp;quot;Commands&amp;quot; or an open view of any &amp;quot;Library&amp;quot; now displays just the description of the function call within the AutoDoc instead of displaying the entire AutoDoc and attempting to search for the start of the description. This makes for a cleaner an easier to read display, while the entire AutoDoc file is still instantly available by selecting the Library name itself, or browsing the &amp;quot;AutoDocs&amp;quot; directly. &lt;br /&gt;
* Quick find ANY item in the active list just by typing the first few letters of its name.&lt;br /&gt;
* New &amp;quot;Includes&amp;quot; browsing. Live browse the system includes using the new embedded directory scanner.&lt;br /&gt;
* Convenient &amp;quot;Send To&amp;quot; menu for launching a helpful set of external viewers right from the SDK Browser. Quickly open source files into the editor of your choice, or open HTML files directly into your web browser of choice. You can also launch the currently selected file with &amp;quot;MultiView&amp;quot;, &amp;quot;AmiPDF&amp;quot;, or even &amp;quot;Unarc&amp;quot; those archives. &lt;br /&gt;
* Improved interface handles all Library, Commands, AutoDocs, and Includes browsing under the &amp;quot;SDK&amp;quot; clicktab, while also giving the user a &amp;quot;Project&amp;quot; tab and directory scan lister for browsing their own project source or any where you need to, quickly and easily from one tool. &lt;br /&gt;
* Extensive keyboard controls to enhance the existing &amp;quot;mouse-over&amp;quot; focused movement keys and &amp;quot;mouse-wheel&amp;quot; support. &lt;br /&gt;
* Programmable SDK and search paths. &lt;br /&gt;
* Programmable EDITOR and WEBBROWSER tooltypes for use by the &amp;quot;Send To&amp;quot; menu.&lt;br /&gt;
&lt;br /&gt;
[http://bitbybitsoftwaregroup.com/sdkbrowser/index.php SDK Browser webpage]&lt;br /&gt;
&lt;br /&gt;
== vbcc ==&lt;br /&gt;
&lt;br /&gt;
vbcc is a highly optimizing portable and retargetable ISO C compiler available for AmigaOS. It supports ISO C according to ISO/IEC 9899:1989 and a subset of the new standard ISO/IEC 9899:1999 (C99).&lt;br /&gt;
&lt;br /&gt;
[http://sun.hasenbraten.de/vbcc/ vbcc webpage]&lt;br /&gt;
&lt;br /&gt;
== Vim ==&lt;br /&gt;
&lt;br /&gt;
Vim is a highly configurable text editor built to make creating and changing any kind of text very efficient. Vim is rock stable and is continuously being developed to become even better. Among its features are:&lt;br /&gt;
&lt;br /&gt;
* persistent, multi-level undo tree&lt;br /&gt;
* extensive plugin system&lt;br /&gt;
* support for hundreds of programming languages and file formats&lt;br /&gt;
* powerful search and replace&lt;br /&gt;
* integrates with many tools&lt;br /&gt;
&lt;br /&gt;
Please note that this is not a straight port of the upstream version. It includes a full MUI GUI with most of the bells and whistles found in Vim on any of the major platforms.  &amp;quot;TheBar&amp;quot; custom class must be installed for MUI for this version of Vim.&lt;br /&gt;
&lt;br /&gt;
[https://sourceforge.net/projects/spaden/ AmigaOS Vim webpage]&lt;br /&gt;
&lt;br /&gt;
[https://github.com/amiga-mui/thebar TheBar custom class webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10364</id>
		<title>AmigaOS Apps Development</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Development&amp;diff=10364"/>
		<updated>2019-05-12T16:08:16Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* GNU Compiler Collection GCC */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you are interested in developing applications for AmigaOS please note that the [[DeveloperDoc:Main|Developer Section]] contains documentation that is useful for developing applications, device drivers, games and other programming projects on AmigaOS. The [[Tutorials:Main|Tutorial Section]] contains a couple of hands-on tutorials that are intended to allow beginning developers to get into programming with step-by-step examples. Finally, the [[Autodocs:Main|Autodocs section]] contains the well-known &#039;&#039;autodocs&#039;&#039;, function-by-function documentation of libraries and devices in the AmigaOS system.&lt;br /&gt;
&lt;br /&gt;
Additional assistance is available at [http://forum.hyperion-entertainment.com/ Hyperion Entertainment Forums] and [http://www.os4coding.net/ OS4 Coding].&lt;br /&gt;
&lt;br /&gt;
The following is a sampling of software development applications that may assist with development for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications, with the exception of the official AmigaOS Software Development Kit, is neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Amiga Image Storage System AISS ==&lt;br /&gt;
&lt;br /&gt;
The Amiga Image Storage System AISS is an environment to store, access and maintain toolbar images.  This can also be used in conjunction with AISS Viewer to easily locate and reference resources into development projects.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aiss.lha Amiga Image Storage System AISS OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=graphics/aiss/aissview.lha AISS Viewer OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== AmigaOS Software Development Kit ==&lt;br /&gt;
&lt;br /&gt;
The official AmigaOS Software Development Kit contains everything needed to get started writing native applications for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS Software Development Kit download from Hyperion Entertainment]&lt;br /&gt;
&lt;br /&gt;
== AutoDoc Reader ==&lt;br /&gt;
&lt;br /&gt;
This is a great freeware program to view any text file (autodocs, C-header and others) with database and search options. This is very useful to read the autodocs from the Software Development Kit. Developers documentation in autodoc format is often needed in everyday work. Getting familiar with a lot of files and searching tons of text for desired information is not an easy task. That&#039;s where the idea of writing a program that could ease using autodocs originated.&lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Possibility of creating a database of ours autodocs files,&lt;br /&gt;
* Fast and easy documents browsing,&lt;br /&gt;
* Possibility of independent loading of autodocs not included in a base,&lt;br /&gt;
* Search engine for functions, methods and parameters,&lt;br /&gt;
* Easy usage with mouse or keyboard. &lt;br /&gt;
&lt;br /&gt;
The program can act as separate viewer or autodoc-viewing module for other software (e.g. DOpus or GED).&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/misc/AutoDocReader_1v65 AutoDoc Reader Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== Awk ==&lt;br /&gt;
&lt;br /&gt;
Awk, the powerful language to manipulate and process text files, is available for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/awk.lha Awk OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CMake ==&lt;br /&gt;
&lt;br /&gt;
CMake is a cross platform build tool used to easily build complex projects across different platforms with a single build process. It has been ported to&lt;br /&gt;
AmigaOS with the intention of making porting of various complex softwares easier for AmigaOS developers.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/cross/cmake.lha CMake OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== CodeBench == &lt;br /&gt;
&lt;br /&gt;
CodeBench is an Integrated Development Environment (IDE).&lt;br /&gt;
&lt;br /&gt;
Designed purely for use on the latest version of AmigaOS, CodeBench is a management system that is modular to allow adaptation to various programming languages.&lt;br /&gt;
&lt;br /&gt;
The tabbed editor allowing multiple files to be open at any one time. Syntax highlighting and all the usual functions are included: Cut, Copy, Paste, Undo, Find, Replace, Indent etc. Blocks of pre-built code can also be inserted as well as handling highlighted blocks. Also supports color &amp;quot; themes&amp;quot; for familiarity.&lt;br /&gt;
&lt;br /&gt;
Utilising a &#039;project&#039; based system, all files are grouped together by type and are easily accessible from the Project Window. Editing is a simple matter of selecting the required file and it is opened in the built-in editor. Creating the finished article from the project is a one click event from the toolbar.&lt;br /&gt;
&lt;br /&gt;
[http://www.codebench.co.uk/ CodeBench webpage]&lt;br /&gt;
&lt;br /&gt;
== Cubic IDE ==&lt;br /&gt;
&lt;br /&gt;
The central component of Cubic IDE is GoldED, a fully-featured developers editor for selected versions of AmigaOS. Cubic IDE includes the Installation Wizard, an AmigaGuide authoring mode, LISP and Rexx support packages, the HTML editing environment Webworld and various other add-ons. Together, they form a set of tools for all steps of your development process, from writing source codes and installations over documentation to creation of a web site for your final product.&lt;br /&gt;
&lt;br /&gt;
The editor offers all functions you can expect from a modern program.&lt;br /&gt;
&lt;br /&gt;
* Unlimited undo and redo, configurable syntax highlighting, templates, folding, automatic backups, macro recording and extensive rexx support.&lt;br /&gt;
* Single document interface and multiple document interface (all texts in one window)&lt;br /&gt;
* Advanced layout and block functions.&lt;br /&gt;
* Very high speed&lt;br /&gt;
* Optional input aids including context-sensitive completion and automatic case correction.&lt;br /&gt;
* Plug-In interface&lt;br /&gt;
* Support for encryption&lt;br /&gt;
* Spellchecking&lt;br /&gt;
&lt;br /&gt;
All aspects of the Cubic IDE interface are configurable: fonts, colors, toolbars, menus, mouse, etc. Tabbed dialogs simplify the configuration. The software can handle an unlimited number of open screens and windows. Background processes like printing are multithreaded and do not block the user interface.  The editor recognizes file types and automatically adjusts the editing environment. For example, the menu will show compiler-specific functions after loading a C source code.&lt;br /&gt;
&lt;br /&gt;
Cubic IDE seamlessly integrates with SAS/C, vbcc, gcc and the StormC3 development environment.&lt;br /&gt;
&lt;br /&gt;
* Free C/C++ compiler and software development kit included for your convenience for AmigaOS.&lt;br /&gt;
* Revised online version of &amp;quot;The C Book&amp;quot; included for C beginners.&lt;br /&gt;
* Configurable references system for includes, source codes and other material helps you with finding information quickly. &lt;br /&gt;
* The QuickInfo function constantly shows information related to the word under the cursor (e.g. parameters of OS functions).&lt;br /&gt;
* Source level debugger support for StormC3 users (breakpoints are displayed next to the text).&lt;br /&gt;
* The editor automatically highlights matching brackets.&lt;br /&gt;
* Symbol browser lists all functions, structures, labels etc. defined in your source codes.&lt;br /&gt;
* Built-in grep support allows you to search patterns in a list of files.&lt;br /&gt;
&lt;br /&gt;
[https://www.softwareandcircuits.com/division/amiga/products/cubic/index.html Cubic IDE webpage]&lt;br /&gt;
&lt;br /&gt;
== Debug 101 ==&lt;br /&gt;
&lt;br /&gt;
Debug 101 is a source debugger for AmigaOS.  It contains many of the features found in other debuggers like GDB as well as a ReAction GUI.&lt;br /&gt;
&lt;br /&gt;
[http://www.os4depot.net/index.php?function=showfile&amp;amp;file=development/debug/db101.lha Debug 101 OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Emperor ==&lt;br /&gt;
&lt;br /&gt;
Emperor is a very powerful software to write GUI-based programs. There are C/C++- source codes that are generated by Emperor. They can be easily translated by an external C/C++-Compiler. Developer wanted to make parameterizing of the Graphical User Interface (GUI) and its macro-elements as easy as possible. Following standard-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Screens&lt;br /&gt;
* Windows&lt;br /&gt;
* Reaction gadgets&lt;br /&gt;
* Menus&lt;br /&gt;
* Popup-menus&lt;br /&gt;
* Requests&lt;br /&gt;
* ASL-requests&lt;br /&gt;
* Locale-catalogs &lt;br /&gt;
&lt;br /&gt;
Following NON-GUI-elements are implemented: &lt;br /&gt;
&lt;br /&gt;
* Functionmacros&lt;br /&gt;
* Install-scripts&lt;br /&gt;
* ToolTypes&lt;br /&gt;
* Includes&lt;br /&gt;
* Libraries&lt;br /&gt;
* Declare variables&lt;br /&gt;
* InterConnection maps between gadgets&lt;br /&gt;
* Create list-arrays for gadgets &lt;br /&gt;
&lt;br /&gt;
With Emperor you are generating a complete C/C++-source code, which only must be compiled by an external compiler. Aim of this program is to assure software developer to create their programs (its source code) by Emperor, because the making of software (opening of windows, file- and fontrequests, menus etc.) is often equal and must not longer copied by programmers from other source codes. Emperor decrees about one or more macros for every GUI-element. Like the menus: here you must, for creating the complete Project-menu (open, close, save, print etc.) and its translation, (in Locale-&amp;quot;.catalog&amp;quot;-file) only select the corresponding entry in the list. This is also possible with requests e.g. by making a QuitRequest. These are called in the own source code as function &amp;quot;REQUESTNAME();&amp;quot;. But the program should also be for Amigans, who never programmed before, and want an easy way in the programming of AmigaOS-GUIs. &lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/guitool/emperor.lha Emperor OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== Free Pascal ==&lt;br /&gt;
&lt;br /&gt;
Free Pascal is a professional Pascal compiler available for AmigaOS that can target many processor architectures.&lt;br /&gt;
&lt;br /&gt;
[https://blog.alb42.de/fpc-amigaos-4/ Free Pascal for AmigaOS webpage]&lt;br /&gt;
&lt;br /&gt;
== adtools GNU Compiler Collection (GCC) ==&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;adtools&amp;quot; project is the Amiga development tools project that hosts a number of tools that can be used for cross-compiling between various platforms and developing applications for AmigaOS and other Amiga-like platforms.   The suite is based on the GCC compiler suite.  &lt;br /&gt;
&lt;br /&gt;
[https://github.com/sba1/adtools adtools webpage]&lt;br /&gt;
&lt;br /&gt;
== Gui4Cli ==&lt;br /&gt;
&lt;br /&gt;
Gui4Cli is a simple interpreted, event-driven language (no need for previous programming knowledge), which allows you to easily construct great-looking, resizable, font-sensitive GadTools GUIs which (among many other things) can be used to form command lines that can be sent to AmigaDOS or an ARexx port of an other program, for execution. It has many other capabilities too, things like directory &amp;amp; database listviews, maths evaluation, graphics, timers, commodities, file notifications, pipes, appicons etc. etc. With it you can control just about any aspect of the Amiga. Think of it as &amp;quot;Visual DOS&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[http://gui4cli.com/ami/gcmain.htm Gui4Cli webpage]&lt;br /&gt;
&lt;br /&gt;
== Hollywood ==&lt;br /&gt;
&lt;br /&gt;
Hollywood is a multimedia-oriented programming language that can be used to create graphical applications very easily. It was designed with the paradigm to make software creation as easy as possible in mind. Thus, Hollywood is suited for beginners and advanced users alike. Hollywood comes with an extensive function library (encompassing over 800 different commands) that simplifies the creation of games, presentations, and applications, to a great extent. Having been in development since 2002 it is a very mature and stable software package today.&lt;br /&gt;
&lt;br /&gt;
One of the highlights of Hollywood is its inbuilt cross-compiler which can be used to deploy software on many different platforms without having to change a single line of the code. The cross-compiler can compile for all platforms from any platform Hollywood is running on. For instance, you can compile macOS application bundles using the Windows version of Hollywood. There is even an optional add-on that can convert Hollywood applets into stand-alone APKs for release on Android! Android development has never been so easy!&lt;br /&gt;
&lt;br /&gt;
Hollywood is a light-weight, but still powerful programming language whose core is just about two megabytes in size and does not require any external components. Hence, it is ideal for creating programs which run right out of the box. In fact, Hollywood programs will run perfectly from an USB flash drive without any prior installation whatsoever.&lt;br /&gt;
&lt;br /&gt;
Platform architectures currently supported include AmigaOS, Android, iOS, MacOS, Windows, Linux and more.&lt;br /&gt;
&lt;br /&gt;
[https://www.hollywood-mal.com/ Hollywood webpage]&lt;br /&gt;
&lt;br /&gt;
== Lua / LOVE / tolua++ ==&lt;br /&gt;
&lt;br /&gt;
Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description.&lt;br /&gt;
&lt;br /&gt;
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal&lt;br /&gt;
for configuration, scripting, and rapid prototyping.&lt;br /&gt;
&lt;br /&gt;
LOVE is an awesome framework you can use to make 2D games in Lua. It&#039;s free, open-source, and works on Windows, Mac OS X, Linux and AmigaOS.&lt;br /&gt;
&lt;br /&gt;
tolua++ is an extension of toLua, a tool to integrate C/C++ code with Lua. tolua++ includes new features oriented to c++, such as class templates.&lt;br /&gt;
&lt;br /&gt;
tolua is a tool that greatly simplifies the integration of C/C++ code with Lua. Based on a &amp;quot;cleaned&amp;quot; header file, tolua automatically generates the binding code to access C/C++ features from Lua. Using Lua-5.0 API and metamethod facilities, the current version automatically maps C/C++ constants, external variables, functions, namespace, classes, and methods to Lua. It also provides facilities to create Lua modules.&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/liblua.lha Lua OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/game/love.lha LOVE OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
[http://os4depot.net/index.php?function=showfile&amp;amp;file=development/language/tolua.lha toula++ OS4Depot webpage]&lt;br /&gt;
&lt;br /&gt;
== MUIRexx ==&lt;br /&gt;
&lt;br /&gt;
MUIRexx is a program which serves as an interface between ARexx and MagicUserInterface (MUI).  MUIRexx does not provide complete access to all of the capabilities of MagicUserInterface (MUI), however, quite a lot of capability is implemented in MUIRexx such as notification, icon buttons, and application objects (objects that react to icons dropped on them), as well as many standard MUI objects.  Complete graphical user interfaces as well as full applications can be developed using MUIRexx and ARexx macros.  Additionally, it is also possible to dynamically change or add objects after the application has been created.&lt;br /&gt;
&lt;br /&gt;
[http://aminet.net/package/dev/mui/MUIRexx_3_0a.lha MUIRexx Aminet webpage]&lt;br /&gt;
&lt;br /&gt;
== NoWinED ==&lt;br /&gt;
&lt;br /&gt;
NoWinED is a MUI-based TextEditor that can handle more files simultaneously, using different &amp;quot;pages&amp;quot; for each file. The fact that it is impossible to find a MUI TextEditor on Amiga powerful enough to be used instead of Notepad/Editpad and other editors does not have a reason.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Handling of multiple files through tabs that can be managed via titleButtons, a list, and/or an useful context menu which you can open if you click with right mouse button on right scroll titlebutton (this one appears when it&#039;s necessary)&lt;br /&gt;
* Context menus&lt;br /&gt;
* Search and replace module&lt;br /&gt;
* Search into opened files module&lt;br /&gt;
* File Drag &amp;amp; Drop: dragging one or more files on the NoWinED list the files will be opened in new tabs, dragging a file on a page will open it on the current page. Finally dragging more files on a tab will open the first file in the current tab, and the others in new pages (AROS lacks Drag &amp;amp; Drop)&lt;br /&gt;
* Basic texteditor features (C&amp;amp;P, select all, Undo, Redo, etc...). &lt;br /&gt;
* Usage from keyboard supported&lt;br /&gt;
* UTF support (you can load UTF files and export UTF with/without BOM or ASCII)&lt;br /&gt;
* CR/LF/CR+LF support (you can load any kind of txt file and export text with LF/CR/CR+LF)&lt;br /&gt;
* Wrapping process of your text at the column you want&lt;br /&gt;
* Backup of all opened files (you can set time between a backup process and another one)&lt;br /&gt;
* AutoSave of current file (you can set time between a autosave process and another one)&lt;br /&gt;
* Programmable Fn keys with independent profiles&lt;br /&gt;
* Graphic printout&lt;br /&gt;
&lt;br /&gt;
[http://shinkuro.altervista.org/amiga/software/nowined.htm NoWinED webpage]&lt;br /&gt;
&lt;br /&gt;
== PortablE ==&lt;br /&gt;
&lt;br /&gt;
PortablE is a recreation of the AmigaE programming language, along with many improvements, and the aim of being portable across many platforms.&lt;br /&gt;
&lt;br /&gt;
PortablE works by translating your E code into C++, and then using GCC to compile it into an executable that you can run.  But you don&#039;t need to worry about these details, because the PEGCC program will handle them for you. PortablE needs an installation of GCC, which is free &amp;amp; easily installed.&lt;br /&gt;
&lt;br /&gt;
[http://cshandley.co.uk/portable/ PortableE webpage]&lt;br /&gt;
&lt;br /&gt;
== ProAction ==&lt;br /&gt;
&lt;br /&gt;
A powerful interface between any Arexx enabled scripting language and the AmigaOS ReAction GUI system.  ProAction provides GUIs for script writers, using a unique &amp;quot;dual ARexx Port&amp;quot; approach.  ProAction itself is an ARexx host which provides functions for building and managing the GUI, then GUI events are sent as commands to an ARexx port managed by the script.&lt;br /&gt;
&lt;br /&gt;
It can be used from any language that can support an ARexx host. (ARexx (with rexxsupport.libray) python via arexx.so etc etc)&lt;br /&gt;
&lt;br /&gt;
[http://www.broad.ology.org.uk/amiga/proaction/index.html ProAction webpage]&lt;br /&gt;
&lt;br /&gt;
== SDK Browser ==&lt;br /&gt;
&lt;br /&gt;
The SDK Browser provides any Amiga Programmer a quick reference tool into the live AmigaOS Software Development Kit installation on your Amiga, via a 100% graphical (GUI) based tool. It can help you find the format (prototype) for any AmigaOS4.x system call as well as lookup a specific structure reference, method, tag item, what-have-you, quicker than any other tool. Or, you can simply use it as a great way to wander through the AmigaOS4.x development documentation (AutoDocs, Includes, etc.) to learn more about how to program for this great machine and its powerful operating system. There is a great deal of (largely untapped) power available with the &amp;quot;standard&amp;quot; OS if you only know where to look. &lt;br /&gt;
&lt;br /&gt;
Features include:&lt;br /&gt;
&lt;br /&gt;
* Fully multitasking search bar with start/stop and pause/resume. File pattern filter added to search bar, and maintained separately for each search type. Interact with results as they are found, or continue to use all other parts of the SDK Browser as the search continues in the background. Search will continue even when hidden or iconified, and is controllable from the commodity exchange as well. &lt;br /&gt;
* History Bar. Quickly return to any of the last 20 items that have been viewed previously. Browse forward or back with the arrow buttons, or pull down and select a new position within the browser history. The history bar works like a combination of a web browser forward and back buttons and a rotating 20 item tabbed display. Giving you the flexibility to quickly work with the last 20 items that have been referenced already. &lt;br /&gt;
* Support for more than one interface(API) found within the same library. If the XML file for a given library contains more than one interface for accessing that library, then the SDK Browser will create a new browsable Library tree for each interface and name them with their respective interface name. This is also why the Interface name was added to each library entry under the Library list. &lt;br /&gt;
* Faster than ever before using newly optimized viewing routines and less disk access.&lt;br /&gt;
* Function calls under &amp;quot;Commands&amp;quot; or an open view of any &amp;quot;Library&amp;quot; now displays just the description of the function call within the AutoDoc instead of displaying the entire AutoDoc and attempting to search for the start of the description. This makes for a cleaner an easier to read display, while the entire AutoDoc file is still instantly available by selecting the Library name itself, or browsing the &amp;quot;AutoDocs&amp;quot; directly. &lt;br /&gt;
* Quick find ANY item in the active list just by typing the first few letters of its name.&lt;br /&gt;
* New &amp;quot;Includes&amp;quot; browsing. Live browse the system includes using the new embedded directory scanner.&lt;br /&gt;
* Convenient &amp;quot;Send To&amp;quot; menu for launching a helpful set of external viewers right from the SDK Browser. Quickly open source files into the editor of your choice, or open HTML files directly into your web browser of choice. You can also launch the currently selected file with &amp;quot;MultiView&amp;quot;, &amp;quot;AmiPDF&amp;quot;, or even &amp;quot;Unarc&amp;quot; those archives. &lt;br /&gt;
* Improved interface handles all Library, Commands, AutoDocs, and Includes browsing under the &amp;quot;SDK&amp;quot; clicktab, while also giving the user a &amp;quot;Project&amp;quot; tab and directory scan lister for browsing their own project source or any where you need to, quickly and easily from one tool. &lt;br /&gt;
* Extensive keyboard controls to enhance the existing &amp;quot;mouse-over&amp;quot; focused movement keys and &amp;quot;mouse-wheel&amp;quot; support. &lt;br /&gt;
* Programmable SDK and search paths. &lt;br /&gt;
* Programmable EDITOR and WEBBROWSER tooltypes for use by the &amp;quot;Send To&amp;quot; menu.&lt;br /&gt;
&lt;br /&gt;
[http://bitbybitsoftwaregroup.com/sdkbrowser/index.php SDK Browser webpage]&lt;br /&gt;
&lt;br /&gt;
== vbcc ==&lt;br /&gt;
&lt;br /&gt;
vbcc is a highly optimizing portable and retargetable ISO C compiler available for AmigaOS. It supports ISO C according to ISO/IEC 9899:1989 and a subset of the new standard ISO/IEC 9899:1999 (C99).&lt;br /&gt;
&lt;br /&gt;
[http://sun.hasenbraten.de/vbcc/ vbcc webpage]&lt;br /&gt;
&lt;br /&gt;
== Vim ==&lt;br /&gt;
&lt;br /&gt;
Vim is a highly configurable text editor built to make creating and changing any kind of text very efficient. Vim is rock stable and is continuously being developed to become even better. Among its features are:&lt;br /&gt;
&lt;br /&gt;
* persistent, multi-level undo tree&lt;br /&gt;
* extensive plugin system&lt;br /&gt;
* support for hundreds of programming languages and file formats&lt;br /&gt;
* powerful search and replace&lt;br /&gt;
* integrates with many tools&lt;br /&gt;
&lt;br /&gt;
Please note that this is not a straight port of the upstream version. It includes a full MUI GUI with most of the bells and whistles found in Vim on any of the major platforms.  &amp;quot;TheBar&amp;quot; custom class must be installed for MUI for this version of Vim.&lt;br /&gt;
&lt;br /&gt;
[https://sourceforge.net/projects/spaden/ AmigaOS Vim webpage]&lt;br /&gt;
&lt;br /&gt;
[https://github.com/amiga-mui/thebar TheBar custom class webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10134</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10134"/>
		<updated>2019-03-10T21:51:15Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Neverball */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Aquaria ==&lt;br /&gt;
&lt;br /&gt;
A massive ocean world, teeming with life and filled with ancient secrets.&lt;br /&gt;
&lt;br /&gt;
Join Naija, a lone underwater dweller in search of her family, as she explores the depths of Aquaria.&lt;br /&gt;
&lt;br /&gt;
She&#039;ll travel from hidden caves, shrouded in darkness, to beautiful, sunlit oases, all lovingly handcrafted by its two creators.&lt;br /&gt;
&lt;br /&gt;
Naija&#039;s story, narrated fully with voice overs, will become yours, as you join her on this magnificent adventure.&lt;br /&gt;
&lt;br /&gt;
[https://www.amigasoft.net/aquaria/ Amigasoft game webpage]&lt;br /&gt;
&lt;br /&gt;
== Ask Me Up XXL ==&lt;br /&gt;
&lt;br /&gt;
Ask Me Up XXL is a video game about general knowledge.&lt;br /&gt;
&lt;br /&gt;
The principle is quite simple: 1 question, 4 possible answers ... &lt;br /&gt;
&lt;br /&gt;
Choose the right one! &lt;br /&gt;
&lt;br /&gt;
You know all celebrities&#039; secrets? You can easily put a city on a map. You know who is the first white sprinter to have officially run 100m in under 10 seconds? Or you have no idea about it?&lt;br /&gt;
&lt;br /&gt;
In all cases, our quiz is for you and you will learn while having fun! Play alone or with others, share your high scores with your friends, check your statistics to analyze progress ... All this is possible!&lt;br /&gt;
&lt;br /&gt;
[http://glames.online.fr/products/askmeup_xxl.html Boing Attitude game webpage]&lt;br /&gt;
&lt;br /&gt;
== Descent Freespace: The Great War ==&lt;br /&gt;
&lt;br /&gt;
FreeSpace takes place in a fictional future where humans have discovered how to travel long distances by jumping into subspace, and have spread among the stars as the Galactic Terran Alliance (GTA).&lt;br /&gt;
&lt;br /&gt;
Descent: FreeSpace The Great War puts the player in starfighter flying out on missions to investigate, protect, or destroy certain targets. Some have categorized it as a flight simulator, since it has more controls and commands than a typical arcade game. In the single-player mode, the player flies through a series of missions in a campaign.&lt;br /&gt;
&lt;br /&gt;
The game features multiplayer matches online or over a local area network (LAN). Players can either band together to complete cooperative missions, or split up into teams to battle against one another.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php/where-to-buy/direct-downloads/182-descent-freespace-amigaos Descent Freespace: The Great War game webpage]&lt;br /&gt;
&lt;br /&gt;
== Digital Universe for AmigaOS ==&lt;br /&gt;
&lt;br /&gt;
Digital Universe, a highly sophisticated planetarium software package, is available for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://www.digitaluniverse.org.uk Digital Universe webpage]&lt;br /&gt;
&lt;br /&gt;
== Gorky 17 ==&lt;br /&gt;
&lt;br /&gt;
Gorky 17 is a horror conspiracy game mixing elements of strategy and RPG gameplay. You, the player, command a small group of NATO soldiers who must reveal the mystery behind the sudden appearance of hybrid creatures in a small Polish city named Lubin.&lt;br /&gt;
&lt;br /&gt;
The city is being terrorized, the area is surrounded by NATO troops and media from all over the world, and the first group sent into the city disappears without a trace.&lt;br /&gt;
&lt;br /&gt;
The main hero of the story is the 40-year old soldier Cole Sullivan, a commando team member with extensive scientific knowledge. His team`s task: to explain the hybrids` presence and to find the missing members of Group One. But that, of course, is just the beginning...&lt;br /&gt;
&lt;br /&gt;
It is your task to discover the secrets behind Gorky 17.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php/games/gorky-17 Gorky 17 game webpage]&lt;br /&gt;
&lt;br /&gt;
== Neverball ==&lt;br /&gt;
&lt;br /&gt;
Neverball sees you guide a ball through a series of complex grids and courses with the aim of either collecting as much cash as you can, beating a time limit or reaching a certain goal. You guide the ball by tilting the course side to side but one false move either way sees you fall to your death!&lt;br /&gt;
&lt;br /&gt;
There are many courses to choose from to challenge your skills and reactions, there are also a selection of in-game challenges as well that you may want to attempt.  Controlling the ball in Neverball is extremely tricky at times. You&#039;ll need to home your skills to make sure your ball doesn&#039;t just roll off the edge, hit a barrier or simply run out of control. It can take several goes before you can even complete one course on the easy level, this game will keep you coming back for more.&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve got the patience to guide a ball through some seemingly impossible levels you&#039;ll enjoy Neverball.&lt;br /&gt;
&lt;br /&gt;
[http://www.os4depot.net/index.php?function=showfile&amp;amp;file=game/misc/neverball-bin.lha Neverball OS4Depot page]&lt;br /&gt;
&lt;br /&gt;
== Nexuiz ==&lt;br /&gt;
&lt;br /&gt;
Nexuiz is a fast paced 3D deathmatch game project created online by a team of developers called Alientrap.&lt;br /&gt;
&lt;br /&gt;
It is available for download for Amiga, Windows, Mac, and Linux (all in the same archive).&lt;br /&gt;
&lt;br /&gt;
The first version was released May 31st 2005, released entirely GPL and free over the net, a first for a project of its kind. Since then it has been downloaded over 1.5 million times, and the game is still being updated and developed, currently at version 2.5 and new releases being developed.&lt;br /&gt;
&lt;br /&gt;
[https://www.amigasoft.net/download-games/ Amigasoft game webpage]&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: F1&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing game webpage]&lt;br /&gt;
&lt;br /&gt;
== Tower 57 ==&lt;br /&gt;
&lt;br /&gt;
In a dystopian, dieselpunk world, where Megatowers are the only enclaves of civilization, a group of extraordinary individuals is sent to infiltrate the reclusive Tower 57. Their skills, clips&#039; capacity &amp;amp; the ability to cooperate will decide on their fate.&lt;br /&gt;
&lt;br /&gt;
Tower 57 is a TOP-DOWN TWIN STICK SHOOTER with 16-bit inspired pixel art, destructible environments and heavy focus on CO-OP. It is also a modern take on what made AMIGA games so great back in the days.&lt;br /&gt;
&lt;br /&gt;
[https://benitosub.itch.io/tower-57 Tower 57 game webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10133</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10133"/>
		<updated>2019-03-10T21:47:34Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Aquaria */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Aquaria ==&lt;br /&gt;
&lt;br /&gt;
A massive ocean world, teeming with life and filled with ancient secrets.&lt;br /&gt;
&lt;br /&gt;
Join Naija, a lone underwater dweller in search of her family, as she explores the depths of Aquaria.&lt;br /&gt;
&lt;br /&gt;
She&#039;ll travel from hidden caves, shrouded in darkness, to beautiful, sunlit oases, all lovingly handcrafted by its two creators.&lt;br /&gt;
&lt;br /&gt;
Naija&#039;s story, narrated fully with voice overs, will become yours, as you join her on this magnificent adventure.&lt;br /&gt;
&lt;br /&gt;
[https://www.amigasoft.net/aquaria/ Amigasoft game webpage]&lt;br /&gt;
&lt;br /&gt;
== Ask Me Up XXL ==&lt;br /&gt;
&lt;br /&gt;
Ask Me Up XXL is a video game about general knowledge.&lt;br /&gt;
&lt;br /&gt;
The principle is quite simple: 1 question, 4 possible answers ... &lt;br /&gt;
&lt;br /&gt;
Choose the right one! &lt;br /&gt;
&lt;br /&gt;
You know all celebrities&#039; secrets? You can easily put a city on a map. You know who is the first white sprinter to have officially run 100m in under 10 seconds? Or you have no idea about it?&lt;br /&gt;
&lt;br /&gt;
In all cases, our quiz is for you and you will learn while having fun! Play alone or with others, share your high scores with your friends, check your statistics to analyze progress ... All this is possible!&lt;br /&gt;
&lt;br /&gt;
[http://glames.online.fr/products/askmeup_xxl.html Boing Attitude game webpage]&lt;br /&gt;
&lt;br /&gt;
== Descent Freespace: The Great War ==&lt;br /&gt;
&lt;br /&gt;
FreeSpace takes place in a fictional future where humans have discovered how to travel long distances by jumping into subspace, and have spread among the stars as the Galactic Terran Alliance (GTA).&lt;br /&gt;
&lt;br /&gt;
Descent: FreeSpace The Great War puts the player in starfighter flying out on missions to investigate, protect, or destroy certain targets. Some have categorized it as a flight simulator, since it has more controls and commands than a typical arcade game. In the single-player mode, the player flies through a series of missions in a campaign.&lt;br /&gt;
&lt;br /&gt;
The game features multiplayer matches online or over a local area network (LAN). Players can either band together to complete cooperative missions, or split up into teams to battle against one another.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php/where-to-buy/direct-downloads/182-descent-freespace-amigaos Descent Freespace: The Great War game webpage]&lt;br /&gt;
&lt;br /&gt;
== Digital Universe for AmigaOS ==&lt;br /&gt;
&lt;br /&gt;
Digital Universe, a highly sophisticated planetarium software package, is available for AmigaOS.&lt;br /&gt;
&lt;br /&gt;
[http://www.digitaluniverse.org.uk Digital Universe webpage]&lt;br /&gt;
&lt;br /&gt;
== Gorky 17 ==&lt;br /&gt;
&lt;br /&gt;
Gorky 17 is a horror conspiracy game mixing elements of strategy and RPG gameplay. You, the player, command a small group of NATO soldiers who must reveal the mystery behind the sudden appearance of hybrid creatures in a small Polish city named Lubin.&lt;br /&gt;
&lt;br /&gt;
The city is being terrorized, the area is surrounded by NATO troops and media from all over the world, and the first group sent into the city disappears without a trace.&lt;br /&gt;
&lt;br /&gt;
The main hero of the story is the 40-year old soldier Cole Sullivan, a commando team member with extensive scientific knowledge. His team`s task: to explain the hybrids` presence and to find the missing members of Group One. But that, of course, is just the beginning...&lt;br /&gt;
&lt;br /&gt;
It is your task to discover the secrets behind Gorky 17.&lt;br /&gt;
&lt;br /&gt;
[http://www.hyperion-entertainment.com/index.php/games/gorky-17 Gorky 17 game webpage]&lt;br /&gt;
&lt;br /&gt;
== Neverball ==&lt;br /&gt;
&lt;br /&gt;
Neverball sees you guide a ball through a series of complex grids and courses with the aim of either collecting as much cash as you can, beating a time limit or reaching a certain goal. You guide the ball by tilting the course side to side but one false move either way sees you fall to your death!&lt;br /&gt;
&lt;br /&gt;
There are many courses to choose from to challenge your skills and reactions, there are also a selection of in-game challenges as well that you may want to attempt.  Controlling the ball in Neverball is extremely tricky at times. You&#039;ll need to home your skills to make sure your ball doesn&#039;t just roll off the edge, hit a barrier or simply run out of control. It can take several goes before you can even complete one course on the easy level, this game will keep you coming back for more.&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve got the patience to guide a ball through some seemingly impossible levels you&#039;ll enjoy Neverball.&lt;br /&gt;
&lt;br /&gt;
[http://www.os4depot.net/share/game/misc/neverball-bin.lha Neverball download]&lt;br /&gt;
&lt;br /&gt;
== Nexuiz ==&lt;br /&gt;
&lt;br /&gt;
Nexuiz is a fast paced 3D deathmatch game project created online by a team of developers called Alientrap.&lt;br /&gt;
&lt;br /&gt;
It is available for download for Amiga, Windows, Mac, and Linux (all in the same archive).&lt;br /&gt;
&lt;br /&gt;
The first version was released May 31st 2005, released entirely GPL and free over the net, a first for a project of its kind. Since then it has been downloaded over 1.5 million times, and the game is still being updated and developed, currently at version 2.5 and new releases being developed.&lt;br /&gt;
&lt;br /&gt;
[https://www.amigasoft.net/download-games/ Amigasoft game webpage]&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: F1&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing game webpage]&lt;br /&gt;
&lt;br /&gt;
== Tower 57 ==&lt;br /&gt;
&lt;br /&gt;
In a dystopian, dieselpunk world, where Megatowers are the only enclaves of civilization, a group of extraordinary individuals is sent to infiltrate the reclusive Tower 57. Their skills, clips&#039; capacity &amp;amp; the ability to cooperate will decide on their fate.&lt;br /&gt;
&lt;br /&gt;
Tower 57 is a TOP-DOWN TWIN STICK SHOOTER with 16-bit inspired pixel art, destructible environments and heavy focus on CO-OP. It is also a modern take on what made AMIGA games so great back in the days.&lt;br /&gt;
&lt;br /&gt;
[https://benitosub.itch.io/tower-57 Tower 57 game webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Applications&amp;diff=10124</id>
		<title>AmigaOS Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Applications&amp;diff=10124"/>
		<updated>2019-03-10T18:39:03Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Disclaimer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Disclaimer ===&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
= Applications =&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Apps Games|Games]] - Games on AmigaOS4&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10123</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10123"/>
		<updated>2019-03-10T18:37:22Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Ask Me Up XXL */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Ask Me Up XXL ==&lt;br /&gt;
&lt;br /&gt;
Ask Me Up XXL is a video game about general knowledge.&lt;br /&gt;
&lt;br /&gt;
The principle is quite simple: 1 question, 4 possible answers ... &lt;br /&gt;
&lt;br /&gt;
Choose the right one! &lt;br /&gt;
&lt;br /&gt;
You know all celebrities&#039; secrets? You can easily put a city on a map. You know who is the first white sprinter to have officially run 100m in under 10 seconds? Or you have no idea about it?&lt;br /&gt;
&lt;br /&gt;
In all cases, our quiz is for you and you will learn while having fun! Play alone or with others, share your high scores with your friends, check your statistics to analyze progress ... All this is possible!&lt;br /&gt;
&lt;br /&gt;
[http://glames.online.fr/products/askmeup_xxl.html Boing Attitude game webpage]&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: Fl&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing game webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10122</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10122"/>
		<updated>2019-03-10T18:36:51Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Disclaimer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
=== Disclaimer ===&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Ask Me Up XXL ==&lt;br /&gt;
&lt;br /&gt;
Ask Me Up XXL is a video game about general knowledge.&lt;br /&gt;
&lt;br /&gt;
The principle is quite simple: 1 question, 4 possible answers ... &lt;br /&gt;
&lt;br /&gt;
Choose the right one! &lt;br /&gt;
&lt;br /&gt;
You know all celebrities&#039; secrets? You can easily put a city on a map. You know who is the first white sprinter to have officially run 100m in under 10 seconds? Or you have no idea about it?&lt;br /&gt;
&lt;br /&gt;
In all cases, our quiz is for you and you will learn while having fun! Play alone or with others, share your high scores with your friends, check your statistics to analyze progress ... All this is possible!&lt;br /&gt;
&lt;br /&gt;
[http://glames.online.fr/products/askmeup_xxl.html Boing Attitude game webpage]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: Fl&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing game webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10121</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10121"/>
		<updated>2019-03-10T18:27:04Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
= Disclaimer =&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Ask Me Up XXL ==&lt;br /&gt;
&lt;br /&gt;
Ask Me Up XXL is a video game about general knowledge.&lt;br /&gt;
&lt;br /&gt;
The principle is quite simple: 1 question, 4 possible answers ... &lt;br /&gt;
&lt;br /&gt;
Choose the right one! &lt;br /&gt;
&lt;br /&gt;
You know all celebrities&#039; secrets? You can easily put a city on a map. You know who is the first white sprinter to have officially run 100m in under 10 seconds? Or you have no idea about it?&lt;br /&gt;
&lt;br /&gt;
In all cases, our quiz is for you and you will learn while having fun! Play alone or with others, share your high scores with your friends, check your statistics to analyze progress ... All this is possible!&lt;br /&gt;
&lt;br /&gt;
[http://glames.online.fr/products/askmeup_xxl.html Boing Attitude game webpage]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: Fl&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing game webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10120</id>
		<title>AmigaOS Apps Games</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Apps_Games&amp;diff=10120"/>
		<updated>2019-03-10T18:22:19Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: Created page with &amp;quot; The following is a sampling of games you might enjoy on AmigaOS4.  = Disclaimer = The following list of applications are neither endorsed by nor supported by Hyperion Enterta...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
The following is a sampling of games you might enjoy on AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
= Disclaimer =&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
== Swamp Defense 2 ==&lt;br /&gt;
&lt;br /&gt;
Fight countless enemies with a huge selection of gun turrets (in the form of comic heroes) and&lt;br /&gt;
additional helpers (mines, air support, block wall) on more than 60 maps. Earn&lt;br /&gt;
coins to obtain improvements in the integrated shop system and to buy new towers.&lt;br /&gt;
&lt;br /&gt;
Features:&lt;br /&gt;
&lt;br /&gt;
* Shop system for buying and improving towers and for purchasing special weapons&lt;br /&gt;
* 9 defense towers, capable of improvement (2 improvements each within a battle)&lt;br /&gt;
* Support towers, special attacks and elements that can be placed along the path&lt;br /&gt;
* Unique opponents - 54 unlockable maps + 9 bonus maps&lt;br /&gt;
* Tower control (control of direction and aim of a tower)&lt;br /&gt;
* Weapons: pistol, electron beam, fire fart, adhesive cream, skillet, rocket launcher, dynamite, lethal injection, electric nail gun&lt;br /&gt;
* Power-up for each tower: damage, rate of fire, range can be placed along the path: mine, adhesive cream fence, block wall&lt;br /&gt;
* Supporters: fire power expansion, range expansion&lt;br /&gt;
* Overall assistance: area bomb, atomic bomb, air support&lt;br /&gt;
* Global Help in game: Fl&lt;br /&gt;
&lt;br /&gt;
[http://www.amiboing.de/gameDetail.php?id=20 AmiBoing Swamp Defense 2 webpage]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaOS_Applications&amp;diff=10119</id>
		<title>AmigaOS Applications</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaOS_Applications&amp;diff=10119"/>
		<updated>2019-03-10T18:12:35Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Applications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Disclaimer =&lt;br /&gt;
The following list of applications are neither endorsed by nor supported by Hyperion Entertainment. This list is strictly informational only.&lt;br /&gt;
&lt;br /&gt;
= Applications =&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Apps Games|Games]] - Games on AmigaOS4&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=9327</id>
		<title>UserDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=9327"/>
		<updated>2018-01-12T03:32:39Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaOS platform targets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Welcome to AmigaOS ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS was born in 1985 and delivered what contemporary personal computer operating systems could only dream of.  As the first &amp;quot;multimedia&amp;quot; operating system, it was trivial for AmigaOS computers to display animations while playing music and reading data from disks.  Such multimedia and multitasking finesse drew many people to this system.  Some of them are famous: [http://www.amigahistory.co.uk/warhol.html Andy Warhol], Sir Arthur C. Clarke, [http://www.polyphoto.com/upchug/AEcastro.html NASA], Hollywood and the TV broadcasting industry, and many others that thought [http://www.youtube.com/watch?v=PWeO5IkCssk only Amiga makes it possible].&lt;br /&gt;
&lt;br /&gt;
Today many people still think AmigaOS has something special that makes it more interesting and rewarding than other systems. This system allows the user to control the computer, not the other way around. It is a system you fully understand that is easier and more flexible to use.  In other words, AmigaOS is &#039;&#039;&#039;more fun&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS:  The flexible operating system ===&lt;br /&gt;
AmigaOS is an operating system:  a collection of efficient programs written to start the computer, let the user control the computer, and present feedback to the user.&lt;br /&gt;
&lt;br /&gt;
AmigaOS is designed with ease of use and flexibility in mind. To begin with, AmigaOS provides a clear view of your computer, your applications and files. A number of methods are available to let your computer serve you, whether graphically with a mouse, using the &amp;quot;Shell&amp;quot; command line, or by some other means the user prefers.&lt;br /&gt;
&lt;br /&gt;
AmigaOS strives to avoid stupid limitations that can be found on other systems. AmigaOS users can organise their files the way they like. There are few limits on file hierarchy, locations and file names.  Drives don&#039;t have to be named with a letter or cryptic names (such as C:, or sda1), your files don&#039;t have to reside in your &amp;quot;Documents&amp;quot; folder and your hard drives aren&#039;t hidden from you. If you&#039;re not writing to drives and you want to &amp;quot;shut down&amp;quot;, why wait for the OS to allow that?  With AmigaOS, just hit the power switch. Done.&lt;br /&gt;
&lt;br /&gt;
An Amiga does not start with pre-installed applications serving some sales conglomerate, marketing organization or their big brother. AmigaOS does not do actions behind the user&#039;s back. As unique as it is today, the AmigaOS computer serves the user and not the other way around. With one of the largest proportions of user-programmers around, the trustworthy AmigaOS user-friendly ethic is mirrored in AmigaOS applications.&lt;br /&gt;
&lt;br /&gt;
Since the first versions more than twenty-five years ago, AmigaOS has also been designed to serve efficiently. Optimizing  applications and OS code has always been the goal of programmers and developers of this operating system.  The result is an operating system and applications that take less space on your hard drives, waste less time loading, consume less memory, require less processing power, and respond more quickly to the user.&lt;br /&gt;
&lt;br /&gt;
And every update of AmigaOS doesn&#039;t demand you must buy newer, more powerful hardware. AmigaOS currently runs on twenty year old 200MHz computers or brand new dual core 1,800MHz computers.  It&#039;s the user&#039;s choice how they want to &#039;&#039;&#039;enjoy&#039;&#039;&#039; AmigaOS.&lt;br /&gt;
&lt;br /&gt;
=== Some AmigaOS features ===&lt;br /&gt;
Here are some of the features of AmigaOS that make it easy to control your computer. Some of these concepts were copied by other operating systems which tend to show they are the correct way of doing things.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Small footprint:&#039;&#039;&#039; AmigaOS can work with 64 MB of memory. On disk, a default installation only takes around 200 MB.  The smaller footprint translates into a more responsive user experience given any hardware.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Straightforward operating system design:&#039;&#039;&#039; With a clear layout and easy to understand names  (Classes, Libs, Fonts, Prefs, Storage, etc.),  you can easily understand what everything in AmigaOS is and what it does for you.  Nothing is hidden from the user and the user is not restricted by AmigaOS.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;User configurable graphic interface:&#039;&#039;&#039;  Using the provided &amp;quot;preferences editors,&amp;quot; the user can dramatically reconfigure how AmigaOS looks, sounds, runs and responds to every user whim.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;File recognition based on file content:&#039;&#039;&#039;  You can name a file &#039;&#039;&#039;whatever you want&#039;&#039;&#039;, even without an extension. Examples: &amp;quot;my file&amp;quot; or &amp;quot;picture of Jay in Santa Clara&amp;quot;.  There is no need to add an extension to explain what the file is, like &amp;quot;.txt&amp;quot; or &amp;quot;.jpg&amp;quot;. AmigaOS really examines the &#039;&#039;&#039;file content&#039;&#039;&#039; to recognise what type of file it is.  &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Logical assignments:&#039;&#039;&#039; Easily set and use logical names names for directories located anywhere on your system.  For example, &amp;quot;Auto:&amp;quot; can point to your directory &amp;quot;car show pictures&amp;quot; buried on your media drive.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ram disk concept:&#039;&#039;&#039;  On AmigaOS there is a special disk called the &#039;&#039;&#039;Ram disk&#039;&#039;&#039; which represents a part of your computer memory. This area is not fixed. It automatically grows whenever you store files in it.  For example, it&#039;s a great place to unpack files to install from there, greatly speeding up the installation.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Command line and graphical user interfaces:&#039;&#039;&#039;  Both the the graphical user interface (GUI) and command line interface (where you type commands into a window with the keyboard)  can be used to manage AmigaOS, its programs and files.   Both interfaces are intergated with each other so you can easily use command lines from the GUI or open graphical elements from a command line.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;ARexx Ports:&#039;&#039;&#039;  Throughout AmigaOS and third party programs, &amp;quot;ARexx&amp;quot; message ports let one application talk with others so that apps work together to serve the user.  AmigaOS also provides the lightweight ARexx and modern Python programming languages that can control AmigaOS and applications with ARexx ports.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Resident Commands:&#039;&#039;&#039; Commands can be made resident, i.e., they are kept in memory so that they can be reused with no loading time.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Restart only the operating system:&#039;&#039;&#039; if you feel the need to restart the system, you can do so by restarting &#039;&#039;&#039;only AmigaOS&#039;&#039;&#039; and not the whole computer.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS platform targets ===&lt;br /&gt;
&lt;br /&gt;
While the original versions of AmigaOS ran on computers of the eighties using Motorola 68k series CPU chips, the current AmigaOS runs on computers using PowerPC processor chips [http://www.amigaos.net/content/72/supported-hardware hardware].  These can be older Amiga computers (also called &amp;quot;Classic Amigas&amp;quot;) with PPC &amp;quot;accelerator cards&amp;quot; or new generation Amiga PPC computers. &lt;br /&gt;
&lt;br /&gt;
In this guide, we will concentrate on the current AmigaOS running on the supported hardware:&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne A1222]] model by [http://www.a-eon.com A-Eon Technology]&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne X5000]] model by [http://www.a-eon.com A-Eon Technology]&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne X1000]] model by [http://www.a-eon.com A-Eon Technology]&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne 500]], Sam460, Sam440ep and Sam440-flex models by [http://www.acube-systems.com ACube Systems]&lt;br /&gt;
&lt;br /&gt;
* [[Pegasos II]] model by [http://www.bplan-gmbh.de bplan GmbH]&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne XE and MicroA1-C]] models by [http://en.wikipedia.org/wiki/Eyetech Eyetech Group Ltd].&lt;br /&gt;
&lt;br /&gt;
* [[Classic Amiga]] 4000(T), 3000(T) and 1200 models by Commodore Business Machines (when equipped with PowerPC accelerator cards).&lt;br /&gt;
&lt;br /&gt;
== How does AmigaOS work? - Concepts ==&lt;br /&gt;
&lt;br /&gt;
In this page we will discuss  [[UserDoc:How AmigaOS Works|how AmigaOS works]]:&lt;br /&gt;
&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#The_most_important_components|The most important components]] (Exec, AmigaDOS, Intuition...)&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#How_is_my_data_stored.3F|how files and data are stored]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#All_AmigaOS_components|all AmigaOS components are described]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#AmigaOS_boot_procedure|how AmigaOS is booted on your Amiga computer]]&lt;br /&gt;
* [[Workbench/Prefs|AmigaOS settings programs]]&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
== How to use AmigaOS? ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS is a collection of components that oversee the computer hardware &amp;amp; data and provide the user with easy, understandable tools to manage and use them.&lt;br /&gt;
&lt;br /&gt;
In the following [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS pages]] we will discuss the basic concepts:&lt;br /&gt;
&lt;br /&gt;
* how to use AmigaOS&lt;br /&gt;
* what the AmigaOS graphic user interface is composed of &lt;br /&gt;
* what interfaces AmigaOS provides, including the [[UserDoc:Workbench|Workbench]], the [[UserDoc:Shell|Shell]] or scripting languages.&lt;br /&gt;
&lt;br /&gt;
From the introduction page, you can continue with more detailed pages on the [[UserDoc:Workbench|Workbench]] and the [[AmigaDOS manual]] .   Now let&#039;s start with this [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS]].&lt;br /&gt;
&lt;br /&gt;
== Manuals ==&lt;br /&gt;
&lt;br /&gt;
[[UserDoc:AmigaOS File Systems|AmigaOS File Systems]] - AmigaOS File Systems&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Manual]] - AmigaOS Manual&lt;br /&gt;
&lt;br /&gt;
[[Bars &amp;amp; Pipes Professional]] - MIDI Sequencer&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9104</id>
		<title>DeveloperDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9104"/>
		<updated>2017-01-22T20:18:03Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Many programming languages can be used on AmigaOS.  They range from scripting languages to comprehensive compiled langauges:&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOS Manual: ARexx|ARexx]]: the native AmigaOS scripting language, good for beginners,small projects and talking between applications.&lt;br /&gt;
* Python: a common cross platform scripting language ported to &amp;amp; included with AmigaOS.&lt;br /&gt;
* C: the primary compiled language for AmigaOS.&lt;br /&gt;
* [https://aglet.web.runbox.net/ Modula2]: the compiled language that evolved from Pascal.&lt;br /&gt;
* [http://cshandley.co.uk/portable/PortablE.html E]: an Amiga native compiled language.&lt;br /&gt;
&lt;br /&gt;
ARexx is built into AmigaOS and its original documentation can be found in [[AmigaOS Manual: ARexx|this part]] of the Developer&#039;s Wiki.&lt;br /&gt;
&lt;br /&gt;
A native compiler for the C language is part of the downloadable [http://www.hyperion-entertainment.biz/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS SDK].&lt;br /&gt;
&lt;br /&gt;
Most of the remaining AmigaOS Developers Wiki provides the latest information on how to program systems running AmigaOS 4.x with the C language. It has been updated for Release 4.0 and higher of AmigaOS and covers all the computer systems which run the Amiga operating system from the Commodore A1200 all the way up to the AmigaOne X5000..&lt;br /&gt;
&lt;br /&gt;
The Wiki assumes some previous experience with programming and familiarity with computers in general. Although it is not required, a knowledge of the C programming language will make it much easier to understand the material in this book. Most of the Amiga operating system is written in C, hence C is the language used for the programming examples. &lt;br /&gt;
&lt;br /&gt;
Many of the AmigaOS concepts, methods described in the wiki for C will also be applicable to other compiled languages, with some variations.  Please see the documentation of the respective languages.&lt;br /&gt;
&lt;br /&gt;
This wiki is intended for the following audiences:&lt;br /&gt;
&lt;br /&gt;
* Programmers who want to create application software for AmigaOS systems.&lt;br /&gt;
* Software developers who want to upgrade their software for Release 4.0 or higher of the operating system.&lt;br /&gt;
* Anyone who wants to know more about how AmigaOS works.&lt;br /&gt;
&lt;br /&gt;
The system software is organized into related groups of functions called libraries. The same basic organization is used for this wiki.&lt;br /&gt;
&lt;br /&gt;
== Software Development Kit (SDK) ==&lt;br /&gt;
&lt;br /&gt;
You can find the [http://www.hyperion-entertainment.biz/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS SDK at this location].&lt;br /&gt;
&lt;br /&gt;
[[SDK Release Notes|Release Notes]]&lt;br /&gt;
&lt;br /&gt;
[[SDK FAQ|Frequency Asked Questions]]&lt;br /&gt;
&lt;br /&gt;
[[Autodocs:Main|Autodocs]]&lt;br /&gt;
&lt;br /&gt;
[[Fundamental Types]]&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
[[Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries]]&lt;br /&gt;
&lt;br /&gt;
[[Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Resources]]&lt;br /&gt;
&lt;br /&gt;
[[User Interface Style Guide]]&lt;br /&gt;
&lt;br /&gt;
== General Information ==&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Versions]]&lt;br /&gt;
&lt;br /&gt;
[[Controlling Application Stack]]&lt;br /&gt;
&lt;br /&gt;
[[GUI Programming]]&lt;br /&gt;
&lt;br /&gt;
[[Programming in the Amiga Environment]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries and Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Migration Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Troubleshooting Your Software]]&lt;br /&gt;
&lt;br /&gt;
[[Understanding the alert error numbers]]&lt;br /&gt;
&lt;br /&gt;
[[Release 4 Compatibility]]&lt;br /&gt;
&lt;br /&gt;
[[Writing apps for Xena]]&lt;br /&gt;
&lt;br /&gt;
[[AmigaGuide 101]]&lt;br /&gt;
&lt;br /&gt;
[[Installation Utility]]&lt;br /&gt;
&lt;br /&gt;
[[Optimized Window Refreshing]]&lt;br /&gt;
&lt;br /&gt;
[[Autodoc Style Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Debug Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[AmiDock and Dockies]]&lt;br /&gt;
&lt;br /&gt;
[[Command Line Interface]]&lt;br /&gt;
&lt;br /&gt;
[[DCFS and LNFS Low Level Data Structures]]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9103</id>
		<title>DeveloperDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9103"/>
		<updated>2017-01-22T20:11:44Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Many programming languages can be used on AmigaOS.  They range from scripting languages to comprehensive compiled langauges:&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOS Manual: ARexx|ARexx]]: the native AmigaOS scripting language, good for beginners,small projects and talking between applications.&lt;br /&gt;
* Python: a common cross platform scripting language ported to &amp;amp; included with AmigaOS.&lt;br /&gt;
* C: the primary compiled language for AmigaOS.&lt;br /&gt;
* [https://aglet.web.runbox.net/ Modula2]: the compiled language that evolved from Pascal.&lt;br /&gt;
* [http://cshandley.co.uk/portable/PortablE.html E]: an Amiga native compiled language.&lt;br /&gt;
&lt;br /&gt;
ARexx is built into AmigaOS and its original documentation can be found in [[AmigaOS Manual: ARexx|this part]] of the Developer&#039;s Wiki.&lt;br /&gt;
&lt;br /&gt;
A native compiler for the C language is part of the downloadable [http://www.amigaos.net/content/81/sdk AmigaOS SDK].&lt;br /&gt;
&lt;br /&gt;
Most of the remaining AmigaOS Developers Wiki provides the latest information on how to program systems running AmigaOS 4.x with the C language. It has been updated for Release 4.0 and higher of AmigaOS and covers all the computer systems which run the Amiga operating system from the Commodore A1200 all the way up to the AmigaOne X5000..&lt;br /&gt;
&lt;br /&gt;
The Wiki assumes some previous experience with programming and familiarity with computers in general. Although it is not required, a knowledge of the C programming language will make it much easier to understand the material in this book. Most of the Amiga operating system is written in C, hence C is the language used for the programming examples. &lt;br /&gt;
&lt;br /&gt;
Many of the AmigaOS concepts, methods described in the wiki for C will also be applicable to other compiled languages, with some variations.  Please see the documentation of the respective languages.&lt;br /&gt;
&lt;br /&gt;
This wiki is intended for the following audiences:&lt;br /&gt;
&lt;br /&gt;
* Programmers who want to create application software for AmigaOS systems.&lt;br /&gt;
* Software developers who want to upgrade their software for Release 4.0 or higher of the operating system.&lt;br /&gt;
* Anyone who wants to know more about how AmigaOS works.&lt;br /&gt;
&lt;br /&gt;
The system software is organized into related groups of functions called libraries. The same basic organization is used for this wiki.&lt;br /&gt;
&lt;br /&gt;
== Software Development Kit (SDK) ==&lt;br /&gt;
&lt;br /&gt;
You can find the [http://www.hyperion-entertainment.biz/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS SDK at this location].&lt;br /&gt;
&lt;br /&gt;
[[SDK Release Notes|Release Notes]]&lt;br /&gt;
&lt;br /&gt;
[[SDK FAQ|Frequency Asked Questions]]&lt;br /&gt;
&lt;br /&gt;
[[Autodocs:Main|Autodocs]]&lt;br /&gt;
&lt;br /&gt;
[[Fundamental Types]]&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
[[Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries]]&lt;br /&gt;
&lt;br /&gt;
[[Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Resources]]&lt;br /&gt;
&lt;br /&gt;
[[User Interface Style Guide]]&lt;br /&gt;
&lt;br /&gt;
== General Information ==&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Versions]]&lt;br /&gt;
&lt;br /&gt;
[[Controlling Application Stack]]&lt;br /&gt;
&lt;br /&gt;
[[GUI Programming]]&lt;br /&gt;
&lt;br /&gt;
[[Programming in the Amiga Environment]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries and Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Migration Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Troubleshooting Your Software]]&lt;br /&gt;
&lt;br /&gt;
[[Understanding the alert error numbers]]&lt;br /&gt;
&lt;br /&gt;
[[Release 4 Compatibility]]&lt;br /&gt;
&lt;br /&gt;
[[Writing apps for Xena]]&lt;br /&gt;
&lt;br /&gt;
[[AmigaGuide 101]]&lt;br /&gt;
&lt;br /&gt;
[[Installation Utility]]&lt;br /&gt;
&lt;br /&gt;
[[Optimized Window Refreshing]]&lt;br /&gt;
&lt;br /&gt;
[[Autodoc Style Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Debug Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[AmiDock and Dockies]]&lt;br /&gt;
&lt;br /&gt;
[[Command Line Interface]]&lt;br /&gt;
&lt;br /&gt;
[[DCFS and LNFS Low Level Data Structures]]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9102</id>
		<title>DeveloperDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9102"/>
		<updated>2017-01-22T20:09:08Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Many programming languages can be used on AmigaOS.  They range from scripting languages to comprehensive compiled langauges:&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOS Manual: ARexx|ARexx]]: the native AmigaOS scripting language, good for beginners,small projects and talking between applications.&lt;br /&gt;
* Python: a common cross platform scripting language ported to &amp;amp; included with AmigaOS.&lt;br /&gt;
* C: the primary compiled language for AmigaOS.&lt;br /&gt;
* [https://aglet.web.runbox.net/ Modula2]: the compiled language that evolved from Pascal.&lt;br /&gt;
* [http://cshandley.co.uk/portable/PortablE.html E]: an Amiga native compiled language.&lt;br /&gt;
&lt;br /&gt;
ARexx is built into AmigaOS and its original documentation can be found in [[AmigaOS Manual: ARexx|this part]] of the Developer&#039;s Wiki.&lt;br /&gt;
&lt;br /&gt;
The C language is part of the downloadable [http://www.amigaos.net/content/81/sdk AmigaOS SDK].&lt;br /&gt;
&lt;br /&gt;
Most of the remaining AmigaOS Developers Wiki provides the latest information on how to program systems running AmigaOS 4.x with the C language. It has been updated for Release 4.0 and higher of AmigaOS and covers all the computer systems which run the Amiga operating system from the Commodore A1200 all the way up to the AmigaOne X5000..&lt;br /&gt;
&lt;br /&gt;
The Wiki assumes some previous experience with programming and familiarity with computers in general. Although it is not required, a knowledge of the C programming language will make it much easier to understand the material in this book. Most of the Amiga operating system is written in C, hence C is the language used for the programming examples. &lt;br /&gt;
&lt;br /&gt;
Many of the AmigaOS concepts, methods described in the wiki for C will also be applicable to other compiled languages, with some variations.  Please see the documentation of the respective languages.&lt;br /&gt;
&lt;br /&gt;
This wiki is intended for the following audiences:&lt;br /&gt;
&lt;br /&gt;
* Programmers who want to create application software for AmigaOS systems.&lt;br /&gt;
* Software developers who want to upgrade their software for Release 4.0 or higher of the operating system.&lt;br /&gt;
* Anyone who wants to know more about how AmigaOS works.&lt;br /&gt;
&lt;br /&gt;
The system software is organized into related groups of functions called libraries. The same basic organization is used for this wiki.&lt;br /&gt;
&lt;br /&gt;
== Software Development Kit (SDK) ==&lt;br /&gt;
&lt;br /&gt;
You can find the [http://www.hyperion-entertainment.biz/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS SDK at this location].&lt;br /&gt;
&lt;br /&gt;
[[SDK Release Notes|Release Notes]]&lt;br /&gt;
&lt;br /&gt;
[[SDK FAQ|Frequency Asked Questions]]&lt;br /&gt;
&lt;br /&gt;
[[Autodocs:Main|Autodocs]]&lt;br /&gt;
&lt;br /&gt;
[[Fundamental Types]]&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
[[Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries]]&lt;br /&gt;
&lt;br /&gt;
[[Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Resources]]&lt;br /&gt;
&lt;br /&gt;
[[User Interface Style Guide]]&lt;br /&gt;
&lt;br /&gt;
== General Information ==&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Versions]]&lt;br /&gt;
&lt;br /&gt;
[[Controlling Application Stack]]&lt;br /&gt;
&lt;br /&gt;
[[GUI Programming]]&lt;br /&gt;
&lt;br /&gt;
[[Programming in the Amiga Environment]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries and Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Migration Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Troubleshooting Your Software]]&lt;br /&gt;
&lt;br /&gt;
[[Understanding the alert error numbers]]&lt;br /&gt;
&lt;br /&gt;
[[Release 4 Compatibility]]&lt;br /&gt;
&lt;br /&gt;
[[Writing apps for Xena]]&lt;br /&gt;
&lt;br /&gt;
[[AmigaGuide 101]]&lt;br /&gt;
&lt;br /&gt;
[[Installation Utility]]&lt;br /&gt;
&lt;br /&gt;
[[Optimized Window Refreshing]]&lt;br /&gt;
&lt;br /&gt;
[[Autodoc Style Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Debug Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[AmiDock and Dockies]]&lt;br /&gt;
&lt;br /&gt;
[[Command Line Interface]]&lt;br /&gt;
&lt;br /&gt;
[[DCFS and LNFS Low Level Data Structures]]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9101</id>
		<title>DeveloperDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=DeveloperDoc:Main&amp;diff=9101"/>
		<updated>2017-01-22T19:54:35Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Many programming languages can be used on AmigaOS.  They range from scripting languages to comprehensive compiled langauges:&lt;br /&gt;
&lt;br /&gt;
* ARexx: the native AmigaOS scripting language, good for beginners,small projects and talking between applications.&lt;br /&gt;
* Python: a common cross platform scripting language ported to &amp;amp; included with AmigaOS.&lt;br /&gt;
* C: the most comprehensive compiled language for AmigaOS.&lt;br /&gt;
* [http://home.ntelos.net/~tbreeden/ Modula-2]: the compiled language that evolved from Pascal.&lt;br /&gt;
* [http://cshandley.co.uk/portable/PortablE.html E]: an Amiga native compiled language.&lt;br /&gt;
&lt;br /&gt;
The C language is the primary compiled programming language of the Amiga and is available in the Amiga [http://www.amigaos.net/content/81/sdk SDK].  The original documentation for ARexx is available in the Wiki here and still applies to the latest versions of AmigaOS4.&lt;br /&gt;
&lt;br /&gt;
Most of the AmigaOS Developers Wiki provides the latest information on how to program systems running AmigaOS 4.x with the C language. It has been updated for Release 4.0 and higher of AmigaOS and covers all the computer systems which run the Amiga operating system from the Commodore A1200 all the way up to the AmigaOne X5000..&lt;br /&gt;
&lt;br /&gt;
The Wiki assumes some previous experience with programming and familiarity with computers in general. Although it is not required, a knowledge of the C programming language will make it much easier to understand the material in this book. Most of the Amiga operating system is written in C, hence C is the language used for the programming examples. &lt;br /&gt;
&lt;br /&gt;
Many of the AmigaOS concepts, methods described in the wiki for C will also be applicable to other compiled languages, with some variations.  Please see the documentation of the respective languages.&lt;br /&gt;
&lt;br /&gt;
This wiki is intended for the following audiences:&lt;br /&gt;
&lt;br /&gt;
* Programmers who want to create application software for AmigaOS systems.&lt;br /&gt;
* Software developers who want to upgrade their software for Release 4.0 or higher of the operating system.&lt;br /&gt;
* Anyone who wants to know more about how AmigaOS works.&lt;br /&gt;
&lt;br /&gt;
The system software is organized into related groups of functions called libraries. The same basic organization is used for this wiki.&lt;br /&gt;
&lt;br /&gt;
== Software Development Kit (SDK) ==&lt;br /&gt;
&lt;br /&gt;
You can find the [http://www.hyperion-entertainment.biz/index.php?option=com_registration&amp;amp;view=files&amp;amp;parent=30&amp;amp;Itemid=63 AmigaOS SDK at this location].&lt;br /&gt;
&lt;br /&gt;
[[SDK Release Notes|Release Notes]]&lt;br /&gt;
&lt;br /&gt;
[[SDK FAQ|Frequency Asked Questions]]&lt;br /&gt;
&lt;br /&gt;
[[Autodocs:Main|Autodocs]]&lt;br /&gt;
&lt;br /&gt;
[[Fundamental Types]]&lt;br /&gt;
&lt;br /&gt;
== Reference ==&lt;br /&gt;
&lt;br /&gt;
[[Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries]]&lt;br /&gt;
&lt;br /&gt;
[[Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Resources]]&lt;br /&gt;
&lt;br /&gt;
[[User Interface Style Guide]]&lt;br /&gt;
&lt;br /&gt;
== General Information ==&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Versions]]&lt;br /&gt;
&lt;br /&gt;
[[Controlling Application Stack]]&lt;br /&gt;
&lt;br /&gt;
[[GUI Programming]]&lt;br /&gt;
&lt;br /&gt;
[[Programming in the Amiga Environment]]&lt;br /&gt;
&lt;br /&gt;
[[Libraries and Devices]]&lt;br /&gt;
&lt;br /&gt;
[[Migration Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Troubleshooting Your Software]]&lt;br /&gt;
&lt;br /&gt;
[[Understanding the alert error numbers]]&lt;br /&gt;
&lt;br /&gt;
[[Release 4 Compatibility]]&lt;br /&gt;
&lt;br /&gt;
[[Writing apps for Xena]]&lt;br /&gt;
&lt;br /&gt;
[[AmigaGuide 101]]&lt;br /&gt;
&lt;br /&gt;
[[Installation Utility]]&lt;br /&gt;
&lt;br /&gt;
[[Optimized Window Refreshing]]&lt;br /&gt;
&lt;br /&gt;
[[Autodoc Style Guide]]&lt;br /&gt;
&lt;br /&gt;
[[Debug Kernel]]&lt;br /&gt;
&lt;br /&gt;
[[AmiDock and Dockies]]&lt;br /&gt;
&lt;br /&gt;
[[Command Line Interface]]&lt;br /&gt;
&lt;br /&gt;
[[DCFS and LNFS Low Level Data Structures]]&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=7760</id>
		<title>UserDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=7760"/>
		<updated>2014-09-21T15:26:01Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaOS platform targets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Welcome to AmigaOS ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS was born in 1985 and delivered what contemporary personal computer operating systems could only dream of.  As the first &amp;quot;multimedia&amp;quot; operating system, it was trivial for AmigaOS computers to display animations while playing music and reading data from disks.  Such multimedia and multitasking finesse drew many people to this system.  Some of them are famous: [http://www.amigahistory.co.uk/warhol.html Andy Warhol], Sir Arthur C. Clarke, [http://www.polyphoto.com/upchug/AEcastro.html NASA], Hollywood and the TV broadcasting industry, and many others that thought [http://www.youtube.com/watch?v=PWeO5IkCssk only Amiga makes it possible].&lt;br /&gt;
&lt;br /&gt;
Today many people still think AmigaOS has something special that makes it more interesting and rewarding than other systems. This system allows the user to control the computer, not the other way around. It is a system you fully understand that is easier and more flexible to use.  In other words, AmigaOS is &#039;&#039;&#039;more fun&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS:  The flexible operating system ===&lt;br /&gt;
AmigaOS is an operating system:  a collection of efficient programs written to start the computer, let the user control the computer, and present feedback to the user.&lt;br /&gt;
&lt;br /&gt;
AmigaOS is designed with ease of use and flexibility in mind. To begin with, AmigaOS provides a clear view of your computer, your applications and files. A number of methods are available to let your computer serve you, whether graphically with a mouse, using the &amp;quot;Shell&amp;quot; command line, or by some other means the user prefers.&lt;br /&gt;
&lt;br /&gt;
AmigaOS strives to avoid stupid limitations that can be found on other systems. AmigaOS users can organise their files the way they like. There are few limits on file hierarchy, locations and file names.  Drives don&#039;t have to be named with a letter or cryptic names (such as C:, or sda1), your files don&#039;t have to reside in your &amp;quot;Documents&amp;quot; folder and your hard drives aren&#039;t hidden from you. If you&#039;re not writing to drives and you want to &amp;quot;shut down&amp;quot;, why wait for the OS to allow that?  With AmigaOS, just hit the power switch. Done.&lt;br /&gt;
&lt;br /&gt;
An Amiga does not start with pre-installed applications serving some sales conglomerate, marketing organization or their big brother. AmigaOS does not do actions behind the user&#039;s back. As unique as it is today, the AmigaOS computer serves the user and not the other way around. With one of the largest proportions of user-programmers around, the trustworthy AmigaOS user-friendly ethic is mirrored in AmigaOS applications.&lt;br /&gt;
&lt;br /&gt;
Since the first versions more than twenty-five years ago, AmigaOS has also been designed to serve efficiently. Optimizing  applications and OS code has always been the goal of programmers and developers of this operating system.  The result is an operating system and applications that take less space on your hard drives, waste less time loading, consume less memory, require less processing power, and respond more quickly to the user.&lt;br /&gt;
&lt;br /&gt;
And every update of AmigaOS doesn&#039;t demand you must buy newer, more powerful hardware. AmigaOS currently runs on twenty year old 200MHz computers or brand new dual core 1,800MHz computers.  It&#039;s the user&#039;s choice how they want to &#039;&#039;&#039;enjoy&#039;&#039;&#039; AmigaOS.&lt;br /&gt;
&lt;br /&gt;
=== Some AmigaOS features ===&lt;br /&gt;
Here are some of the features of AmigaOS that make it easy to control your computer. Some of these concepts were copied by other operating systems which tend to show they are the correct way of doing things.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Small footprint:&#039;&#039;&#039; AmigaOS can work with 64 MB of memory. On disk, a default installation only takes around 200 MB.  The smaller footprint translates into a more responsive user experience given any hardware.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Straightforward operating system design:&#039;&#039;&#039; With a clear layout and easy to understand names  (Classes, Libs, Fonts, Prefs, Storage, etc.),  you can easily understand what everything in AmigaOS is and what it does for you.  Nothing is hidden from the user and the user is not restricted by AmigaOS.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;User configurable graphic interface:&#039;&#039;&#039;  Using the provided &amp;quot;preferences editors,&amp;quot; the user can dramatically reconfigure how AmigaOS looks, sounds, runs and responds to every user whim.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;File recognition based on file content:&#039;&#039;&#039;  You can name a file &#039;&#039;&#039;whatever you want&#039;&#039;&#039;, even without an extension. Examples: &amp;quot;my file&amp;quot; or &amp;quot;picture of Jay in Santa Clara&amp;quot;.  There is no need to add an extension to explain what the file is, like &amp;quot;.txt&amp;quot; or &amp;quot;.jpg&amp;quot;. AmigaOS really examines the &#039;&#039;&#039;file content&#039;&#039;&#039; to recognise what type of file it is.  &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Logical assignments:&#039;&#039;&#039; Easily set and use logical names names for directories located anywhere on your system.  For example, &amp;quot;Auto:&amp;quot; can point to your directory &amp;quot;car show pictures&amp;quot; buried on your media drive.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ram disk concept:&#039;&#039;&#039;  On AmigaOS there is a special disk called the &#039;&#039;&#039;Ram disk&#039;&#039;&#039; which represents a part of your computer memory. This area is not fixed. It automatically grows whenever you store files in it.  For example, it&#039;s a great place to unpack files to install from there, greatly speeding up the installation.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Command line and graphical user interfaces:&#039;&#039;&#039;  Both the the graphical user interface (GUI) and command line interface (where you type commands into a window with the keyboard)  can be used to manage AmigaOS, its programs and files.   Both interfaces are intergated with each other so you can easily use command lines from the GUI or open graphical elements from a command line.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;ARexx Ports:&#039;&#039;&#039;  Throughout AmigaOS and third party programs, &amp;quot;ARexx&amp;quot; message ports let one application talk with others so that apps work together to serve the user.  AmigaOS also provides the lightweight ARexx and modern Python programming languages that can control AmigaOS and applications with ARexx ports.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Resident Commands:&#039;&#039;&#039; Commands can be made resident, i.e., they are kept in memory so that they can be reused with no loading time.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Restart only the operating system:&#039;&#039;&#039; if you feel the need to restart the system, you can do so by restarting &#039;&#039;&#039;only AmigaOS&#039;&#039;&#039; and not the whole computer.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS platform targets ===&lt;br /&gt;
&lt;br /&gt;
While the original versions of AmigaOS ran on computers of the eighties using Motorola 68k series CPU chips, the current AmigaOS runs on computers using PowerPC processor chips [http://www.amigaos.net/content/72/supported-hardware hardware].  These can be older Amiga computers (also called &amp;quot;Classic Amigas&amp;quot;) with PPC &amp;quot;accelerator cards&amp;quot; or new generation Amiga PPC computers. &lt;br /&gt;
&lt;br /&gt;
In this guide, we will concentrate on the current AmigaOS running on the supported hardware:&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne X1000]] model by [http://www.a-eon.com A-Eon Technology]&lt;br /&gt;
&lt;br /&gt;
* [[AmigaOne 500]], Sam460, Sam440ep and Sam440-flex models by [http://www.acube-systems.com ACube Systems]&lt;br /&gt;
&lt;br /&gt;
* [[Pegasos II]] model by [http://www.bplan-gmbh.de bplan GmbH]&lt;br /&gt;
&lt;br /&gt;
* AmigaOne XE and micro-A1 models by [http://en.wikipedia.org/wiki/Eyetech Eyetech Group Ltd].&lt;br /&gt;
&lt;br /&gt;
* Amiga 4000(T), 3000(T) and 1200 models by Commodore Business Machines (when equipped with PowerPC accelerator cards).&lt;br /&gt;
&lt;br /&gt;
== How does AmigaOS work? - Concepts ==&lt;br /&gt;
&lt;br /&gt;
In this page we will discuss  [[UserDoc:How AmigaOS Works|how AmigaOS works]]:&lt;br /&gt;
&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#The_most_important_components|The most important components]] (Exec, AmigaDOS, Intuition...)&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#How_is_my_data_stored.3F|how files and data are stored]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#All_AmigaOS_components|all AmigaOS components are described]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#AmigaOS_boot_procedure|how AmigaOS is booted on your Amiga computer]]&lt;br /&gt;
* AmigaOS settings programs&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
== How to use AmigaOS? ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS is a collection of components that oversee the computer hardware &amp;amp; data and provide the user with easy, understandable tools to manage and use them.&lt;br /&gt;
&lt;br /&gt;
In the following [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS pages]] we will discuss the basic concepts:&lt;br /&gt;
&lt;br /&gt;
* how to use AmigaOS&lt;br /&gt;
* what the AmigaOS graphic user interface is composed of &lt;br /&gt;
* what interfaces AmigaOS provides, including the [[UserDoc:Workbench|Workbench]], the [[UserDoc:Shell|Shell]] or scripting languages.&lt;br /&gt;
&lt;br /&gt;
From the introduction page, you can continue with more detailed pages on the [[UserDoc:Workbench|Workbench]] and the [[AmigaDOS manual]] .   Now let&#039;s start with this [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS]].&lt;br /&gt;
&lt;br /&gt;
== Manuals ==&lt;br /&gt;
&lt;br /&gt;
[[UserDoc:AmigaOS File Systems|AmigaOS File Systems]] - AmigaOS File Systems&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Manual]] - AmigaOS Manual&lt;br /&gt;
&lt;br /&gt;
[[Bars &amp;amp; Pipes Professional]] - MIDI Sequencer&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=UserDoc:How_AmigaOS_Works&amp;diff=7759</id>
		<title>UserDoc:How AmigaOS Works</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=UserDoc:How_AmigaOS_Works&amp;diff=7759"/>
		<updated>2014-09-21T15:19:14Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* The Workbench */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As already mentioned, AmigaOS was a pioneer in the early days of personal computing in delivering sophistication that contemporary systems could only have dreamt of and pretended to offer. Today, AmigaOS continues to offer a straightforward elegance that seems to be overlooked in the development of other platforms. Thanks to the concepts behind AmigaOS, the system is easy to understand and to use by everyone.&lt;br /&gt;
&lt;br /&gt;
In this page we will explore all these concepts of AmigaOS. Also you will learn here the naming of all parts of the system.&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
AmigaOS is made of different components which are either mandatory i.e. AmigaOS will not work without them or components the user can choose to use or not. All these components can have one or mutiple interfaces a user or a developer can use to operate with the components and through them to control the operating system.&lt;br /&gt;
&lt;br /&gt;
= The most important components =&lt;br /&gt;
&lt;br /&gt;
== Exec, the AmigaOS kernel ==&lt;br /&gt;
&lt;br /&gt;
Exec is the kernel of AmigaOS. It is the component that pilots all other components. It is responsible of running programs, dealing with computer memory, managing low-level resources that programs may need. In other words, it organises everything to make the operating system run.&lt;br /&gt;
&lt;br /&gt;
It is made of different parts that cannot be moved outside the kernel: the scheduler, the memory pager and the 68k interpretive emulator.&lt;br /&gt;
&lt;br /&gt;
== AmigaDOS: the underlying system ==&lt;br /&gt;
&lt;br /&gt;
The word &amp;quot;DOS&amp;quot; was originally an acronym for &amp;quot;Disk Operating System&amp;quot;. Some say it should be &amp;quot;Disk Based Operating System&amp;quot; as it does a lot more than operate a disk and that it was really an operating system based (stored) on disks.  Some say it should be &amp;quot;Device Operating System&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The whole AmigaDOS system includes things such as:&lt;br /&gt;
&lt;br /&gt;
* A set of commands that can be used in the Shell window and elsewhere.&lt;br /&gt;
* A system for saving data to disk and retrieving it from disk.&lt;br /&gt;
* A system for filing data on disks.&lt;br /&gt;
* An interface for peripherals such as keyboards, monitors, printers, etc.&lt;br /&gt;
* A method of running programs&lt;br /&gt;
* A multitasking system for running more than one program at a time.&lt;br /&gt;
* etc. etc. etc.&lt;br /&gt;
&lt;br /&gt;
Read the [[AmigaDOS manual]] to understand and learn everything about AmigaDOS.&lt;br /&gt;
&lt;br /&gt;
== The Graphics library ==&lt;br /&gt;
&lt;br /&gt;
The Graphics library handles every low level graphic operations like designing pixels on the monitor, creating graphic elements (bobs, sprites) and also writing text output.&lt;br /&gt;
&lt;br /&gt;
== Intuition ==&lt;br /&gt;
&lt;br /&gt;
The Intuition library is responsible for every graphical objects: windows, screens, gadgets, mouse pointers... It lays between any graphic program and the graphics library.&lt;br /&gt;
&lt;br /&gt;
== The Workbench ==&lt;br /&gt;
&lt;br /&gt;
The Workbench is the graphical place where you will manage your computer and all your files. The name was chosen because the user will use tools to create and work with the computer.&lt;br /&gt;
&lt;br /&gt;
[[File:Wb.png|320px]]&lt;br /&gt;
&lt;br /&gt;
== The Shell ==&lt;br /&gt;
&lt;br /&gt;
While some people prefer to control the operating system using their mouse, others prefer using the keyboard. The shell is a text based window when you can type commands to execute actions in the operating system. In the shell the commands will display the results of their execution.&lt;br /&gt;
&lt;br /&gt;
== ARexx - inter-program communication by scripting ==&lt;br /&gt;
&lt;br /&gt;
The ARexx scripting language can be used to operate the Workbench and the most important Amiga applications from a script containing ARexx commands. This is extremely useful to perform repetitive tasks or to do what the controlled application was not even design to do.&lt;br /&gt;
After a learning curve, everybody can use ARexx as it is built in the system and the scripts can be executed immediately like any other tool.&lt;br /&gt;
&lt;br /&gt;
= How is my data stored? =&lt;br /&gt;
== Files ==&lt;br /&gt;
=== Executable files ===&lt;br /&gt;
Programs you can start are stored in executable files. They contain binary code directly understandable by the computer. They are files with an executable bit, a flag that shows AmigaOS that such file will do something when started.&lt;br /&gt;
An example is a music player. When you start this executable, the player opens and you can start playing music files.&lt;br /&gt;
&lt;br /&gt;
AmigaOS can run two different kinds of executable files: the AmigaOS native programs made for the PowerPC processor and programs created for the Motorola 68k processors. The laters are executed inside an emulation that transcripts them into PowerPC code.&lt;br /&gt;
&lt;br /&gt;
==== Scripts ====&lt;br /&gt;
&lt;br /&gt;
Scripts are text files containing a list of commands. So they are not strictly executables like &#039;&#039;binary code&#039;&#039; files but they can be executed by AmigaOS like if they were.&lt;br /&gt;
This is the case with AmigaDOS and ARexx scripts. These files need to have the executable bit, and the script bit.&lt;br /&gt;
&lt;br /&gt;
=== Data files ===&lt;br /&gt;
Files that are not executable are data files. These contain some data that will be manipulated by programs. Some examples are a music file, a video file or a text document.&lt;br /&gt;
&lt;br /&gt;
== Directories/Drawers ==&lt;br /&gt;
In order to organise things a bit, files are not all of them in the same place. We create directories which like drawers of a cabinet will store different files of the same kind.&lt;br /&gt;
Often the name &#039;&#039;directory&#039;&#039; is used when talking about the directory which is stored on a disk. The graphical interface of AmigaOS being called the Workbench, directories are often called &#039;&#039;drawers&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Note: directories are often called &#039;&#039;folders&#039;&#039; on other systems.&lt;br /&gt;
&lt;br /&gt;
== Disks, partitions and volumes ==&lt;br /&gt;
=== Disks ===&lt;br /&gt;
Disks are storage medium you can purchase on a computer store. We use them to store our files. They can be internal hard disks, external ones or a USB disk drive.&lt;br /&gt;
&lt;br /&gt;
=== Partitions ===&lt;br /&gt;
A disk is often very big and many users prefer to make it more organised. This is done virtually splitting the disk into several smaller parts. This operation is known as creating partitions on a disk.&lt;br /&gt;
&lt;br /&gt;
[[File:Partitions.png|Small part of Media Toolbox showing different partitions on the harddisk]]&lt;br /&gt;
&lt;br /&gt;
On this screenshot you can see one harddisk with many partitions. Each color corresponds to a different filesystem which defines how data is stored. Also you can see a greyed area which is a blank area on the disk i.e. no partition is defined at this position.&lt;br /&gt;
&lt;br /&gt;
=== Volumes ===&lt;br /&gt;
A partition is a physical area on a disk. To access it with AmigaOS we could read the physical data off the partition but it&#039;s not an easy way. To make it easier AmigaOS uses the concept of volumes. These are virtual representations of a partition. The volumes have a name so AmigaOS and therefore the user can access all files/directories stored on it in a very practical way: just by using its name.&lt;br /&gt;
&lt;br /&gt;
= How to identify files/directories =&lt;br /&gt;
&lt;br /&gt;
== On the Workbench ==&lt;br /&gt;
&lt;br /&gt;
The Workbench being graphical, a lot of things are understandable just by looking at them. That&#039;s why icons are often enough to understand what kind of object it represents: a file, a directory, a disk...&lt;br /&gt;
&lt;br /&gt;
In case you have a doubt, just look at the information on an icon. The Workbench will tell you the type of the object. It is displayed next to its name.&lt;br /&gt;
&lt;br /&gt;
== In a shell ==&lt;br /&gt;
&lt;br /&gt;
In a shell you need to issue the command &#039;&#039;&#039;list&#039;&#039;&#039; to see if an object is a file or a directory.&lt;br /&gt;
&lt;br /&gt;
[[File:Files-dirs-in-shell.png|The &#039;&#039;&#039;list&#039;&#039;&#039; command shows a file of 925678 bytes and two directories]]&lt;br /&gt;
&lt;br /&gt;
A file will be displayed with its size, whereas a directory will be displayed with the text &#039;&#039;&#039;Dir&#039;&#039;&#039; next to it.&lt;br /&gt;
&lt;br /&gt;
Also, as you can see on the screenshot, the list command displays other characteristics on these 3 items: the protection bits and the date they were updated the last time. The command also sums up what it just listed.&lt;br /&gt;
&lt;br /&gt;
= All AmigaOS components =&lt;br /&gt;
&lt;br /&gt;
AmigaOS is made of components that are needed as soon as the system starts or later when the user or the system needs them.&lt;br /&gt;
&lt;br /&gt;
== Kickstart modules ==&lt;br /&gt;
&lt;br /&gt;
These components are the heart of AmigaOS. Their duties is to do graphics, to handle discs or to handle all reads/writes to files. Also one of them is the AmigaOS kernel which is some kind of director handling the work of all other components.&lt;br /&gt;
These Kickstart modules are loaded at the beginning of the operating system boot process (read [[UserDoc:How_AmigaOS_Works#AmigaOS_boot_procedure|here]]). You can find all them in the &#039;&#039;&#039;Kickstart&#039;&#039;&#039; directory in the system volume. Here is a list:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory modules ===&lt;br /&gt;
&lt;br /&gt;
The following modules are required in any AmigaOS system. Without one of these, the system will not start.&lt;br /&gt;
&lt;br /&gt;
* kernel - The kernel works like a conductor in an orchestra. Its job is to make everything works together. It creates processes, handle memory usage, defines the way other components will access peripherals...etc. Note that the AmigaOS kernel is not based on any other kernel. It is a self made kernel that works since 1983.&lt;br /&gt;
* loader - this component handles the loading of all other kickstart modules&lt;br /&gt;
* battclock.resource.kmod - this module handles reading/writing the battery backed up clock which is used on all computers to keep the date and time&lt;br /&gt;
* bootimage - this is the boot picture. It is displayed during the start sequence of AmigaOS&lt;br /&gt;
* bootmenu.kmod - this component handles the Early Startup Menu the use can use to define some settings before starting AmigaOS&lt;br /&gt;
* con-handler.kmod - it directs the read and write requests to the console window, to a serial AUX: device or any other supported interface&lt;br /&gt;
* console.device.kmod - it opens a window and reads/writes text to and from that window&lt;br /&gt;
* diskboot.kmod - handles the booting of AmigaOS from a supported disk&lt;br /&gt;
* diskboot.config - this is a text file experienced users can modify to change the boot behaviour of AmigaOS&lt;br /&gt;
* dos.library.kmod - this module is a collection of functions that any program can use to perform actions on disks, files and directories&lt;br /&gt;
* elf.library.kmod - handles the loading of executable programs&lt;br /&gt;
* env-handler.kmod - handles the read/writes of environment variables&lt;br /&gt;
* FileSystem.resource.kmod - handles the use of the different filesystems&lt;br /&gt;
* gadtools.library.kmod - collection of functions used to create all graphic objects like gadgets, sliders, menus...&lt;br /&gt;
* gameport.device.kmod - handles the read/writes of game pads and joysticks&lt;br /&gt;
* graphics.library.kmod - collection of functions used to draw graphic elements on the monitor&lt;br /&gt;
* hunk.library.kmod - set of functions to read a data stream into memory&lt;br /&gt;
* input.device.kmod - handles of input events like keyboard events or mouse clicks&lt;br /&gt;
* intuition.library.kmod - collection of functions to create and handle all graphic elements (screens, windows, the mouse pointer...)&lt;br /&gt;
* layers.library.kmod - set of functions to be used to handle different layers in graphic operations&lt;br /&gt;
* keyboard.device.kmod - driver for the keyboard&lt;br /&gt;
* keymap.library.kmod - functions to handle different keymaps&lt;br /&gt;
* newlib.library.kmod - collection of functions to perform memory operations (allocating memory, copying memory areas... )&lt;br /&gt;
* nonvolatile.library.kmod - provides a simple means for an application developer to manage nonvolatile storage&lt;br /&gt;
* nvram.resource.kmod - handles the read/writes to the EEPROM chip present on many AmigaOS computers&lt;br /&gt;
* PCIGraphics.card - driver that supports the use of different graphic cards&lt;br /&gt;
* ram-handler.kmod - functions that handles the &#039;&#039;&#039;Ram disk:&#039;&#039;&#039; special disk&lt;br /&gt;
* ramdrive.device.kmod - device that allows the usage of the ramdrive device &#039;&#039;&#039;RAD:&#039;&#039;&#039; disk&lt;br /&gt;
* ramlib.kmod - loads disk based libraries and devices for exec.library&lt;br /&gt;
* rtg.library - library of functions perform lowlevel graphic operations on graphic cards&lt;br /&gt;
* shell.kmod - the AmigaOS command line interface&lt;br /&gt;
* strap.kmod - module that handles booting on different disk devices&lt;br /&gt;
* timer.device.kmod - driver to give access to timing functions&lt;br /&gt;
&lt;br /&gt;
=== Filesystem support ===&lt;br /&gt;
&lt;br /&gt;
These kickstart modules can be loaded or left aside. If you want to use a particular filesystem on your disk partitions, you need to load the corresponding filesystem module.&lt;br /&gt;
&lt;br /&gt;
* CDFileSystem - handles the CD-ROM disks with data stored in different formats: ISO9660, HFS...&lt;br /&gt;
* SmartFilesystem - allows to store data on partitions in SFS0 and SFS2&lt;br /&gt;
* JXFileSystem - allows to create partitions in JXFS&lt;br /&gt;
* FastFileSystem - allows the usage of partitions in FFS and FFS2 layouts&lt;br /&gt;
* diskcache.library.kmod - component required by the SmartFileSystem and JXFileSystem modules&lt;br /&gt;
&lt;br /&gt;
=== Hardware drivers ===&lt;br /&gt;
&lt;br /&gt;
==== Graphic cards drivers ====&lt;br /&gt;
&lt;br /&gt;
* 3dfxVoodoo.chip&lt;br /&gt;
* 3DLabsPermedia2.chip&lt;br /&gt;
* ATIRadeon.chip&lt;br /&gt;
* RadeonHD.chip&lt;br /&gt;
* siliconmotion502.chip&lt;br /&gt;
&lt;br /&gt;
==== Disk drivers ====&lt;br /&gt;
&lt;br /&gt;
Each of these drivers allow the use of disks connected to a disk controller. These files are named with the name of the controller they support. As an example, the &#039;&#039;&#039;sii3114ide.device.kmod&#039;&#039;&#039; allows to use disks connected on a &#039;&#039;&#039;Silicon Image SiI3114&#039;&#039;&#039; controller chip.&lt;br /&gt;
&lt;br /&gt;
* it8212ide.device.kmod&lt;br /&gt;
* lsi53c8xx.device.kmod&lt;br /&gt;
* sam460sata.device.kmod&lt;br /&gt;
* sii3112ide.device.kmod&lt;br /&gt;
* sii3512ide.device.kmod&lt;br /&gt;
* sii3114ide.device.kmod&lt;br /&gt;
* sii0680ide.device.kmod&lt;br /&gt;
* sii3132ide.device.kmod&lt;br /&gt;
&lt;br /&gt;
==== USB drivers ====&lt;br /&gt;
&lt;br /&gt;
* hub.usbfd&lt;br /&gt;
* usbsys.device&lt;br /&gt;
* usbresource.library&lt;br /&gt;
* ehci.usbhcd&lt;br /&gt;
* ohci.usbhcd&lt;br /&gt;
* uhci.usbhcd&lt;br /&gt;
* massstorage.usbfd&lt;br /&gt;
&lt;br /&gt;
==== Other drivers ====&lt;br /&gt;
&lt;br /&gt;
* bootkeyboard.usbfd - allows a USB keyboard to be used even before the USB stack is loaded&lt;br /&gt;
* bootmouse.usbfd - allows a USB mouse to be used even before the USB stack is loaded&lt;br /&gt;
* fpga.resource.kmod - allows to use the FPGA components which are present on some Amiga computers&lt;br /&gt;
* i2c.resource.kmod - allows to use the i2c interface present on some Amiga computers&lt;br /&gt;
* xena.resource.kmod - provides access to the Xena chip on the AmigaOne X1000&lt;br /&gt;
&lt;br /&gt;
=== Misc modules ===&lt;br /&gt;
&lt;br /&gt;
* petunia.library.kmod - this module contains the Just-In-Time emulator that allows AmigaOS to run programs made for the Motorola 68k processor&lt;br /&gt;
&lt;br /&gt;
== System components ==&lt;br /&gt;
&lt;br /&gt;
[[File:Workbench_directory_listing.png|frame|right|List of directories and files present at the root of any AmigaOS system]]&lt;br /&gt;
&lt;br /&gt;
Beside the kickstart modules, AmigaOS uses many different components that can be loaded only when used. These files are stored in different directories in the system volume.&lt;br /&gt;
Here is described a default AmigaOS installation.&lt;br /&gt;
&lt;br /&gt;
* C&lt;br /&gt;
This directory contains AmigaDOS &#039;&#039;&#039;C&#039;&#039;&#039;ommands&lt;br /&gt;
* Classes&lt;br /&gt;
contains different object elements easy to be used in any program: gadgets, requesters, graphic table, windows...&lt;br /&gt;
* Devs&lt;br /&gt;
contains definition for &#039;&#039;&#039;Dev&#039;&#039;&#039;ices&lt;br /&gt;
* Emulation&lt;br /&gt;
contains files used for the 68k emulation (though E-UAE)&lt;br /&gt;
* Fonts&lt;br /&gt;
contains various systems fonts&lt;br /&gt;
* Internet&lt;br /&gt;
contains a dialer to connect to Internet&lt;br /&gt;
* Kickstart&lt;br /&gt;
contains the kickstart modules&lt;br /&gt;
* L&lt;br /&gt;
contains hand&#039;&#039;&#039;l&#039;&#039;&#039;ers and filesystems&lt;br /&gt;
* Libs&lt;br /&gt;
contains dynamic &#039;&#039;&#039;Libr&#039;&#039;&#039;airies of functions&lt;br /&gt;
* Locale&lt;br /&gt;
contains all files used to localise the system (catalogs, keymaps...)&lt;br /&gt;
* MUI&lt;br /&gt;
contains the needed files for programs that use the MUI third party graphic interface&lt;br /&gt;
* Prefs&lt;br /&gt;
contains the preference programs used to customise AmigaOS&lt;br /&gt;
* S&lt;br /&gt;
contains the &#039;&#039;&#039;S&#039;&#039;&#039;cripts&lt;br /&gt;
* SObjs&lt;br /&gt;
contains .so shared object library files&lt;br /&gt;
* Storage&lt;br /&gt;
contains other optional files&lt;br /&gt;
* System&lt;br /&gt;
contains some programs used by the system itself (i.e. you don&#039;t need to run them yourself) or low-level programs like disk tools&lt;br /&gt;
* [[Utilities]]&lt;br /&gt;
contains several programs you can use to achieve some tasks on AmigaOS&lt;br /&gt;
&lt;br /&gt;
= Motorola 680x0 Emulators =&lt;br /&gt;
&lt;br /&gt;
For a long time Amigas have had the famous Motorola 680x0 processors as the central unit for execution. Unfortunately the time of the 680x0 series is passing in favor of other architectures. The new era of processors reached the Amiga some time ago, when expansion boards became available for extending the Classic systems with the raw power of a PowerPC processor.&lt;br /&gt;
&lt;br /&gt;
In the old operating system (AmigaOS 3.x) it was not possible to gain the full advantage of the new processors. The system itself and most of the applications required the original Motorola 680x0 processor. There was no 680x0 emulation available for the PowerPCs, so the 680x0 could not be &amp;quot;switched off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Thus the new processors remained as a powerful, but mostly unused adjunct to the main 680x0 processor. &amp;quot;Native&amp;quot; PowerPC programs were rare, and every time a PowerPC program called the system, a so called &amp;quot;context switch&amp;quot; occurred between the 680x0 and PowerPC code, often causing a large performance penalty.&lt;br /&gt;
&lt;br /&gt;
The new Amiga platform is based on the PowerPC processor family, therefore the new version of the AmigaOS has to smooth the transition from the 680x0 series, which is achieved by emulating the old processor architecture. The operating system itself is written almost 100 percent for the PowerPC processors, but the 680x0 legacy applications require an emulated 680x0 processor. &lt;br /&gt;
&lt;br /&gt;
== Two 680x0 Emulators ==&lt;br /&gt;
&lt;br /&gt;
In version 4.0 of AmigaOS, two different emulators were implemented; one is the successor of BlackBox emulation, it is an interpretive emulator, thus the emulation speed is mediocre. On the other hand it has a very low &amp;quot;reaction time&amp;quot;, and is ideal for time critical parts, such as interrupts.&lt;br /&gt;
&lt;br /&gt;
The other is Petunia, the &amp;quot;JIT emulator&amp;quot;. A fast, but less compatible way of emulation of the legacy Motorola processors. It is intended mainly for emulating applications, and therefore, when execution of the application leaves the bounds of the application&#039;s code segment, emulation falls back to the interpretive method, where it does its job and returns to the JIT emulation again.&lt;br /&gt;
&lt;br /&gt;
Dynamic recompilation (also called just-in-time compilation or simply JIT compilation) is a technique of translating foreign processor machine code to native machine code, &amp;quot;on the fly&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This technique is common nowadays, commonly applied in JAVA virtual machines, and it is also used with success in several emulators. In dynamic recompilation there is the possibility of runtime optimization of the emulated code by collecting statistics of the execution process. Therefore (theoretically) the final executed code can be even faster than the original code on its original processor.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
&lt;br /&gt;
Emulated opcodes:&lt;br /&gt;
* all user and supervisor level opcodes of the Motorola 68040&lt;br /&gt;
* all FPU opcodes of the Motorola 68881/68882 &lt;br /&gt;
&lt;br /&gt;
AmigaOS claims only 68020/68881 compatibility to applications because this is the safest compatibility level, but both emulators are compatible with the machine code up to the level of 68040/060 processors.&lt;br /&gt;
&lt;br /&gt;
At compile time, a low level flag and branch control analysis allows on-the-fly optimizations of compiled code.&lt;br /&gt;
&lt;br /&gt;
== Removing the JIT Emulator ==&lt;br /&gt;
&lt;br /&gt;
Using the dynamic translation requires a lot more memory than the interpretive emulation. The translated code needs to be stored somewhere, not to mention the data collection tables.&lt;br /&gt;
&lt;br /&gt;
If speed is not as important as the memory consumption of the system, then the JIT emulator can be removed, leaving the job to the interpretive emulator.&lt;br /&gt;
&lt;br /&gt;
Thanks to the modular design of AmigaOS kickstart, all you need to do is edit the &amp;quot;Sys:Kickstart/Kicklayout&amp;quot; file, simply put a semicolon (;) at the beginning of the module line of Petunia.library.kmod. After rebooting the system from cold, the JIT emulator will not be reloaded. Make sure that you alter the appropriate configuration in the Kicklayout file, there may be several alternative configurations, with different names like &amp;quot;DefaultJIT&amp;quot;, or &amp;quot;DefaultNoJIT&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Configuring the Emulators ==&lt;br /&gt;
&lt;br /&gt;
Petunia cooperates with a so called &amp;quot;black list&amp;quot;. By default Petunia emulates every 680x0 program or library that is loaded by DOS.library/LoadSeg function, but if an executable or library shows incompatibilities with Petunia, then it can be explicitly inhibited from the dynamic recompilation by specifying it in a list file.&lt;br /&gt;
&lt;br /&gt;
If an executable needs to be added to the list, then it can be done by extending the file &amp;quot;DEVS:applications.dos&amp;quot; with the &#039;&#039;&#039;Compatibility&#039;&#039;&#039; preferences program from the Prefs drawer of the system. Adding a program name to the list and checking it will prevent Petunia from emulating that program, and it will be interpreted instead by the built-in interpreter.&lt;br /&gt;
&lt;br /&gt;
Removing a program from the list or unchecking (thus allowing Petunia to emulate it again) can be done with the same preferences program.&lt;br /&gt;
&lt;br /&gt;
Please note: some programs consist of multiple executables (shared libraries, plugins). If you want to fully disable the translation of such programs, then every part must be added to the list.&lt;br /&gt;
&lt;br /&gt;
For example to disable UnArc fully, you would have to add all files from libs:xad and also xadmaster.library to the list. &lt;br /&gt;
&lt;br /&gt;
= AmigaOS boot procedure =&lt;br /&gt;
&lt;br /&gt;
Basically a computer with AmigaOS does the following when the power button is pushed:&lt;br /&gt;
&lt;br /&gt;
* [[File:Uboot.jpg|200px]]&lt;br /&gt;
the BIOS ([[UserDoc:BIOS|Uboot]] or [[UserDoc:BIOS|CFE]]) of the computer initialises the hardware: graphic card, USB ports... At this point, the monitor wakes up and the first information are displayed. This allows to see if hardware is correctly recognised. As an example you can see if a hard drive is correctly connected into the machine and your BIOS is correctly setup to make this drive useable.&lt;br /&gt;
* depending on how you setup the BIOS it will look on the harddisk to find the Second Level Booter (SLB). This program is stored on the first sectors of the disk. Whereas the BIOS does not know about AmigaOS disk structure, the SLB will be able to &#039;&#039;understand&#039;&#039; the AmigaOS partitions and files. In other words, it is the link between the BIOS and the rest of the boot procedure. Its goal is also to give you the ability to start several configurations present on the same drive.&lt;br /&gt;
* [[File:SLB.png|200px]]&lt;br /&gt;
the SLB will analyses all Amiga partitions on the disk it is installed on. It will read each [[UserDoc:kickstart_configuration|system configuration]] it finds on the partitions. It will show all available configurations for the user to select one to load.&lt;br /&gt;
The user can define many different kickstart configurations to choose from. Also both AmigaOS and Linux can be selected for boot.&lt;br /&gt;
* [[File:Kmods loading.png|200px]]&lt;br /&gt;
the SLB loads the kickstart files of the selected configuration and executes the &#039;&#039;&#039;Loader&#039;&#039;&#039; module&lt;br /&gt;
* &#039;&#039;&#039;Loader&#039;&#039;&#039; executes the kickstart modules (Exec, devices, libraries...)&lt;br /&gt;
* AmigaOS becomes alive displaying the AmigaOS boot picture on the monitor&lt;br /&gt;
* the AmigaDOS library executes the [[UserDoc:System_Scripts#startup-sequence|startup-sequence]] script found on the system volume&lt;br /&gt;
* the Startup-sequence will be executed and all commands it contains are executed. It means that starting from here the boot procedure is easy to follow and understand.&lt;br /&gt;
* the Workbench is started&lt;br /&gt;
&lt;br /&gt;
At this point the user can use his/her computer.&lt;br /&gt;
&lt;br /&gt;
= How to make a Bootable USB Memory Stick for AmigaOS 4.1 =&lt;br /&gt;
&lt;br /&gt;
By Julian Margetson (&amp;quot;Spectre660&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
Prerequisites:&lt;br /&gt;
* USB memory stick of 2 GB or less in size.&lt;br /&gt;
* It is best to only have one USB mass storage device connected while you are creating your bootable USB memory stick.&lt;br /&gt;
* Plug the USB memory stick into a USB port on your machine.&lt;br /&gt;
* Note that the device will be formatted so make sure that you use an empty memory stick or one that does not contain any data that you need or backup the contents before you begin.&lt;br /&gt;
&lt;br /&gt;
Procedure:&lt;br /&gt;
# You use Media Toolbox in the System: drawer to prepare the USB stick. On starting Media Toolbox select &#039;&#039;usbdisk.device&#039;&#039; as the device to use.&lt;br /&gt;
# Make certain that you have selected usbdisk.device and not any other device.&lt;br /&gt;
# Click on &amp;quot;Start&amp;quot;&lt;br /&gt;
# You will see the usb mass storage unit connected in a list.&lt;br /&gt;
# Make sure that the Unit type displayed for the USB memory stick is &amp;quot;Removable hard disk&amp;quot;&lt;br /&gt;
# Select that Unit by clicking on it.&lt;br /&gt;
# The first thing that you need to do is to install the RDB onto the USB Memory Stick.&lt;br /&gt;
# Click on the  &amp;quot;Install&amp;quot; button.&lt;br /&gt;
# A window Labeled &amp;quot;RDB/disk geometry editing&amp;quot; comes up.&lt;br /&gt;
## Towards the bottom of the window is the &amp;quot;AmigaOne boot code (SLB)&amp;quot; section.&lt;br /&gt;
## Select the &amp;quot;Install&amp;quot; button .&lt;br /&gt;
## A file requester  &amp;quot;Select AmigaOne Boot Code&amp;quot; now comes  up with the Drawer choice defaulting to &amp;quot;l:&amp;quot;&lt;br /&gt;
## Select file &amp;quot;slb_v2&amp;quot;. &lt;br /&gt;
## Select Ok.&lt;br /&gt;
## You are now returned to the &amp;quot;RDB/disk geometry editing window&amp;quot;.&lt;br /&gt;
## Select &amp;quot;Ok-accept changes&amp;quot;.&lt;br /&gt;
# You are now returned to the display showing the attached USB unit.&lt;br /&gt;
# Select &amp;quot;Edit partitions and Filesystems&amp;quot;. You will now see the Window &#039;Editing partitions for disk&amp;quot;&lt;br /&gt;
# Select &amp;quot;Add partition&amp;quot;&lt;br /&gt;
# This defaults to using the whole device as a single partition.&lt;br /&gt;
# It is possible to use create more partitions but for this tutorial we will only use one.&lt;br /&gt;
# You now need to give the partition a unique name (e.g. USB0 or something that is different from any of the existing partitions on your hard drive). This is done by changing the default DH0 in the &amp;quot;Name&amp;quot; box.&lt;br /&gt;
# Now make sure that the Boxes &amp;quot;Automount&amp;quot; and &amp;quot;Bootable&amp;quot; are  selected and show the &amp;quot;Tick mark&amp;quot;.&lt;br /&gt;
# You need to set &amp;quot;Boot priority&amp;quot; to higher than the boot priority of your hard drive boot partition(s). This is done by increasing Boot priority by clicking on the &amp;quot;+&amp;quot; to the right of the &amp;quot;boot priority&amp;quot; box. Normally you can set the boot priority to 2 .&lt;br /&gt;
# Next it is time to select the file system to use.&lt;br /&gt;
# Select &amp;quot;Select filesystem/edit details&amp;quot;.&lt;br /&gt;
# The Window &amp;quot;Editing details for partition &#039;USB0&#039;&amp;quot;  ,or whatever partition name you used, comes up.&lt;br /&gt;
## Select the file system that you are going to use by selecting the pull down menu under &amp;quot;Filesystem chooser&amp;quot;.&lt;br /&gt;
## Only filesystems SFS/00 or SFS/02 will work for a bootable device.&lt;br /&gt;
## The option that gives the most flexibility at the moment is SFS/00 as a USB stick in this format can be read and written to using another compatible system in the event that you need to make modifications after it is created without a booting AmigaOS 4.1 machine.&lt;br /&gt;
## Next select Blocksize from the &amp;quot;Blocksize&amp;quot; pull down menu. 512 is the correct size to use.&lt;br /&gt;
## Now Select &amp;quot;Ok-accept changes&amp;quot;.&lt;br /&gt;
## Your are now returned to the &amp;quot;Edit partitions for disk&amp;quot; window.&lt;br /&gt;
## Again select &amp;quot;Ok-accept changes&amp;quot;&lt;br /&gt;
# You are now returned to the window showing the USB mass storage unit list.&lt;br /&gt;
# Select &amp;quot;Save to disk&amp;quot;&lt;br /&gt;
# A requester pops up with the options &amp;quot;Yes, Save.&amp;quot; or &amp;quot;No!&amp;quot;&lt;br /&gt;
# Select the &amp;quot;Yes, save.&amp;quot; option.&lt;br /&gt;
# You now close Media Toolbox by clicking on the close icon (X) on the left of the Media Toolbox window.&lt;br /&gt;
# This will give you a requester advising that you need to reboot the machine for the changes to take effect. At this point you need to remove the USB memory stick for the machine. If you do not then the Machine will attempt boot from it before it is formatted and the required Kickstart and AmigaOS 4.1 files are copied to it.&lt;br /&gt;
# Select &amp;quot;Yes, reboot NOW!&amp;quot;.&lt;br /&gt;
# Once you have rebooted connect your USB Memory Stick to a USB port.&lt;br /&gt;
# A disk icon &amp;quot;USB0:Uninitialized&amp;quot; (or whatever partition name you used) appears on Workbench.&lt;br /&gt;
# You now need to format the device.&lt;br /&gt;
# To format Select this Icon and go to the Workbench &amp;quot;Icons&amp;quot; menu .&lt;br /&gt;
# Select &amp;quot;Format Disk&amp;quot;&lt;br /&gt;
# You can give the USB Memory Stick a unique name and  select whether you want a Trashcan or not.&lt;br /&gt;
# You can use either a full Format or a  Quick Format. Full Format may take a few minutes.&lt;br /&gt;
# Once formatted the USB Memory Stick is ready for you to copy the required files from you hard drive or AmigaOS Install CD to it in order to boot AmigaOS 4.1 from it.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=UserDoc:AmigaOS_File_Systems&amp;diff=7758</id>
		<title>UserDoc:AmigaOS File Systems</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=UserDoc:AmigaOS_File_Systems&amp;diff=7758"/>
		<updated>2014-09-21T15:10:29Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SFS\00 and SFS\02 support other block sizes but only 512 bytes should be used since it is slower with larger blocks. JXFS only supports 512 block size. Recovery tools are located in MediatToolbox in the SYS:System drawer. Always have a backup.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ AmigaOS File System Table&lt;br /&gt;
!&lt;br /&gt;
! FastFileSystem&amp;lt;br/&amp;gt;(FFS)&lt;br /&gt;
! FastFileSystem 2&amp;lt;br/&amp;gt;(FFS2)&lt;br /&gt;
! SmartFileSystem&amp;lt;br/&amp;gt;(SFS)&lt;br /&gt;
! SmartFileSystem 2&amp;lt;br/&amp;gt;(SFS2)&lt;br /&gt;
! JXFS&lt;br /&gt;
|-&lt;br /&gt;
| Bootable?&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| DosType&lt;br /&gt;
| DOS\03 0x444f5303&lt;br /&gt;
| DOS\07 0x444f5307&lt;br /&gt;
| SFS\00 0x53465300&lt;br /&gt;
| SFS\02 0x53465302&lt;br /&gt;
| JXF\04 0x4A584604&lt;br /&gt;
|-&lt;br /&gt;
| Max. Filename Length&lt;br /&gt;
| 30 characters&lt;br /&gt;
| 107 characters&lt;br /&gt;
| 107 characters&lt;br /&gt;
| 107 characters&lt;br /&gt;
| 107 characters&lt;br /&gt;
|-&lt;br /&gt;
| Max. Parition Size&lt;br /&gt;
| 2 TB to 128 TB&lt;br /&gt;
| 2 TB to 128 TB&lt;br /&gt;
| 128 GB&lt;br /&gt;
| 1 TB&lt;br /&gt;
| 256 TB&lt;br /&gt;
|-&lt;br /&gt;
| Max. File Size&lt;br /&gt;
| 4 GB - 2 Bytes&lt;br /&gt;
| 4 GB - 2 Bytes&lt;br /&gt;
| 4 GB - 2 Bytes&lt;br /&gt;
| 1 TB&lt;br /&gt;
| 256 TB&lt;br /&gt;
|-&lt;br /&gt;
| Supported Block Size&lt;br /&gt;
| 512 to 32768&lt;br /&gt;
| 512 to 32768&lt;br /&gt;
| only 512&lt;br /&gt;
| only 512&lt;br /&gt;
| only 512&lt;br /&gt;
|-&lt;br /&gt;
| Comments&lt;br /&gt;
| Legacy file system, not recommended for AmigaOS 4.x due to lack of long filename support. Can be used for bootloader partition in AmigaOS 4.x only setup.&lt;br /&gt;
| Current file system, bootable, can be used with AmigaOS 4.x, recovery tools available, not as fast as SFS, requires validation if disk error.&lt;br /&gt;
| Current file system, bootable, can be used with AmigaOS 4.x, some recovery tools available. Fast, does not require validation if disk error.&lt;br /&gt;
| Current file system, bootable, can be used with AmigaOS 4.x. Fast, does not require validation if disk error. No Recovery tools.&lt;br /&gt;
| Fastest but not backwards compatible with some 68K legacy software nor software which abuses DOS packets. No recovery tools.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=7757</id>
		<title>UserDoc:Main</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=UserDoc:Main&amp;diff=7757"/>
		<updated>2014-09-21T15:08:03Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaOS platform targets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Welcome to AmigaOS ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS was born in 1985 and delivered what contemporary personal computer operating systems could only dream of.  As the first &amp;quot;multimedia&amp;quot; operating system, it was trivial for AmigaOS computers to display animations while playing music and reading data from disks.  Such multimedia and multitasking finesse drew many people to this system.  Some of them are famous: [http://www.amigahistory.co.uk/warhol.html Andy Warhol], Sir Arthur C. Clarke, [http://www.polyphoto.com/upchug/AEcastro.html NASA], Hollywood and the TV broadcasting industry, and many others that thought [http://www.youtube.com/watch?v=PWeO5IkCssk only Amiga makes it possible].&lt;br /&gt;
&lt;br /&gt;
Today many people still think AmigaOS has something special that makes it more interesting and rewarding than other systems. This system allows the user to control the computer, not the other way around. It is a system you fully understand that is easier and more flexible to use.  In other words, AmigaOS is &#039;&#039;&#039;more fun&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS:  The flexible operating system ===&lt;br /&gt;
AmigaOS is an operating system:  a collection of efficient programs written to start the computer, let the user control the computer, and present feedback to the user.&lt;br /&gt;
&lt;br /&gt;
AmigaOS is designed with ease of use and flexibility in mind. To begin with, AmigaOS provides a clear view of your computer, your applications and files. A number of methods are available to let your computer serve you, whether graphically with a mouse, using the &amp;quot;Shell&amp;quot; command line, or by some other means the user prefers.&lt;br /&gt;
&lt;br /&gt;
AmigaOS strives to avoid stupid limitations that can be found on other systems. AmigaOS users can organise their files the way they like. There are few limits on file hierarchy, locations and file names.  Drives don&#039;t have to be named with a letter or cryptic names (such as C:, or sda1), your files don&#039;t have to reside in your &amp;quot;Documents&amp;quot; folder and your hard drives aren&#039;t hidden from you. If you&#039;re not writing to drives and you want to &amp;quot;shut down&amp;quot;, why wait for the OS to allow that?  With AmigaOS, just hit the power switch. Done.&lt;br /&gt;
&lt;br /&gt;
An Amiga does not start with pre-installed applications serving some sales conglomerate, marketing organization or their big brother. AmigaOS does not do actions behind the user&#039;s back. As unique as it is today, the AmigaOS computer serves the user and not the other way around. With one of the largest proportions of user-programmers around, the trustworthy AmigaOS user-friendly ethic is mirrored in AmigaOS applications.&lt;br /&gt;
&lt;br /&gt;
Since the first versions more than twenty-five years ago, AmigaOS has also been designed to serve efficiently. Optimizing  applications and OS code has always been the goal of programmers and developers of this operating system.  The result is an operating system and applications that take less space on your hard drives, waste less time loading, consume less memory, require less processing power, and respond more quickly to the user.&lt;br /&gt;
&lt;br /&gt;
And every update of AmigaOS doesn&#039;t demand you must buy newer, more powerful hardware. AmigaOS currently runs on twenty year old 200MHz computers or brand new dual core 1,800MHz computers.  It&#039;s the user&#039;s choice how they want to &#039;&#039;&#039;enjoy&#039;&#039;&#039; AmigaOS.&lt;br /&gt;
&lt;br /&gt;
=== Some AmigaOS features ===&lt;br /&gt;
Here are some of the features of AmigaOS that make it easy to control your computer. Some of these concepts were copied by other operating systems which tend to show they are the correct way of doing things.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Small footprint:&#039;&#039;&#039; AmigaOS can work with 64 MB of memory. On disk, a default installation only takes around 200 MB.  The smaller footprint translates into a more responsive user experience given any hardware.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Straightforward operating system design:&#039;&#039;&#039; With a clear layout and easy to understand names  (Classes, Libs, Fonts, Prefs, Storage, etc.),  you can easily understand what everything in AmigaOS is and what it does for you.  Nothing is hidden from the user and the user is not restricted by AmigaOS.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;User configurable graphic interface:&#039;&#039;&#039;  Using the provided &amp;quot;preferences editors,&amp;quot; the user can dramatically reconfigure how AmigaOS looks, sounds, runs and responds to every user whim.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;File recognition based on file content:&#039;&#039;&#039;  You can name a file &#039;&#039;&#039;whatever you want&#039;&#039;&#039;, even without an extension. Examples: &amp;quot;my file&amp;quot; or &amp;quot;picture of Jay in Santa Clara&amp;quot;.  There is no need to add an extension to explain what the file is, like &amp;quot;.txt&amp;quot; or &amp;quot;.jpg&amp;quot;. AmigaOS really examines the &#039;&#039;&#039;file content&#039;&#039;&#039; to recognise what type of file it is.  &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Logical assignments:&#039;&#039;&#039; Easily set and use logical names names for directories located anywhere on your system.  For example, &amp;quot;Auto:&amp;quot; can point to your directory &amp;quot;car show pictures&amp;quot; buried on your media drive.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Ram disk concept:&#039;&#039;&#039;  On AmigaOS there is a special disk called the &#039;&#039;&#039;Ram disk&#039;&#039;&#039; which represents a part of your computer memory. This area is not fixed. It automatically grows whenever you store files in it.  For example, it&#039;s a great place to unpack files to install from there, greatly speeding up the installation.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Command line and graphical user interfaces:&#039;&#039;&#039;  Both the the graphical user interface (GUI) and command line interface (where you type commands into a window with the keyboard)  can be used to manage AmigaOS, its programs and files.   Both interfaces are intergated with each other so you can easily use command lines from the GUI or open graphical elements from a command line.&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;ARexx Ports:&#039;&#039;&#039;  Throughout AmigaOS and third party programs, &amp;quot;ARexx&amp;quot; message ports let one application talk with others so that apps work together to serve the user.  AmigaOS also provides the lightweight ARexx and modern Python programming languages that can control AmigaOS and applications with ARexx ports.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Resident Commands:&#039;&#039;&#039; Commands can be made resident, i.e., they are kept in memory so that they can be reused with no loading time.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Restart only the operating system:&#039;&#039;&#039; if you feel the need to restart the system, you can do so by restarting &#039;&#039;&#039;only AmigaOS&#039;&#039;&#039; and not the whole computer.&lt;br /&gt;
&lt;br /&gt;
=== AmigaOS platform targets ===&lt;br /&gt;
&lt;br /&gt;
While the original versions of AmigaOS ran on computers of the eighties using Motorola 68k series CPU chips, the current AmigaOS runs on computers using PowerPC processor chips [http://www.amigaos.net/content/72/supported-hardware hardware].  These can be older Amiga computers (also called &amp;quot;Classic Amigas&amp;quot;) with PPC &amp;quot;accelerator cards&amp;quot; or new generation Amiga PPC computers. &lt;br /&gt;
&lt;br /&gt;
In this guide, we will concentrate on the current AmigaOS running on the supported hardware:&lt;br /&gt;
&lt;br /&gt;
[[AmigaOne X1000]] model by [http://www.a-eon.com A-Eon Technology]&lt;br /&gt;
&lt;br /&gt;
[[AmigaOne 500]], Sam460, Sam440ep and Sam440-flex models by [http://www.acube-systems.com ACube Systems]&lt;br /&gt;
&lt;br /&gt;
[[Pegasos II]] model by [http://www.bplan-gmbh.de bplan GmbH]&lt;br /&gt;
&lt;br /&gt;
AmigaOne XE and micro-A1 models by [http://en.wikipedia.org/wiki/Eyetech Eyetech Group Ltd].&lt;br /&gt;
&lt;br /&gt;
Amiga 4000(T), 3000(T) and 1200 models by Commodore Business Machines (when equipped with PowerPC accelerator cards).&lt;br /&gt;
&lt;br /&gt;
== How does AmigaOS work? - Concepts ==&lt;br /&gt;
&lt;br /&gt;
In this page we will discuss  [[UserDoc:How AmigaOS Works|how AmigaOS works]]:&lt;br /&gt;
&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#The_most_important_components|The most important components]] (Exec, AmigaDOS, Intuition...)&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#How_is_my_data_stored.3F|how files and data are stored]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#All_AmigaOS_components|all AmigaOS components are described]]&lt;br /&gt;
* [[UserDoc:How_AmigaOS_Works#AmigaOS_boot_procedure|how AmigaOS is booted on your Amiga computer]]&lt;br /&gt;
* AmigaOS settings programs&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
== How to use AmigaOS? ==&lt;br /&gt;
&lt;br /&gt;
AmigaOS is a collection of components that oversee the computer hardware &amp;amp; data and provide the user with easy, understandable tools to manage and use them.&lt;br /&gt;
&lt;br /&gt;
In the following [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS pages]] we will discuss the basic concepts:&lt;br /&gt;
&lt;br /&gt;
* how to use AmigaOS&lt;br /&gt;
* what the AmigaOS graphic user interface is composed of &lt;br /&gt;
* what interfaces AmigaOS provides, including the [[UserDoc:Workbench|Workbench]], the [[UserDoc:Shell|Shell]] or scripting languages.&lt;br /&gt;
&lt;br /&gt;
From the introduction page, you can continue with more detailed pages on the [[UserDoc:Workbench|Workbench]] and the [[AmigaDOS manual]] .   Now let&#039;s start with this [[UserDoc:Introduction to AmigaOS|Introduction to AmigaOS]].&lt;br /&gt;
&lt;br /&gt;
== Manuals ==&lt;br /&gt;
&lt;br /&gt;
[[UserDoc:AmigaOS File Systems|AmigaOS File Systems]] - AmigaOS File Systems&lt;br /&gt;
&lt;br /&gt;
[[AmigaOS Manual]] - AmigaOS Manual&lt;br /&gt;
&lt;br /&gt;
[[Bars &amp;amp; Pipes Professional]] - MIDI Sequencer&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7756</id>
		<title>AmigaDOS manual</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7756"/>
		<updated>2014-09-21T14:55:10Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaDOS commands */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AmigaDOS manual ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
Many beginners are rather confused by the differences between the terms &amp;quot;AmigaDOS&amp;quot; and &amp;quot;Shell&amp;quot;.  Some people think they just use the Shell or they are just using AmigaDOS commands in a shell window.&lt;br /&gt;
&lt;br /&gt;
The AmigaDOS software is contained in files stored on the system partition. They are all binaries, either programs directly usable by the user, or libraries and other sets of functions usable by any program or AmigaDOS itself.&lt;br /&gt;
&lt;br /&gt;
You can think of AmigaDOS as a complete system for operating the computer and its peripherals. In order to talk with AmigaDOS the user will use a shell to type commands and get the results from them.&lt;br /&gt;
&lt;br /&gt;
=== The Shell ===&lt;br /&gt;
&lt;br /&gt;
The Shell is a &amp;quot;command line interface&amp;quot; (CLI) that provides a lot of features to interact with the operating system.&lt;br /&gt;
Simply put, it means that you use an &amp;quot;interface&amp;quot; (in this case a shell window) to send commands to the computer which will use this same interface to display results to your commands.&lt;br /&gt;
&lt;br /&gt;
For historical reasons, you will still find references to the CLI in AmigaOS but this is really a shell that is used everywhere in the system.&lt;br /&gt;
&lt;br /&gt;
[[File:Shell.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now learn the basics and more complex uses of the [[UserDoc:Shell|AmigaOS shell]].&lt;br /&gt;
&lt;br /&gt;
=== AmigaDOS commands ===&lt;br /&gt;
&lt;br /&gt;
For commands and arguments used in the AmigaOS command line (&amp;quot;CLI&amp;quot;), please see the [[AmigaOS Manual: AmigaDOS|AmigaDOS pages]] (currently historic documentation - to be updated).&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7755</id>
		<title>AmigaDOS manual</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7755"/>
		<updated>2014-09-21T14:53:51Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaDOS commands */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AmigaDOS manual ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
Many beginners are rather confused by the differences between the terms &amp;quot;AmigaDOS&amp;quot; and &amp;quot;Shell&amp;quot;.  Some people think they just use the Shell or they are just using AmigaDOS commands in a shell window.&lt;br /&gt;
&lt;br /&gt;
The AmigaDOS software is contained in files stored on the system partition. They are all binaries, either programs directly usable by the user, or libraries and other sets of functions usable by any program or AmigaDOS itself.&lt;br /&gt;
&lt;br /&gt;
You can think of AmigaDOS as a complete system for operating the computer and its peripherals. In order to talk with AmigaDOS the user will use a shell to type commands and get the results from them.&lt;br /&gt;
&lt;br /&gt;
=== The Shell ===&lt;br /&gt;
&lt;br /&gt;
The Shell is a &amp;quot;command line interface&amp;quot; (CLI) that provides a lot of features to interact with the operating system.&lt;br /&gt;
Simply put, it means that you use an &amp;quot;interface&amp;quot; (in this case a shell window) to send commands to the computer which will use this same interface to display results to your commands.&lt;br /&gt;
&lt;br /&gt;
For historical reasons, you will still find references to the CLI in AmigaOS but this is really a shell that is used everywhere in the system.&lt;br /&gt;
&lt;br /&gt;
[[File:Shell.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now learn the basics and more complex uses of the [[UserDoc:Shell|AmigaOS shell]].&lt;br /&gt;
&lt;br /&gt;
=== AmigaDOS commands ===&lt;br /&gt;
&lt;br /&gt;
For commands and arguments used in the AmigaOS command line (&amp;quot;CLI&amp;quot;), please see the [[AmigaOS Manual: AmigaDOS|AmigaDOS pages]].&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7754</id>
		<title>AmigaDOS manual</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmigaDOS_manual&amp;diff=7754"/>
		<updated>2014-09-21T14:52:19Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* AmigaDOS manual */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AmigaDOS manual ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
Many beginners are rather confused by the differences between the terms &amp;quot;AmigaDOS&amp;quot; and &amp;quot;Shell&amp;quot;.  Some people think they just use the Shell or they are just using AmigaDOS commands in a shell window.&lt;br /&gt;
&lt;br /&gt;
The AmigaDOS software is contained in files stored on the system partition. They are all binaries, either programs directly usable by the user, or libraries and other sets of functions usable by any program or AmigaDOS itself.&lt;br /&gt;
&lt;br /&gt;
You can think of AmigaDOS as a complete system for operating the computer and its peripherals. In order to talk with AmigaDOS the user will use a shell to type commands and get the results from them.&lt;br /&gt;
&lt;br /&gt;
=== The Shell ===&lt;br /&gt;
&lt;br /&gt;
The Shell is a &amp;quot;command line interface&amp;quot; (CLI) that provides a lot of features to interact with the operating system.&lt;br /&gt;
Simply put, it means that you use an &amp;quot;interface&amp;quot; (in this case a shell window) to send commands to the computer which will use this same interface to display results to your commands.&lt;br /&gt;
&lt;br /&gt;
For historical reasons, you will still find references to the CLI in AmigaOS but this is really a shell that is used everywhere in the system.&lt;br /&gt;
&lt;br /&gt;
[[File:Shell.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now learn the basics and more complex uses of the [[UserDoc:Shell|AmigaOS shell]].&lt;br /&gt;
&lt;br /&gt;
=== AmigaDOS commands ===&lt;br /&gt;
&lt;br /&gt;
C commands, command line arguments, please see the [[AmigaOS Manual: AmigaDOS|AmigaDOS pages]].&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7694</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7694"/>
		<updated>2014-05-12T03:24:58Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* General Issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga (at the port number&lt;br /&gt;
following the colon - &amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   Webpages?  More?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an image file&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can process them and respond to web visitors.  To dig deeper you can&lt;br /&gt;
search the many sources online or in your local bookstore on HTTP communications&lt;br /&gt;
and the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server can optionally send diagnostics output so you know what requests are&lt;br /&gt;
being received and how they are responded to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also no reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that you could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and requests are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server program will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each instance of the internet server handles each incoming request, quickly&lt;br /&gt;
relays the necessary information from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there are RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities - that isn&#039;t reflected in the simple examples above.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7693</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7693"/>
		<updated>2014-05-12T03:22:22Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Just Webpages? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga (at the port number&lt;br /&gt;
following the colon - &amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   Webpages?  More?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an image file&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can process them and respond to web visitors.  To dig deeper you can&lt;br /&gt;
search the many sources online or in your local bookstore on HTTP communications&lt;br /&gt;
and the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server can optionally send diagnostics output so you know what requests are&lt;br /&gt;
being received and how they are responded to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also no reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that you could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and requests are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server program will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each instance of the internet server handles each incoming request, quickly&lt;br /&gt;
relays the necessary information from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there are RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7692</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7692"/>
		<updated>2014-05-12T03:11:42Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Where to go?   Webpages?  More? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga (at the port number&lt;br /&gt;
following the colon - &amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   Webpages?  More?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an image file&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can process them and respond to web visitors.  To dig deeper you can&lt;br /&gt;
search the many sources online or in your local bookstore on HTTP communications&lt;br /&gt;
and the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server can optionally send diagnostics output so you know what requests are&lt;br /&gt;
being received and how they are responded to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7691</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7691"/>
		<updated>2014-05-12T03:09:33Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Where to go?   More Webpages? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga (at the port number&lt;br /&gt;
following the colon - &amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   Webpages?  More?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an image file&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can process them and respond to web visitors.  To dig deeper you can&lt;br /&gt;
search the many sources online or in your local bookstore on HTTP communications&lt;br /&gt;
and the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7690</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7690"/>
		<updated>2014-05-12T03:06:53Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Let&amp;#039;s See Our Server! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga (at the port number&lt;br /&gt;
following the colon - &amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7689</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7689"/>
		<updated>2014-05-12T02:58:38Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Roadshow Configuration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide, as described below.  Both of these can&lt;br /&gt;
be configured using Internet Prefs.  You can also make this configuration by&lt;br /&gt;
manually editing the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation/Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could manually be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can otherwise make this adjustment to Roadshow&#039;s server list by manually adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7688</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7688"/>
		<updated>2014-05-12T02:47:37Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* EXAMPLE TWO:  IPserver.c */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this server out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7687</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7687"/>
		<updated>2014-05-12T02:30:54Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Respond to the Visitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of strings (in the &#039;&#039;&#039;lines&#039;&#039;&#039; array)&lt;br /&gt;
of a very simple webpage through Roadshow, to our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
While our two samples of code simply receive and respond to an incoming web request,&lt;br /&gt;
one can imagine where this code can be expanded provide useful service and more&lt;br /&gt;
complex interactions.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7686</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7686"/>
		<updated>2014-05-12T00:27:02Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Receive the Request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use &amp;quot;DebugPrintf&amp;quot; for diagnostics output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7685</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7685"/>
		<updated>2014-05-12T00:23:14Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Receive the Request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
of the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see so long a request with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use another protocol, the processing of&lt;br /&gt;
the received data would likely happe3n elsewhere.&lt;br /&gt;
&lt;br /&gt;
As you see, we do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  With the above code, the diagnostics&lt;br /&gt;
output will show the entire incoming request on the serial port.  Of course,&lt;br /&gt;
there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7684</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7684"/>
		<updated>2014-05-12T00:15:23Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Ideas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
* Check stock quotes from a financial site.&lt;br /&gt;
* Get package tracking information from a shipping site.&lt;br /&gt;
* Check for new emails on a POP email server.&lt;br /&gt;
* Convert currencies with a financial or travel web site.&lt;br /&gt;
* Check for files on an FTP server.&lt;br /&gt;
* Send messages with a SMTP email server.&lt;br /&gt;
* Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7683</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7683"/>
		<updated>2014-05-12T00:06:27Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Ideas */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 * Check stock quotes from a financial site.&lt;br /&gt;
 * Get package tracking information from a shipping site.&lt;br /&gt;
 * Check for new emails on a POP email server.&lt;br /&gt;
 * Convert currencies with a financial or travel web site.&lt;br /&gt;
 * Check for files on an FTP server.&lt;br /&gt;
 * Send messages with a SMTP email server.&lt;br /&gt;
 * Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7682</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7682"/>
		<updated>2014-05-11T23:44:42Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Designing Your Network Client */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used, in formatting the request and processing&lt;br /&gt;
received data.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
and more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or one which invites such&lt;br /&gt;
connections (some even publish API&#039;s and example code for you to use),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external elements, your&lt;br /&gt;
code should provide for the possibility things may not&lt;br /&gt;
succeed or the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make modifying those things easy as possible (even&lt;br /&gt;
by the user?).&lt;br /&gt;
&lt;br /&gt;
For example, the parsing strings could be kept in the program&#039;s tooltype&lt;br /&gt;
or a config text file, you could provide a GUI for managing the strings, or&lt;br /&gt;
employ an external, editable ARexx macro for processing.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7681</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7681"/>
		<updated>2014-05-11T23:25:38Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* An Internet Client */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Such applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one3 opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
When Roadshow gets online, it creates a virtual TCP: device.  To open&lt;br /&gt;
a connection, one opens a virtual file on the TCP: device to the URL and&lt;br /&gt;
port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a web server of the &amp;quot;Weather Underground&amp;quot;&lt;br /&gt;
website.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protocol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of an  &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a web server, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets mimic submitting a &amp;quot;GET&amp;quot; request (as if from IBrowse).&lt;br /&gt;
A simple HTTP version 1.1 GET request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;&amp;lt;path&amp;gt;&#039;&#039;&#039; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;domain&amp;gt;&#039;&#039;&#039; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their path name for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Such a GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our open&lt;br /&gt;
TCP: file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The empty line at the end (with just a &amp;quot;\r\n&amp;quot;) completes the&lt;br /&gt;
GET request, after which the server will reply to your program.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the web server, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server in this example, you can&lt;br /&gt;
combine the domain and path values above and enter them in your web&lt;br /&gt;
browser&#039;s URL string gadget, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded in your browser, viewing the page source (f.e., IBrowse&lt;br /&gt;
menu item &amp;quot;Page/Display Source...&amp;quot;) will show you the same HTML text that your&lt;br /&gt;
program will receive after sending the GET request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your application can parse the received lines for whatever&lt;br /&gt;
data your application is trying to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want to find.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of the above elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for an IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned WeatherUnderground.com web page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.  Should this happen, you get to use what&lt;br /&gt;
you learned above to upgrade or replace this example.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public web servers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any web browser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecessary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demonstrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?  The AmiNet &lt;br /&gt;
also has many examples of simple clients (with C source code or in&lt;br /&gt;
readable ARexx) that can be studied for means and methods.&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then responds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a fail-safe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&#039;&#039;Italic text&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Critically, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is critically important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized path names and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using inter-process&lt;br /&gt;
communications (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosyncrasies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interrupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a server should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7521</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7521"/>
		<updated>2014-04-13T20:56:15Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* General Issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implrementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should consider in developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, it&#039;s not guaranteed &lt;br /&gt;
the next transaction your server receives is that logged-in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and status of a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things, if possible.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7520</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7520"/>
		<updated>2014-04-13T20:51:24Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Just Webpages? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server pair of applications that just&lt;br /&gt;
talked with each other.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, here are some&lt;br /&gt;
basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or unfettered file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one also has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine for&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request to an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains continuously running&lt;br /&gt;
while each of internet server instance handles an incoming request, gets the information it&lt;br /&gt;
needs from the master program and quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point usage requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.  That&#039;s beyond the scope of this article.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved with the&lt;br /&gt;
handling of network user load that should be explored in implementing a serious&lt;br /&gt;
server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more a complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  With each new client&lt;br /&gt;
and platform encountered, the more important implrementation details of a&lt;br /&gt;
protocol are likely to be.&lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7519</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7519"/>
		<updated>2014-04-13T20:37:56Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Where to go?   More Webpages? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, performs no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot;) tells the server what the browser is looking for.&lt;br /&gt;
For example, if you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers actually make two connections to the&lt;br /&gt;
server, with one of them saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is requesting your server send an icon&lt;br /&gt;
that it can display on the browser tab.  Just like that, anything in the URL&lt;br /&gt;
after the machine&#039;s network name (or IP address) and the port number&lt;br /&gt;
is taken as a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.  Of course, you should make sure your&lt;br /&gt;
server continues outputting the request contents so you know what your server&lt;br /&gt;
is getting and should respond to.&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7518</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7518"/>
		<updated>2014-04-13T20:28:02Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Let&amp;#039;s See Our Server! */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have the IP address or defined host&lt;br /&gt;
name for your Amiga running the test server program.  The URL should&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser and send it the preset webpage.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7517</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7517"/>
		<updated>2014-04-13T20:24:54Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Servers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Naturally, you should enter the server program path &amp;amp; name for your own system.&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are correctly configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7516</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7516"/>
		<updated>2014-04-13T20:21:20Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Servers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
their type, wait method and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7515</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7515"/>
		<updated>2014-04-13T20:19:10Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Services */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
types and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7514</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7514"/>
		<updated>2014-04-13T20:17:28Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* EXMAPLE TWO:  IPserver.c */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
to check if the program was run from the Workbench and to tell the user not to.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving your Amiga&#039;s internet visitors.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this server and where visitors will find it.&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
type and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7513</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7513"/>
		<updated>2014-04-13T20:13:49Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Respond to the Visitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  Then we &amp;quot;flush&amp;quot; the output&lt;br /&gt;
stream and quit our program.&lt;br /&gt;
&lt;br /&gt;
The request was received, our little webpage sent, we quit and Roadshow takes&lt;br /&gt;
care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
that tells a user this program wasn&#039;t meant to be run from the Workbench.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving internet visitors to your Amiga.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
type and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7512</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7512"/>
		<updated>2014-04-13T20:10:57Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Respond to the Visitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use another &amp;quot;standard&amp;quot; stream (know as &amp;quot;stdout&amp;quot;) to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdout&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
diagnostic print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  At then end we &amp;quot;flush&amp;quot;&lt;br /&gt;
the output and quit our program.  The request was received, our webpage&lt;br /&gt;
sent and Roadshow takes care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
that tells a user this program wasn&#039;t meant to be run from the Workbench.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving internet visitors to your Amiga.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
type and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7511</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7511"/>
		<updated>2014-04-13T20:09:15Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Respond to the Visitor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use the same &amp;quot;stdin&amp;quot; stream to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdin&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
doagnostics print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
In this example, we create a basic loop that feeds a predefined series of lines&lt;br /&gt;
of a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  At then end we &amp;quot;flush&amp;quot;&lt;br /&gt;
the output and quit our program.  The request was received, our webpage&lt;br /&gt;
sent and Roadshow takes care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
that tells a user this program wasn&#039;t meant to be run from the Workbench.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving internet visitors to your Amiga.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
type and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
	<entry>
		<id>https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7510</id>
		<title>AmiWest 2013 Lesson 4</title>
		<link rel="alternate" type="text/html" href="https://wiki.amigaos.net/w/index.php?title=AmiWest_2013_Lesson_4&amp;diff=7510"/>
		<updated>2014-04-13T20:07:22Z</updated>

		<summary type="html">&lt;p&gt;Paul Sadlik: /* Receive the Request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simple IP Clients &amp;amp; Servers =&lt;br /&gt;
&lt;br /&gt;
Simple network access is easy!&lt;br /&gt;
&lt;br /&gt;
Developing applications that use TCP/IP &amp;quot;sockets&amp;quot; for network communications&lt;br /&gt;
have a reputation of being a challenging task.  But AmigaOS and its Roadshow &lt;br /&gt;
TCP/IP stack provides a couple of built-in shorthand mechanisms for easily&lt;br /&gt;
creating simple network clients and servers: the TCP: handler and Roadshow&#039;s&lt;br /&gt;
Superserver.&lt;br /&gt;
&lt;br /&gt;
Using these Roadshow shortcuts, creating simple network client and server&lt;br /&gt;
applications for single user or light-duty uses is no more complicated than&lt;br /&gt;
reading or writing a file.  The real challenge is understanding the protocol&lt;br /&gt;
to be used (f.e. HTTP communications with web browsers) and being careful not&lt;br /&gt;
to create a security risk on your or another user&#039;s Amiga.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Client==&lt;br /&gt;
&lt;br /&gt;
First, we will look at creating a small client to retrieve some simple&lt;br /&gt;
information from an Internet website.  Similar applications could be made&lt;br /&gt;
to retrieve basic information like stock quotes, email contents, &lt;br /&gt;
server conditions or other basic interactions.  Aminet has a number&lt;br /&gt;
examples of such clients written in ARexx that use the TCP: device&lt;br /&gt;
that can be examined.&lt;br /&gt;
&lt;br /&gt;
The Roadshow shortcut we will use is its built-in TCP: handler.  This is&lt;br /&gt;
mechanism that creates a virtual filesystem device  (&amp;quot;TCP:&amp;quot;) whenever&lt;br /&gt;
Roadhsow gets online.  To interact with a remote server, one just opens a&lt;br /&gt;
file with the name being the URL of the server and port to be accessed.&lt;br /&gt;
&lt;br /&gt;
===Connect to the Server===&lt;br /&gt;
&lt;br /&gt;
To begin with, one opens a connection to the internet server as if one&lt;br /&gt;
were opening a file.  As described above, when Roadshow gets online, it&lt;br /&gt;
creates a virtual TCP: device.  To open a connection, one opens a file&lt;br /&gt;
to the URL and port in question using this format:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
TCP:&amp;lt;server URL&amp;gt;/&amp;lt;port number&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For example, to connect to the website &amp;quot;www.wunderground.com&amp;quot; one would&lt;br /&gt;
use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fileh = fopen(&amp;quot;TCP:www.wunderground.com/80&amp;quot;,&amp;quot;r+&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The file name starts with TCP:, then the website URL and finally the&lt;br /&gt;
port number - here &amp;quot;80&amp;quot; is site&#039;s HTTP port (used by almost all websites).&lt;br /&gt;
&lt;br /&gt;
Typically, the port number reflects the type of port or protocol that&lt;br /&gt;
is to be used.  Such protocols could be FTP (file transfer), POP/SMTP&lt;br /&gt;
(email) or many others.  Port 80 is usually used for HTTP communications&lt;br /&gt;
with websites.&lt;br /&gt;
&lt;br /&gt;
If the file open request is successful, your Amiga is then connected to&lt;br /&gt;
that server and any further interaction with the &amp;quot;fileh&amp;quot; file handle&lt;br /&gt;
communicates directly with that port on that server.  In this case,&lt;br /&gt;
we would have connected to a websserver.&lt;br /&gt;
&lt;br /&gt;
===Talk to the Server===&lt;br /&gt;
&lt;br /&gt;
Once one has connected to a server, knowledge of the communications&lt;br /&gt;
protoccol for that type of connection is required.   &lt;br /&gt;
&lt;br /&gt;
For each of those, a server expects a certain format of interaction to&lt;br /&gt;
proceed and respond.  Fortunately, common protocols are publicly&lt;br /&gt;
documented.&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers&lt;br /&gt;
&lt;br /&gt;
For each protocol there is usually an &amp;quot;RFC&amp;quot; document that describes how one&lt;br /&gt;
uses the protocol, interacts with the port and accomplishes that protocol&#039;s&lt;br /&gt;
goals.&lt;br /&gt;
&lt;br /&gt;
In the case of &amp;quot;HTTP&amp;quot; (or a &amp;quot;Hypertext Transfer Protocol&amp;quot;) connection to&lt;br /&gt;
a webserver, we are usually expected to submit a &amp;quot;GET&amp;quot; request.  Here are&lt;br /&gt;
a couple more complete references on the HTTP protocol:&lt;br /&gt;
&lt;br /&gt;
	http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol&lt;br /&gt;
&lt;br /&gt;
	http://tools.ietf.org/html/rfc2616&lt;br /&gt;
&lt;br /&gt;
To keep things simple, lets just look at submitting a &amp;quot;GET&amp;quot; request, such&lt;br /&gt;
as a web browser, like IBrowse, would do.  A simple HTTP version 1.1 GET &lt;br /&gt;
request would include the following lines:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	GET /&amp;lt;path&amp;gt; HTTP/1.1&lt;br /&gt;
	host: &amp;lt;domain&amp;gt;&lt;br /&gt;
	user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)&lt;br /&gt;
	Pragma: no-cache&lt;br /&gt;
	Accept-Language: en, *&lt;br /&gt;
	Accept: text/html;level=3&lt;br /&gt;
	Accept: text/html;version=3.0&lt;br /&gt;
	Accept: */*&lt;br /&gt;
	&amp;lt;blank line&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;path&amp;gt; would be the rest of the URL (if any) on that system and&lt;br /&gt;
&amp;lt;domain&amp;gt; is the name of the server.  &lt;br /&gt;
&lt;br /&gt;
Using the &amp;quot;WeatherUnderground&amp;quot; website URL from above and their pathname for&lt;br /&gt;
searching for airport conditions, we can find the current conditions at&lt;br /&gt;
Washington&#039;s Dulles International Airport with these domain &amp;amp; path values:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   URL = www.wunderground.com&lt;br /&gt;
   PATH = cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The GET request syntax can be transcribed into C code which builds the entire&lt;br /&gt;
request in a string and then sends it to the server with a simple &amp;quot;fprintf&amp;quot; to our &lt;br /&gt;
open file handle, as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, the variables &amp;quot;path&amp;quot; and &amp;quot;domain&amp;quot; are used to fill in some&lt;br /&gt;
blanks in the request.  The blank line at the end completes the GET request, &lt;br /&gt;
after which the server will reply using the same file handle.&lt;br /&gt;
&lt;br /&gt;
===Listen to the Server===&lt;br /&gt;
&lt;br /&gt;
Once the GET request has been sent to the webserver, the server will start&lt;br /&gt;
sending back either the requested webpage (or other content) or an error page.&lt;br /&gt;
To see what sort of content is returned by the server, you can combine the&lt;br /&gt;
domain and path values above and enter them in your web browser:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   www.wunderground.com/cgi-bin/findweather/getForecast?query=IAD&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once the page is loaded, viewing the page source (f.e., IBrowse menu item&lt;br /&gt;
&amp;quot;Page/Display Source...&amp;quot;) will show you the same text that your program&lt;br /&gt;
will receive after sending the get request.&lt;br /&gt;
&lt;br /&gt;
As such, your program needs to start reading from the same file handle&lt;br /&gt;
the request was sent with.  This loop will print out the first hundred&lt;br /&gt;
lines returned:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	count = 0;&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		printf(&amp;quot;line %ld = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// process lines received here !&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Within this loop your applcation can parse the received lines for whatever&lt;br /&gt;
data your application is tryng to obtain.  In the case of our example program below,&lt;br /&gt;
the program searches for a string precedes the weather information we want.&lt;br /&gt;
&lt;br /&gt;
After the returned content has been read, output or otherwise processed,&lt;br /&gt;
simply closing the file handle will close the connection to the server:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===EXAMPLE ONE: IPClient.c===&lt;br /&gt;
&lt;br /&gt;
All of these elements are combined in the following example program&lt;br /&gt;
&amp;quot;IPClient.c&amp;quot; that asks you for a IATA airport code (f.e., IAD = Washington&lt;br /&gt;
Dulles, FRA=Frankfurt, SYD=Sydney), then parses &amp;amp; prints out the weather&lt;br /&gt;
conditions from the returned page.  &lt;br /&gt;
&lt;br /&gt;
Please Note: this example program worked with the wunderground.com&lt;br /&gt;
website in 2013-2014, as the served webpages change over time, it is &lt;br /&gt;
likely the parsing in this example is likely to fail and the program&lt;br /&gt;
no longer return useful information.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPclient&lt;br /&gt;
** Date: 12-10-2013 18:51:10&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPclient v.02 (12.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
char URL[200] = &amp;quot;www.wunderground.com/cgi-bin/findweather/getForecast?query=&amp;quot;;&lt;br /&gt;
char domain[200];&lt;br /&gt;
char path[200];&lt;br /&gt;
char fname[256] = &amp;quot;&amp;quot;;&lt;br /&gt;
#define MAX_STR 2056&lt;br /&gt;
char line[MAX_STR] = &amp;quot;&amp;quot;;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
uint16 uLen;&lt;br /&gt;
uint16 dLen;&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char *found;&lt;br /&gt;
FILE *fileh;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	// get URL from user&lt;br /&gt;
	printf(&amp;quot;IPclient example\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	printf(&amp;quot;   enter airport code &amp;gt;&amp;quot;);&lt;br /&gt;
	fgets(line,sizeof(line),stdin);&lt;br /&gt;
	line[strlen(line)-1] = &#039;\0&#039;;		// strip \n off end of string&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// append airport code on URLprefix&lt;br /&gt;
	strcat(URL,line);&lt;br /&gt;
	&lt;br /&gt;
	// parse domain from path&lt;br /&gt;
	uLen = strlen(URL) - 2;&lt;br /&gt;
	strcpy(domain,strtok(URL,&amp;quot;/\n&amp;quot;));&lt;br /&gt;
	dLen = strlen(domain);&lt;br /&gt;
	if (uLen&amp;gt;dLen)&lt;br /&gt;
		strcpy(path,strtok(NULL,&amp;quot;\n&amp;quot;));&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;   No chars remain for path\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;   URL domain &amp;gt;%s&amp;lt;\n&amp;quot;,domain);&lt;br /&gt;
	printf(&amp;quot;   URL path &amp;gt;%s&amp;lt;\n&amp;quot;,path);&lt;br /&gt;
	&lt;br /&gt;
	// build URL filename from domain name&lt;br /&gt;
	strcpy(fname,&amp;quot;TCP:&amp;quot;);&lt;br /&gt;
	strcat(fname,domain);&lt;br /&gt;
	strcat(fname,&amp;quot;/80&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// open file access to URL&lt;br /&gt;
	printf(&amp;quot;      Opening URL &amp;gt;%s&amp;lt;\n&amp;quot;,fname);&lt;br /&gt;
	fileh = fopen(fname,&amp;quot;r+&amp;quot;);&lt;br /&gt;
	if (fileh == NULL)&lt;br /&gt;
	{&lt;br /&gt;
		printf(&amp;quot;Couldn&#039;t open connection domain server via \&amp;quot;%s\&amp;quot;\n&amp;quot;,fname);&lt;br /&gt;
		return RETURN_ERROR;&lt;br /&gt;
	};&lt;br /&gt;
	printf(&amp;quot;      TCP: file opened\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// build web req text&lt;br /&gt;
	strcpy(line,&amp;quot;GET /&amp;quot;);&lt;br /&gt;
	strcat(line,path);&lt;br /&gt;
	strcat(line,&amp;quot; HTTP/1.1\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;host: &amp;quot;);&lt;br /&gt;
	strcat(line,domain);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;user-agent: IBrowse/2.4 (AmigaOS 4.1; PPC; 68K build)\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Pragma: no-cache\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept-Language: en, *\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;level=3\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: text/html;version=3.0\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;Accept: */*\r\n&amp;quot;);&lt;br /&gt;
	strcat(line,&amp;quot;\r\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// send web req line to server&lt;br /&gt;
	fprintf(fileh,&amp;quot;%s&amp;quot;,line);&lt;br /&gt;
	strcpy(line,&amp;quot;&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;      Web req sent\n&amp;quot;);&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,fileh) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		++ count;&lt;br /&gt;
		//printf(&amp;quot;line %d = %s\n&amp;quot;,count,inStr);&lt;br /&gt;
		&lt;br /&gt;
		// look for name of airport&lt;br /&gt;
		found = strstr(inStr,&amp;quot;og:title&amp;quot;);&lt;br /&gt;
		if (found != NULL)&lt;br /&gt;
		{&lt;br /&gt;
			found = strtok(inStr,&amp;quot;=&amp;quot;);&lt;br /&gt;
			found = strtok(NULL,&amp;quot;=&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;WeatherUnderground.com reports:\n&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Airport   = %s\n&amp;quot;,strtok(NULL,&amp;quot;|&amp;quot;)+1);&lt;br /&gt;
			printf(&amp;quot;   Temp      =%s F\n&amp;quot;,strtok(NULL,&amp;quot;&amp;amp;&amp;quot;));&lt;br /&gt;
			found = strtok(NULL,&amp;quot;|&amp;quot;);&lt;br /&gt;
			printf(&amp;quot;   Condition =%s\n&amp;quot;,strtok(NULL,&amp;quot;\&amp;quot;&amp;quot;));			&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;======================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	// close file&lt;br /&gt;
	fclose(fileh);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Designing Your Network Client===&lt;br /&gt;
&lt;br /&gt;
As you see, the above code and the example program, the mechanics&lt;br /&gt;
of connecting to a internet server and obtaining data are relatively&lt;br /&gt;
trivial.  The real challenge for the developer lies in understanding&lt;br /&gt;
the protocol used and in processing the data sent and received.&lt;br /&gt;
&lt;br /&gt;
Public webservers make for fairly rich and easy targets to interact&lt;br /&gt;
with.  You can explore simple interaction with any webbrowser and mimic&lt;br /&gt;
that interaction with your code.  In many cases, you can control the&lt;br /&gt;
feedback just by crafting the web request as we did above and then&lt;br /&gt;
parse the results.&lt;br /&gt;
&lt;br /&gt;
Naturally, the more complicated the interactions, like logging into&lt;br /&gt;
a website, would require much more knowledge of the protocols used&lt;br /&gt;
more complicated code that is beyond the scope of this tutorial.&lt;br /&gt;
&lt;br /&gt;
But there are a number of basic topics you should consider when&lt;br /&gt;
designing a web client!&lt;br /&gt;
&lt;br /&gt;
====Server Suitability:====&lt;br /&gt;
&lt;br /&gt;
Unless you are connecting to your own server or it invites such&lt;br /&gt;
connections (some publish API&#039;s for you to make such connections),&lt;br /&gt;
your application&#039;s &amp;quot;visit&amp;quot; may not be welcome or even legal.&lt;br /&gt;
&lt;br /&gt;
At the very least, your program should &amp;quot;tread lightly&amp;quot; - do not abuse&lt;br /&gt;
the server with unnecesary or intrusive requests.  Furthermore, if &lt;br /&gt;
your client uses the resources of someone else&#039;s server, you should&lt;br /&gt;
credit the server within your application and documentation.&lt;br /&gt;
&lt;br /&gt;
====Server Changes:====&lt;br /&gt;
&lt;br /&gt;
As with any programming that interacts with external inputs, your&lt;br /&gt;
code should provide for the possibility the connection may not&lt;br /&gt;
succeed or that the returned results may not be what was expected.&lt;br /&gt;
&lt;br /&gt;
As servers and websites change over time, the processing and&lt;br /&gt;
parsing of your program may often have to change accordingly.  &lt;br /&gt;
To maintain your program and deal with such changes, you may want&lt;br /&gt;
to consider how to make changing those things easy (by the user?).&lt;br /&gt;
The parsing strings could be kept in program tooltypes or config&lt;br /&gt;
text file, you could provide a GUI for managing the parsing, employ&lt;br /&gt;
an external, editable ARexx macro.&lt;br /&gt;
&lt;br /&gt;
====Protocol Details &amp;amp; Vagaries:====&lt;br /&gt;
&lt;br /&gt;
Our example code presented a very simple interaction with a web&lt;br /&gt;
server using the a widely supported version of the HTTP protocol.&lt;br /&gt;
As one develops an application and uses a protocol, one should get&lt;br /&gt;
familiar with the details of that protocol.  Typically a &amp;quot;RFC&amp;quot;&lt;br /&gt;
document (as linked above) will describe the details of how things&lt;br /&gt;
are to work and how they might fail.  Your application should be&lt;br /&gt;
careful to comply with the details of the protocol (&amp;quot;Are we sending&lt;br /&gt;
a CR-LF or LF-CR?!&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
===Ideas===&lt;br /&gt;
&lt;br /&gt;
The above example was just a quick, simple exercise in demosntrating&lt;br /&gt;
the use of the AmigaOS Roadshow TCP: handler to access a web server.&lt;br /&gt;
There are many ways applications could be created to have simple&lt;br /&gt;
interactions with all sorts internet services, such as:&lt;br /&gt;
&lt;br /&gt;
 · Check stock quotes from a financial site.&lt;br /&gt;
 · Get package tracking information from a shipping site.&lt;br /&gt;
 · Check for new emails on a POP email server.&lt;br /&gt;
 · Convert currencies with a financial or travel web site.&lt;br /&gt;
 · Check for files on an FTP server.&lt;br /&gt;
 · Send messages with a SMTP email server.&lt;br /&gt;
 · Look up words on a dictionary website.&lt;br /&gt;
&lt;br /&gt;
You could also write your own server for another Amiga and interact&lt;br /&gt;
with your own client.   A remote controlled media player?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==An Internet Server==&lt;br /&gt;
&lt;br /&gt;
Next we will look at creating a simple internet server program that relies on AmigaOS Roadshow&#039;s &amp;quot;SuperServer&amp;quot; to receive the incoming&lt;br /&gt;
internet connection and share it with our application.&lt;br /&gt;
&lt;br /&gt;
Simply speaking, once Roadshow is configured to recognize the incoming&lt;br /&gt;
request and that your application is there to handle it; our program&lt;br /&gt;
just has to deal with another case of simple file-like interaction.&lt;br /&gt;
&lt;br /&gt;
For this example, we will create a simple server that accepts an HTTP&lt;br /&gt;
protocol request (like from IBrowse) and then respponds to it with a&lt;br /&gt;
simple webpage.  Of course, you could write a server to serve an&lt;br /&gt;
interactive webpage, some machine information, media files, etc.&lt;br /&gt;
Just be careful.&lt;br /&gt;
&lt;br /&gt;
===Receive the Request===&lt;br /&gt;
&lt;br /&gt;
When Roadshow receives an internet request on the designated port that&lt;br /&gt;
corresponds to our server, it starts our server program and routes the&lt;br /&gt;
network connection to our program using the &amp;quot;standard&amp;quot; input stream&lt;br /&gt;
(otherwise known as &amp;quot;stdin&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Our application then reads the stream almost like reading from any&lt;br /&gt;
other file or user input, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	// read in the response&lt;br /&gt;
	while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++ count;&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
		&lt;br /&gt;
As you can see, we loop reading incoming lines until we encounter a&lt;br /&gt;
line with two or fewer characters (essentially an empty line with&lt;br /&gt;
what should be a CR-LF).  There is also a counter that kicks us out&lt;br /&gt;
if the loop if we read 100 lines - that&#039;s a sign something else is &lt;br /&gt;
wrong, we should never see that with the HTTP protocol.&lt;br /&gt;
&lt;br /&gt;
With the HTTP protocol, the first line is where we would see what is&lt;br /&gt;
being requested.  Were our server to use other protocols, we may have to&lt;br /&gt;
add our server&#039;s &amp;quot;intelligence&amp;quot; elsewhere.&lt;br /&gt;
&lt;br /&gt;
We also do all our diagnostics output using the &amp;quot;DebugPrintf&amp;quot;. Which&lt;br /&gt;
means we either need to run Sashimi or watch output on the serial port&lt;br /&gt;
(with your second Amiga, naturally).  In the case of this example, we&lt;br /&gt;
will see the entire incoming request printed out on the serial port.&lt;br /&gt;
Of course, there&#039;s a reason why we have to use the serial for our debug output...&lt;br /&gt;
&lt;br /&gt;
===Respond to the Visitor===&lt;br /&gt;
&lt;br /&gt;
Once we&#039;ve read the (almost) empty line at the end of the incoming&lt;br /&gt;
web request, we will use the same &amp;quot;stdin&amp;quot; stream to respond to our&lt;br /&gt;
internet visitor.&lt;br /&gt;
&lt;br /&gt;
Anything we output to &amp;quot;stdin&amp;quot; will be sent by Roadshow back to our&lt;br /&gt;
internet visitor.  This is the reason why we used the serial port for&lt;br /&gt;
doagnostics print outs, since a simple &amp;quot;printf&amp;quot; would have gone to&lt;br /&gt;
our web visitor.&lt;br /&gt;
&lt;br /&gt;
Instead, we create a loop that feeds a predefined series of lines&lt;br /&gt;
for a very simple webpage to Roadshow and our web visitor:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
	//loop thru text writing to stdout&lt;br /&gt;
	do&lt;br /&gt;
	{&lt;br /&gt;
		if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);			&lt;br /&gt;
			if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			fflush(stdout);&lt;br /&gt;
		}&lt;br /&gt;
		else&lt;br /&gt;
		{&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
		++l;&lt;br /&gt;
	} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, our loop ends when we hit an empty line in our webpage&lt;br /&gt;
definition or a maximum of 25 lines (a failsafe).  At then end we &amp;quot;flush&amp;quot;&lt;br /&gt;
the output and quit our program.  The request was received, our webpage&lt;br /&gt;
sent and Roadshow takes care of all the housekeeping.&lt;br /&gt;
&lt;br /&gt;
===EXMAPLE TWO:  IPserver.c===&lt;br /&gt;
&lt;br /&gt;
We can see all these pieces and the definition of our simple webpage in&lt;br /&gt;
the full program here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
************************************************************&lt;br /&gt;
**&lt;br /&gt;
** Created by: CodeBench 0.41 (12.10.2013)&lt;br /&gt;
** Project: IPserver&lt;br /&gt;
** Date: 13-10-2013 23:41:17&lt;br /&gt;
**&lt;br /&gt;
************************************************************&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/exec.h&amp;gt;&lt;br /&gt;
#include &amp;lt;proto/dos.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		GLOBAL VARIABLES&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
STATIC CONST_STRPTR version USED = &amp;quot;$VER: IPserver 0.14 (13.10.2013)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// define maximum web request lines &amp;amp; length&lt;br /&gt;
#define MAX_STR 2048&lt;br /&gt;
&lt;br /&gt;
// ARS path &amp;amp; file name&lt;br /&gt;
uint16 count = 0;&lt;br /&gt;
char inStr[MAX_STR];&lt;br /&gt;
&lt;br /&gt;
CONST_STRPTR lines[] =&lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;HTTP/1.0\015&amp;quot;,&lt;br /&gt;
	&amp;quot;Content-Type: text/html\015&amp;quot;,&lt;br /&gt;
	&amp;quot;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;TITLE&amp;gt;IPserver&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TABLE WIDTH=100%&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE WIDTH=90%&amp;gt;&amp;lt;TR&amp;gt;&amp;lt;TD&amp;gt;&amp;lt;B&amp;gt;&amp;lt;H1&amp;gt;WELCOME&amp;lt;/H1&amp;gt;&amp;lt;/B&amp;gt;&amp;lt;BR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD BGCOLOR=\&amp;quot;6688ee\&amp;quot;&amp;gt;&amp;lt;H3&amp;gt;&amp;lt;P&amp;gt;&amp;lt;P&amp;gt;&amp;lt;FONT COLOR=\&amp;quot;white\&amp;quot;&amp;gt;&amp;lt;B&amp;gt;AmigaOS IPserver example&amp;lt;/B&amp;gt;&amp;lt;/FONT&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;TR&amp;gt;&amp;lt;TD ALIGN=\&amp;quot;center\&amp;quot; BGCOLOR=\&amp;quot;cccccc\&amp;quot;&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;BR&amp;gt;&amp;lt;TABLE CELLSPACING=0 WIDTH=90%&amp;gt;&amp;lt;TR BGCOLOR=\&amp;quot;ffffff\&amp;quot;&amp;gt;&amp;lt;TD WIDTH=100&amp;gt;&amp;lt;H4&amp;gt;&amp;lt;B&amp;gt;And so it begins...&amp;lt;/B&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;TD&amp;gt; Your Amiga internet server! &amp;lt;/TD&amp;gt;&amp;lt;/TR&amp;gt;&amp;lt;/TABLE&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;lt;/TR&amp;gt;&amp;lt;/TD&amp;gt;&amp;lt;/TABLE&amp;gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;\015&amp;quot;,&lt;br /&gt;
	&amp;quot;&amp;quot;&lt;br /&gt;
};&lt;br /&gt;
uint16 l = 0;&lt;br /&gt;
&lt;br /&gt;
/*****************************************************************************&lt;br /&gt;
 *		PROGRAM START&lt;br /&gt;
 *****************************************************************************/&lt;br /&gt;
&lt;br /&gt;
// Starting program&lt;br /&gt;
int main(int argc,char **argv)&lt;br /&gt;
{&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver starting\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	//		Was program started from shell or WB ?&lt;br /&gt;
	if (argc &amp;gt; 0)&lt;br /&gt;
	{&lt;br /&gt;
		&lt;br /&gt;
		// read in the response&lt;br /&gt;
		while( (fgets(inStr,MAX_STR,(FILE *)stdin) != NULL) &amp;amp;&amp;amp; (count&amp;lt;100) )&lt;br /&gt;
		{&lt;br /&gt;
			//  ####   Test for CR-LR only line&lt;br /&gt;
			if (strlen(inStr)&amp;lt;3)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   received nearly empty line, ending read loop.\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			++ count;&lt;br /&gt;
			IExec-&amp;gt;DebugPrintF(&amp;quot;   %s\n&amp;quot;,inStr,NULL,NULL,NULL);&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;FINISHED READING WEB REQUEST\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;SERVING WEB PAGE...\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		&lt;br /&gt;
		//loop thru text writing to stdout&lt;br /&gt;
		do&lt;br /&gt;
		{&lt;br /&gt;
			if (strlen(lines[l]) &amp;gt; 0)&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   printing line = %s\n&amp;quot;,lines[l],NULL,NULL);&lt;br /&gt;
				&lt;br /&gt;
				if (fprintf(stdout,&amp;quot;%s\n&amp;quot;,lines[l]) &amp;lt; 0)&lt;br /&gt;
				{&lt;br /&gt;
					IExec-&amp;gt;DebugPrintF(&amp;quot;ERROR printing line\n&amp;quot;,NULL,NULL);&lt;br /&gt;
					break;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				fflush(stdout);&lt;br /&gt;
			}&lt;br /&gt;
			else&lt;br /&gt;
			{&lt;br /&gt;
				IExec-&amp;gt;DebugPrintF(&amp;quot;   empty line, loop end\n&amp;quot;,NULL,NULL);&lt;br /&gt;
				break;&lt;br /&gt;
			}&lt;br /&gt;
			++l;&lt;br /&gt;
		} while (l &amp;lt; 25);		// emergency loop escape to stop endlessness&lt;br /&gt;
		&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
		IExec-&amp;gt;DebugPrintF(&amp;quot;Web service finished... \n&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
		printf(&amp;quot;IPserver started from Workbench - Don&#039;t do it again, this is a Roadshow app!\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;IPserver Quitting!\n&amp;quot;);&lt;br /&gt;
	IExec-&amp;gt;DebugPrintF(&amp;quot;======================================\n&amp;quot;);&lt;br /&gt;
	&lt;br /&gt;
	return RETURN_OK;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see there&#039;s also a bit of housekeeping code at the beginning&lt;br /&gt;
that tells a user this program wasn&#039;t meant to be run from the Workbench.&lt;br /&gt;
As it stands, this is program is only meant to be used by Roadshow for&lt;br /&gt;
serving internet visitors to your Amiga.&lt;br /&gt;
&lt;br /&gt;
But how do we test this all out?  First we have to let Roadshow know that&lt;br /&gt;
we&#039;ve created this &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Roadshow Configuration===&lt;br /&gt;
&lt;br /&gt;
There are two areas where Roadshow needs to be told about your server&lt;br /&gt;
and the service it is going to provide.  Both of these can be configured&lt;br /&gt;
using Internet Prefs.  You can also make this configuration by editing&lt;br /&gt;
the &amp;quot;servers&amp;quot; and &amp;quot;services&amp;quot; files in the &amp;quot;DEVS:internet/&amp;quot; directory.&lt;br /&gt;
Configuration of these files is described in the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   SYS:Documentation?Roadshow/README&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you would like to spare your user from having to do either of those&lt;br /&gt;
chores, your application can even modify those files.  As soon as&lt;br /&gt;
Roadshow sees those files have been modified, it will reconfigure itself&lt;br /&gt;
accordingly.&lt;br /&gt;
&lt;br /&gt;
====Services====&lt;br /&gt;
&lt;br /&gt;
First, we need to tell Roadshow about the &amp;quot;service&amp;quot; we are providing.&lt;br /&gt;
If one opens Internet Prefs and clicks on the &amp;quot;Services&amp;quot; page, one will&lt;br /&gt;
see a list of standard internet services with their TCPIP port numbers,&lt;br /&gt;
type and aliases.&lt;br /&gt;
&lt;br /&gt;
Click the &amp;quot;New...&amp;quot; button to define a new Service.  An &amp;quot;Add service&amp;quot;&lt;br /&gt;
window will open where we can define how our server will be accessed.&lt;br /&gt;
Criticially, we need to pick a port number that is not already in use.&lt;br /&gt;
Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Name = IPserver&lt;br /&gt;
   Port = 7600&lt;br /&gt;
   Type = tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then we click &amp;quot;Use&amp;quot; to accept our new values.  As soon as one clicks&lt;br /&gt;
&amp;quot;Save&amp;quot; in Internet Prefs, this service will be recognized by Roadshow.&lt;br /&gt;
&lt;br /&gt;
The same configuration could be added to Roadshow by adding this line&lt;br /&gt;
(in port number location) into the file &amp;quot;DEVS:Internet/Services&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer         7600/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As soon as one saves the file, Roadshow will be notified and adjust&lt;br /&gt;
itself for the service.&lt;br /&gt;
&lt;br /&gt;
====Servers====&lt;br /&gt;
&lt;br /&gt;
Before we can use the service above, we also need to tell Roadshow&lt;br /&gt;
about our server app and where to find it.  Again, this can be done&lt;br /&gt;
while in Internet Prefs.  Click on the &amp;quot;Servers&amp;quot; page and one will see&lt;br /&gt;
any servers configured with the services they provide (as set above),&lt;br /&gt;
type, wait and program path.&lt;br /&gt;
&lt;br /&gt;
Click on the &amp;quot;New...&amp;quot; button to define a new Server.  In the &amp;quot;Add server&amp;quot;&lt;br /&gt;
window we can define what sort of service our server is for, the&lt;br /&gt;
characteristics of how it will be called and where it is located on&lt;br /&gt;
our Amiga system.  Such settings could be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   Service = IPserver&lt;br /&gt;
   Type = Stream&lt;br /&gt;
   Stack = 65536&lt;br /&gt;
   Program = &amp;lt;where are server program is&amp;gt;&lt;br /&gt;
   Arguments = &amp;lt;empty&amp;gt;&lt;br /&gt;
   Active = &amp;lt;checked&amp;gt;&lt;br /&gt;
   Wait for completion = &amp;lt;not checked&amp;gt;&lt;br /&gt;
   Use socket I/O streams = &amp;lt;checked&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again we click &amp;quot;Use&amp;quot; to accept our new Server entry and saving Internet&lt;br /&gt;
Prefs will adjust Roadshow.&lt;br /&gt;
&lt;br /&gt;
We can also make this adjustment to Roadshow&#039;s server list by adding the&lt;br /&gt;
following line to the &amp;quot;DEVS:Internet/servers&amp;quot; file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   IPServer        stream     dos stack=65536 data:Projects/C/OS4ex-IPserver/IPserver.debug&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Again, saving the file is automatically noticed by Roadhsow.&lt;br /&gt;
&lt;br /&gt;
Once both the service and server are configured, Roadshow is ready&lt;br /&gt;
to use our new server.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Let&#039;s See Our Server!===&lt;br /&gt;
&lt;br /&gt;
To test our new server example, you can access it by connecting to your&lt;br /&gt;
Amiga and the designated IP port number.  On the same machine, you can&lt;br /&gt;
enter this in your browser URL line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://localhost:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From another machine, you will need to have your test server Amiga&#039;s&lt;br /&gt;
IP address or a host name configured on your network.  The URL would&lt;br /&gt;
look something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   http://192.168.1.07:7600/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In any case, the browser will connect to your Amiga at the port number&lt;br /&gt;
following the colon (&amp;quot;:&amp;quot;) and Roadshow will call up your server program&lt;br /&gt;
and let it talk to your browser.&lt;br /&gt;
&lt;br /&gt;
===Where to go?   More Webpages?===&lt;br /&gt;
&lt;br /&gt;
Clearly the above example does little more than say &amp;quot;Hello World&amp;quot; to a&lt;br /&gt;
visiting web browser user.  It offers no interactivity, preforms no task&lt;br /&gt;
and serves no media.  &lt;br /&gt;
&lt;br /&gt;
When this web server receives the incoming web request, the first line&lt;br /&gt;
(starting with &amp;quot;GET&amp;quot; tells the server what the browser is looking for.&lt;br /&gt;
If you watch the serial output and connect with a newer browser than&lt;br /&gt;
IBrowse, you can see most browsers make two connections with one of&lt;br /&gt;
them looking saying:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
   GET /favicon.ico HTTP/1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In that case, the browser is looking to see if your server has an icon&lt;br /&gt;
to send for the displaying on the browser tab.  Just like that, anything&lt;br /&gt;
written in URL after the machine&#039;s name or IP address and the port number&lt;br /&gt;
is taken a requested path and your server will receive it after &amp;quot;GET&amp;quot; in&lt;br /&gt;
the first line of the request.&lt;br /&gt;
&lt;br /&gt;
This just scratches the surface of requests your server may receive and&lt;br /&gt;
how it can respond to web visitors.  To dig deeper you can search the&lt;br /&gt;
many sources online or in your local bookstore on HTTP communications and&lt;br /&gt;
the formatting of HTML webpages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Just Webpages?===&lt;br /&gt;
&lt;br /&gt;
There&#039;s also ne reason why your server needs to be limited to dealing&lt;br /&gt;
with browsers and sending webpages.  The internet is full of other&lt;br /&gt;
protocols and services that your could write a server for.  Or you could&lt;br /&gt;
create your own online client and server functionality.&lt;br /&gt;
&lt;br /&gt;
Just as we discussed with creating an Internet client, there are many&lt;br /&gt;
topics you should consider when designing an internet server program.&lt;br /&gt;
It&#039;s not just about the coding!&lt;br /&gt;
&lt;br /&gt;
====Security====&lt;br /&gt;
&lt;br /&gt;
Obviously, opening your Amiga with an internet server represents more of a&lt;br /&gt;
risk than if you had done nothing.  So it is criticially important one&lt;br /&gt;
considers security when creating a server.  While it&#039;s beyond the scope&lt;br /&gt;
of this article to inclusively discuss all the issues involved, there&lt;br /&gt;
are basics to consider.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t blindly serve sensitive information to visitors.  How can you be&lt;br /&gt;
sure who&#039;s at the other end of the connection and who might be watching&lt;br /&gt;
along the way?  Even if randomized pathnames and request are used by&lt;br /&gt;
your server, there&#039;s no guarantee the connection is 100% secure.&lt;br /&gt;
&lt;br /&gt;
Limit commands and functions served to visitors.  Obviously, creating a&lt;br /&gt;
means of offering anything like command line access or full file &lt;br /&gt;
editing/deleting powers to a web visitor would represent dangerous hole&lt;br /&gt;
in any system&#039;s security.  But one has to make sure no whatsoever holes&lt;br /&gt;
or bugs exist in the server design that would let such access slip&lt;br /&gt;
through.&lt;br /&gt;
&lt;br /&gt;
====Server Instances &amp;amp; Load====&lt;br /&gt;
&lt;br /&gt;
One has to keep in mind the &amp;quot;SuperServer&amp;quot; method where Roadshow runs&lt;br /&gt;
your server also means your server will be executed with each and every&lt;br /&gt;
request Roadshow receives for that port.  In each case, your server&lt;br /&gt;
will do its duty and then be expected to quit.  That should be fine&lt;br /&gt;
light duty, personal server tasks.&lt;br /&gt;
&lt;br /&gt;
But one should focus server development on keeping things as&lt;br /&gt;
&amp;quot;lightweight&amp;quot; and simple as possible.  If the server needs to do&lt;br /&gt;
read data files or perform other complicated initialization, this may&lt;br /&gt;
slow reaction time for each incoming request an unacceptable level.&lt;br /&gt;
&lt;br /&gt;
To avoid time consuming chores, one might considering using interprocess&lt;br /&gt;
communciations (such as ARexx messages) to interact with a separate&lt;br /&gt;
master program that handles all the housekeeping and remains running&lt;br /&gt;
while each of internet server instance handles an incoming request and&lt;br /&gt;
quits.  &lt;br /&gt;
&lt;br /&gt;
Naturally, at some point use requirements may require one bypasses the&lt;br /&gt;
Roadshow  SuperServer method of running servers and goes to using &lt;br /&gt;
longhand socket programming that is better suited to heavy duty use&lt;br /&gt;
- like running a serious public server.&lt;br /&gt;
&lt;br /&gt;
Furthermore, there are whole areas of study and technology involved&lt;br /&gt;
with the handling of network user load that should be applied to any&lt;br /&gt;
serious server system.&lt;br /&gt;
&lt;br /&gt;
====Protocols and Compatibility====&lt;br /&gt;
&lt;br /&gt;
As one develops a more complex or interactive server meant to handle&lt;br /&gt;
a wider group of users (even those on lesser platforms!), one needs&lt;br /&gt;
to pay much closer attention to the protocols involved.  &lt;br /&gt;
&lt;br /&gt;
As mentioned in elsewhere in this text, there RFC&#039;s that describe the&lt;br /&gt;
formal protocols and there are likely countless webpages that address&lt;br /&gt;
idiosynacracies of implementing the protocols.&lt;br /&gt;
&lt;br /&gt;
Beyond all those, a developer will need to do serious testing with as&lt;br /&gt;
wide a pool of possible clients to refine a server&#039;s operation.  &amp;quot;You&lt;br /&gt;
aren&#039;t in Kansas anymore!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==General Issues==&lt;br /&gt;
&lt;br /&gt;
Whether creating a server or a client program, there are many general&lt;br /&gt;
issues that one should considerin developing such programs.&lt;br /&gt;
&lt;br /&gt;
====Complexity and Speed====&lt;br /&gt;
&lt;br /&gt;
These days it seems like few developers on lesser platforms care terribly&lt;br /&gt;
much about optimization and speed.  Those platforms typically just throw&lt;br /&gt;
more horsepower &amp;amp; memory at their chores and try to go about their business.&lt;br /&gt;
&lt;br /&gt;
In the Amiga world, without the glut of idle horsepower, development of&lt;br /&gt;
any applications and internet clients &amp;amp; servers in particular should be&lt;br /&gt;
mindful of overhead.  For every client or server transaction, there is&lt;br /&gt;
likely some user that clicked a button and is waiting for an answer.&lt;br /&gt;
Keep things simple and optimize!&lt;br /&gt;
&lt;br /&gt;
====Incomplete transactions====&lt;br /&gt;
&lt;br /&gt;
Since all these programs are dependent on communications over many links,&lt;br /&gt;
these programs need to have a robustness for failed links.  Transfers can&lt;br /&gt;
be interupted mid-stream.  Received data can be incomplete or corrupted.&lt;br /&gt;
These applications need to have the error trapping to deal with such real&lt;br /&gt;
possibilities.&lt;br /&gt;
&lt;br /&gt;
====Statelessness====&lt;br /&gt;
&lt;br /&gt;
Given the nature of internet communications and web browsing in particular,&lt;br /&gt;
servers and clients need to be &amp;quot;stateless&amp;quot; as possible.  While a visitor&lt;br /&gt;
may have just &amp;quot;logged in&amp;quot; to your server, there&#039;s no automatic way to know&lt;br /&gt;
the next transaction your server receives is that logged in user, that&lt;br /&gt;
the user hasn&#039;t left or hit the back or reload button on their browser&lt;br /&gt;
(reloading the log-in page again).  So a servers should avoid making&lt;br /&gt;
assumptions about the state of the connection and interaction with a&lt;br /&gt;
visitor whenever possible or provide explicit means for addressing such&lt;br /&gt;
things.&lt;/div&gt;</summary>
		<author><name>Paul Sadlik</name></author>
	</entry>
</feed>