Berkeley sockets' passivesock portbase meaning - c

I am tried to understand the passive socket by tracing the code
http://merkez.ube.ege.edu.tr/~erciyes/ube528/passivesock.c
And I found that the following code
/* Map service name to port number */
if(pse = getservbyname(service, protocol)){
sin.sin_port = htons(ntohs((u_short)pse->s_port) + portbase);
}
else if((sin.sin_port = htons((u_short)atoi(service))) == 0){
errexit("can't get \"%s\" service entry\n", service);
}
I have some question about the htons(ntohs((u_short)pse->s_port) + portbase);
What is the portbase, I found the comment u_short portbase = 0; /* port base, for non-root servers */ but still know what it means?
I have googled it by 'passive socket portbase' but cannot find useful information.
Thx in advance.

Ports below 1024 are system ports and require superuser privileges to access (i.e. root) [1]. As such when running this program as a non root user you may want to remap that port numbers to start at a different base from 0. e.g. by starting at port 1024 no ports will be in the superuser restricted zone (e.g. our well known port 80 will now be 1104). You could choose to map these anywhere.
The comment is the give away:/* port base, for non-root servers */, combined with the fact that this variable is NEVER set anywhere in that file. Only ever is it read. So when using this C library, you are free to set port base before calling any of the functions in order to remap the ports.

Related

3 sockets created for one libevent bind on Windows?

I'm writing a BitTorrent client to learn some more about networking, and I've got something that I'm struggling to Google for. As part of the BT spec, I need a server to listen for peer connections to my computer. In the win32 port, I have code like this to setup my server
struct sockaddr_in saServer;
struct hostent* localHost;
char* localIP;
// Get the local host information
localHost = gethostbyname("");
localIP = inet_ntoa(*(struct in_addr *)*localHost->h_addr_list);
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr(localIP);
saServer.sin_port = htons(6881);
struct evconnlistener *listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (SOCKADDR*)&saServer, sizeof(saServer));
That seems to work, but if I look at netstat, I see the following,
BitTorrentClient.exe 6092 TCP hostname 50216 localhost 50217 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname 50217 localhost 50216 ESTABLISHED
BitTorrentClient.exe 6092 TCP hostname.home 6881 hostname 0 LISTENING
Why are there two other connections, one from port 50216->50217 and one looping back from 50217->50216? I was expected to have just one listening connection on port 6881. Is this a libevent quirk, or something more fundamental related to networking?
What can I search for to understand what the other two ports are used for?
This is most likely a result of libevent calling evutil_make_internal_pipe_ internally.
Libevent creates internal "pipes" for inter-thread communication and signal delivery using socketpair(2) on POSIX-compliant systems, whereas on Windows libevent has to resort to manually connecting two sockets together instead.

C - getaddrinfo returns "Servname not supported for ai_socktype"

