! \brief * parses [proto:]host[:port] where proto= udp|tcp|tls * \return 0 on success and -1 on failure */
| 315 | * \return 0 on success and -1 on failure |
| 316 | */ |
| 317 | inline static int parse_phostport(char* s, int slen, char** host, int* hlen, |
| 318 | int* port, int* proto) |
| 319 | { |
| 320 | char* first; /* first ':' occurrence */ |
| 321 | char* second; /* second ':' occurrence */ |
| 322 | char* p; |
| 323 | int bracket; |
| 324 | str tmp; |
| 325 | char* end; |
| 326 | |
| 327 | first=second=0; |
| 328 | bracket=0; |
| 329 | end = s + slen; |
| 330 | |
| 331 | /* find the first 2 ':', ignoring possible ipv6 addresses |
| 332 | * (substrings between []) |
| 333 | */ |
| 334 | for(p=s; p<end ; p++){ |
| 335 | switch(*p){ |
| 336 | case '[': |
| 337 | bracket++; |
| 338 | if (bracket>1) goto error_brackets; |
| 339 | break; |
| 340 | case ']': |
| 341 | bracket--; |
| 342 | if (bracket<0) goto error_brackets; |
| 343 | break; |
| 344 | case ':': |
| 345 | if (bracket==0){ |
| 346 | if (first==0) first=p; |
| 347 | else if( second==0) second=p; |
| 348 | else goto error_colons; |
| 349 | } |
| 350 | break; |
| 351 | } |
| 352 | } |
| 353 | if (p==s) return -1; |
| 354 | if (*(p-1)==':') goto error_colons; |
| 355 | |
| 356 | if (first==0){ /* no ':' => only host */ |
| 357 | *host=s; |
| 358 | *hlen=(int)(p-s); |
| 359 | *port=0; |
| 360 | *proto=0; |
| 361 | return 0; |
| 362 | } |
| 363 | if (second){ /* 2 ':' found => check if valid */ |
| 364 | if (parse_proto((unsigned char*)s, first-s, proto)<0) |
| 365 | goto error_proto; |
| 366 | tmp.s = second+1; |
| 367 | tmp.len = end - tmp.s; |
| 368 | if (str2int( &tmp, (unsigned int*)port )==-1) goto error_port; |
| 369 | *host=first+1; |
| 370 | *hlen=(int)(second-*host); |
| 371 | return 0; |
| 372 | } |
| 373 | /* only 1 ':' found => it's either proto:host or host:port */ |
| 374 | tmp.s = first+1; |
no test coverage detected