So, after I got this error, I've been looking for an answer in here, almost everyone had a difficult way to fix this error but no one explained why this error occurs at all, so I don't find this question to be exactly duplicate.
I wrote a TCP socket in C and I used "getaddrinfo" function to make the socket work with hostnames, well it worked perfectly! you can find my codes on github.
but when I tried to create a UDP socket by "getaddrinfo" I got this error:
Servname not supported for ai_socktype
client.c
const char *host = argv[1];
const char *service = argv[2];
const char *string = argv[3];
struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_UNSPEC;
addrCriteria.ai_socktype = SOCK_DGRAM;
addrCriteria.ai_protocol = IPPROTO_UDP;
struct addrinfo *servAddr;
int ret = getaddrinfo(host, service, &addrCriteria, &servAddr);
if(ret != 0)
sysError(gai_strerror(ret));
I realized that when I give "service" a numeric input like 8080, no errors would return but when I use a string as service name like "tproxy" which points to port/8081, 'gai_strerror' returns mentioned error.
Obviously, gai_strerror says: "service names not supported for 'SOCK_DGRAM' socket types", but why? I mean the exact reason for "getaddrinfo" not supporting name services over UDP sockets?
Is there any other way to use service names with UDP sockets instead of port numbers? how?
TL;DR: There is no tproxy UDP port.
If you look up the tproxy service for UDP sockets in your service database,
getent services tproxy/udp
You get no output, because tproxy is not an UDP service. If you look at all tproxy services regardless of the protocol, getent services | grep -e tproxy, you'll see
tproxy 8081/tcp
which means that tproxy service is only defined for TCP protocol.
This means that if you ask getaddrinfo() for an UDP socket for service 8081, you will not find anything, because tproxy is only defined for TCP and not UDP.
Compare to the case where you ask for and UDP socket for xmpp-client service. At least my service database (getent services xmpp-client/udp) responds with
xmpp-client 5222/udp jabber-client
and indeed, getaddrinfo() happily provides the socket description for such UDP sockets (using xmpp-client or jabber-client as the service).
So, there are services like xmpp-client that do have both TCP and UDP ports defined. On my system, getent services | grep -e xmpp-client shows
xmpp-client 5222/tcp jabber-client
xmpp-client 5222/udp jabber-client
Because TCP and UDP are different protocols over IP, it makes sense that a service could use a different port number for TCP and UDP communications. So, it is unreasonable to assume that the service database should just return the same port numbers for TCP and UDP sockets.
In other words, you encounter the error because you mistakenly assume that because some service uses a TCP port, with a name registered in the service database, you should be able to use that name to specify an UDP port number, too.
TCP and UDP are separate protocols, and their port number spaces are separate. For example, TCP port 512 is used by the Unix exec r-service, whereas UDP port 512 is used by the biff mail notification service.
When a non-numeric value is given for the service parameter, it is looked up (on Linux) in the /etc/services file. This file maps a service name to a port/protocol. Below are some sample entries:
ssh 22/tcp
telnet 23/tcp
domain 53/tcp # name-domain server
domain 53/udp
The reason you're getting an error is because there is no UDP entry in your /etc/services file for "tproxy". Take a look at this file and look for an entry that does specify a UDP port such as "domain". That should have entries for both 53/tcp and 53/udp. If you pass in "domain" as the service name you should get a result back.

STM32 USB VCP (Virtual Com Port)

I generated a code for "stm32f103c8t6" with CubeMX for USB VCP, when I add "CDC_Transmit_FS" command to send data, the port isn't recognized by windows10!
what should I do? Here is the code which is compiled without error:
#include "stm32f1xx_hal.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
int main(void)
{
uint8_t Text[] = "Hello\r\n";
while (1)
{
CDC_Transmit_FS(Text,6); /*when commented the port is recognized*/
HAL_Delay(1000);
}
}
There are three things you need to check in my experience:
startup_stm32f405xx.s --> Increase the Heap size. I use heap size 800 and stack size 800 as well.
usbd_cdc_if.c --> APP_RX_DATA_SIZE 64 and APP_TX_DATA_SIZE 64
usbd_cdc_if.c --> add below code to the CDC_Control_FS() function
Code:
case CDC_SET_LINE_CODING:
tempbuf[0]=pbuf[0];
tempbuf[1]=pbuf[1];
tempbuf[2]=pbuf[2];
tempbuf[3]=pbuf[3];
tempbuf[4]=pbuf[4];
tempbuf[5]=pbuf[5];
tempbuf[6]=pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0]=tempbuf[0];
pbuf[1]=tempbuf[1];
pbuf[2]=tempbuf[2];
pbuf[3]=tempbuf[3];
pbuf[4]=tempbuf[4];
pbuf[5]=tempbuf[5];
pbuf[6]=tempbuf[6];
break;
and define the uint8_t tempbuf[7]; in the user private_variables section.
Without the increased heap size, Windows does not react at all.
Without the point 3, Windows will send the baud rate information and then read the baud rate, expecting to get back the same values. Since you do not return any values, the virtual com port remains as driver-not-loaded.
If you do all of that, the Windows 10 out-of-the-box VCP driver can be used. No need to install the very old ST VCP driver on your system.
PS: I read somewhere turning on VSense makes problems, too. Don't know, I have not configured it and all works like a charm.
Put delay before CDC_Transmit_FS call - it will wait for the initiatialization. Your code should be like this
int main(void)
{
uint8_t Text[] = "Hello\r\n";
HAL_Delay(1000);
while (1)
{
CDC_Transmit_FS(Text,6); /*when commented the port is recognized*/
HAL_Delay(1000);
}
}
I had similar issue. I couldn't connect to a port and the port appears as just "virtual com port". I added while loop to wait for USBD_OK from CDC_Transmit_FS. Then it stars work even with out it or a delay after init function. I am not sure what the issue was.
while(CDC_Transmit_FS((uint8_t*)txBuf, strlen(txBuf))!=USBD_OK)
{
}
you may have to install driver to get device recognized as com port
you can get it from st site
if not installed the device is listed with question or exclamation mark on device manager
note that you cannot send until device get connected to host!
not sure that CubeMX CDC_Transmit_FS is checking for this
also instead of delay to resend you shall check the CDC class data "TXSstate"
is 0 mean tx is over.
I know it's a bit late, but I stumbled upon this post and it was extremely helpful.
Here is what I needed to do:
do the Line-Coding (I think only necessary on Windows-Systems)
increase Heap (Stack was left at default 0x200)
Here is what wasn't necessary for me (on a STM32F405RGT6 Chip):
change APP_RX_DATA_SIZE / APP_TX_DATA_SIZE (left it at 2048)
add a delay befor running CDC_Tranmit_FS()
Also some things to consider that happened to me in the past:
be sure to use a USB-Cable with data lines (most charging-cables don't have them)
double check the traces/connections if you use a custom board

error in binding port "Address already in use" TCP socket programming in unix

I've gone through many posts and forums and I'm new to socket programming. Major parts of my code are similar to
BIND ERROR : Address already in use
but then i changed my code so that i include "setsockopt" function like so:
const char* port="5555";
int opt=1;
portno=atoi(port);
//parameters for server address
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(portno);
serv_addr.sin_addr.s_addr=INADDR_ANY;
//bind the socket to the address
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(const char *)&opt,sizeof(int));
if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{close(sockfd);
error("error in binding port!");
}
But still i get the error. I have to close the terminal and restart it in order to use the port again. I want to use a hardcoded port (like i mentioned in the code above)
Thanks a lot in advance
Check to see if the port is in use. Either telnet to that port or use netstat -a. It should be in use (as the error indicates) and kill the appropriate process. Perhaps using ps to find the process.
A port number can only be used by one application at a time. That means you can not start the same program twice expecting both to bind to the same port.
The SO_REUSEADDR is for when the socket bound to an address has already been closed, the same address (ip-address/port pair) can be used again directly.

getting the domain name by code in Linux

I am using getdomainname() and gethostbyname() to try to get the domain of the computer so I can show the correct information on my program. However sometimes these functions don't return the correct information.
Is there any other way (in plain C) to get the domain name in Linux?
Edit: just to make it a bit more clear: I want to check if the computer is part of a domain. If it is, get the domain name.
Currently I am using the functions mentioned above. Are there any others?
#unwind: please DO NOT edit this question for "brevity" if I would like to say thanks I'll say thanks.
Thanks!
If you want to get the (Internet) domain name there are certain issues you need to think about.
A computer can have multiple network interfaces, in fact it almost certainly has at least two including the loopback interface. Each interface has an IP address (possibly more than one) and each IP address can be mapped to from any number of DNS names and entries in the hosts file.
So which, if any of the many possible domain names that getdomainname() returns depends on a whole raft of configuration issues. e.g. which IP address is configured to be the primary address, whether the hosts file is used in preference to DNS, whether the hosts file is correctly configured, whether the IP address has a reverse lookup set and lots of other issues.
For instance, it is fairly common to misconfigure the hosts file. If you see an entry in it like:
192.168.1.1 foohost foohost.example.com
that is wrong. The first host name on a line is the canonical name (for the interface) and subsequent entries are merely aliases. If you want the domain to come out as example.com rather than nothing, it needs to look like this:
192.168.1.1 foohost.example.com foohost
Also, every IP address on the Internet should ideally have a reverse lookup record in DNS which maps the IP address to a hostname and domain. However, there is no rule to say it has to exist or to say that it has to be the domain by which you SSH'd in or pointed your web browser at.
On any given computer, there are many reasons why the domain name is not what you expect.
Unfortunately this information is not always set correctly. First of all, complain to your system administrator.
If all that fails, with something like the following you may get a field res->ai_canonname with a canonical hostname and then also iterate over all IP addresses:
struct addrinfo *res = NULL;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME | (name ? 0 : AI_PASSIVE),
.ai_socktype = SOCK_STREAM,
};
getaddrinfo(name, NULL, &hints, &res);
for (struct addrinfo *p = res; p; p = p->ai_next) {
...
}
You'd then somehow have to select which ones are interesting for you (avoid loopback etc) and try to find a hostname corresponding to one of these IP addresses. But as IP addresses do not necessarily correspond to a valid hostname, this might fail also.
To get the hostname of the computer you are running the program on:
uname
/etc/hostname

Resources